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); }