diff --git a/src/id_intern.rs b/src/id_intern.rs new file mode 100644 index 0000000..e187dea --- /dev/null +++ b/src/id_intern.rs @@ -0,0 +1,41 @@ +use std::collections::BTreeMap; + +use gc_arena::{lock::GcRefLock, Collect, Gc, Rootable}; +use piccolo::{Context, IntoValue, Singleton, UserData, Value}; + +#[derive(Collect)] +#[collect(no_drop)] +struct InternMapSingleton<'gc, A>(GcRefLock<'gc, BTreeMap>>); + +impl<'gc, A> Singleton<'gc> for InternMapSingleton<'gc, A> +where + A: Collect, +{ + fn create(ctx: Context<'gc>) -> Self { + InternMapSingleton(Gc::new(&ctx, Default::default())) + } +} + +pub fn intern_id<'gc, A>(ctx: Context<'gc>, input: A) -> Value<'gc> +where + A: Collect + Ord + Clone + 'static, +{ + let intern_map: &'gc InternMapSingleton<'gc, A> = + ctx.singleton:: InternMapSingleton<'gcb, A>]>(); + let gc_id = intern_map + .0 + .borrow_mut(&ctx) + .entry(input.clone()) + .or_insert_with(|| Gc::new(&ctx, input.clone())) + .clone(); + UserData::<'gc>::new:: Gc<'gcb, A>]>(&ctx, gc_id).into_value(ctx) +} + +pub fn unintern_id<'gc, A>(ctx: Context<'gc>, input: &A) +where + A: Collect + Ord + Clone + 'static, +{ + let intern_map: &InternMapSingleton<'gc, A> = + ctx.singleton:: InternMapSingleton<'gcb, A>]>(); + intern_map.0.borrow_mut(&ctx).remove(input); +} diff --git a/src/lua_state.rs b/src/lua_state.rs index 4207bad..b5dd855 100644 --- a/src/lua_state.rs +++ b/src/lua_state.rs @@ -1,5 +1,5 @@ use anyhow::Error; -use gc_arena::Rootable; +use gc_arena::{Gc, Rootable}; use piccolo::{ self, Callback, Closure, Context, Executor, FromValue, Function, IntoValue, Lua, StashedExecutor, StaticError, Table, UserData, Value, Variadic, @@ -11,6 +11,7 @@ use yew::UseStateSetter; use crate::{ command_handler::debrace, echo_to_term_frame, + id_intern::intern_id, websocket::{connect_websocket, send_message_to_mud, WebSocketId}, GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, TermFrame, }; @@ -36,7 +37,7 @@ impl LuaState { info_table.set( ctx, ctx.intern_static(b"current_frame"), - wrap_frame(ctx, frame), + intern_id::(ctx, frame.clone()), )?; Ok(()) }) @@ -120,6 +121,7 @@ pub fn install_lua_globals( register_command!(echo); register_command!(echo_frame); register_command!(echo_frame_raw); + register_command!(connect_mud); register_command!(sendmud_raw); register_command!(hsplit); register_command!(panel_merge); @@ -281,10 +283,6 @@ fn panel_merge<'gc>( }) } -fn wrap_frame<'gc>(ctx: Context<'gc>, frame: &TermFrame) -> Value<'gc> { - UserData::new::(&ctx, frame.clone()).into() -} - fn try_unwrap_frame<'gc>( ctx: Context<'gc>, value: &Value<'gc>, @@ -292,21 +290,19 @@ fn try_unwrap_frame<'gc>( match u64::from_value(ctx, *value) { Ok(v) => Ok(TermFrame(v)), Err(_) => Ok(UserData::from_value(ctx, *value)? - .downcast::()? + .downcast:: Gc<'gcb, TermFrame>]>()? + .as_ref() .clone()), } } -fn wrap_socketid<'gc>(ctx: Context<'gc>, socket: &WebSocketId) -> Value<'gc> { - UserData::new::(&ctx, socket.clone()).into() -} - fn try_unwrap_socketid<'gc>( ctx: Context<'gc>, value: &Value<'gc>, ) -> Result> { Ok(UserData::from_value(ctx, *value)? - .downcast::()? + .downcast:: Gc<'gcb, WebSocketId>]>()? + .as_ref() .clone()) } @@ -324,7 +320,7 @@ pub fn handle_websocket_output( ctx.fetch(&engine.exec).restart( ctx, input_fn, - (wrap_socketid(ctx, socket), ctx.intern(input)), + (intern_id(ctx, socket.clone()), ctx.intern(input)), ); Ok(()) }) @@ -353,7 +349,7 @@ pub fn handle_websocket_close(socket: &WebSocketId, engine: &mut LuaState) -> Re let input_fn = Function::from_value(ctx, handlers.get(ctx, ctx.intern_static(b"mudclose")))?; ctx.fetch(&engine.exec) - .restart(ctx, input_fn, wrap_socketid(ctx, socket)); + .restart(ctx, input_fn, intern_id(ctx, socket.clone())); Ok(()) }) .map_err(|err| format!("{}", err))?; @@ -394,7 +390,7 @@ fn connect_mud<'gc>( ) -> Callback<'gc> { let global_memo = global_memo.clone(); Callback::from_fn(&ctx, move |ctx, _ex, mut stack| { - let trusted: bool = false; + let mut trusted: bool = false; let name: String = loop { let v: String = stack.from_front(ctx)?; if v == "-trust" { @@ -413,20 +409,17 @@ fn connect_mud<'gc>( } let url: String = stack.from_front(ctx)?; - let new_socket = connect_websocket( - trusted, - &url, - &mut global_memo.ws_registry.borrow_mut(), - &global_memo, - )?; + let new_socket = intern_id( + ctx, + connect_websocket( + trusted, + &url, + &mut global_memo.ws_registry.borrow_mut(), + &global_memo, + )?, + ); - ctx.registry.singleton() - muds.set(ctx, name, new_socket)?; - - let mud: WebSocketId = try_unwrap_socketid(ctx, &stack.pop_front())?; - let msg: piccolo::String = stack.from_front(ctx)?; - send_message_to_mud(&mud, msg.as_bytes(), &global_memo)?; Ok(piccolo::CallbackReturn::Return) }) } diff --git a/src/main.rs b/src/main.rs index 2f833db..8d73fdf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use term_split::TermSplit; use yew::prelude::*; pub mod command_handler; +pub mod id_intern; pub mod lineengine; pub mod lua_state; pub mod parsing;