diff --git a/reactive_graph/src/owner.rs b/reactive_graph/src/owner.rs index 1b1fbfbaa..93aad5109 100644 --- a/reactive_graph/src/owner.rs +++ b/reactive_graph/src/owner.rs @@ -167,6 +167,7 @@ impl Owner { .map(|parent| parent.read().or_poisoned().arena.clone()) .unwrap_or_default(), paused: false, + joined_owners: Vec::new(), })), #[cfg(feature = "hydration")] shared_context, @@ -201,6 +202,7 @@ impl Owner { #[cfg(feature = "sandboxed-arenas")] arena: Default::default(), paused: false, + joined_owners: Vec::new(), })), #[cfg(feature = "hydration")] shared_context, @@ -226,6 +228,7 @@ impl Owner { #[cfg(feature = "sandboxed-arenas")] arena, paused, + joined_owners: Vec::new(), })), #[cfg(feature = "hydration")] shared_context: self.shared_context.clone(), @@ -455,6 +458,7 @@ pub(crate) struct OwnerInner { #[cfg(feature = "sandboxed-arenas")] arena: Arc>, paused: bool, + joined_owners: Vec, } impl Debug for OwnerInner { diff --git a/reactive_graph/src/owner/context.rs b/reactive_graph/src/owner/context.rs index f6384817b..d34021f00 100644 --- a/reactive_graph/src/owner/context.rs +++ b/reactive_graph/src/owner/context.rs @@ -3,9 +3,19 @@ use or_poisoned::OrPoisoned; use std::{ any::{Any, TypeId}, collections::VecDeque, + sync::Arc, }; impl Owner { + #[doc(hidden)] + pub fn join_contexts(&self, other: &Owner) { + self.inner + .write() + .or_poisoned() + .joined_owners + .push(other.clone()); + } + fn provide_context(&self, value: T) { self.inner .write() @@ -26,17 +36,26 @@ impl Owner { if let Some(context) = contexts.remove(&ty) { context.downcast::().ok().map(|n| *n) } else { - while let Some(ref this_parent) = parent.clone() { - let mut this_parent = this_parent.write().or_poisoned(); - let contexts = &mut this_parent.contexts; - let value = contexts.remove(&ty); - let downcast = - value.and_then(|context| context.downcast::().ok()); - if let Some(value) = downcast { - return Some(*value); - } else { - parent = - this_parent.parent.as_ref().and_then(|p| p.upgrade()); + let parent = inner.parent.as_ref().and_then(|p| p.upgrade()); + let joined = inner + .joined_owners + .iter() + .map(|owner| Arc::clone(&owner.inner)); + for parent in parent.into_iter().chain(joined) { + while let Some(ref this_parent) = parent.clone() { + let mut this_parent = this_parent.write().or_poisoned(); + let contexts = &mut this_parent.contexts; + let value = contexts.remove(&ty); + let downcast = + value.and_then(|context| context.downcast::().ok()); + if let Some(value) = downcast { + return Some(*value); + } else { + parent = this_parent + .parent + .as_ref() + .and_then(|p| p.upgrade()); + } } } None @@ -49,22 +68,31 @@ impl Owner { ) -> Option { let ty = TypeId::of::(); let inner = self.inner.read().or_poisoned(); - let mut parent = inner.parent.as_ref().and_then(|p| p.upgrade()); let contexts = &inner.contexts; let reference = if let Some(context) = contexts.get(&ty) { context.downcast_ref::() } else { - while let Some(ref this_parent) = parent.clone() { - let this_parent = this_parent.read().or_poisoned(); - let contexts = &this_parent.contexts; - let value = contexts.get(&ty); - let downcast = - value.and_then(|context| context.downcast_ref::()); - if let Some(value) = downcast { - return Some(cb(value)); - } else { - parent = - this_parent.parent.as_ref().and_then(|p| p.upgrade()); + let parent = inner.parent.as_ref().and_then(|p| p.upgrade()); + let joined = inner + .joined_owners + .iter() + .map(|owner| Arc::clone(&owner.inner)); + for parent in parent.into_iter().chain(joined) { + let mut parent = Some(parent); + while let Some(ref this_parent) = parent.clone() { + let this_parent = this_parent.read().or_poisoned(); + let contexts = &this_parent.contexts; + let value = contexts.get(&ty); + let downcast = + value.and_then(|context| context.downcast_ref::()); + if let Some(value) = downcast { + return Some(cb(value)); + } else { + parent = this_parent + .parent + .as_ref() + .and_then(|p| p.upgrade()); + } } } None @@ -83,17 +111,26 @@ impl Owner { let reference = if let Some(context) = contexts.get_mut(&ty) { context.downcast_mut::() } else { - while let Some(ref this_parent) = parent.clone() { - let mut this_parent = this_parent.write().or_poisoned(); - let contexts = &mut this_parent.contexts; - let value = contexts.get_mut(&ty); - let downcast = - value.and_then(|context| context.downcast_mut::()); - if let Some(value) = downcast { - return Some(cb(value)); - } else { - parent = - this_parent.parent.as_ref().and_then(|p| p.upgrade()); + let parent = inner.parent.as_ref().and_then(|p| p.upgrade()); + let joined = inner + .joined_owners + .iter() + .map(|owner| Arc::clone(&owner.inner)); + for parent in parent.into_iter().chain(joined) { + while let Some(ref this_parent) = parent.clone() { + let mut this_parent = this_parent.write().or_poisoned(); + let contexts = &mut this_parent.contexts; + let value = contexts.get_mut(&ty); + let downcast = + value.and_then(|context| context.downcast_mut::()); + if let Some(value) = downcast { + return Some(cb(value)); + } else { + parent = this_parent + .parent + .as_ref() + .and_then(|p| p.upgrade()); + } } } None