1use parking_lot::RwLock;
2use std::any::{Any, TypeId};
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::sync::atomic::{AtomicUsize, Ordering};
6use std::sync::{Arc, Weak};
7
8thread_local! {
9 static ACTIVE_PROVIDER_FIBERS: RefCell<Vec<(usize, Arc<Fiber>)>> = const { RefCell::new(Vec::new()) };
10}
11
12use crate::fiber::{Fiber, FiberState};
13use crate::registry::{Plugin, RegistryService};
14use crate::service::{CordisError, Service};
15use crate::{FiberId, ReflectService, Symbol};
16
17pub(crate) static NEXT_FIBER_ID: AtomicUsize = AtomicUsize::new(1);
18
19pub type AccessorGetter =
23 Arc<dyn Fn(&Context) -> Result<Option<Arc<dyn Any + Send + Sync>>, CordisError> + Send + Sync>;
24
25pub type AccessorSetter =
28 Arc<dyn Fn(&Context, Arc<dyn Any + Send + Sync>) -> Result<(), CordisError> + Send + Sync>;
29
30#[derive(Clone, Default)]
32pub struct Accessor {
33 getter: Option<AccessorGetter>,
34 setter: Option<AccessorSetter>,
35}
36
37impl Accessor {
38 pub fn read_only<F>(getter: F) -> Self
41 where
42 F: Fn(&Context) -> Result<Option<Arc<dyn Any + Send + Sync>>, CordisError>
43 + Send
44 + Sync
45 + 'static,
46 {
47 Self { getter: Some(Arc::new(getter)), setter: None }
48 }
49
50 pub fn read_write<G, S>(getter: G, setter: S) -> Self
52 where
53 G: Fn(&Context) -> Result<Option<Arc<dyn Any + Send + Sync>>, CordisError>
54 + Send
55 + Sync
56 + 'static,
57 S: Fn(&Context, Arc<dyn Any + Send + Sync>) -> Result<(), CordisError> + Send + Sync + 'static,
58 {
59 Self { getter: Some(Arc::new(getter)), setter: Some(Arc::new(setter)) }
60 }
61
62 pub fn setter_only<S>(setter: S) -> Self
64 where
65 S: Fn(&Context, Arc<dyn Any + Send + Sync>) -> Result<(), CordisError> + Send + Sync + 'static,
66 {
67 Self { getter: None, setter: Some(Arc::new(setter)) }
68 }
69}
70
71struct AccessorSlot {
75 getter: Option<AccessorGetter>,
76 setter: Option<AccessorSetter>,
77 names: parking_lot::Mutex<Vec<String>>,
78}
79
80pub struct EffectHandle {
83 ctx: Weak<Context>,
84 slot: Weak<AccessorSlot>,
85}
86
87impl EffectHandle {
88 pub fn dispose(self) -> bool {
91 let (Some(ctx), Some(slot)) = (self.ctx.upgrade(), self.slot.upgrade()) else {
92 return false;
93 };
94 let names = slot.names.lock().clone();
95 let mut accessors = ctx.accessors.write();
96 let mut removed = false;
97 for name in names {
98 if accessors
99 .get(&name)
100 .is_some_and(|bound| std::sync::Arc::ptr_eq(bound, &slot))
101 {
102 accessors.remove(&name);
103 removed = true;
104 }
105 }
106 removed
107 }
108}
109
110pub struct Context {
111 store: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
112 isolate: RwLock<HashMap<TypeId, Symbol>>,
113 intercept: RwLock<HashMap<TypeId, Vec<Arc<dyn Any + Send + Sync>>>>,
117 accessors: RwLock<HashMap<String, std::sync::Arc<AccessorSlot>>>,
121 versions: RwLock<HashMap<TypeId, u64>>,
122 provided_versions: RwLock<HashMap<TypeId, u64>>,
126 owners: RwLock<HashMap<TypeId, Weak<Fiber>>>,
130 fiber: Arc<Fiber>,
131 parent: Option<Arc<Context>>,
132 root: Weak<Context>,
133}
134
135impl Context {
136 pub(crate) fn with_provider_fiber<R>(
137 self: &Arc<Self>,
138 fiber: &Arc<Fiber>,
139 f: impl FnOnce() -> R,
140 ) -> R {
141 let key = Arc::as_ptr(self) as usize;
142 ACTIVE_PROVIDER_FIBERS.with(|stack| stack.borrow_mut().push((key, fiber.clone())));
143 struct Scope;
144 impl Drop for Scope {
145 fn drop(&mut self) {
146 ACTIVE_PROVIDER_FIBERS.with(|stack| {
147 let _ = stack.borrow_mut().pop();
148 });
149 }
150 }
151 let _scope = Scope;
152 f()
153 }
154
155 fn active_provider_fiber(&self) -> Option<Arc<Fiber>> {
156 let key = self as *const Context as usize;
157 ACTIVE_PROVIDER_FIBERS.with(|stack| {
158 stack
159 .borrow()
160 .iter()
161 .rev()
162 .find(|(context, _)| *context == key)
163 .map(|(_, fiber)| fiber.clone())
164 })
165 }
166 pub fn new_root() -> Arc<Self> {
167 Arc::new_cyclic(|weak| Self {
168 store: RwLock::new(HashMap::new()),
169 isolate: RwLock::new(HashMap::new()),
170 intercept: RwLock::new(HashMap::new()),
171 accessors: RwLock::new(HashMap::new()),
172 versions: RwLock::new(HashMap::new()),
173 provided_versions: RwLock::new(HashMap::new()),
174 owners: RwLock::new(HashMap::new()),
175 fiber: Arc::new(Fiber::new()),
176 parent: None,
177 root: weak.clone(),
178 })
179 }
180
181 pub fn extend(self: &Arc<Self>) -> Arc<Self> {
182 Arc::new(Self {
183 store: RwLock::new(HashMap::new()),
184 isolate: RwLock::new(HashMap::new()),
185 intercept: RwLock::new(HashMap::new()),
186 accessors: RwLock::new(HashMap::new()),
187 versions: RwLock::new(HashMap::new()),
188 provided_versions: RwLock::new(HashMap::new()),
189 owners: RwLock::new(HashMap::new()),
190 fiber: Arc::new(Fiber::new()),
191 parent: Some(self.clone()),
192 root: self.root.clone(),
193 })
194 }
195
196 pub fn isolate_type(self: &Arc<Self>, tid: TypeId, label: impl Into<Symbol>) -> Arc<Self> {
197 let mut parent_isolate = self.isolate.read().clone();
198 parent_isolate.insert(tid, label.into());
199 Arc::new(Self {
200 store: RwLock::new(HashMap::new()),
201 isolate: RwLock::new(parent_isolate),
202 intercept: RwLock::new(HashMap::new()),
203 accessors: RwLock::new(HashMap::new()),
204 versions: RwLock::new(HashMap::new()),
205 provided_versions: RwLock::new(HashMap::new()),
206 owners: RwLock::new(HashMap::new()),
207 fiber: Arc::new(Fiber::new()),
208 parent: Some(self.clone()),
209 root: self.root.clone(),
210 })
211 }
212
213 pub fn isolate<T: Service>(self: &Arc<Self>, label: impl Into<Symbol>) -> Arc<Self> {
214 self.isolate_type(TypeId::of::<T>(), label)
215 }
216
217 pub fn intercept<T: Service>(self: &Arc<Self>, val: T) -> Arc<Self> {
218 let child = self.extend();
219 let tid = TypeId::of::<T>();
220 let any: Arc<dyn Any + Send + Sync> = Arc::new(val);
221 child.intercept.write().entry(tid).or_default().push(any);
223 child
225 }
226
227 pub const VERSION_MAJOR_SCALE: u64 = 100_000;
248
249 pub fn provide_versioned<T: Any + Send + Sync>(
254 self: &Arc<Self>,
255 value: T,
256 version: u64,
257 ) -> Arc<T> {
258 let owner = self.active_provider_fiber();
259 self.provide_impl(Arc::new(value), owner.as_ref(), Some(version))
260 }
261
262 pub fn provider_version(&self, tid: TypeId) -> u64 {
270 if let Some(v) = self.provided_versions.read().get(&tid) {
271 return *v;
272 }
273 if let Some(parent) = &self.parent {
274 return parent.provider_version(tid);
275 }
276 0
277 }
278
279 pub fn provide<T: Service>(self: &Arc<Self>, svc: T) -> Arc<T> {
281 let owner = self.active_provider_fiber();
282 self.provide_impl(Arc::new(svc), owner.as_ref(), None)
283 }
284
285 pub(crate) fn provide_on_fiber<T: Service>(
289 self: &Arc<Self>,
290 svc: Arc<T>,
291 owner: &Arc<Fiber>,
292 ) -> Arc<T> {
293 self.provide_impl(svc, Some(owner), None)
294 }
295
296 fn provide_impl<T: Any + Send + Sync>(
306 self: &Arc<Self>,
307 svc: Arc<T>,
308 owner: Option<&Arc<Fiber>>,
309 semantic_version: Option<u64>,
310 ) -> Arc<T> {
311 let tid = TypeId::of::<T>();
312 if let Some(events) = self.get_unintercepted::<crate::EventsService>() {
317 if crate::events::blocking_intercept_set(&events, std::any::type_name::<T>()).is_err()
318 {
319 tracing::info!(
320 service = std::any::type_name::<T>(),
321 "internal/set vetoed provider write; previous value stays"
322 );
323 let prev_any = self.store.read().get(&tid).cloned();
324 return prev_any.and_then(|any| any.downcast::<T>().ok()).unwrap_or(svc);
325 }
326 }
327 let any: Arc<dyn Any + Send + Sync> = svc.clone();
328 let prev = self.store.write().insert(tid, any.clone());
329 if tid == TypeId::of::<ReflectService>() {
330 if let Ok(reflect) = any.downcast::<ReflectService>() {
331 reflect.set_context(self);
332 }
333 }
334 let prev_owner = if let Some(owner) = owner {
335 self.owners.write().insert(tid, Arc::downgrade(owner))
336 } else {
337 self.owners.write().remove(&tid)
338 };
339 {
340 let mut versions = self.versions.write();
341 *versions.entry(tid).or_insert(0) += 1;
342 }
343 let prev_semantic = match semantic_version {
344 Some(v) => self.provided_versions.write().insert(tid, v),
345 None => self.provided_versions.write().remove(&tid),
346 };
347 if let Some(reflect) = self.get::<ReflectService>() {
348 reflect.notify(tid);
349 }
350 let weak = Arc::downgrade(self);
351 let undo: Box<dyn FnOnce() + Send> = Box::new(move || {
352 if let Some(ctx) = weak.upgrade() {
353 {
357 let mut store = ctx.store.write();
358 if let Some(prev_any) = prev {
359 store.insert(tid, prev_any);
360 } else {
361 store.remove(&tid);
362 }
363 let mut owners = ctx.owners.write();
364 if let Some(previous) = prev_owner {
365 owners.insert(tid, previous);
366 } else {
367 owners.remove(&tid);
368 }
369 let mut versions = ctx.versions.write();
370 if let Some(v) = versions.get_mut(&tid) {
371 *v = v.saturating_sub(1);
372 if *v == 0 {
373 versions.remove(&tid);
374 }
375 }
376 match prev_semantic {
380 Some(v) => {
381 ctx.provided_versions.write().insert(tid, v);
382 }
383 None => {
384 ctx.provided_versions.write().remove(&tid);
385 }
386 }
387 }
388 if let Some(reflect) = ctx.get::<ReflectService>() {
389 reflect.notify(tid);
390 }
391 }
392 });
393 owner
394 .cloned()
395 .unwrap_or_else(|| self.fiber.clone())
396 .push_undo(undo);
397 svc
398 }
399
400 pub fn remove<T: Service>(self: &Arc<Self>) -> Result<Option<Arc<T>>, CordisError> {
410 let tid = TypeId::of::<T>();
411 if self.store.read().contains_key(&tid) {
412 if let Some(registry) = self.get::<RegistryService>() {
413 let key = (tid, self.isolate_label(tid));
414 let consumers = registry.reliance_count(&key);
415 if consumers > 0 {
416 return Err(CordisError::Configuration(format!(
417 "guarded withdrawal: {consumers} active consumer(s) still rely on {}",
418 std::any::type_name::<T>()
419 )));
420 }
421 }
422 }
423 Self::remove_forced::<T>(self)
424 }
425
426 pub(crate) fn remove_forced<T: Service>(
430 self: &Arc<Self>,
431 ) -> Result<Option<Arc<T>>, CordisError> {
432 let tid = TypeId::of::<T>();
433 let removed = {
434 let mut store = self.store.write();
435 store.remove(&tid)
436 };
437 if let Some(any) = removed {
438 let previous_owner = self.owners.write().remove(&tid);
439 {
441 let mut versions = self.versions.write();
442 if let Some(v) = versions.get_mut(&tid) {
443 *v = v.saturating_sub(1);
444 if *v == 0 {
445 versions.remove(&tid);
446 }
447 }
448 }
449 if let Some(reflect) = self.get::<ReflectService>() {
451 reflect.notify(tid);
452 }
453 let weak = Arc::downgrade(self);
455 let fiber = self
456 .active_provider_fiber()
457 .unwrap_or_else(|| self.fiber.clone());
458 let any_clone = any.clone();
459 let undo: Box<dyn FnOnce() + Send> = Box::new(move || {
460 if let Some(ctx) = weak.upgrade() {
461 ctx.store.write().insert(tid, any_clone);
462 if let Some(owner) = previous_owner {
463 ctx.owners.write().insert(tid, owner);
464 }
465 let mut versions = ctx.versions.write();
466 let e = versions.entry(tid).or_insert(0);
467 *e += 1;
468 }
469 });
470 fiber.push_undo(undo);
471 Ok(any.downcast::<T>().ok())
473 } else {
474 Ok(None)
475 }
476 }
477
478 pub(crate) fn provide_untyped(
485 self: &Arc<Self>,
486 tid: TypeId,
487 any: Arc<dyn Any + Send + Sync>,
488 ) -> Result<(), TypeId> {
489 let mut store = self.store.write();
490 if store.contains_key(&tid) {
491 return Err(tid);
492 }
493 if tid == TypeId::of::<ReflectService>() {
494 if let Ok(reflect) = any.clone().downcast::<ReflectService>() {
495 reflect.set_context(self);
496 }
497 }
498 store.insert(tid, any);
499 Ok(())
500 }
501
502 pub(crate) fn take_untyped(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
506 self.store.write().remove(&tid)
507 }
508
509 pub(crate) fn get_untyped(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
512 self.store.read().get(&tid).cloned()
513 }
514
515 pub(crate) fn bind_intercept_untyped(&self, tid: TypeId, any: Arc<dyn Any + Send + Sync>) {
518 self.intercept.write().entry(tid).or_default().push(any);
521 }
522
523 pub(crate) fn peek_intercept_untyped(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
525 self.intercept.read().get(&tid).and_then(|layers| layers.last()).cloned()
526 }
527
528 pub(crate) fn remove_intercept_untyped(&self, tid: TypeId) {
531 let mut intercept = self.intercept.write();
532 if let Some(layers) = intercept.get_mut(&tid) {
533 layers.pop();
534 if layers.is_empty() {
535 intercept.remove(&tid);
536 }
537 }
538 }
539
540 pub fn get_relaxed<T: Service>(&self) -> Option<Arc<T>> {
550 let tid = TypeId::of::<T>();
551 if self.isolate_label(tid).is_none() {
552 if let Some(any) = self.intercept.read().get(&tid).and_then(|l| l.last()) {
553 if let Ok(arc) = any.clone().downcast::<T>() {
554 return Some(arc);
555 }
556 }
557 }
558 if let Some(any) = self.store.read().get(&tid) {
559 let transitioning = self
560 .owners
561 .read()
562 .get(&tid)
563 .and_then(Weak::upgrade)
564 .map(|fiber| {
565 matches!(
566 fiber.state(),
567 FiberState::Active { .. }
568 | FiberState::Loading
569 | FiberState::Reloading
570 | FiberState::Unloading { .. }
571 | FiberState::Pending
572 )
573 })
574 .unwrap_or(true);
575 if transitioning && !self.disposed_owner(tid) {
578 if let Ok(arc) = any.clone().downcast::<T>() {
579 return Some(arc);
580 }
581 }
582 return None;
583 }
584 if self.isolate.read().contains_key(&tid) {
585 return self.parent.as_ref().and_then(|parent| {
586 if parent.isolate_label(tid) == self.isolate_label(tid) {
587 parent.get_relaxed::<T>()
588 } else {
589 None
590 }
591 });
592 }
593 self.parent.as_ref().and_then(|parent| parent.get_relaxed::<T>())
594 }
595
596 fn disposed_owner(&self, tid: TypeId) -> bool {
598 self.owners
599 .read()
600 .get(&tid)
601 .and_then(Weak::upgrade)
602 .map(|fiber| fiber.is_disposed())
603 .unwrap_or(false)
604 }
605
606 pub fn get<T: Service>(&self) -> Option<Arc<T>> {
607 if let Some(events) = self.get_unintercepted::<crate::EventsService>() {
611 match crate::events::blocking_intercept_get(&events, std::any::type_name::<T>()) {
612 crate::events::ReadVerdict::Pass => {}
613 crate::events::ReadVerdict::RedirectFrame => {
614 return self.get_from_parent_frame::<T>();
615 }
616 crate::events::ReadVerdict::Refuse => return None,
617 }
618 }
619 self.get_impl::<T>()
620 }
621
622 fn get_unintercepted<T: Service>(&self) -> Option<Arc<T>> {
627 self.get_impl::<T>()
628 }
629
630 fn get_from_parent_frame<T: Service>(&self) -> Option<Arc<T>> {
634 let Some(parent) = &self.parent else {
635 return None;
636 };
637 if parent.isolate_label(TypeId::of::<T>()) != self.isolate_label(TypeId::of::<T>()) {
638 return None;
639 }
640 parent.get_impl::<T>()
643 }
644
645 fn get_impl<T: Service>(&self) -> Option<Arc<T>> {
648 let tid = TypeId::of::<T>();
649 if self.isolate_label(tid).is_none() {
652 if let Some(any) = self.intercept.read().get(&tid).and_then(|l| l.last()) {
653 if let Ok(arc) = any.clone().downcast::<T>() {
654 return Some(arc);
655 }
656 }
657 }
658 let mut local_provider = false;
659 if let Some(any) = self.store.read().get(&tid) {
660 local_provider = true;
661 let active = self
662 .owners
663 .read()
664 .get(&tid)
665 .and_then(Weak::upgrade)
666 .map(|fiber| matches!(fiber.state(), FiberState::Active { .. }))
667 .unwrap_or(true);
668 if active {
669 if let Ok(arc) = any.clone().downcast::<T>() {
670 if arc.check() {
671 return Some(arc);
672 }
673 }
674 }
675 }
676 if local_provider {
677 return None;
678 }
679 if self.isolate.read().contains_key(&tid) {
683 return self.parent.as_ref().and_then(|parent| {
684 if parent.isolate_label(tid) == self.isolate_label(tid) {
685 parent.get_impl::<T>()
686 } else {
687 None
688 }
689 });
690 }
691 self.parent.as_ref().and_then(|parent| parent.get_impl::<T>())
692 }
693
694 fn duplicate_provider_error(tid: TypeId) -> CordisError {
699 CordisError::DuplicateProvider {
700 name: format!("{tid:?}"),
701 owner: "context".to_string(),
702 }
703 }
704
705 pub fn get_version(&self, tid: TypeId) -> u64 {
706 if let Some(v) = self.versions.read().get(&tid) {
707 return *v;
708 }
709 if let Some(parent) = &self.parent {
710 return parent.get_version(tid);
711 }
712 0
713 }
714
715 pub(crate) fn is_available(&self, tid: TypeId) -> bool {
716 if self
717 .isolate_label(tid)
718 .is_none()
719 && self.intercept.read().get(&tid).is_some_and(|layers| !layers.is_empty())
720 {
721 return true;
722 }
723 if self.store.read().contains_key(&tid) {
724 return self
725 .owners
726 .read()
727 .get(&tid)
728 .and_then(Weak::upgrade)
729 .map(|fiber| matches!(fiber.state(), FiberState::Active { .. }))
730 .unwrap_or(true);
731 }
732 if self.isolate.read().contains_key(&tid) {
733 return self.parent.as_ref().is_some_and(|parent| {
734 parent.isolate_label(tid) == self.isolate_label(tid) && parent.is_available(tid)
735 });
736 }
737 self.parent
738 .as_ref()
739 .is_some_and(|parent| parent.is_available(tid))
740 }
741
742 pub fn isolate_label(&self, tid: TypeId) -> Option<Symbol> {
743 if let Some(label) = self.isolate.read().get(&tid).cloned() {
744 return Some(label);
745 }
746 if let Some(parent) = &self.parent {
747 return parent.isolate_label(tid);
748 }
749 None
750 }
751
752 pub fn provided_type_ids(&self) -> Vec<TypeId> {
754 self.store.read().keys().copied().collect()
755 }
756
757 pub fn bind_isolate(&self, tid: TypeId, label: impl Into<Symbol>) {
762 self.isolate.write().insert(tid, label.into());
763 }
764
765 pub fn bind_intercept<T: Service>(&self, val: T) {
769 let tid = TypeId::of::<T>();
770 let any: Arc<dyn Any + Send + Sync> = Arc::new(val);
771 self.intercept.write().entry(tid).or_default().push(any);
772 }
773 pub fn register_accessor(
785 self: &Arc<Self>,
786 name: &str,
787 accessor: Accessor,
788 ) -> Result<EffectHandle, CordisError> {
789 let mut accessors = self.accessors.write();
790 if accessors.contains_key(name) {
791 return Err(CordisError::DuplicateProvider {
792 name: name.to_string(),
793 owner: "accessor".to_string(),
794 });
795 }
796 let slot = std::sync::Arc::new(AccessorSlot {
797 getter: accessor.getter,
798 setter: accessor.setter,
799 names: parking_lot::Mutex::new(vec![name.to_string()]),
800 });
801 accessors.insert(name.to_string(), slot.clone());
802 Ok(EffectHandle {
803 ctx: Arc::downgrade(self),
804 slot: Arc::downgrade(&slot),
805 })
806 }
807
808 pub fn alias(self: &Arc<Self>, alias: &str, target: &str) -> Result<(), CordisError> {
811 let mut accessors = self.accessors.write();
812 let slot = accessors.get(target).cloned().ok_or_else(|| {
813 CordisError::ServiceNotFound(format!(
814 "cannot alias '{alias}': no property named '{target}'"
815 ))
816 })?;
817 if accessors.contains_key(alias) {
818 return Err(CordisError::DuplicateProvider {
819 name: alias.to_string(),
820 owner: "accessor".to_string(),
821 });
822 }
823 slot.names.lock().push(alias.to_string());
824 accessors.insert(alias.to_string(), slot);
825 Ok(())
826 }
827
828 pub fn read_property(
832 &self,
833 name: &str,
834 ) -> Result<Option<Arc<dyn Any + Send + Sync>>, CordisError> {
835 let slot = self.accessors.read().get(name).cloned();
836 let Some(slot) = slot else {
837 return Ok(None);
838 };
839 match &slot.getter {
840 Some(getter) => getter(self),
841 None => Ok(None),
842 }
843 }
844
845 pub fn read_property_typed<T: Any + Send + Sync>(
848 &self,
849 name: &str,
850 ) -> Result<Option<Arc<T>>, CordisError> {
851 match self.read_property(name)? {
852 None => Ok(None),
853 Some(any) => any.downcast::<T>().map(Some).map_err(|_| {
854 CordisError::PropertyTypeMismatch {
855 name: name.to_string(),
856 expected: std::any::type_name::<T>().to_string(),
857 }
858 }),
859 }
860 }
861
862 pub fn write_property(
868 self: &Arc<Self>,
869 name: &str,
870 value: Arc<dyn Any + Send + Sync>,
871 ) -> Result<(), CordisError> {
872 let slot = self.accessors.read().get(name).cloned();
873 let Some(slot) = slot else {
874 return Err(CordisError::ServiceNotFound(format!(
875 "cannot set property '{name}': no accessor declared"
876 )));
877 };
878 let Some(setter) = &slot.setter else {
879 return Err(CordisError::ReadOnlyProperty(name.to_string()));
880 };
881 setter(self, value)
882 }
883
884 pub fn intercept_chain(&self, tid: TypeId) -> Vec<Arc<dyn Any + Send + Sync>> {
891 let mut chain = match &self.parent {
892 Some(parent)
895 if !self.isolate.read().contains_key(&tid)
896 || parent.isolate_label(tid) == self.isolate_label(tid) =>
897 {
898 parent.intercept_chain(tid)
899 }
900 _ => Vec::new(),
901 };
902 if let Some(layers) = self.intercept.read().get(&tid) {
903 chain.extend(layers.iter().cloned());
904 }
905 chain
906 }
907
908 pub fn chains_structurally_equal(
914 a: &[Arc<dyn Any + Send + Sync>],
915 b: &[Arc<dyn Any + Send + Sync>],
916 ) -> bool {
917 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| Arc::ptr_eq(x, y))
918 }
919
920 pub fn get_isolated<T: Service>(&self, label: &str) -> Option<Arc<T>> {
924 let tid = TypeId::of::<T>();
925 let my_label = self.isolate.read().get(&tid).cloned();
926 match my_label.as_deref() {
927 Some(l) if l == label => {
928 if let Some(any) = self.store.read().get(&tid) {
930 let active = self
931 .owners
932 .read()
933 .get(&tid)
934 .and_then(Weak::upgrade)
935 .map(|fiber| matches!(fiber.state(), FiberState::Active { .. }))
936 .unwrap_or(true);
937 if active {
938 if let Ok(arc) = any.clone().downcast::<T>() {
939 if arc.check() {
940 return Some(arc);
941 }
942 }
943 }
944 }
945 if let Some(parent) = &self.parent {
947 return parent.get_isolated::<T>(label);
948 }
949 None
950 }
951 Some(_) => {
952 None
954 }
955 None => {
956 if let Some(parent) = &self.parent {
958 return parent.get_isolated::<T>(label);
959 }
960 None
961 }
962 }
963 }
964
965 pub fn with_intercept<T: Service>(self: &Arc<Self>, val: T) -> Arc<Self> {
968 self.intercept(val)
969 }
970
971 pub async fn inject<T: Service>(self: &Arc<Self>) -> Arc<T> {
978 if let Some(value) = self.get::<T>() {
979 return value;
980 }
981 if let Some(reflect) = self.get::<ReflectService>() {
982 let mut rx = reflect.ensure_notifier(TypeId::of::<T>());
983 loop {
984 if let Some(value) = self.get::<T>() {
985 return value;
986 }
987 if rx.changed().await.is_err() {
988 break;
989 }
990 }
991 }
992 loop {
993 if let Some(value) = self.get::<T>() {
994 return value;
995 }
996 tokio::time::sleep(std::time::Duration::from_millis(5)).await;
997 }
998 }
999
1000 pub fn provide_arc<T: Service>(self: &Arc<Self>, svc: Arc<T>) -> Arc<T> {
1001 let owner = self.active_provider_fiber();
1002 self.provide_impl(svc, owner.as_ref(), None)
1003 }
1004
1005 pub fn fiber(&self) -> Arc<Fiber> {
1006 self.fiber.clone()
1007 }
1008
1009 pub fn snapshot_len(&self) -> usize {
1011 self.store.read().len()
1012 }
1013
1014 pub async fn plugin<S: Service>(self: &Arc<Self>, svc: S) -> Result<FiberId, CordisError> {
1015 let tid = TypeId::of::<S>();
1016 if self.store.read().contains_key(&tid) {
1017 return Err(Self::duplicate_provider_error(tid));
1018 }
1019 let fiber = self.fiber.clone();
1020 fiber.set_state(FiberState::Loading);
1021 let disposable = match svc.init(self).await {
1022 Ok(d) => d,
1023 Err(e) => {
1024 fiber.set_state(FiberState::Failed {
1025 error: Some(e.to_string()),
1026 });
1027 return Err(e);
1028 }
1029 };
1030 let svc_arc = self.provide(svc);
1031 let fid = NEXT_FIBER_ID.fetch_add(1, Ordering::SeqCst) as u64;
1032 if let Some(d) = disposable {
1033 let undo: Box<dyn FnOnce() + Send> = Box::new(move || {
1034 d.dispose();
1035 });
1036 fiber.push_undo(undo);
1037 }
1038 if svc_arc.check() {
1039 let epoch = fiber.compute_epoch(self);
1040 fiber.set_epoch(epoch.clone());
1041 fiber.set_state(FiberState::Active { epoch });
1042 } else {
1043 fiber.set_state(FiberState::Inactive { error: None });
1044 if let Some(reflect) = self.get::<ReflectService>() {
1045 reflect.notify(tid);
1046 }
1047 }
1048 if let Some(reflect) = self.get::<ReflectService>() {
1049 let _ = reflect.ensure_notifier(tid);
1050 reflect.set_context(self);
1051 }
1052 Ok(fid)
1053 }
1054
1055 pub async fn plugin_with<P: Plugin>(
1056 self: &Arc<Self>,
1057 plugin: P,
1058 config: P::Config,
1059 ) -> Result<FiberId, CordisError> {
1060 if let Some(registry) = self.get::<RegistryService>() {
1061 return registry.plugin(self, plugin, config);
1062 }
1063 let tid = TypeId::of::<P::Provides>();
1064 if self.store.read().contains_key(&tid) {
1065 return Err(Self::duplicate_provider_error(tid));
1066 }
1067 self.fiber.set_state(FiberState::Loading);
1068 let provides = match plugin.apply(self, config) {
1069 Ok(p) => p,
1070 Err(e) => {
1071 self.fiber.set_state(FiberState::Failed {
1072 error: Some(e.to_string()),
1073 });
1074 return Err(e);
1075 }
1076 };
1077 self.provide_arc(provides);
1078 let epoch = self.fiber.compute_epoch(self);
1079 self.fiber.set_epoch(epoch.clone());
1080 self.fiber.set_state(FiberState::Active { epoch });
1081 let fid = NEXT_FIBER_ID.fetch_add(1, Ordering::SeqCst) as u64;
1082 Ok(fid)
1083 }
1084}
1085
1086#[cfg(test)]
1087mod relaxed_tests {
1088 use super::*;
1089 use crate::fiber::FiberState;
1090
1091 #[tokio::test]
1096 async fn relaxed_read_succeeds_while_provider_transitioning() {
1097 #[derive(Debug)]
1098 struct TransitionProbe(u32);
1099 impl Service for TransitionProbe {}
1100
1101 let ctx = Context::new_root();
1102 let fiber = Arc::new(Fiber::new());
1103 fiber.set_reload_context(&ctx);
1104 fiber.set_id(96_001);
1105
1106 let svc = Arc::new(TransitionProbe(7));
1109 ctx.provide_on_fiber(svc, &fiber);
1110
1111 assert!(ctx.get::<TransitionProbe>().is_none());
1113
1114 for state in [
1115 FiberState::Loading,
1116 FiberState::Reloading,
1117 FiberState::Unloading { error: None },
1118 FiberState::Pending,
1119 ] {
1120 fiber.set_state(state.clone());
1121 let relaxed = ctx.get_relaxed::<TransitionProbe>();
1122 assert!(
1123 relaxed.is_some(),
1124 "relaxed read must succeed in {state:?}"
1125 );
1126 assert_eq!(
1127 relaxed.as_ref().map(|s| s.0),
1128 Some(7),
1129 "the transitioning value itself is served"
1130 );
1131 }
1132
1133 fiber.set_state(FiberState::Failed {
1135 error: Some("boom".into()),
1136 });
1137 assert!(
1138 ctx.get_relaxed::<TransitionProbe>().is_none(),
1139 "Failed owner must stay invisible to relaxed reads"
1140 );
1141
1142 fiber.set_state(FiberState::Inactive { error: None });
1144 let _ = fiber.dispose().await;
1145 assert!(
1146 ctx.get_relaxed::<TransitionProbe>().is_none(),
1147 "disposed owner must stay invisible to relaxed reads"
1148 );
1149 }
1150}
1151
1152#[cfg(test)]
1153mod accessor_tests {
1154 use super::*;
1155 use parking_lot::Mutex as StdMutex;
1156
1157 #[derive(Debug, PartialEq)]
1158 struct PropValue(pub u64);
1159
1160 fn read_cell_getter(
1161 cell: Arc<StdMutex<u64>>,
1162 ) -> impl Fn(&Context) -> Result<Option<Arc<dyn Any + Send + Sync>>, CordisError>
1163 + Send
1164 + Sync
1165 + 'static {
1166 move |_| {
1167 Ok(Some(Arc::new(PropValue(*cell.lock()))
1168 as Arc<dyn Any + Send + Sync>))
1169 }
1170 }
1171
1172 #[test]
1173 fn accessor_read_write_roundtrip() {
1174 let ctx = Context::new_root();
1175 let cell = Arc::new(StdMutex::new(1u64));
1176 let write_cell = cell.clone();
1177 let _handle = ctx
1178 .register_accessor(
1179 "quota",
1180 Accessor::read_write(
1181 read_cell_getter(cell.clone()),
1182 move |_ctx, value: Arc<dyn Any + Send + Sync>| {
1183 let v = value
1184 .downcast::<PropValue>()
1185 .map_err(|_| CordisError::Internal("bad property type".into()))?;
1186 *write_cell.lock() = v.0;
1187 Ok(())
1188 },
1189 ),
1190 )
1191 .unwrap();
1192
1193 let got = ctx.read_property_typed::<PropValue>("quota").unwrap().unwrap();
1194 assert_eq!(*got, PropValue(1));
1195 ctx.write_property("quota", Arc::new(PropValue(42))).unwrap();
1196 let got = ctx.read_property_typed::<PropValue>("quota").unwrap().unwrap();
1197 assert_eq!(*got, PropValue(42));
1198 assert_eq!(*cell.lock(), 42);
1199
1200 match ctx.read_property_typed::<String>("quota") {
1202 Err(CordisError::PropertyTypeMismatch { name, .. }) => assert_eq!(name, "quota"),
1203 other => panic!("expected PropertyTypeMismatch, got {other:?}"),
1204 }
1205 }
1206
1207 #[test]
1208 fn duplicate_accessor_declaration_rejected() {
1209 let ctx = Context::new_root();
1210 ctx.register_accessor("dup", Accessor::read_only(|_| Ok(None)))
1211 .expect("first declaration wins");
1212 match ctx.register_accessor("dup", Accessor::read_only(|_| Ok(None))) {
1213 Err(CordisError::DuplicateProvider { name, owner }) => {
1214 assert_eq!(name, "dup");
1215 assert_eq!(owner, "accessor");
1216 }
1217 Err(other) => panic!("expected DuplicateProvider, got {other:?}"),
1218 Ok(_) => panic!("duplicate declaration must be rejected"),
1219 }
1220 }
1221
1222 #[test]
1223 fn readonly_property_rejects_set() {
1224 let ctx = Context::new_root();
1225 let _handle = ctx
1226 .register_accessor(
1227 "ro",
1228 Accessor::read_only(read_cell_getter(Arc::new(StdMutex::new(7u64)))),
1229 )
1230 .unwrap();
1231 let err = ctx.write_property("ro", Arc::new(PropValue(9))).unwrap_err();
1232 assert!(matches!(err, CordisError::ReadOnlyProperty(ref n) if n == "ro"));
1233 assert_eq!(
1235 *ctx.read_property_typed::<PropValue>("ro").unwrap().unwrap(),
1236 PropValue(7)
1237 );
1238 }
1239
1240 #[test]
1241 fn dispose_accessor_resolves_none() {
1242 let ctx = Context::new_root();
1243 let handle = ctx
1244 .register_accessor("gone", Accessor::read_only(|_| Ok(None)))
1245 .unwrap();
1246 assert!(ctx.read_property("gone").unwrap().is_none());
1247 assert!(handle.dispose(), "live handle reports removal");
1248 assert!(ctx.read_property("gone").unwrap().is_none());
1250 let err = ctx.write_property("gone", Arc::new(PropValue(1))).unwrap_err();
1251 assert!(
1252 matches!(err, CordisError::ServiceNotFound(ref m) if m.contains("cannot set property")),
1253 "unexpected error: {err}"
1254 );
1255 let handle2 = ctx
1257 .register_accessor("gone2", Accessor::read_only(|_| Ok(None)))
1258 .unwrap();
1259 assert!(handle2.dispose());
1260 assert!(ctx.read_property("gone2").unwrap().is_none());
1261 }
1262
1263 #[test]
1264 fn alias_resolves_same_value() {
1265 let ctx = Context::new_root();
1266 let cell = Arc::new(StdMutex::new(5u64));
1267 let write_cell = cell.clone();
1268 let handle = ctx
1269 .register_accessor(
1270 "primary",
1271 Accessor::read_write(
1272 read_cell_getter(cell),
1273 move |_ctx, value: Arc<dyn Any + Send + Sync>| {
1274 *write_cell.lock() =
1275 value.downcast::<PropValue>().unwrap().0;
1276 Ok(())
1277 },
1278 ),
1279 )
1280 .unwrap();
1281 ctx.alias("nick", "primary").expect("alias binds");
1282
1283 assert_eq!(
1285 *ctx.read_property_typed::<PropValue>("nick").unwrap().unwrap(),
1286 PropValue(5)
1287 );
1288 ctx.write_property("nick", Arc::new(PropValue(6))).unwrap();
1290 assert_eq!(
1291 *ctx.read_property_typed::<PropValue>("primary").unwrap().unwrap(),
1292 PropValue(6)
1293 );
1294
1295 assert!(matches!(
1297 ctx.alias("nick", "primary"),
1298 Err(CordisError::DuplicateProvider { .. })
1299 ));
1300 assert!(matches!(
1301 ctx.alias("x", "missing"),
1302 Err(CordisError::ServiceNotFound(_))
1303 ));
1304
1305 assert!(handle.dispose());
1307 assert!(ctx.read_property("primary").unwrap().is_none());
1308 assert!(ctx.read_property("nick").unwrap().is_none());
1309 }
1310
1311 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
1312 async fn accessor_bypasses_intercept_waterfalls() {
1313 struct Marker;
1314 impl crate::Service for Marker {}
1315
1316 let ctx = Context::new_root();
1317 let events = Arc::new(crate::EventsService::new());
1318 ctx.provide_arc(events.clone());
1319
1320 let _get_gate = events
1322 .on(crate::events::INTERNAL_GET_EVENT.into(), |_p| async move {
1323 Ok(serde_json::json!({ "refuse": true }))
1324 });
1325 let _set_gate = events
1326 .on(crate::events::INTERNAL_SET_EVENT.into(), |_p| async move {
1327 Ok(serde_json::json!("vetoed"))
1328 });
1329
1330 ctx.provide(Marker);
1332 assert!(
1333 ctx.get::<Marker>().is_none(),
1334 "internal/get waterfall must refuse strict reads in this test"
1335 );
1336
1337 let cell = Arc::new(StdMutex::new(3u64));
1339 let write_cell = cell.clone();
1340 let _handle = ctx
1341 .register_accessor(
1342 "open",
1343 Accessor::read_write(
1344 read_cell_getter(cell),
1345 move |_c, value: Arc<dyn Any + Send + Sync>| {
1346 *write_cell.lock() =
1347 value.downcast::<PropValue>().unwrap().0;
1348 Ok(())
1349 },
1350 ),
1351 )
1352 .unwrap();
1353 assert_eq!(
1354 *ctx.read_property_typed::<PropValue>("open").unwrap().unwrap(),
1355 PropValue(3),
1356 "accessor read bypasses internal/get"
1357 );
1358 ctx.write_property("open", Arc::new(PropValue(4))).unwrap();
1359 assert_eq!(
1360 *ctx.read_property_typed::<PropValue>("open").unwrap().unwrap(),
1361 PropValue(4),
1362 "accessor write bypasses internal/set"
1363 );
1364 }
1365}
1366
1367#[cfg(test)]
1368mod intercept_chain_tests {
1369 use super::*;
1370
1371 #[derive(Debug)]
1372 struct LayerSvc(pub u64);
1373 impl crate::Service for LayerSvc {}
1374
1375 #[tokio::test]
1376 async fn chained_layers_append_innermost_effective() {
1377 let ctx = Context::new_root();
1378 ctx.bind_intercept(LayerSvc(1));
1379 assert_eq!(ctx.get::<LayerSvc>().unwrap().0, 1);
1380 ctx.bind_intercept(LayerSvc(2));
1381 assert_eq!(ctx.get::<LayerSvc>().unwrap().0, 2, "innermost layer wins");
1382 let chain = ctx.intercept_chain(TypeId::of::<LayerSvc>());
1383 assert_eq!(chain.len(), 2);
1384 assert_eq!(chain[0].clone().downcast::<LayerSvc>().unwrap().0, 1);
1385 assert_eq!(chain[1].clone().downcast::<LayerSvc>().unwrap().0, 2);
1386 }
1387
1388 #[tokio::test]
1389 async fn intercept_chain_returns_all_layers_in_order() {
1390 let root = Context::new_root();
1391 let mid = root.intercept(LayerSvc(10));
1392 let leaf = mid.intercept(LayerSvc(11));
1393 leaf.bind_intercept(LayerSvc(12));
1394
1395 let chain = leaf.intercept_chain(TypeId::of::<LayerSvc>());
1396 assert_eq!(chain.len(), 3);
1397 let vals: Vec<u64> = chain
1398 .iter()
1399 .map(|a| a.clone().downcast::<LayerSvc>().unwrap().0)
1400 .collect();
1401 assert_eq!(vals, vec![10, 11, 12], "outermost..innermost order");
1402 assert_eq!(leaf.get::<LayerSvc>().unwrap().0, 12);
1403
1404 assert!(Context::chains_structurally_equal(
1407 &chain,
1408 &leaf.intercept_chain(TypeId::of::<LayerSvc>())
1409 ));
1410 let fresh_root = Context::new_root();
1411 let fresh_mid = fresh_root.intercept(LayerSvc(10));
1412 let fresh_leaf = fresh_mid.intercept(LayerSvc(11));
1413 fresh_leaf.bind_intercept(LayerSvc(12));
1414 assert!(!Context::chains_structurally_equal(
1415 &chain,
1416 &fresh_leaf.intercept_chain(TypeId::of::<LayerSvc>())
1417 ));
1418 }
1419
1420 #[tokio::test]
1421 async fn inject_appends_layer() {
1422 let ctx = Context::new_root();
1423 let tid = TypeId::of::<LayerSvc>();
1424
1425 ctx.bind_intercept_untyped(tid, Arc::new(LayerSvc(20)) as Arc<dyn Any + Send + Sync>);
1427 ctx.bind_intercept_untyped(tid, Arc::new(LayerSvc(21)) as Arc<dyn Any + Send + Sync>);
1428 assert_eq!(ctx.intercept_chain(tid).len(), 2);
1429 assert_eq!(ctx.get::<LayerSvc>().unwrap().0, 21);
1430
1431 ctx.remove_intercept_untyped(tid);
1433 assert_eq!(ctx.intercept_chain(tid).len(), 1);
1434 assert_eq!(ctx.get::<LayerSvc>().unwrap().0, 20);
1435 ctx.remove_intercept_untyped(tid);
1436 assert!(ctx.intercept_chain(tid).is_empty());
1437 assert!(ctx.get::<LayerSvc>().is_none());
1438 }
1439}