Skip to content

Instantly share code, notes, and snippets.

@matthunz
Created November 7, 2024 19:03
Show Gist options
  • Save matthunz/7bd56646ce05f0cd738dd55b4f8b74aa to your computer and use it in GitHub Desktop.
Save matthunz/7bd56646ce05f0cd738dd55b4f8b74aa to your computer and use it in GitHub Desktop.
use std::{
cell::{RefCell, UnsafeCell},
mem,
ops::Deref,
};
fn main() {
let c = Component::new(app);
let mut scope = Scope::new(c);
scope.run();
}
fn app<'a>(scope: &'a Scope) -> Option<Component<'a>> {
let x = scope.use_state(|| String::new());
Some(Component::new(|_: &'a Scope| {
dbg!(&*x.read());
x.write(|s| s.push('x'));
None
}))
}
pub struct Ref<'a, T> {
value: &'a T,
}
impl<T> Deref for Ref<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
pub struct State<T> {
value: T,
}
impl<T> State<T> {
pub fn read(&self) -> Ref<T> {
Ref { value: &self.value }
}
pub fn write(&self, f: impl FnOnce(&mut T) + 'static) {
todo!()
}
}
pub struct Scope {
component: Component<'static>,
next: Option<Box<Self>>,
states: RefCell<Vec<*mut ()>>,
}
impl Scope {
pub fn new(component: Component<'_>) -> Self {
Self {
component: unsafe { mem::transmute(component) },
next: None,
states: RefCell::new(Vec::new()),
}
}
pub fn run(&mut self) {
let r = self as *mut Scope;
self.component.run(unsafe { mem::transmute(&mut *r) });
}
pub fn use_state<'a, T: 'a>(&'a self, make_value: impl FnOnce() -> T) -> &'a State<T> {
let mut states = self.states.borrow_mut();
let boxed = Box::new(State {
value: make_value(),
});
states.push(Box::into_raw(boxed) as _);
let ptr = *states.last().unwrap();
drop(states);
unsafe { &mut *(ptr as *mut State<T>) }
}
}
pub struct Component<'a> {
f: Box<dyn Fn(&'a mut Scope)>,
}
impl<'a> Component<'a> {
pub fn new(f: impl Fn(&'a Scope) -> Option<Component<'a>> + 'a) -> Self {
let f: Box<dyn Fn(&mut Scope)> = Box::new(move |scope| {
let scope_ref = unsafe { mem::transmute(&*scope) };
let content = f(scope_ref);
if let Some(content) = content {
scope.next = Some(Box::new(Scope {
component: unsafe { mem::transmute(content) },
next: None,
states: RefCell::new(Vec::new()),
}));
let r = (&mut **scope.next.as_mut().unwrap()) as *mut Scope;
scope
.next
.as_ref()
.unwrap()
.component
.run(unsafe { &mut *r });
}
});
Self {
f: unsafe { mem::transmute(f) },
}
}
pub fn run(&self, scope: &'a mut Scope) {
(self.f)(scope);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment