|
@@ -115,6 +115,11 @@ impl<'src, P> Context<'src, P> {
|
|
|
todo!()
|
|
|
}
|
|
|
|
|
|
+ /// Get's this context's ScopeId
|
|
|
+ pub fn get_scope_id(&self) -> ScopeId {
|
|
|
+ self.scope.our_arena_idx.clone()
|
|
|
+ }
|
|
|
+
|
|
|
/// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
|
|
|
///
|
|
|
/// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
|
|
@@ -200,9 +205,13 @@ Any function prefixed with "use" should not be called conditionally.
|
|
|
///
|
|
|
///
|
|
|
///
|
|
|
- pub fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
|
|
- let mut cxs = self.scope.shared_contexts.borrow_mut();
|
|
|
+ pub fn use_provide_context<T, F>(self, init: F) -> &'src Rc<T>
|
|
|
+ where
|
|
|
+ T: 'static,
|
|
|
+ F: FnOnce() -> T,
|
|
|
+ {
|
|
|
let ty = TypeId::of::<T>();
|
|
|
+ let contains_key = self.scope.shared_contexts.borrow().contains_key(&ty);
|
|
|
|
|
|
let is_initialized = self.use_hook(
|
|
|
|_| false,
|
|
@@ -214,18 +223,30 @@ Any function prefixed with "use" should not be called conditionally.
|
|
|
|_| {},
|
|
|
);
|
|
|
|
|
|
- match (is_initialized, cxs.contains_key(&ty)) {
|
|
|
+ match (is_initialized, contains_key) {
|
|
|
// Do nothing, already initialized and already exists
|
|
|
(true, true) => {}
|
|
|
|
|
|
// Needs to be initialized
|
|
|
(false, false) => {
|
|
|
log::debug!("Initializing context...");
|
|
|
- cxs.insert(ty, Rc::new(init()));
|
|
|
+ let initialized = Rc::new(init());
|
|
|
+ let p = self
|
|
|
+ .scope
|
|
|
+ .shared_contexts
|
|
|
+ .borrow_mut()
|
|
|
+ .insert(ty, initialized);
|
|
|
+ log::info!(
|
|
|
+ "There are now {} shared contexts for scope {:?}",
|
|
|
+ self.scope.shared_contexts.borrow().len(),
|
|
|
+ self.scope.our_arena_idx,
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
|
|
|
- }
|
|
|
+ };
|
|
|
+
|
|
|
+ self.use_context::<T>()
|
|
|
}
|
|
|
|
|
|
/// There are hooks going on here!
|
|
@@ -234,26 +255,19 @@ Any function prefixed with "use" should not be called conditionally.
|
|
|
}
|
|
|
|
|
|
/// Uses a context, storing the cached value around
|
|
|
- pub fn try_use_context<T: 'static>(self) -> Result<&'src Rc<T>> {
|
|
|
+ ///
|
|
|
+ /// If a context is not found on the first search, then this call will be "dud", always returning "None" even if a
|
|
|
+ /// context was added later. This allows using another hook as a fallback
|
|
|
+ ///
|
|
|
+ pub fn try_use_context<T: 'static>(self) -> Option<&'src Rc<T>> {
|
|
|
struct UseContextHook<C> {
|
|
|
par: Option<Rc<C>>,
|
|
|
- we: Option<Weak<C>>,
|
|
|
}
|
|
|
|
|
|
self.use_hook(
|
|
|
- move |_| UseContextHook {
|
|
|
- par: None as Option<Rc<T>>,
|
|
|
- we: None as Option<Weak<T>>,
|
|
|
- },
|
|
|
- move |hook| {
|
|
|
+ move |_| {
|
|
|
let mut scope = Some(self.scope);
|
|
|
-
|
|
|
- if let Some(we) = &hook.we {
|
|
|
- if let Some(re) = we.upgrade() {
|
|
|
- hook.par = Some(re);
|
|
|
- return Ok(hook.par.as_ref().unwrap());
|
|
|
- }
|
|
|
- }
|
|
|
+ let mut par = None;
|
|
|
|
|
|
let ty = TypeId::of::<T>();
|
|
|
while let Some(inner) = scope {
|
|
@@ -261,35 +275,38 @@ Any function prefixed with "use" should not be called conditionally.
|
|
|
"Searching {:#?} for valid shared_context",
|
|
|
inner.our_arena_idx
|
|
|
);
|
|
|
- let shared_contexts = inner.shared_contexts.borrow();
|
|
|
+ let shared_ctx = {
|
|
|
+ let shared_contexts = inner.shared_contexts.borrow();
|
|
|
+
|
|
|
+ log::debug!(
|
|
|
+ "This component has {} shared contexts",
|
|
|
+ shared_contexts.len()
|
|
|
+ );
|
|
|
+ shared_contexts.get(&ty).map(|f| f.clone())
|
|
|
+ };
|
|
|
|
|
|
- if let Some(shared_cx) = shared_contexts.get(&ty) {
|
|
|
+ if let Some(shared_cx) = shared_ctx {
|
|
|
log::debug!("found matching cx");
|
|
|
let rc = shared_cx
|
|
|
.clone()
|
|
|
.downcast::<T>()
|
|
|
.expect("Should not fail, already validated the type from the hashmap");
|
|
|
|
|
|
- hook.we = Some(Rc::downgrade(&rc));
|
|
|
- hook.par = Some(rc);
|
|
|
- return Ok(hook.par.as_ref().unwrap());
|
|
|
+ par = Some(rc);
|
|
|
+ break;
|
|
|
} else {
|
|
|
match inner.parent_idx {
|
|
|
Some(parent_id) => {
|
|
|
- let parent = inner
|
|
|
- .arena_link
|
|
|
- .get(parent_id)
|
|
|
- .ok_or_else(|| Error::FatalInternal("Failed to find parent"))?;
|
|
|
-
|
|
|
- scope = Some(parent);
|
|
|
+ scope = inner.arena_link.get(parent_id);
|
|
|
}
|
|
|
- None => return Err(Error::MissingSharedContext),
|
|
|
+ None => break,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- Err(Error::MissingSharedContext)
|
|
|
+ //
|
|
|
+ UseContextHook { par }
|
|
|
},
|
|
|
+ move |hook| hook.par.as_ref(),
|
|
|
|_| {},
|
|
|
)
|
|
|
}
|