Implement UserData interning + websocket connect

This commit is contained in:
Condorra 2024-09-07 00:17:16 +10:00
parent 1df6e574d2
commit 466566a6c5
3 changed files with 62 additions and 27 deletions

41
src/id_intern.rs Normal file
View File

@ -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<A, Gc<'gc, A>>>);
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::<Rootable!['gcb => 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::<Rootable!['gcb => 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::<Rootable!['gcb => InternMapSingleton<'gcb, A>]>();
intern_map.0.borrow_mut(&ctx).remove(input);
}

View File

@ -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::<TermFrame>(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::<Rootable![TermFrame]>(&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::<Rootable![TermFrame]>()?
.downcast::<Rootable!['gcb => Gc<'gcb, TermFrame>]>()?
.as_ref()
.clone()),
}
}
fn wrap_socketid<'gc>(ctx: Context<'gc>, socket: &WebSocketId) -> Value<'gc> {
UserData::new::<Rootable![WebSocketId]>(&ctx, socket.clone()).into()
}
fn try_unwrap_socketid<'gc>(
ctx: Context<'gc>,
value: &Value<'gc>,
) -> Result<WebSocketId, piccolo::Error<'gc>> {
Ok(UserData::from_value(ctx, *value)?
.downcast::<Rootable![WebSocketId]>()?
.downcast::<Rootable!['gcb => 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)
})
}

View File

@ -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;