Hi, I'm currently trying to implement a Jupyter Notebook-like editor for a small programming language i'm working on.
I'm using socketioxide, axum, and tokio to set up a server that can receive connections coming from the frontend of this project (made with React).
Every time a new client connects, an on_connect
function should run and should then wait for events from the client with the event name of "run". The first thing on_connect
does is create a hashmap that stores a user's environment for any variables they declare. if there is an assignment, like let a = 1 2 ; 3 4
, it will store "a" in the hashmap with the corresponding variable.
async fn on_connect(socket: SocketRef) {
info!("socket connected: {}{}{}", BLUE, socket.id, DFLT);
let mut env: HashMap<String, LalaType> = HashMap::new();
socket.on("run", move |s: SocketRef, Data::<Cell>(data)| {
info!("Received message from {}{}{}: {:?}", BLUE, s.id, DFLT, data);
let input = data.cell_text.trim();
let _ = data.auth.trim();
let ast = parser::parse(input).unwrap();
info!("env before interpreting: {:?}", env);
let response = interp(&ast, Some(&mut env), true).unwrap();
info!("env after interpreting: {:?}", env);
let output = CellOutput {
output: response
};
info!("Sending message to {}{}{}: {:?}", BLUE, s.id, DFLT, output);
let _ = s.emit("output", output);
});
}
you can see the full file here.
the problem is that the env hashmap does not persist across messages. so if i send a message like this:
run {cell_text: "let a = 1 2 ; 3 4", auth: "123"}
it will store it in the hashmap properly, and i can see the env is updated by my info!
print under the declaration of response
. however, if i then send a new message: run {cell_text: "a", auth: "123"}
it will show that the hashmap is empty before interpreting.
example output:
2024-04-28T21:03:29.485458Z INFO lala_bin: socket connected: PjUxAlEmQJgCQUlD
2024-04-28T21:03:30.934609Z INFO lala_bin: Received message from PjUxAlEmQJgCQUlD: Cell { auth: "123", cell_text: "let a = 1 2 3 ; 4 5 6 ; 7 8 9" }
2024-04-28T21:03:30.934766Z INFO lala_bin: env before interpreting: {}
2024-04-28T21:03:30.934792Z INFO lala_bin: env after interpreting: {"a": Matrix(Matrix { rows: 3, cols: 3, data: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] })}
2024-04-28T21:03:30.934805Z INFO lala_bin: Sending message to PjUxAlEmQJgCQUlD: CellOutput { output: "[1.00 2.00 3.00]\n[4.00 5.00 6.00]\n[7.00 8.00 9.00]\n" }
2024-04-28T21:03:32.069759Z INFO lala_bin: Received message from PjUxAlEmQJgCQUlD: Cell { auth: "123", cell_text: "a" }
2024-04-28T21:03:32.069869Z INFO lala_bin: env before interpreting: {}
thread 'tokio-runtime-worker' panicked at src/interp.rs:176:60:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
i've done some experimenting and even just declaring an i32 before socket.on()
and incrementing it in the closure doesn't seem to make the variable's new value stick. how can i make the closure update my hashmap and have these changes be reflected outside of the closure?