#How can I retain the same memory address between lua instances??

111 messages · Page 1 of 1 (latest)

sinful quarry
#

this is my functions.rs

use crate::app::telnet::TelnetClient;
use egui::Color32;
use mlua::prelude::*;
use std::sync::{Arc, Mutex};

pub struct LuaFunctions {
    telnet_client: Arc<Mutex<TelnetClient>>,
}

impl LuaFunctions {
    // Method for the print function
    pub fn print(&self, text: String) -> LuaResult<()> {
        println!("this is being called");
        let mut telnet_client = self.telnet_client.lock().unwrap();
        telnet_client.append_text(&text, Color32::WHITE);
        Ok(())
    }

    // Method for the color_print function
    pub fn color_print(&self, (text, color): (String, String)) -> LuaResult<()> {
        let color = match color.as_str() {
            "red" => Color32::RED,
            "green" => Color32::GREEN,
            "blue" => Color32::BLUE,
            _ => Color32::WHITE,
        };
        let mut telnet_client = self.telnet_client.lock().unwrap();
        telnet_client.append_text(&text, color);
        Ok(())
    }
}

// Function to initialize and expose the functions to Lua
pub fn init_lua(lua: &Lua, telnet_client: Arc<Mutex<TelnetClient>>) -> LuaResult<()> {
    println!("Initializing Lua environment with custom print functions...");
    println!("Lua instance address in init_lua: {:p}", lua);

    let print_functions = LuaFunctions {
        telnet_client: telnet_client.clone(),
    };
    let color_print_functions = LuaFunctions { telnet_client };

    let globals = lua.globals();
    let print_function = lua.create_function(move |_, text: String| print_functions.print(text))?;
    globals.set("print", print_function)?;
    println!("Custom print function set in Lua environment.");
    let test_script = r#"
    print("Hello from Lua!")
    test_value = (test_value or 0) + 1
    print('Test value:', test_value)
"#;

    match lua.load(test_script).exec() {
        Ok(_) => println!("Test script executed successfully."),
        Err(e) => println!("Error executing test script: {:?}", e),
    }

    let color_print_function = lua.create_function(move |_, args: (String, String)| {
        color_print_functions.color_print(args)
    })?;
    globals.set("color_print", color_print_function)?;
    println!("Custom color_print function set in Lua environment.");

    println!("Lua environment initialized successfully.");

    Ok(())
}

#

posting the next portion right meow

#

this is in my app.rs

use std::cell::RefCell;
pub mod ansi_color;
pub mod functions;
mod miniwindow;
mod styles;
pub mod telnet;
use crate::app::functions::init_lua;
use crate::app::telnet::TelnetClient;
use egui::Color32;
use egui::TextBuffer;
use miniwindow::WindowResizeTest;
use mlua::{Function, Lua};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::Instant;
#[derive(serde::Deserialize, serde::Serialize, Default)]
#[serde(default)]
pub struct TemplateApp {
    label: String,
    value: f32,
    window_resize_test: WindowResizeTest,
    #[serde(skip)]
    telnet_client: telnet::TelnetClient,
    show_connection_prompt: RefCell<bool>, // Using RefCell
    ip_address: String,
    port: u16,
    command: String,
    command_history: Vec<String>,
    current_history_index: usize,
    fps: f64,
    #[serde(skip)]
    last_frame_time: Option<Instant>,
    #[serde(skip)]
    last_frame_update: Option<Instant>,
    #[serde(skip)]
    frame_durations: VecDeque<f64>, // Use VecDeque for efficient push/pop operations
    #[serde(skip)]
    last_update_time: Option<Instant>,
    show_lua_execution_window: RefCell<bool>,
    #[serde(skip)]
    lua: Lua,
    lua_code: String,
    lua_output_buffer: Arc<Mutex<String>>,
}

impl TemplateApp {
    pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
        println!("Creating new TemplateApp instance");
        // Set the custom style
        let style = styles::default_style();
        cc.egui_ctx.set_style(style);

        let font = styles::custom_font();
        cc.egui_ctx.set_fonts(font);

        // Create a new TelnetClient instance wrapped in an Arc<Mutex>
        let telnet_client = Arc::new(Mutex::new(TelnetClient::new()));

        // Create a new Lua instance
        let lua = Lua::new();
        println!("Lua instance address in TemplateApp: {:p}", &lua);

