1use std::{
37 any::{Any, TypeId},
38 collections::{HashMap, HashSet, VecDeque},
39 hash::Hash,
40 sync::{Arc, Mutex},
41};
42
43use tokio::sync::broadcast;
44
45use super::{Identifier, IdentifierFilter};
46use crate::runtime::process::Id;
47
48const DEFAULT_CHANNEL_CAPACITY: usize = 16;
49
50tokio::task_local! {
51 pub(crate) static CURRENT_DATASPACE: DataspaceRegistry;
52}
53
54#[derive(Clone, Debug, PartialEq, Eq)]
56pub enum AssertionUpdate<T> {
57 Asserted(Identifier, T),
59
60 Retracted(Identifier),
62}
63
64#[derive(Clone, PartialEq, Eq, Hash)]
66struct StorageKey {
67 type_id: TypeId,
68 identifier: Identifier,
69}
70
71impl StorageKey {
72 fn new<T: 'static>(identifier: Identifier) -> Self {
73 Self {
74 type_id: TypeId::of::<T>(),
75 identifier,
76 }
77 }
78}
79
80trait AnyChannel: Send + Sync {
82 fn send_retraction(&self, id: &Identifier);
84
85 fn as_any(&self) -> &dyn Any;
87}
88
89struct TypedChannel<T: Clone + Send + Sync + 'static> {
91 tx: broadcast::Sender<AssertionUpdate<T>>,
92}
93
94impl<T: Clone + Send + Sync + 'static> AnyChannel for TypedChannel<T> {
95 fn send_retraction(&self, id: &Identifier) {
96 let _ = self.tx.send(AssertionUpdate::Retracted(id.clone()));
97 }
98
99 fn as_any(&self) -> &dyn Any {
100 self
101 }
102}
103
104struct FilteredChannel {
106 type_id: TypeId,
107 filter: IdentifierFilter,
108 sender: Box<dyn AnyChannel>,
109}
110
111struct StoredValue {
113 value: Box<dyn Any + Send + Sync>,
114 owner: Id,
115}
116
117struct RegistryState {
119 channels: HashMap<StorageKey, Box<dyn AnyChannel>>,
121
122 filtered_channels: Vec<FilteredChannel>,
124
125 current_values: HashMap<StorageKey, StoredValue>,
129
130 process_assertions: HashMap<Id, HashSet<StorageKey>>,
132
133 channel_capacity: usize,
135}
136
137impl RegistryState {
138 fn new(channel_capacity: usize) -> Self {
139 Self {
140 channels: HashMap::new(),
141 filtered_channels: Vec::new(),
142 current_values: HashMap::new(),
143 process_assertions: HashMap::new(),
144 channel_capacity,
145 }
146 }
147
148 fn get_or_create_exact_sender<T>(&mut self, key: StorageKey) -> broadcast::Receiver<AssertionUpdate<T>>
150 where
151 T: Clone + Send + Sync + 'static,
152 {
153 let channel = self.channels.entry(key).or_insert_with(|| {
154 let (tx, _) = broadcast::channel::<AssertionUpdate<T>>(self.channel_capacity);
155 Box::new(TypedChannel { tx })
156 });
157
158 let typed = channel
159 .as_any()
160 .downcast_ref::<TypedChannel<T>>()
161 .unwrap_or_else(|| unreachable!("type mismatch in dataspace registry"));
164
165 typed.tx.subscribe()
166 }
167
168 fn create_filtered_sender<T>(&mut self, filter: IdentifierFilter) -> broadcast::Receiver<AssertionUpdate<T>>
170 where
171 T: Clone + Send + Sync + 'static,
172 {
173 let (tx, rx) = broadcast::channel::<AssertionUpdate<T>>(self.channel_capacity);
174
175 self.filtered_channels.push(FilteredChannel {
176 type_id: TypeId::of::<T>(),
177 filter,
178 sender: Box::new(TypedChannel { tx }),
179 });
180
181 rx
182 }
183
184 fn notify_retraction(&self, key: &StorageKey) {
186 if let Some(ch) = self.channels.get(key) {
187 ch.send_retraction(&key.identifier);
188 }
189
190 for filtered in &self.filtered_channels {
191 if filtered.type_id == key.type_id && filtered.filter.matches(&key.identifier) {
192 filtered.sender.send_retraction(&key.identifier);
193 }
194 }
195 }
196}
197
198struct DataspaceRegistryInner {
200 state: Mutex<RegistryState>,
201}
202
203#[derive(Clone)]
213pub struct DataspaceRegistry {
214 inner: Arc<DataspaceRegistryInner>,
215}
216
217impl Default for DataspaceRegistry {
218 fn default() -> Self {
219 Self::new()
220 }
221}
222
223impl DataspaceRegistry {
224 pub fn new() -> Self {
226 Self::with_channel_capacity(DEFAULT_CHANNEL_CAPACITY)
227 }
228
229 pub fn try_current() -> Option<Self> {
231 CURRENT_DATASPACE.try_with(|ds| ds.clone()).ok()
232 }
233
234 pub fn with_channel_capacity(capacity: usize) -> Self {
236 Self {
237 inner: Arc::new(DataspaceRegistryInner {
238 state: Mutex::new(RegistryState::new(capacity)),
239 }),
240 }
241 }
242
243 pub fn assert<T>(&self, value: T, id: impl Into<Identifier>)
249 where
250 T: Clone + Send + Sync + 'static,
251 {
252 let id = id.into();
253 let key = StorageKey::new::<T>(id.clone());
254 let caller = Id::current();
255 let mut state = self.inner.state.lock().unwrap();
256
257 if let Some(existing) = state.current_values.get(&key) {
259 debug_assert_eq!(
260 existing.owner, caller,
261 "process {caller:?} attempted to update assertion owned by {:?}",
262 existing.owner
263 );
264 if existing.owner != caller {
265 return;
266 }
267 }
268
269 state.current_values.insert(
271 key.clone(),
272 StoredValue {
273 value: Box::new(value.clone()),
274 owner: caller,
275 },
276 );
277
278 state.process_assertions.entry(caller).or_default().insert(key.clone());
280
281 if let Some(ch) = state.channels.get(&key) {
283 if let Some(typed) = ch.as_any().downcast_ref::<TypedChannel<T>>() {
284 let _ = typed.tx.send(AssertionUpdate::Asserted(id.clone(), value.clone()));
285 }
286 }
287
288 let type_id = TypeId::of::<T>();
290 for channel in &state.filtered_channels {
291 if channel.type_id == type_id && channel.filter.matches(&id) {
292 if let Some(typed) = channel.sender.as_any().downcast_ref::<TypedChannel<T>>() {
293 let _ = typed.tx.send(AssertionUpdate::Asserted(id.clone(), value.clone()));
294 }
295 }
296 }
297 }
298
299 pub fn retract<T>(&self, id: impl Into<Identifier>)
303 where
304 T: Clone + Send + Sync + 'static,
305 {
306 let id = id.into();
307 let key = StorageKey::new::<T>(id.clone());
308 let caller = Id::current();
309 let mut state = self.inner.state.lock().unwrap();
310
311 let Some(stored) = state.current_values.get(&key) else {
313 return;
314 };
315
316 debug_assert_eq!(
317 stored.owner, caller,
318 "process {caller:?} attempted to retract assertion owned by {:?}",
319 stored.owner
320 );
321 if stored.owner != caller {
322 return;
323 }
324
325 state.current_values.remove(&key);
327
328 if let Some(keys) = state.process_assertions.get_mut(&caller) {
329 keys.remove(&key);
330 if keys.is_empty() {
331 state.process_assertions.remove(&caller);
332 }
333 }
334
335 state.notify_retraction(&key);
336 }
337
338 pub(crate) fn retract_all_for_process(&self, process_id: Id) {
343 let mut state = self.inner.state.lock().unwrap();
344
345 let Some(keys) = state.process_assertions.remove(&process_id) else {
346 return;
347 };
348
349 for key in keys {
350 state.current_values.remove(&key);
351 state.notify_retraction(&key);
352 }
353 }
354
355 pub fn current_values<T>(&self, filter: IdentifierFilter) -> Vec<T>
360 where
361 T: Clone + Send + Sync + 'static,
362 {
363 let type_id = TypeId::of::<T>();
364 let state = self.inner.state.lock().unwrap();
365 state
366 .current_values
367 .iter()
368 .filter(|(key, _)| key.type_id == type_id && filter.matches(&key.identifier))
369 .filter_map(|(_, stored)| stored.value.downcast_ref::<T>().cloned())
370 .collect()
371 }
372
373 pub fn subscribe<T>(&self, filter: IdentifierFilter) -> Subscription<T>
379 where
380 T: Clone + Send + Sync + 'static,
381 {
382 let mut state = self.inner.state.lock().unwrap();
383
384 match filter {
385 IdentifierFilter::Exact(ref id) => {
386 let key = StorageKey::new::<T>(id.clone());
387 let rx = state.get_or_create_exact_sender::<T>(key.clone());
388
389 let pending: VecDeque<_> = state
391 .current_values
392 .get(&key)
393 .and_then(|stored| stored.value.downcast_ref::<T>())
394 .map(|value| AssertionUpdate::Asserted(id.clone(), value.clone()))
395 .into_iter()
396 .collect();
397
398 Subscription { pending, rx }
399 }
400 filter @ (IdentifierFilter::All | IdentifierFilter::Prefix(_)) => {
401 let rx = state.create_filtered_sender::<T>(filter.clone());
402
403 let type_id = TypeId::of::<T>();
405 let pending: VecDeque<_> = state
406 .current_values
407 .iter()
408 .filter(|(key, _)| key.type_id == type_id && filter.matches(&key.identifier))
409 .filter_map(|(key, stored)| {
410 stored
411 .value
412 .downcast_ref::<T>()
413 .map(|value| AssertionUpdate::Asserted(key.identifier.clone(), value.clone()))
414 })
415 .collect();
416
417 Subscription { pending, rx }
418 }
419 }
420 }
421}
422
423pub struct Subscription<T> {
425 pending: VecDeque<AssertionUpdate<T>>,
426 rx: broadcast::Receiver<AssertionUpdate<T>>,
427}
428
429impl<T> Subscription<T>
430where
431 T: Clone + Send + Sync + 'static,
432{
433 pub async fn recv(&mut self) -> Option<AssertionUpdate<T>> {
439 if let Some(value) = self.pending.pop_front() {
442 return Some(value);
443 }
444
445 loop {
446 match self.rx.recv().await {
447 Ok(value) => return Some(value),
448 Err(broadcast::error::RecvError::Lagged(_)) => continue,
449 Err(broadcast::error::RecvError::Closed) => return None,
450 }
451 }
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use std::future::pending;
458
459 use tokio_test::{assert_pending, assert_ready, assert_ready_eq, task::spawn as test_spawn};
460
461 use super::*;
462 use crate::runtime::process::Process;
463
464 #[test]
465 fn subscribe_then_assert() {
466 let registry = DataspaceRegistry::new();
467 let id = Identifier::numeric(1);
468
469 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
470 registry.assert(42u32, id.clone());
471
472 let mut recv = test_spawn(sub.recv());
473 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 42)));
474 }
475
476 #[test]
477 fn multiple_subscribers_receive_same_assertion() {
478 let registry = DataspaceRegistry::new();
479 let id = Identifier::numeric(1);
480
481 let mut sub1 = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
482 let mut sub2 = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
483
484 registry.assert(42u32, id.clone());
485
486 let mut recv1 = test_spawn(sub1.recv());
487 assert_ready_eq!(recv1.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
488
489 let mut recv2 = test_spawn(sub2.recv());
490 assert_ready_eq!(recv2.poll(), Some(AssertionUpdate::Asserted(id, 42)));
491 }
492
493 #[test]
494 fn assert_without_subscribers_stores_value() {
495 let registry = DataspaceRegistry::new();
496 let id = Identifier::numeric(1);
497
498 registry.assert(42u32, id.clone());
500
501 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
503 let mut recv = test_spawn(sub.recv());
504 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 42)));
505 }
506
507 #[test]
508 fn different_types_same_identifier() {
509 let registry = DataspaceRegistry::new();
510 let id = Identifier::numeric(1);
511
512 let mut sub_u32 = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
513 let mut sub_string = registry.subscribe::<String>(IdentifierFilter::exact(id.clone()));
514
515 registry.assert(42u32, id.clone());
516 registry.assert("hello".to_string(), id.clone());
517
518 let mut recv_u32 = test_spawn(sub_u32.recv());
519 assert_ready_eq!(recv_u32.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
520
521 let mut recv_string = test_spawn(sub_string.recv());
522 assert_ready_eq!(
523 recv_string.poll(),
524 Some(AssertionUpdate::Asserted(id, "hello".to_string()))
525 );
526 }
527
528 #[test]
529 fn process_identifier() {
530 let registry = DataspaceRegistry::new();
531 let pid = crate::runtime::process::Id::new();
532 let id = Identifier::from(pid);
533
534 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
535 registry.assert(42u32, id.clone());
536
537 let mut recv = test_spawn(sub.recv());
538 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 42)));
539 }
540
541 #[test]
542 fn channel_closed_returns_none() {
543 let registry = DataspaceRegistry::new();
544 let id = Identifier::numeric(1);
545
546 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id));
547
548 drop(registry);
550
551 let mut recv = test_spawn(sub.recv());
552 assert_ready_eq!(recv.poll(), None);
553 }
554
555 #[test]
556 fn lagged_subscriber_recovers() {
557 let registry = DataspaceRegistry::with_channel_capacity(2);
559 let id = Identifier::numeric(1);
560
561 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
562
563 for i in 0..10 {
565 registry.assert(i as u32, id.clone());
566 }
567
568 let mut recv = test_spawn(sub.recv());
570 let value = assert_ready!(recv.poll());
571 assert!(value.is_some());
572 }
573
574 #[test]
575 fn multiple_values_received_in_order() {
576 let registry = DataspaceRegistry::new();
577 let id = Identifier::numeric(1);
578
579 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
580
581 registry.assert(1u32, id.clone());
582 registry.assert(2u32, id.clone());
583 registry.assert(3u32, id.clone());
584
585 let mut recv = test_spawn(sub.recv());
586 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 1)));
587 drop(recv);
588
589 let mut recv = test_spawn(sub.recv());
590 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 2)));
591 drop(recv);
592
593 let mut recv = test_spawn(sub.recv());
594 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 3)));
595 }
596
597 #[test]
598 fn assert_then_retract() {
599 let registry = DataspaceRegistry::new();
600 let id = Identifier::numeric(1);
601
602 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
603
604 registry.assert(42u32, id.clone());
605 registry.retract::<u32>(id.clone());
606
607 let mut recv = test_spawn(sub.recv());
608 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
609 drop(recv);
610
611 let mut recv = test_spawn(sub.recv());
612 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id)));
613 }
614
615 #[test]
616 fn retract_without_subscribers_succeeds() {
617 let registry = DataspaceRegistry::new();
618 let id = Identifier::numeric(1);
619
620 registry.retract::<u32>(id);
622 }
623
624 #[test]
625 fn multiple_subscribers_receive_retraction() {
626 let registry = DataspaceRegistry::new();
627 let id = Identifier::numeric(1);
628
629 let mut sub1 = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
630 let mut sub2 = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
631
632 registry.assert(42u32, id.clone());
633 registry.retract::<u32>(id.clone());
634
635 let mut recv1 = test_spawn(sub1.recv());
637 assert_ready_eq!(recv1.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
638 drop(recv1);
639
640 let mut recv2 = test_spawn(sub2.recv());
641 assert_ready_eq!(recv2.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
642 drop(recv2);
643
644 let mut recv1 = test_spawn(sub1.recv());
646 assert_ready_eq!(recv1.poll(), Some(AssertionUpdate::Retracted(id.clone())));
647
648 let mut recv2 = test_spawn(sub2.recv());
649 assert_ready_eq!(recv2.poll(), Some(AssertionUpdate::Retracted(id)));
650 }
651
652 #[test]
653 fn assert_retract_assert_sequence() {
654 let registry = DataspaceRegistry::new();
655 let id = Identifier::numeric(1);
656
657 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
658
659 registry.assert(1u32, id.clone());
660 registry.retract::<u32>(id.clone());
661 registry.assert(2u32, id.clone());
662
663 let mut recv = test_spawn(sub.recv());
664 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 1)));
665 drop(recv);
666
667 let mut recv = test_spawn(sub.recv());
668 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id.clone())));
669 drop(recv);
670
671 let mut recv = test_spawn(sub.recv());
672 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 2)));
673 }
674
675 #[test]
676 fn all_filter_receives_from_multiple_identifiers() {
677 let registry = DataspaceRegistry::new();
678 let id1 = Identifier::numeric(1);
679 let id2 = Identifier::numeric(2);
680
681 let mut sub = registry.subscribe::<u32>(IdentifierFilter::all());
682
683 registry.assert(1u32, id1.clone());
684 registry.assert(2u32, id2.clone());
685
686 let mut recv = test_spawn(sub.recv());
687 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id1, 1)));
688 drop(recv);
689
690 let mut recv = test_spawn(sub.recv());
691 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id2, 2)));
692 }
693
694 #[test]
695 fn all_filter_receives_retraction() {
696 let registry = DataspaceRegistry::new();
697 let id = Identifier::numeric(1);
698
699 let mut sub = registry.subscribe::<u32>(IdentifierFilter::all());
700
701 registry.assert(42u32, id.clone());
702 registry.retract::<u32>(id.clone());
703
704 let mut recv = test_spawn(sub.recv());
705 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
706 drop(recv);
707
708 let mut recv = test_spawn(sub.recv());
709 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id)));
710 }
711
712 #[test]
713 fn all_filter_and_exact_both_receive() {
714 let registry = DataspaceRegistry::new();
715 let id = Identifier::numeric(1);
716
717 let mut specific = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
718 let mut all = registry.subscribe::<u32>(IdentifierFilter::all());
719
720 registry.assert(42u32, id.clone());
721
722 let mut recv_specific = test_spawn(specific.recv());
723 assert_ready_eq!(recv_specific.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
724
725 let mut recv_all = test_spawn(all.recv());
726 assert_ready_eq!(recv_all.poll(), Some(AssertionUpdate::Asserted(id, 42)));
727 }
728
729 #[test]
730 fn all_filter_created_before_exact_channels() {
731 let registry = DataspaceRegistry::new();
732
733 let mut all = registry.subscribe::<u32>(IdentifierFilter::all());
735
736 let id = Identifier::numeric(1);
737 registry.assert(42u32, id.clone());
738
739 let mut recv = test_spawn(all.recv());
740 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 42)));
741 }
742
743 #[test]
744 fn subscribe_receives_current_value() {
745 let registry = DataspaceRegistry::new();
746 let id = Identifier::numeric(1);
747
748 registry.assert(42u32, id.clone());
750
751 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
753 let mut recv = test_spawn(sub.recv());
754 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 42)));
755 }
756
757 #[test]
758 fn subscribe_after_retract_gets_nothing_pending() {
759 let registry = DataspaceRegistry::new();
760 let id = Identifier::numeric(1);
761
762 registry.assert(42u32, id.clone());
764 registry.retract::<u32>(id.clone());
765
766 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id));
767
768 drop(registry);
770
771 let mut recv = test_spawn(sub.recv());
772 assert_ready_eq!(recv.poll(), None);
773 }
774
775 #[test]
776 fn all_filter_receives_current_values() {
777 let registry = DataspaceRegistry::new();
778 let id1 = Identifier::numeric(1);
779 let id2 = Identifier::numeric(2);
780
781 registry.assert(1u32, id1.clone());
783 registry.assert(2u32, id2.clone());
784
785 let mut sub = registry.subscribe::<u32>(IdentifierFilter::all());
786
787 let mut recv = test_spawn(sub.recv());
789 let v1 = assert_ready!(recv.poll());
790 drop(recv);
791
792 let mut recv = test_spawn(sub.recv());
793 let v2 = assert_ready!(recv.poll());
794
795 let mut received = [v1.unwrap(), v2.unwrap()];
796 received.sort_by_key(|update| match update {
797 AssertionUpdate::Asserted(_, v) => *v,
798 AssertionUpdate::Retracted(_) => 0,
799 });
800
801 assert_eq!(received[0], AssertionUpdate::Asserted(id1, 1));
802 assert_eq!(received[1], AssertionUpdate::Asserted(id2, 2));
803 }
804
805 #[test]
806 fn subscribe_receives_current_then_future() {
807 let registry = DataspaceRegistry::new();
808 let id = Identifier::numeric(1);
809
810 registry.assert(1u32, id.clone());
812
813 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
814
815 registry.assert(2u32, id.clone());
817
818 let mut recv = test_spawn(sub.recv());
820 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 1)));
821 drop(recv);
822
823 let mut recv = test_spawn(sub.recv());
824 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 2)));
825 }
826
827 #[test]
828 fn prefix_filter_matches_named_identifiers() {
829 let registry = DataspaceRegistry::new();
830 let id1 = Identifier::named("metrics.cpu");
831 let id2 = Identifier::named("metrics.mem");
832 let id3 = Identifier::named("logs.error");
833
834 let mut sub = registry.subscribe::<u32>(IdentifierFilter::prefix("metrics."));
835
836 registry.assert(1u32, id1.clone());
837 registry.assert(2u32, id2.clone());
838 registry.assert(3u32, id3);
839
840 let mut recv = test_spawn(sub.recv());
842 let v1 = assert_ready!(recv.poll());
843 drop(recv);
844
845 let mut recv = test_spawn(sub.recv());
846 let v2 = assert_ready!(recv.poll());
847
848 let mut received = [v1.unwrap(), v2.unwrap()];
849 received.sort_by_key(|update| match update {
850 AssertionUpdate::Asserted(_, v) => *v,
851 AssertionUpdate::Retracted(_) => 0,
852 });
853
854 assert_eq!(received[0], AssertionUpdate::Asserted(id1, 1));
855 assert_eq!(received[1], AssertionUpdate::Asserted(id2, 2));
856 }
857
858 #[test]
859 fn prefix_filter_does_not_match_numeric() {
860 let registry = DataspaceRegistry::new();
861 let id = Identifier::numeric(42);
862
863 let mut sub = registry.subscribe::<u32>(IdentifierFilter::prefix("any"));
864
865 registry.assert(1u32, id);
866
867 drop(registry);
869
870 let mut recv = test_spawn(sub.recv());
871 assert_ready_eq!(recv.poll(), None);
872 }
873
874 #[test]
875 fn prefix_filter_replays_matching_current_values() {
876 let registry = DataspaceRegistry::new();
877 let id1 = Identifier::named("svc.alpha");
878 let id2 = Identifier::named("svc.beta");
879 let id3 = Identifier::named("other.gamma");
880
881 registry.assert(1u32, id1.clone());
883 registry.assert(2u32, id2.clone());
884 registry.assert(3u32, id3);
885
886 let mut sub = registry.subscribe::<u32>(IdentifierFilter::prefix("svc."));
887
888 let mut recv = test_spawn(sub.recv());
890 let v1 = assert_ready!(recv.poll());
891 drop(recv);
892
893 let mut recv = test_spawn(sub.recv());
894 let v2 = assert_ready!(recv.poll());
895
896 let mut received = [v1.unwrap(), v2.unwrap()];
897 received.sort_by_key(|update| match update {
898 AssertionUpdate::Asserted(_, v) => *v,
899 AssertionUpdate::Retracted(_) => 0,
900 });
901
902 assert_eq!(received[0], AssertionUpdate::Asserted(id1, 1));
903 assert_eq!(received[1], AssertionUpdate::Asserted(id2, 2));
904 }
905
906 #[test]
907 fn try_current_returns_none_outside_context() {
908 assert!(DataspaceRegistry::try_current().is_none());
909 }
910
911 #[test]
912 fn current_and_try_current_work_within_scope() {
913 let registry = DataspaceRegistry::new();
914 let registry_clone = registry.clone();
915
916 let mut scope_fut = test_spawn(CURRENT_DATASPACE.scope(registry, async {
917 let current = DataspaceRegistry::try_current();
918 assert!(current.is_some());
919
920 let current = current.unwrap();
922 let id = Identifier::named("test");
923 current.assert(42u32, id.clone());
924
925 let mut sub = registry_clone.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
926 let value = sub.recv().await;
927 assert_eq!(value, Some(AssertionUpdate::Asserted(id, 42)));
928 }));
929 assert_ready!(scope_fut.poll());
930 }
931
932 #[test]
933 fn retract_all_for_process_retracts_all_owned_assertions() {
934 let registry = DataspaceRegistry::new();
935 let process_id = Id::new();
936 let id1 = Identifier::named("val1");
937 let id2 = Identifier::named("val2");
938
939 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(process_id, || {
941 registry.assert(1u32, id1.clone());
942 registry.assert(2u32, id2.clone());
943 });
944
945 let mut sub1 = registry.subscribe::<u32>(IdentifierFilter::exact(id1.clone()));
947 let mut sub2 = registry.subscribe::<u32>(IdentifierFilter::exact(id2.clone()));
948
949 let mut recv = test_spawn(sub1.recv());
951 let _ = assert_ready!(recv.poll());
952 drop(recv);
953
954 let mut recv = test_spawn(sub2.recv());
955 let _ = assert_ready!(recv.poll());
956 drop(recv);
957
958 registry.retract_all_for_process(process_id);
960
961 let mut recv = test_spawn(sub1.recv());
963 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id1)));
964 drop(recv);
965
966 let mut recv = test_spawn(sub2.recv());
967 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id2)));
968 }
969
970 #[test]
971 fn retract_all_for_process_does_not_affect_other_processes() {
972 let registry = DataspaceRegistry::new();
973 let pid_a = Id::new();
974 let pid_b = Id::new();
975 let id_a = Identifier::named("a");
976 let id_b = Identifier::named("b");
977
978 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
979 registry.assert(1u32, id_a.clone());
980 });
981 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_b, || {
982 registry.assert(2u32, id_b.clone());
983 });
984
985 registry.retract_all_for_process(pid_a);
987
988 let mut sub_b = registry.subscribe::<u32>(IdentifierFilter::exact(id_b.clone()));
990 let mut recv = test_spawn(sub_b.recv());
991 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id_b, 2)));
992 drop(recv);
993
994 let mut sub_a = registry.subscribe::<u32>(IdentifierFilter::exact(id_a));
996 drop(registry);
997 let mut recv = test_spawn(sub_a.recv());
998 assert_ready_eq!(recv.poll(), None);
999 }
1000
1001 #[test]
1002 fn retract_all_for_process_notifies_filtered_subscribers() {
1003 let registry = DataspaceRegistry::new();
1004 let process_id = Id::new();
1005 let id = Identifier::named("val");
1006
1007 let mut all_sub = registry.subscribe::<u32>(IdentifierFilter::all());
1008
1009 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(process_id, || {
1010 registry.assert(42u32, id.clone());
1011 });
1012
1013 let mut recv = test_spawn(all_sub.recv());
1015 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
1016 drop(recv);
1017
1018 registry.retract_all_for_process(process_id);
1020
1021 let mut recv = test_spawn(all_sub.recv());
1023 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id)));
1024 }
1025
1026 #[test]
1027 fn manual_retract_cleans_up_process_tracking() {
1028 let registry = DataspaceRegistry::new();
1029 let process_id = Id::new();
1030 let id = Identifier::named("val");
1031
1032 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
1033
1034 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(process_id, || {
1035 registry.assert(42u32, id.clone());
1036 });
1037
1038 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(process_id, || {
1040 registry.retract::<u32>(id.clone());
1041 });
1042
1043 let mut recv = test_spawn(sub.recv());
1045 let _ = assert_ready!(recv.poll());
1046 drop(recv);
1047
1048 let mut recv = test_spawn(sub.recv());
1049 let _ = assert_ready!(recv.poll());
1050 drop(recv);
1051
1052 registry.retract_all_for_process(process_id);
1054
1055 drop(registry);
1057 let mut recv = test_spawn(sub.recv());
1058 assert_ready_eq!(recv.poll(), None);
1059 }
1060
1061 #[test]
1062 fn retract_all_for_unknown_process_is_noop() {
1063 let registry = DataspaceRegistry::new();
1064 registry.retract_all_for_process(Id::new());
1066 }
1067
1068 #[test]
1069 fn instrumented_process_retracts_on_normal_completion() {
1070 let registry = DataspaceRegistry::new();
1071 let process = Process::supervisor_with_dataspace("test_worker", None, Some(registry.clone())).unwrap();
1072 let id = "from_worker";
1073
1074 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id));
1075
1076 let mut recv_fut = test_spawn(sub.recv());
1078 assert!(!recv_fut.is_woken());
1079 assert_pending!(recv_fut.poll());
1080
1081 let mut worker = test_spawn(process.into_process_future(async {
1083 DataspaceRegistry::try_current()
1084 .expect("dataspace registry should be available")
1085 .assert(42u32, "from_worker");
1086 }));
1087
1088 assert_ready!(worker.poll());
1090
1091 assert!(recv_fut.is_woken());
1093 assert_ready_eq!(recv_fut.poll(), Some(AssertionUpdate::Asserted(id.into(), 42)));
1094
1095 drop(recv_fut);
1096
1097 let mut recv_fut = test_spawn(sub.recv());
1099 assert_pending!(recv_fut.poll());
1100 assert!(!recv_fut.is_woken());
1101
1102 drop(worker);
1104
1105 assert!(recv_fut.is_woken());
1107 assert_ready_eq!(recv_fut.poll(), Some(AssertionUpdate::Retracted(id.into())));
1108 }
1109
1110 #[test]
1111 fn instrumented_process_retracts_on_drop_before_completion() {
1112 let registry = DataspaceRegistry::new();
1113 let process = Process::supervisor_with_dataspace("test_worker", None, Some(registry.clone())).unwrap();
1114 let id = "from_worker";
1115
1116 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id));
1117
1118 let mut recv_fut = test_spawn(sub.recv());
1120 assert!(!recv_fut.is_woken());
1121 assert_pending!(recv_fut.poll());
1122
1123 let mut worker = test_spawn(process.into_process_future(async {
1125 DataspaceRegistry::try_current()
1126 .expect("dataspace registry should be available")
1127 .assert(42u32, "from_worker");
1128 pending::<()>().await;
1129 }));
1130
1131 assert_pending!(worker.poll());
1133
1134 assert!(recv_fut.is_woken());
1136 assert_ready_eq!(recv_fut.poll(), Some(AssertionUpdate::Asserted(id.into(), 42)));
1137
1138 drop(recv_fut);
1139
1140 let mut recv_fut = test_spawn(sub.recv());
1142 assert_pending!(recv_fut.poll());
1143 assert!(!recv_fut.is_woken());
1144
1145 drop(worker);
1147
1148 assert!(recv_fut.is_woken());
1150 assert_ready_eq!(recv_fut.poll(), Some(AssertionUpdate::Retracted(id.into())));
1151 }
1152
1153 #[test]
1154 fn instrumented_process_retracts_multiple_types_on_drop() {
1155 let registry = DataspaceRegistry::new();
1156 let process = Process::supervisor_with_dataspace("test_worker", None, Some(registry.clone())).unwrap();
1157 let id_num = "number";
1158 let id_str = "text";
1159
1160 let mut sub_u32 = registry.subscribe::<u32>(IdentifierFilter::exact(id_num));
1161 let mut sub_str = registry.subscribe::<String>(IdentifierFilter::exact(id_str));
1162
1163 let mut recv_u32_fut = test_spawn(sub_u32.recv());
1165 let mut recv_str_fut = test_spawn(sub_str.recv());
1166 assert!(!recv_u32_fut.is_woken());
1167 assert!(!recv_str_fut.is_woken());
1168 assert_pending!(recv_u32_fut.poll());
1169 assert_pending!(recv_str_fut.poll());
1170
1171 let mut worker = test_spawn(process.into_process_future(async {
1173 let ds = DataspaceRegistry::try_current().expect("dataspace registry should be available");
1174 ds.assert(42u32, id_num);
1175 ds.assert("hello".to_string(), id_str);
1176 pending::<()>().await;
1177 }));
1178
1179 assert_pending!(worker.poll());
1181
1182 assert!(recv_u32_fut.is_woken());
1184 assert!(recv_str_fut.is_woken());
1185 assert_ready_eq!(recv_u32_fut.poll(), Some(AssertionUpdate::Asserted(id_num.into(), 42)));
1186 assert_ready_eq!(
1187 recv_str_fut.poll(),
1188 Some(AssertionUpdate::Asserted(id_str.into(), "hello".to_string()))
1189 );
1190
1191 drop(recv_u32_fut);
1192 drop(recv_str_fut);
1193
1194 let mut recv_u32 = test_spawn(sub_u32.recv());
1196 let mut recv_str = test_spawn(sub_str.recv());
1197 assert_pending!(recv_u32.poll());
1198 assert_pending!(recv_str.poll());
1199 assert!(!recv_u32.is_woken());
1200 assert!(!recv_str.is_woken());
1201
1202 drop(worker);
1204
1205 assert!(recv_u32.is_woken());
1206 assert!(recv_str.is_woken());
1207 assert_ready_eq!(recv_u32.poll(), Some(AssertionUpdate::Retracted(id_num.into())));
1208 assert_ready_eq!(recv_str.poll(), Some(AssertionUpdate::Retracted(id_str.into())));
1209 }
1210
1211 #[test]
1212 #[cfg(not(debug_assertions))]
1213 fn retract_from_non_owner_is_ignored() {
1214 let registry = DataspaceRegistry::new();
1215 let pid_a = Id::new();
1216 let pid_b = Id::new();
1217 let id = Identifier::named("owned_by_a");
1218
1219 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1221 registry.assert(42u32, id.clone());
1222 });
1223
1224 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_b, || {
1226 registry.retract::<u32>(id.clone());
1227 });
1228
1229 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
1231 let mut recv = test_spawn(sub.recv());
1232 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
1233 drop(recv);
1234
1235 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1237 registry.retract::<u32>(id.clone());
1238 });
1239
1240 let mut recv = test_spawn(sub.recv());
1242 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Retracted(id)));
1243 }
1244
1245 #[test]
1246 #[cfg(debug_assertions)]
1247 #[should_panic(expected = "attempted to retract assertion owned by")]
1248 fn retract_from_non_owner_panics_in_debug() {
1249 let registry = DataspaceRegistry::new();
1250 let pid_a = Id::new();
1251 let pid_b = Id::new();
1252 let id = Identifier::named("owned_by_a");
1253
1254 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1255 registry.assert(42u32, id.clone());
1256 });
1257
1258 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_b, || {
1259 registry.retract::<u32>(id.clone());
1260 });
1261 }
1262
1263 #[test]
1264 #[cfg(not(debug_assertions))]
1265 fn reassert_from_non_owner_is_ignored() {
1266 let registry = DataspaceRegistry::new();
1267 let pid_a = Id::new();
1268 let pid_b = Id::new();
1269 let id = Identifier::named("owned_by_a");
1270
1271 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1273 registry.assert(42u32, id.clone());
1274 });
1275
1276 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_b, || {
1278 registry.assert(99u32, id.clone());
1279 });
1280
1281 let mut sub = registry.subscribe::<u32>(IdentifierFilter::exact(id.clone()));
1283 let mut recv = test_spawn(sub.recv());
1284 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id.clone(), 42)));
1285 drop(recv);
1286
1287 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1289 registry.assert(100u32, id.clone());
1290 });
1291
1292 let mut recv = test_spawn(sub.recv());
1294 assert_ready_eq!(recv.poll(), Some(AssertionUpdate::Asserted(id, 100)));
1295 }
1296
1297 #[test]
1298 #[cfg(debug_assertions)]
1299 #[should_panic(expected = "attempted to update assertion owned by")]
1300 fn reassert_from_non_owner_panics_in_debug() {
1301 let registry = DataspaceRegistry::new();
1302 let pid_a = Id::new();
1303 let pid_b = Id::new();
1304 let id = Identifier::named("owned_by_a");
1305
1306 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_a, || {
1307 registry.assert(42u32, id.clone());
1308 });
1309
1310 crate::runtime::process::CURRENT_PROCESS_ID.sync_scope(pid_b, || {
1311 registry.assert(99u32, id.clone());
1312 });
1313 }
1314}