wip: recoil
This commit is contained in:
1 parent
3cfa1fe125
commit
ee67654f58
31 files changed
+1369
-235
No files matched your search
@@ -32,3 +32,109 @@ impl Properties for () {
|
||||
pub fn fc_to_builder<T: Properties>(_f: FC<T>) -> T::Builder {
|
||||
T::builder()
|
||||
}
|
||||
|
||||
mod testing {
|
||||
use std::any::Any;
|
||||
|
||||
// trait PossibleProps {
|
||||
// type POut: PartialEq;
|
||||
// fn as_partial_eq(&self) -> Option<&Self::POut> {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<T: PartialEq> PossibleProps for T {
|
||||
// type POut = Self;
|
||||
// }
|
||||
|
||||
// struct SomeProps2<'a> {
|
||||
// inner: &'a str,
|
||||
// }
|
||||
|
||||
// Fallback trait for to all types to default to `false`.
|
||||
trait NotEq {
|
||||
const IS_EQ: bool = false;
|
||||
}
|
||||
impl<T> NotEq for T {}
|
||||
|
||||
// Concrete wrapper type where `IS_COPY` becomes `true` if `T: Copy`.
|
||||
struct IsEq<G, T>(std::marker::PhantomData<(G, T)>);
|
||||
|
||||
impl<G: PartialEq, T: PartialEq<G>> IsEq<G, T> {
|
||||
// Because this is implemented directly on `IsCopy`, it has priority over
|
||||
// the `NotCopy` trait impl.
|
||||
//
|
||||
// Note: this is a *totally different* associated constant from that in
|
||||
// `NotCopy`. This does not specialize the `NotCopy` trait impl on `IsCopy`.
|
||||
const IS_EQ: bool = true;
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct SomeProps {
|
||||
inner: &'static str,
|
||||
}
|
||||
|
||||
struct SomeProps2 {
|
||||
inner: &'static str,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let g = IsEq::<SomeProps, SomeProps>::IS_EQ;
|
||||
|
||||
// let g = IsEq::<Vec<u32>>::IS_COPY;
|
||||
// let g = IsEq::<u32>::IS_COPY;
|
||||
// dbg!(g);
|
||||
|
||||
// let props = SomeProps { inner: "asd" };
|
||||
|
||||
// let intermediate: Box<dyn PartialEq<SomeProps>> = Box::new(props);
|
||||
// let as_any: Box<dyn Any> = Box::new(intermediate);
|
||||
|
||||
// let as_partialeq = as_any
|
||||
// .downcast_ref::<Box<dyn PartialEq<SomeProps>>>()
|
||||
// .unwrap();
|
||||
}
|
||||
|
||||
// struct blah {}
|
||||
// #[reorder_args]
|
||||
pub fn blah(a: i32, b: &str, c: &str) {}
|
||||
|
||||
// pub mod blah {
|
||||
// pub const a: u8 = 0;
|
||||
// pub const b: u8 = 1;
|
||||
// }
|
||||
|
||||
trait Eat {}
|
||||
impl Eat for fn() {}
|
||||
impl<T> Eat for fn(T) {}
|
||||
impl<T, K> Eat for fn(T, K) {}
|
||||
|
||||
mod other {
|
||||
use super::blah;
|
||||
fn test2() {
|
||||
// rsx!{
|
||||
// div {
|
||||
// Ele {
|
||||
// a: 10,
|
||||
// b: "asd"
|
||||
// c: impl Fn() -> ()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// becomes
|
||||
|
||||
// const reorder: fn(_, _) = |a, b| {};
|
||||
// blah::META;
|
||||
// let a = 10;
|
||||
// let b = "asd";
|
||||
// let g = [10, 10.0];
|
||||
// let c = g.a;
|
||||
|
||||
// blah(10, "asd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod style {}
|
||||
+40
-21
@@ -10,6 +10,8 @@ pub use use_reducer_def::use_reducer;
|
||||
pub use use_ref_def::use_ref;
|
||||
pub use use_state_def::use_state;
|
||||
|
||||
use crate::innerlude::Context;
|
||||
|
||||
mod use_state_def {
|
||||
use crate::innerlude::*;
|
||||
use std::{
|
||||
@@ -213,26 +215,31 @@ mod use_ref_def {
|
||||
use crate::innerlude::*;
|
||||
use std::{cell::RefCell, ops::DerefMut};
|
||||
|
||||
pub struct UseRef<T: 'static> {
|
||||
_current: RefCell<T>,
|
||||
}
|
||||
impl<T: 'static> UseRef<T> {
|
||||
fn new(val: T) -> Self {
|
||||
Self {
|
||||
_current: RefCell::new(val),
|
||||
}
|
||||
}
|
||||
// pub struct UseRef<T: 'static> {
|
||||
// _current: RefCell<T>,
|
||||
// }
|
||||
// impl<T: 'static> UseRef<T> {
|
||||
// fn new(val: T) -> Self {
|
||||
// Self {
|
||||
// _current: RefCell::new(val),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn modify(&self, modifier: impl FnOnce(&mut T)) {
|
||||
let mut val = self._current.borrow_mut();
|
||||
let val_as_ref = val.deref_mut();
|
||||
modifier(val_as_ref);
|
||||
}
|
||||
// pub fn set(&self, new: T) {
|
||||
// let mut val = self._current.borrow_mut();
|
||||
// *val = new;
|
||||
// }
|
||||
|
||||
pub fn current(&self) -> std::cell::Ref<'_, T> {
|
||||
self._current.borrow()
|
||||
}
|
||||
}
|
||||
// pub fn modify(&self, modifier: impl FnOnce(&mut T)) {
|
||||
// let mut val = self._current.borrow_mut();
|
||||
// let val_as_ref = val.deref_mut();
|
||||
// modifier(val_as_ref);
|
||||
// }
|
||||
|
||||
// pub fn current(&self) -> std::cell::Ref<'_, T> {
|
||||
// self._current.borrow()
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Store a mutable value between renders!
|
||||
/// To read the value, borrow the ref.
|
||||
@@ -240,10 +247,10 @@ mod use_ref_def {
|
||||
/// Modifications to this value do not cause updates to the component
|
||||
/// Attach to inner context reference, so context can be consumed
|
||||
pub fn use_ref<'a, T: 'static>(
|
||||
ctx: &'_ Context<'a>,
|
||||
ctx: Context<'a>,
|
||||
initial_state_fn: impl FnOnce() -> T + 'static,
|
||||
) -> &'a UseRef<T> {
|
||||
ctx.use_hook(|| UseRef::new(initial_state_fn()), |state| &*state, |_| {})
|
||||
) -> &'a RefCell<T> {
|
||||
ctx.use_hook(|| RefCell::new(initial_state_fn()), |state| &*state, |_| {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,3 +346,15 @@ mod use_reducer_def {
|
||||
// };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_is_initialized(ctx: Context) -> bool {
|
||||
let val = use_ref(ctx, || false);
|
||||
match *val.borrow() {
|
||||
true => true,
|
||||
false => {
|
||||
//
|
||||
*val.borrow_mut() = true;
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,5 +142,15 @@ pub mod prelude {
|
||||
pub use crate::diff::DiffMachine;
|
||||
|
||||
pub use crate::debug_renderer::DebugRenderer;
|
||||
pub use crate::dioxus_main;
|
||||
pub use crate::hooks::*;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! dioxus_main {
|
||||
($i:ident) => {
|
||||
fn main() {
|
||||
todo!("this macro is a placeholder for launching a dioxus app on different platforms. \nYou probably don't want to use this, but it's okay for small apps.")
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//! Dedicated styling system for Components
|
||||
//! ---------------------------------------
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
|
||||
enum Styles {
|
||||
background,
|
||||
backgroundAttachment,
|
||||
backgroundColor,
|
||||
backgroundImage,
|
||||
backgroundPosition,
|
||||
backgroundRepeat,
|
||||
border,
|
||||
borderBottom,
|
||||
borderBottomColor,
|
||||
borderBottomStyle,
|
||||
borderBottomWidth,
|
||||
borderColor,
|
||||
borderLeft,
|
||||
borderLeftColor,
|
||||
borderLeftStyle,
|
||||
borderLeftWidth,
|
||||
borderRight,
|
||||
borderRightColor,
|
||||
borderRightStyle,
|
||||
borderRightWidth,
|
||||
borderStyle,
|
||||
borderTop,
|
||||
borderTopColor,
|
||||
borderTopStyle,
|
||||
borderTopWidth,
|
||||
borderWidth,
|
||||
clear,
|
||||
clip,
|
||||
color,
|
||||
cursor,
|
||||
display,
|
||||
filter,
|
||||
cssFloat,
|
||||
font,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontVariant,
|
||||
fontWeight,
|
||||
height,
|
||||
left,
|
||||
letterSpacing,
|
||||
lineHeight,
|
||||
listStyle,
|
||||
listStyleImage,
|
||||
listStylePosition,
|
||||
listStyleType,
|
||||
margin,
|
||||
marginBottom,
|
||||
marginLeft,
|
||||
marginRight,
|
||||
marginTop,
|
||||
overflow,
|
||||
padding,
|
||||
paddingBottom,
|
||||
paddingLeft,
|
||||
paddingRight,
|
||||
paddingTop,
|
||||
pageBreakAfter,
|
||||
pageBreakBefore,
|
||||
position,
|
||||
strokeDasharray,
|
||||
strokeDashoffset,
|
||||
textAlign,
|
||||
textDecoration,
|
||||
textIndent,
|
||||
textTransform,
|
||||
top,
|
||||
verticalAlign,
|
||||
visibility,
|
||||
width,
|
||||
zIndex,
|
||||
}
|
||||
@@ -24,7 +24,6 @@ use bumpalo::Bump;
|
||||
use generational_arena::Arena;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::{Borrow, BorrowMut},
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
fmt::Debug,
|
||||
@@ -130,7 +129,7 @@ impl VirtualDom {
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
/// ```
|
||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
let mut components = ScopeArena::new(Arena::new());
|
||||
let components = ScopeArena::new(Arena::new());
|
||||
|
||||
// Normally, a component would be passed as a child in the RSX macro which automatically produces OpaqueComponents
|
||||
// Here, we need to make it manually, using an RC to force the Weak reference to stick around for the main scope.
|
||||
@@ -522,7 +521,7 @@ impl Scope {
|
||||
// Therefore, their lifetimes are connected exclusively to the virtual dom
|
||||
fn new<'creator_node>(
|
||||
caller: Weak<OpaqueComponent<'creator_node>>,
|
||||
myidx: ScopeIdx,
|
||||
arena_idx: ScopeIdx,
|
||||
parent: Option<ScopeIdx>,
|
||||
height: u32,
|
||||
event_queue: EventQueue,
|
||||
@@ -531,7 +530,7 @@ impl Scope {
|
||||
log::debug!(
|
||||
"New scope created, height is {}, idx is {:?}",
|
||||
height,
|
||||
myidx
|
||||
arena_idx
|
||||
);
|
||||
|
||||
// The function to run this scope is actually located in the parent's bump arena.
|
||||
@@ -544,7 +543,7 @@ impl Scope {
|
||||
// this is a bit of a hack, but will remain this way until we've figured out a cleaner solution.
|
||||
//
|
||||
// Not the best solution, so TODO on removing this in favor of a dedicated resource abstraction.
|
||||
let broken_caller = unsafe {
|
||||
let caller = unsafe {
|
||||
std::mem::transmute::<
|
||||
Weak<OpaqueComponent<'creator_node>>,
|
||||
Weak<OpaqueComponent<'static>>,
|
||||
@@ -552,18 +551,18 @@ impl Scope {
|
||||
};
|
||||
|
||||
Self {
|
||||
shared_contexts: Default::default(),
|
||||
caller: broken_caller,
|
||||
hooks: RefCell::new(Vec::new()),
|
||||
frames: ActiveFrame::new(),
|
||||
listeners: Default::default(),
|
||||
hookidx: Default::default(),
|
||||
children: Default::default(),
|
||||
caller,
|
||||
parent,
|
||||
arena_idx: myidx,
|
||||
arena_idx,
|
||||
height,
|
||||
event_queue,
|
||||
arena_link,
|
||||
frames: ActiveFrame::new(),
|
||||
hooks: Default::default(),
|
||||
shared_contexts: Default::default(),
|
||||
listeners: Default::default(),
|
||||
hookidx: Default::default(),
|
||||
children: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,8 +593,8 @@ impl Scope {
|
||||
.upgrade()
|
||||
.ok_or(Error::FatalInternal("Failed to get caller"))?;
|
||||
|
||||
// Cast the caller ptr from static to one with our own reference
|
||||
let new_head = unsafe {
|
||||
// Cast the caller ptr from static to one with our own reference
|
||||
std::mem::transmute::<&OpaqueComponent<'static>, &OpaqueComponent<'sel>>(
|
||||
caller.as_ref(),
|
||||
)
|
||||
@@ -621,7 +620,7 @@ impl Scope {
|
||||
.listeners
|
||||
.try_borrow()
|
||||
.ok()
|
||||
.ok_or(Error::FatalInternal("Borrowing listener failed "))?
|
||||
.ok_or(Error::FatalInternal("Borrowing listener failed"))?
|
||||
.get(listener_id as usize)
|
||||
.ok_or(Error::FatalInternal("Event should exist if triggered"))?
|
||||
.as_ref()
|
||||
@@ -797,10 +796,11 @@ impl Scope {
|
||||
|
||||
let internal_state = pinned_state.downcast_mut::<InternalHookState>().expect(
|
||||
r###"
|
||||
Unable to retrive the hook that was initialized in this index.
|
||||
Consult the `rules of hooks` to understand how to use hooks properly.
|
||||
Unable to retrive the hook that was initialized in this index.
|
||||
Consult the `rules of hooks` to understand how to use hooks properly.
|
||||
|
||||
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
|
||||
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
|
||||
Any function prefixed with "use" should not be called conditionally.
|
||||
"###,
|
||||
);
|
||||
|
||||
@@ -813,7 +813,19 @@ impl Scope {
|
||||
// Context API Implementation for Components
|
||||
// ================================================
|
||||
impl Scope {
|
||||
pub fn create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
||||
/// This hook enables the ability to expose state to children further down the VirtualDOM Tree.
|
||||
///
|
||||
/// This is a hook, so it may not be called conditionally!
|
||||
///
|
||||
/// The init method is ran *only* on first use, otherwise it is ignored. However, it uses hooks (ie `use`)
|
||||
/// so don't put it in a conditional.
|
||||
///
|
||||
/// When the component is dropped, so is the context. Be aware of this behavior when consuming
|
||||
/// the context via Rc/Weak.
|
||||
///
|
||||
///
|
||||
///
|
||||
pub fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
||||
let mut ctxs = self.shared_contexts.borrow_mut();
|
||||
let ty = TypeId::of::<T>();
|
||||
|
||||
@@ -837,27 +849,56 @@ impl Scope {
|
||||
ctxs.insert(ty, Rc::new(init()));
|
||||
}
|
||||
|
||||
(false, true) => panic!("Cannot initialize two contexts of the same type"),
|
||||
(true, false) => panic!("Implementation failure resulted in missing context"),
|
||||
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
|
||||
}
|
||||
}
|
||||
|
||||
/// There are hooks going on here!
|
||||
pub fn use_context<T: 'static>(&self) -> Rc<T> {
|
||||
self.try_use_context().unwrap()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn try_use_context<T: 'static>(&self) -> Result<Rc<T>> {
|
||||
let ty = TypeId::of::<T>();
|
||||
|
||||
let mut scope = Some(self);
|
||||
let cached_root = use_ref(self, || None as Option<Weak<T>>);
|
||||
|
||||
// Try to provide the cached version without having to re-climb the tree
|
||||
if let Some(ptr) = cached_root.borrow().as_ref() {
|
||||
if let Some(pt) = ptr.clone().upgrade() {
|
||||
return Ok(pt);
|
||||
} else {
|
||||
/*
|
||||
failed to upgrade the weak is strange
|
||||
this means the root dropped the context (the scope was killed)
|
||||
|
||||
The main idea here is to prevent memory leaks where parents should be cleaning up their own memory.
|
||||
|
||||
However, this behavior allows receivers/providers to move around in the hierarchy.
|
||||
This works because we climb the tree if upgrading the Rc failed.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(inner) = scope {
|
||||
log::debug!("Searching {:#?} for valid shared_context", inner.arena_idx);
|
||||
let shared_contexts = inner.shared_contexts.borrow();
|
||||
if let Some(shared_ctx) = shared_contexts.get(&ty) {
|
||||
return Ok(shared_ctx.clone().downcast().unwrap());
|
||||
let rc = shared_ctx
|
||||
.clone()
|
||||
.downcast()
|
||||
.expect("Should not fail, already validated the type from the hashmap");
|
||||
|
||||
*cached_root.borrow_mut() = Some(Rc::downgrade(&rc));
|
||||
return Ok(rc);
|
||||
} else {
|
||||
match inner.parent {
|
||||
Some(parid) => {
|
||||
Some(parent_id) => {
|
||||
let parent = inner
|
||||
.arena_link
|
||||
.try_get(parid)
|
||||
.try_get(parent_id)
|
||||
.map_err(|_| Error::FatalInternal("Failed to find parent"))?;
|
||||
|
||||
scope = Some(parent);
|
||||
@@ -869,10 +910,6 @@ impl Scope {
|
||||
|
||||
Err(Error::MissingSharedContext)
|
||||
}
|
||||
|
||||
pub fn use_context<T: 'static>(&self) -> Rc<T> {
|
||||
self.try_use_context().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================================================
|
||||
|
||||
Reference in new issue
Block a user