        // Initialize the Lua environment with custom print functions
        if let Err(err) = init_lua(&lua, telnet_client.clone()) {
            eprintln!("Failed to initialize Lua: {:?}", err);
            panic!("Failed to initialize Lua");
        }
        // Create a new TemplateApp instance
        let app = TemplateApp {
            label: "Hello World!".to_owned(),
            value: 2.7,
            window_resize_test: WindowResizeTest::new(),
            telnet_client: telnet::TelnetClient::new(),
            show_connection_prompt: RefCell::new(false),
            ip_address: "127.0.0.1".to_owned(),
            port: 23,
            command: String::new(),
            command_history: Vec::new(),
            current_history_index: 0,
            fps: 0.0,
            last_frame_time: None,
            last_frame_update: None,
            frame_durations: VecDeque::with_capacity(10),
            last_update_time: None,
            show_lua_execution_window: RefCell::new(false),
            lua,
            lua_code: String::new(),
            lua_output_buffer: Arc::new(Mutex::new(String::new())),
        };

        // Initialize the rest, if needed
        if let Some(storage) = cc.storage {
            return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();
        }

        app
    }
}

#
impl eframe::App for TemplateApp {
    fn save(&mut self, storage: &mut dyn eframe::Storage) {
        eframe::set_value(storage, eframe::APP_KEY, self);
    }

    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        let menus: &[(&str, Vec<(&str, Box<dyn Fn(&mut Self, &egui::Context)>)>)] = &[
            (
                "File",
                vec![(
                    "Quit",
                    Box::new(|_, ctx| ctx.send_viewport_cmd(egui::ViewportCommand::Close)),
                )],
            ),
            (
                "Connection",
                vec![(
                    "New",
                    Box::new(|s, _| {
                        s.show_connection_prompt.replace(true);
                    }),
                )],
            ),
        ];
        println!("Lua instance address in eframe: {:p}", &self.lua);
        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
            egui::menu::bar(ui, |ui| {
                for &(menu_name, ref submenus) in menus {
                    ui.menu_button(menu_name, |ui| {
                        for &(submenu_name, ref action) in submenus {
                            if ui.button(submenu_name).clicked() {
                                action(self, ctx);
                            }
                        }
                    });
                }
                ui.add_space(16.0);
                egui::widgets::global_dark_light_mode_buttons(ui);
            });
        });
#

these are the relevant portions of my app.rs... the main issue at hand is the reference to lua in the update function

#
Creating new TemplateApp instance
Lua instance address in TemplateApp: 0x7ffd6b5733f8
Initializing Lua environment with custom print functions...
Lua instance address in init_lua: 0x7ffd6b5733f8
Custom print function set in Lua environment.
this is being called
Appending to Telnet: Hello from Lua!
this is being called
Appending to Telnet: Test value:
Test script executed successfully.
Custom color_print function set in Lua environment.
Lua environment initialized successfully.
Lua instance address in eframe: 0x6238af853510
#

when we create our lua instance in templateapp and init we have a specific memory address and later when we try to access the lua instance in the update function using self.lua the address is different.

#

does anyone have a good solution to overcome this?

pallid scarab
#

You're moving around this lua variable, specifically when creating the app variable in TemplateApp::new(). It having a different address is expected and shouldn't affect its behavior, right?

finite mist
#

Unless there are Pins involved, in which case you'd know, all Rust values are trivially movable and will move around

#

What are you doing to need self.lua (which, I should clarify, is not the memory that the lua code has access to. It's the handle to the lua instance) to stay in a single place?

sinful quarry
#

hmmmm

#

the print function seen in the functions.rs can't be called from within the app.rs... but if i call it from within init_lua (like i did with the test script) it works..

that likely means the lua instance in app.rs is not the same as the lua instance in init_lua

#

which is true, @finite mist as the memory address proves that to be true

finite mist
sinful quarry
#

im a newbie thats why im trying to learn btw

#

oh okay

finite mist
#

A value having moved does not make it a different value

#

It just makes it the same value somewhere else

sinful quarry
#

hmmmm

finite mist
#

Of course, it's possible that you're actually accidentally throwing away your lua handle. What does init_lua look like? Do you ever call Lua::new somewhere else?

sinful quarry
#

i dont get why i cant call the print function from within the app.rs then. the main issue at hand is executing the print function from within the lua execution window

#
use crate::app::telnet::TelnetClient;
use egui::Color32;
use mlua::prelude::*;
use std::sync::{Arc, Mutex};

pub struct LuaFunctions {
    telnet_client: Arc<Mutex<TelnetClient>>,
}

impl LuaFunctions {
    // Method for the print function
    pub fn print(&self, text: String) -> LuaResult<()> {
        println!("this is being called");
        let mut telnet_client = self.telnet_client.lock().unwrap();
        telnet_client.append_text(&text, Color32::WHITE);
        Ok(())
    }

    // Method for the color_print function
    pub fn color_print(&self, (text, color): (String, String)) -> LuaResult<()> {
        let color = match color.as_str() {
            "red" => Color32::RED,
            "green" => Color32::GREEN,
            "blue" => Color32::BLUE,
            _ => Color32::WHITE,
        };
        let mut telnet_client = self.telnet_client.lock().unwrap();
        telnet_client.append_text(&text, color);
        Ok(())
    }
}

// Function to initialize and expose the functions to Lua
pub fn init_lua(lua: &Lua, telnet_client: Arc<Mutex<TelnetClient>>) -> LuaResult<()> {
    println!("Initializing Lua environment with custom print functions...");
    println!("Lua instance address in init_lua: {:p}", lua);

    let print_functions = LuaFunctions {
        telnet_client: telnet_client.clone(),
    };
    let color_print_functions = LuaFunctions { telnet_client };

    let globals = lua.globals();
    let print_function = lua.create_function(move |_, text: String| print_functions.print(text))?;
    globals.set("print", print_function)?;
    println!("Custom print function set in Lua environment.");
    let test_script = r#"
    print("Hello from Lua!")
    test_value = (test_value or 0) + 1
    print('Test value:', test_value)
"#;

    match lua.load(test_script).exec() {
        Ok(_) => println!("Test script executed successfully."),
        Err(e) => println!("Error executing test script: {:?}", e),
    }

    let color_print_function = lua.create_function(move |_, args: (String, String)| {
        color_print_functions.color_print(args)
    })?;
    globals.set("color_print", color_print_function)?;
    println!("Custom color_print function set in Lua environment.");

    println!("Lua environment initialized successfully.");

    Ok(())
}
#

init_lua is seen here

#

and it's called in the app.rs in the templateapp impl (fn new)

        let lua = Lua::new();
        println!("Lua instance address in TemplateApp: {:p}", &lua);

        // Initialize the Lua environment with custom print functions
        if let Err(err) = init_lua(&lua, telnet_client.clone()) {
            eprintln!("Failed to initialize Lua: {:?}", err);
            panic!("Failed to initialize Lua");
        }
#

of note is this portion here, i think, hold on

#

this is where i execute the lua code itself

                                if ui.button("Execute").clicked() {
                                    match self.lua.load(&self.lua_code).exec() {
                                        Ok(_) => {
                                            println!(
                                                "Lua instance address in Execute: {:p}",
                                                &self.lua
                                            );

                                            // Send success message to Telnet client
                                            self.telnet_client.append_text(
                                                "Lua code executed successfully.\n",
                                                Color32::GREEN,
                                            );
                                        }
                                        Err(e) => {
                                            // Send error message to Telnet client
                                            let error_message =
                                                format!("Error executing Lua code: {}\n", e);
                                            self.telnet_client
                                                .append_text(&error_message, Color32::RED);
                                        }
                                    }
                                }
finite mist
#

Hmm. Not very familiar with lua, but I can make a shot in the dark: Inside init_lua, You're sure you're calling your own print function and not accidentally calling the print builtin, right?

sinful quarry
#

oh im indeed calling the print function. its printed in the terminal

#
Creating new TemplateApp instance
Lua instance address in TemplateApp: 0x7ffd6b5733f8
Initializing Lua environment with custom print functions...
Lua instance address in init_lua: 0x7ffd6b5733f8
Custom print function set in Lua environment.
this is being called
Appending to Telnet: Hello from Lua!
this is being called
Appending to Telnet: Test value:
Test script executed successfully.
Custom color_print function set in Lua environment.
Lua environment initialized successfully.
Lua instance address in eframe: 0x6238af853510
#

"this is being called" is from the print function seen in the functions.rs file

#

which is meant to be called from using print("hello") in the lua execution window

finite mist
#

Hmm. Yes, you're calling your own function, this is fair.

sinful quarry
#

the function is currently not working as intended when being called from the window, but as seen

#

if i call it in the init_lua itself

#

it works

#

which is weird, to me

#

and thats why im trying to find out why and learn why xD

#

i do have a public repo if you want to have a poke at it

#

i can just push the existing version.

finite mist
# sinful quarry which is weird, to me

Yes, I understand the issue, you only said it three times 😄 and it is weird.

Unfortunately I'm at work, so I can't poke at a repo, but I can suggest trying to figure out exactly when the function disappears: take your little test script and run it a bunch of times in a bunch of places, and see when it starts failing

sinful quarry
#

xD

#

its ok!

#

yeah i did that and

#

hmmm

#

ill try printing something else instead of the memory address

finite mist
sinful quarry
#

which instance

#

if i execute code in the lua window, it prints

#

but it does not acknowledge or trigger the print function that's specified in functions.rs

#

which is meant to print in the telnet window, instead of the terminal

finite mist
#

And that makes it four times you said that

sinful quarry
#

xD

#

no but

#

its meant to convey the print to the telnet window

finite mist
#

Wait hang on

sinful quarry
#

i just wanted to be clear because its a lot to take in

finite mist
#

Are you trying to have println! write to something other than the terminal?

sinful quarry
#

im not, but that would be nice

#

im having print, a function ive defined, print to the telnet window

#

in a perfect world i could just redirect stdout to the telnet window but thats not what im trying to do right now

finite mist
#

And this brings us back to the previous question

finite mist
# sinful quarry yeah i did that and

Then surely you can say which specific line of code has the property that the print function works before it but doesn't work after it. Can you post that line of code?

sinful quarry
#

thats the main issue at hand right now i guess

finite mist
#

But which specific line of code does it stop working on

sinful quarry
#

i can check, but its never called outside of the init_lua function, unless called in the lua execution window

#

but i can try calling it before that

#

that wont fire off any debug message

#

if i dump that in the update fn it does work. ill keep going down the line

#

yeah if i call it in the templateapp impl it will work

        // Initialize the Lua environment with custom print functions
        if let Err(err) = init_lua(&lua, telnet_client.clone()) {
            eprintln!("Failed to initialize Lua: {:?}", err);
            panic!("Failed to initialize Lua");
        }

        // Call the print function directly (for testing)
        if let Err(err) = lua
            .load(r#"print("Direct call from TemplateApp::new")"#)
            .exec()
        {
            eprintln!("Error calling print function directly: {:?}", err);
        }
#

if i call it in the update function using

        // Call the print function directly (for testing)
        if let Err(err) = self.lua.load(r#"print("Direct call from update")"#).exec() {
            eprintln!("Error calling print function directly: {:?}", err);
        }

it does not indeed Actually call it

#

and the only real difference is the lua vs self.lua

terse burrow
#

if you are really paranoid about the address thing you could make the variable a Box<Lua> to ensure the Lua stays put

#

then if lua: Box<Lua> and you print the value of lua.as_ref() it should be the same no matter how many times you move the box

#

however it would be really weird if this makes a difference and I would consider it a bug in mlua

#

it's more likely that you yourself are somehow creating a different instance

#

why does TemplateApp implement Serialize and Deserialize?

#

you are probably somehow creating a different instance of TemplateApp without using TemplateApp::new()

#

maybe via TemplateApp::default() or via serde

#

you should probably remove the serde and default impls as they do not really make sense

#

since the TemplateApp is useless if not created via new

sinful quarry
#

thanks @terse burrow ill try

sinful quarry
#

none of this worked

#

what do you think about moving the lua instance to the main function instead of templateapp impl

#

there are tons of debug prints in now

#

you can see when "this is being called" is called, and not called, which will denote the custom print function in functions.rs is being called.
in the update function it can't be called no matter what i try. I've actually tried moving the lua instance to the main function as well, I've been flailing on this for a couple of days now and nothing has seemed to work.

#

the issue is definitely something about the lua instance not being the same

#

ive done all kinds of tests to prove that this is definitely the case, i just dont know why or how to solve that issue

terse burrow
#

You didn't remove the default and serde impls

#

Please remove them

#

From TemplateApp

sinful quarry
#

I tried that to no avail though. Heh.

#

So I reverted.

#

i need those anyway for the functionality of the eframe library with saving and loading the app state, right? @terse burrow

#

the only issue im facing is that the instance of lua is somehow not the same, but the templateapp is NOT being recreated more than once or i'd see the print about it

terse burrow
#

No you wouldn't

#

If the app is created by serde or by default new will not be called

#

There's also this

if let Some(storage) = cc.storage {
            return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();
        }
#

In some cases you just... don't return the instance you just created?

#

Idk if that's normal

sinful quarry
#

that is normal

#

that's part of the eframe code to restore state

#

@terse burrow i found out if i move all of the lua creation shit into the update function (which is bad) it works properly

#

so right now im trying to init lua in main again and uhhhhh

#

remove lua from the templateapp struct