1#![allow(clippy::disallowed_types)]
2use core::any::{Any, TypeId};
35use core::fmt;
36use core::pin::Pin;
37
38use crate::std::{boxed::Box, sync::Arc, vec::Vec};
39
40pub use rama_macros::{Extension, FromExtensions};
41use rama_utils::collections::AppendOnlyVec;
42use rama_utils::macros::impl_deref;
43
44#[derive(Clone, Default)]
45pub struct Extensions {
66 extensions: Arc<AppendOnlyVec<TypeErasedExtension, 12, 3>>,
67 parent: Option<Box<Self>>,
68}
69
70impl Extensions {
71 #[inline(always)]
73 #[must_use]
74 pub fn new() -> Self {
75 Self::default()
76 }
77
78 #[must_use]
86 pub fn fork(&self) -> Self {
87 Self {
88 extensions: Arc::new(AppendOnlyVec::new()),
89 parent: Some(Box::new(self.clone())),
90 }
91 }
92
93 #[inline(always)]
95 #[must_use]
96 pub fn parent(&self) -> Option<&Self> {
97 self.parent.as_deref()
98 }
99
100 #[must_use]
109 pub fn with_base(&self, base: &Self) -> Self {
110 let parent = match &self.parent {
111 Some(parent) => parent.with_base(base),
112 None => base.clone(),
113 };
114 Self {
115 extensions: Arc::clone(&self.extensions),
116 parent: Some(Box::new(parent)),
117 }
118 }
119
120 pub fn insert<T: Extension>(&self, val: T) -> &T {
128 let extension = TypeErasedExtension::new(val);
129 let idx = self.extensions.push(extension);
130
131 #[expect(
132 clippy::unwrap_used,
133 reason = "`downcast_ref` can only be none if TypeId doesn't match, but we just inserted this type"
134 )]
135 self.extensions[idx].downcast_ref::<T>().unwrap()
136 }
137
138 pub fn insert_arc<T: Extension>(&self, val: Arc<T>) -> Arc<T> {
145 let extension = TypeErasedExtension::new_arc(val);
146 let idx = self.extensions.push(extension);
147
148 #[expect(
149 clippy::unwrap_used,
150 reason = "`cloned_downcast` can only be none if TypeId doesn't match, but we just inserted this type"
151 )]
152 self.extensions[idx].cloned_downcast::<T>().unwrap()
153 }
154
155 pub fn extend(&self, other: &Self) {
159 for ext in other.extensions.iter() {
160 self.extensions.push(ext.clone());
161 }
162 }
163
164 #[must_use]
172 pub fn contains<T: Extension>(&self) -> bool {
173 self.get_ref::<T>().is_some()
174 }
175
176 #[must_use]
180 pub fn self_contains<T: Extension>(&self) -> bool {
181 let type_id = TypeId::of::<T>();
182 self.extensions
183 .iter()
184 .rev()
185 .any(|item| item.type_id == type_id)
186 }
187
188 #[must_use]
189 pub fn get_ref<T: Extension>(&self) -> Option<&T> {
215 let target = TypeId::of::<T>();
216 let egress_id = TypeId::of::<Egress<Self>>();
217 let ingress_id = TypeId::of::<Ingress<Self>>();
218 for ext in self.extensions.iter().rev() {
219 if ext.type_id == target {
220 if let Some(v) = ext.downcast_ref::<T>() {
221 return Some(v);
222 }
223 } else if ext.type_id == egress_id
224 && let Some(eg) = ext.downcast_ref::<Egress<Self>>()
225 && let Some(v) = eg.0.get_ref::<T>()
226 {
227 return Some(v);
228 } else if ext.type_id == ingress_id
229 && let Some(ig) = ext.downcast_ref::<Ingress<Self>>()
230 && let Some(v) = ig.0.get_ref::<T>()
231 {
232 return Some(v);
233 }
234 }
235 self.parent().and_then(|p| p.get_ref::<T>())
236 }
237
238 #[must_use]
242 pub fn self_get_ref<T: Extension>(&self) -> Option<&T> {
243 let type_id = TypeId::of::<T>();
244 self.extensions
245 .iter()
246 .rev()
247 .find(|item| item.type_id == type_id)
248 .and_then(|ext| ext.downcast_ref())
249 }
250
251 #[must_use]
252 pub fn get_arc<T: Extension>(&self) -> Option<Arc<T>> {
259 let target = TypeId::of::<T>();
260 let egress_id = TypeId::of::<Egress<Self>>();
261 let ingress_id = TypeId::of::<Ingress<Self>>();
262 for ext in self.extensions.iter().rev() {
263 if ext.type_id == target {
264 if let Some(v) = ext.cloned_downcast::<T>() {
265 return Some(v);
266 }
267 } else if ext.type_id == egress_id
268 && let Some(eg) = ext.downcast_ref::<Egress<Self>>()
269 && let Some(v) = eg.0.get_arc::<T>()
270 {
271 return Some(v);
272 } else if ext.type_id == ingress_id
273 && let Some(ig) = ext.downcast_ref::<Ingress<Self>>()
274 && let Some(v) = ig.0.get_arc::<T>()
275 {
276 return Some(v);
277 }
278 }
279 self.parent().and_then(|p| p.get_arc::<T>())
280 }
281
282 #[must_use]
286 pub fn self_get_arc<T: Extension>(&self) -> Option<Arc<T>> {
287 let type_id = TypeId::of::<T>();
288 self.extensions
289 .iter()
290 .rev()
291 .find(|item| item.type_id == type_id)
292 .and_then(|ext| ext.cloned_downcast())
293 }
294
295 pub fn get_many_ref<'a, T: GetManyRef<'a>>(&'a self) -> T::Output {
303 T::get_many_ref(self)
304 }
305
306 pub fn get_many_arc<T: GetManyArc>(&self) -> T::Output {
310 T::get_many_arc(self)
311 }
312
313 #[doc(hidden)]
331 pub fn get_many_erased<'a, const N: usize>(
332 &'a self,
333 targets: &[TypeId; N],
334 out: &mut [Option<(&'a TypeErasedExtension, usize)>; N],
335 ) {
336 let mut rank = 0;
337 self.get_many_erased_ranked(targets, out, &mut rank);
338 }
339
340 fn get_many_erased_ranked<'a, const N: usize>(
341 &'a self,
342 targets: &[TypeId; N],
343 out: &mut [Option<(&'a TypeErasedExtension, usize)>; N],
344 rank: &mut usize,
345 ) {
346 let egress_id = TypeId::of::<Egress<Self>>();
347 let ingress_id = TypeId::of::<Ingress<Self>>();
348 let mut remaining = out.iter().filter(|slot| slot.is_none()).count();
349 if remaining == 0 {
350 return;
351 }
352 for ext in self.extensions.iter().rev() {
353 let current = *rank;
354 *rank += 1;
355 for (i, &tid) in targets.iter().enumerate() {
356 if out[i].is_none() && ext.type_id == tid {
357 out[i] = Some((ext, current));
358 remaining -= 1;
359
360 if remaining == 0 {
361 return;
362 }
363 }
364 }
365
366 if ext.type_id == egress_id
367 && let Some(eg) = ext.downcast_ref::<Egress<Self>>()
368 {
369 eg.0.get_many_erased_ranked(targets, out, rank);
370 remaining = out.iter().filter(|slot| slot.is_none()).count();
371 if remaining == 0 {
372 return;
373 }
374 } else if ext.type_id == ingress_id
375 && let Some(ig) = ext.downcast_ref::<Ingress<Self>>()
376 {
377 ig.0.get_many_erased_ranked(targets, out, rank);
378 remaining = out.iter().filter(|slot| slot.is_none()).count();
379 if remaining == 0 {
380 return;
381 }
382 }
383 }
384 if remaining != 0
385 && let Some(parent) = self.parent()
386 {
387 parent.get_many_erased_ranked(targets, out, rank);
388 }
389 }
390
391 pub fn get_ref_or_insert<T, F>(&self, create_fn: F) -> &T
401 where
402 T: Extension,
403 F: FnOnce() -> T,
404 {
405 self.get_ref().unwrap_or_else(|| self.insert(create_fn()))
406 }
407
408 pub fn get_arc_or_insert<T, F>(&self, create_fn: F) -> Arc<T>
410 where
411 T: Extension,
412 F: FnOnce() -> Arc<T>,
413 {
414 self.get_arc()
415 .unwrap_or_else(|| self.insert_arc(create_fn()))
416 }
417
418 pub fn self_get_ref_or_insert<T, F>(&self, create_fn: F) -> &T
426 where
427 T: Extension,
428 F: FnOnce() -> T,
429 {
430 self.self_get_ref()
431 .unwrap_or_else(|| self.insert(create_fn()))
432 }
433
434 pub fn self_get_arc_or_insert<T, F>(&self, create_fn: F) -> Arc<T>
436 where
437 T: Extension,
438 F: FnOnce() -> Arc<T>,
439 {
440 self.self_get_arc()
441 .unwrap_or_else(|| self.insert_arc(create_fn()))
442 }
443
444 #[must_use]
454 pub fn self_first_ref<T: Extension>(&self) -> Option<&T> {
455 let type_id = TypeId::of::<T>();
456 self.extensions
457 .iter()
458 .find(|item| item.type_id == type_id)
459 .and_then(|ext| ext.downcast_ref())
460 }
461
462 #[must_use]
465 pub fn self_first_arc<T: Extension>(&self) -> Option<Arc<T>> {
466 let type_id = TypeId::of::<T>();
467 self.extensions
468 .iter()
469 .find(|item| item.type_id == type_id)
470 .and_then(|ext| ext.cloned_downcast())
471 }
472
473 pub fn self_iter_ref<T: Extension>(&self) -> impl Iterator<Item = &T> {
479 let type_id = TypeId::of::<T>();
480
481 self.extensions
482 .iter()
483 .rev()
484 .filter(move |item| item.type_id == type_id)
485 .filter_map(TypeErasedExtension::downcast_ref::<T>)
486 }
487
488 pub fn self_iter_arc<T: Extension>(&self) -> impl Iterator<Item = Arc<T>> {
494 let type_id = TypeId::of::<T>();
495
496 self.extensions
497 .iter()
498 .rev()
499 .filter(move |item| item.type_id == type_id)
500 .filter_map(TypeErasedExtension::cloned_downcast::<T>)
501 }
502
503 pub fn self_iter_all(&self) -> impl Iterator<Item = &TypeErasedExtension> {
510 self.extensions.iter()
511 }
512
513 pub fn iter_ref<T: Extension>(&self) -> impl Iterator<Item = &T> + '_ {
530 self.iter_ref_inner::<T>()
531 }
532
533 pub fn iter_arc<T: Extension>(&self) -> impl Iterator<Item = Arc<T>> + '_ {
535 self.iter_arc_inner::<T>()
536 }
537
538 fn iter_ref_inner<T: Extension>(&self) -> Box<dyn Iterator<Item = &T> + '_> {
540 let target = TypeId::of::<T>();
541 let egress_id = TypeId::of::<Egress<Self>>();
542 let ingress_id = TypeId::of::<Ingress<Self>>();
543 let local = self.extensions.iter().rev().flat_map(
544 move |ext| -> Box<dyn Iterator<Item = &T> + '_> {
545 if ext.type_id == target {
546 match ext.downcast_ref::<T>() {
547 Some(v) => Box::new(core::iter::once(v)),
548 None => Box::new(core::iter::empty()),
549 }
550 } else if ext.type_id == egress_id {
551 match ext.downcast_ref::<Egress<Self>>() {
552 Some(e) => e.0.iter_ref_inner::<T>(),
553 None => Box::new(core::iter::empty()),
554 }
555 } else if ext.type_id == ingress_id {
556 match ext.downcast_ref::<Ingress<Self>>() {
557 Some(i) => i.0.iter_ref_inner::<T>(),
558 None => Box::new(core::iter::empty()),
559 }
560 } else {
561 Box::new(core::iter::empty())
562 }
563 },
564 );
565 let parent: Box<dyn Iterator<Item = &T>> = match self.parent() {
566 Some(p) => p.iter_ref_inner::<T>(),
567 None => Box::new(core::iter::empty()),
568 };
569 Box::new(local.chain(parent))
570 }
571
572 fn iter_arc_inner<T: Extension>(&self) -> Box<dyn Iterator<Item = Arc<T>> + '_> {
574 let target = TypeId::of::<T>();
575 let egress_id = TypeId::of::<Egress<Self>>();
576 let ingress_id = TypeId::of::<Ingress<Self>>();
577 let local = self.extensions.iter().rev().flat_map(
578 move |ext| -> Box<dyn Iterator<Item = Arc<T>> + '_> {
579 if ext.type_id == target {
580 match ext.cloned_downcast::<T>() {
581 Some(v) => Box::new(core::iter::once(v)),
582 None => Box::new(core::iter::empty()),
583 }
584 } else if ext.type_id == egress_id {
585 match ext.downcast_ref::<Egress<Self>>() {
586 Some(e) => e.0.iter_arc_inner::<T>(),
587 None => Box::new(core::iter::empty()),
588 }
589 } else if ext.type_id == ingress_id {
590 match ext.downcast_ref::<Ingress<Self>>() {
591 Some(i) => i.0.iter_arc_inner::<T>(),
592 None => Box::new(core::iter::empty()),
593 }
594 } else {
595 Box::new(core::iter::empty())
596 }
597 },
598 );
599 let parent: Box<dyn Iterator<Item = Arc<T>>> = match self.parent() {
600 Some(p) => p.iter_arc_inner::<T>(),
601 None => Box::new(core::iter::empty()),
602 };
603 Box::new(local.chain(parent))
604 }
605
606 #[must_use]
617 pub fn ingress(&self) -> Option<&Ingress<Self>> {
618 self.get_ref::<Ingress<Self>>()
619 }
620
621 #[must_use]
627 pub fn egress(&self) -> Option<&Egress<Self>> {
628 self.get_ref::<Egress<Self>>()
629 }
630
631 pub fn clone_to<T: Extension>(&self, target: &Self) -> Option<Arc<T>> {
633 let item = self.get_arc();
634 if let Some(item) = item.clone() {
635 target.insert_arc(item);
636 };
637
638 item
639 }
640
641 pub fn clone_to_if_absent<T: Extension>(&self, target: &Self) -> Option<Arc<T>> {
650 let item = target.get_arc::<T>();
651 if item.is_some() {
652 return item;
653 }
654
655 self.clone_to(target)
656 }
657}
658
659#[doc(hidden)]
669pub trait FromExtensionsGroup<'a>: Sized {
670 const TARGETS: usize;
672 fn from_ext_targets(targets: &mut [TypeId], offset: usize);
674 fn from_ext_slots(
677 out: &[Option<(&'a TypeErasedExtension, usize)>],
678 offset: usize,
679 ) -> Option<Self>;
680}
681
682pub trait GetManyRef<'a>: Sized {
685 type Output;
687
688 #[doc(hidden)]
689 const SEALED: seal::Seal;
690 #[doc(hidden)]
691 fn get_many_ref(ext: &'a Extensions) -> Self::Output;
692}
693
694pub trait GetManyArc: Sized {
697 type Output;
699
700 #[doc(hidden)]
701 const SEALED: seal::Seal;
702 #[doc(hidden)]
703 fn get_many_arc(ext: &Extensions) -> Self::Output;
704}
705
706macro_rules! impl_get_many {
707 ($n:literal; $($T:ident => $idx:tt),+ $(,)?) => {
708 impl<'a, $($T: Extension),+> GetManyRef<'a> for ($($T,)+) {
709 type Output = ($(Option<&'a $T>,)+);
710
711 const SEALED: seal::Seal = seal::Seal;
712 fn get_many_ref(ext: &'a Extensions) -> Self::Output {
713 let targets = [$(TypeId::of::<$T>()),+];
714 let mut out: [Option<(&'a TypeErasedExtension, usize)>; $n] = [None; $n];
715 ext.get_many_erased(&targets, &mut out);
716 ($(out[$idx].and_then(|(e, _)| e.downcast_ref::<$T>()),)+)
717 }
718 }
719
720 impl<$($T: Extension),+> GetManyArc for ($($T,)+) {
721 type Output = ($(Option<Arc<$T>>,)+);
722
723 const SEALED: seal::Seal = seal::Seal;
724 fn get_many_arc(ext: &Extensions) -> Self::Output {
725 let targets = [$(TypeId::of::<$T>()),+];
726 let mut out: [Option<(&TypeErasedExtension, usize)>; $n] = [None; $n];
727 ext.get_many_erased(&targets, &mut out);
728 ($(out[$idx].and_then(|(e, _)| e.cloned_downcast::<$T>()),)+)
729 }
730 }
731 };
732}
733
734impl_get_many!(1; A => 0);
735impl_get_many!(2; A => 0, B => 1);
736impl_get_many!(3; A => 0, B => 1, C => 2);
737impl_get_many!(4; A => 0, B => 1, C => 2, D => 3);
738impl_get_many!(5; A => 0, B => 1, C => 2, D => 3, E => 4);
739impl_get_many!(6; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5);
740impl_get_many!(7; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6);
741impl_get_many!(8; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7);
742impl_get_many!(9; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8);
743impl_get_many!(10; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9);
744impl_get_many!(11; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9, K => 10);
745impl_get_many!(12; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9, K => 10, L => 11);
746
747impl fmt::Debug for Extensions {
748 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
749 let mut s = f.debug_struct("Extensions");
750 if let Some(parent) = self.parent() {
751 s.field("parent", parent);
752 }
753 s.field(
754 "entries",
755 &self.extensions.iter().map(|e| &e.value).collect::<Vec<_>>(),
756 );
757
758 s.finish()
759 }
760}
761
762#[derive(Clone, Debug)]
763pub struct TypeErasedExtension {
767 type_id: TypeId,
768 value: Arc<dyn Extension>,
769}
770
771impl TypeErasedExtension {
772 pub fn new<T: Extension>(value: T) -> Self {
779 Self {
780 type_id: TypeId::of::<T>(),
781 value: Arc::new(value),
782 }
783 }
784
785 pub fn new_arc<T: Extension>(value: Arc<T>) -> Self {
791 Self {
792 type_id: TypeId::of::<T>(),
793 value,
794 }
795 }
796
797 pub fn type_id(&self) -> TypeId {
799 self.type_id
800 }
801
802 pub fn cloned_downcast<T: Extension>(&self) -> Option<Arc<T>> {
807 let any = self.value.clone() as Arc<dyn Any + Send + Sync>;
808 any.downcast::<T>().ok()
809 }
810
811 pub fn downcast_ref<T: Extension>(&self) -> Option<&T> {
816 let inner_any = self.value.as_ref() as &dyn Any;
817 (inner_any).downcast_ref::<T>()
818 }
819}
820
821#[derive(Debug, Clone, Extension)]
822pub struct Ingress<T>(pub T);
824
825impl_deref!(Ingress);
826
827#[derive(Debug, Clone, Extension)]
828pub struct Egress<T>(pub T);
830
831impl_deref!(Egress);
832
833pub trait Extension: Any + Send + Sync + core::fmt::Debug + 'static {}
878
879pub trait TlsExtension: Extension {}
883
884pub trait HttpExtension: Extension {}
888
889pub trait NetExtension: Extension {}
893
894pub trait UaExtension: Extension {}
898
899pub trait ProxyExtension: Extension {}
903
904pub trait WsExtension: Extension {}
908
909pub trait DnsExtension: Extension {}
913
914pub trait GrpcExtension: Extension {}
918
919pub trait ExtensionsRef {
920 fn extensions(&self) -> &Extensions;
922}
923
924impl ExtensionsRef for Extensions {
925 fn extensions(&self) -> &Extensions {
926 self
927 }
928}
929
930impl<T> ExtensionsRef for &T
931where
932 T: ExtensionsRef,
933{
934 #[inline(always)]
935 fn extensions(&self) -> &Extensions {
936 (**self).extensions()
937 }
938}
939
940impl<T> ExtensionsRef for &mut T
941where
942 T: ExtensionsRef,
943{
944 #[inline(always)]
945 fn extensions(&self) -> &Extensions {
946 (**self).extensions()
947 }
948}
949
950impl<T> ExtensionsRef for Box<T>
951where
952 T: ExtensionsRef,
953{
954 fn extensions(&self) -> &Extensions {
955 (**self).extensions()
956 }
957}
958
959impl<T> ExtensionsRef for Pin<Box<T>>
960where
961 T: ExtensionsRef,
962{
963 fn extensions(&self) -> &Extensions {
964 (**self).extensions()
965 }
966}
967
968impl<T> ExtensionsRef for Arc<T>
969where
970 T: ExtensionsRef,
971{
972 fn extensions(&self) -> &Extensions {
973 (**self).extensions()
974 }
975}
976
977macro_rules! impl_extensions_either {
978 ($id:ident, $($param:ident),+ $(,)?) => {
979 impl<$($param),+,> ExtensionsRef for crate::combinators::$id<$($param),+>
980 where
981 $($param: ExtensionsRef,)+
982 {
983 fn extensions(&self) -> &Extensions {
984 match self {
985 $(crate::combinators::$id::$param(s) => s.extensions(),)+
986 }
987 }
988 }
989 };
990}
991
992crate::combinators::impl_either!(impl_extensions_either);
993
994mod seal {
995 pub struct Seal;
996}
997
998#[cfg(test)]
999mod tests {
1000 use super::*;
1001 use core::any::TypeId;
1002 use core::pin::Pin;
1003 use core::sync::atomic::{AtomicUsize, Ordering};
1004
1005 #[derive(Debug, Clone, PartialEq, Eq, Extension)]
1006 struct TraceNote(String);
1007
1008 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Extension)]
1009 struct RetryBudget(u32);
1010
1011 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Extension)]
1012 struct ConnectionTimeoutMs(u64);
1013
1014 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Extension)]
1015 struct WorkerId(i32);
1016
1017 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Extension)]
1018 struct HealthSignal(u8);
1019
1020 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Extension)]
1021 struct FeatureToggle(bool);
1022
1023 #[test]
1024 fn get_ref_returns_last_inserted() {
1025 let ext = Extensions::new();
1026 ext.insert(TraceNote("first".to_owned()));
1027 ext.insert(TraceNote("second".to_owned()));
1028 ext.insert(TraceNote("third".to_owned()));
1029
1030 assert_eq!(
1031 ext.get_ref::<TraceNote>(),
1032 Some(&TraceNote("third".to_owned()))
1033 );
1034 }
1035
1036 #[test]
1037 fn clone_shares_backing_store() {
1038 let ext = Extensions::new();
1039 ext.insert(TraceNote("first".to_owned()));
1040
1041 let clone = ext.clone();
1042 clone.insert(TraceNote("second".to_owned()));
1043
1044 assert_eq!(
1045 ext.get_ref::<TraceNote>(),
1046 Some(&TraceNote("second".to_owned()))
1047 );
1048 assert_eq!(
1049 clone.get_ref::<TraceNote>(),
1050 Some(&TraceNote("second".to_owned()))
1051 );
1052 }
1053
1054 #[test]
1055 fn get_ref_none_when_absent() {
1056 let ext = Extensions::new();
1057 assert_eq!(ext.get_ref::<TraceNote>(), None);
1058 }
1059
1060 #[test]
1061 fn get_arc_none_when_absent() {
1062 let ext = Extensions::new();
1063 assert!(ext.get_arc::<TraceNote>().is_none());
1064 }
1065
1066 #[test]
1067 fn first_ref_none_when_absent() {
1068 let ext = Extensions::new();
1069 assert_eq!(ext.self_first_ref::<TraceNote>(), None);
1070 }
1071
1072 #[test]
1073 fn first_arc_none_when_absent() {
1074 let ext = Extensions::new();
1075 assert!(ext.self_first_arc::<TraceNote>().is_none());
1076 }
1077
1078 #[test]
1079 fn first_ref_returns_first_inserted() {
1080 let ext = Extensions::new();
1081 ext.insert(TraceNote("first".to_owned()));
1082 ext.insert(TraceNote("second".to_owned()));
1083
1084 assert_eq!(
1085 ext.self_first_ref::<TraceNote>(),
1086 Some(&TraceNote("first".to_owned()))
1087 );
1088 }
1089
1090 #[test]
1091 fn extend_appends_other_extensions() {
1092 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Extension)]
1093 struct DerivedMetric(i32);
1094
1095 let source = Extensions::new();
1096 source.insert(WorkerId(5));
1097 source.insert(DerivedMetric(10));
1098
1099 let target = Extensions::new();
1100 target.extend(&source);
1101
1102 assert_eq!(target.get_ref::<WorkerId>(), Some(&WorkerId(5)));
1103 assert_eq!(target.get_ref::<DerivedMetric>(), Some(&DerivedMetric(10)));
1104 }
1105
1106 #[test]
1107 fn insert_arc_can_be_retrieved_via_get_arc() {
1108 let ext = Extensions::new();
1109 let inserted = ext.insert_arc(Arc::new(TraceNote(String::from("hello"))));
1110 let retrieved = ext.get_arc::<TraceNote>();
1111
1112 assert_eq!(inserted.0.as_str(), "hello");
1113 assert_eq!(retrieved.as_deref().map(|it| it.0.as_str()), Some("hello"));
1114 }
1115
1116 #[test]
1117 fn insert_arc_can_be_retrieved_via_get_ref() {
1118 let ext = Extensions::new();
1119 ext.insert_arc(Arc::new(WorkerId(99)));
1120 assert_eq!(ext.get_ref::<WorkerId>(), Some(&WorkerId(99)));
1121 }
1122
1123 #[test]
1124 fn contains_reports_presence_and_absence() {
1125 let ext = Extensions::new();
1126 assert!(!ext.contains::<RetryBudget>());
1127
1128 ext.insert(RetryBudget(1));
1129 assert!(ext.contains::<RetryBudget>());
1130 assert!(!ext.contains::<ConnectionTimeoutMs>());
1131 }
1132
1133 #[test]
1134 fn get_arc_and_first_arc_report_latest_and_oldest() {
1135 let ext = Extensions::new();
1136 ext.insert_arc(Arc::new(TraceNote(String::from("first"))));
1137 ext.insert_arc(Arc::new(TraceNote(String::from("second"))));
1138
1139 assert_eq!(
1140 ext.self_first_arc::<TraceNote>()
1141 .as_deref()
1142 .map(|it| it.0.as_str()),
1143 Some("first")
1144 );
1145 assert_eq!(
1146 ext.get_arc::<TraceNote>()
1147 .as_deref()
1148 .map(|it| it.0.as_str()),
1149 Some("second")
1150 );
1151 }
1152
1153 #[test]
1154 fn get_ref_or_insert_uses_existing_or_inserts_once() {
1155 let ext = Extensions::new();
1156 ext.insert(RetryBudget(5));
1157
1158 let calls = AtomicUsize::new(0);
1159 let existing = ext.self_get_ref_or_insert(|| {
1160 calls.fetch_add(1, Ordering::SeqCst);
1161 RetryBudget(6)
1162 });
1163 assert_eq!(existing.0, 5u32);
1164 assert_eq!(calls.load(Ordering::SeqCst), 0);
1165
1166 let missing = ext.self_get_ref_or_insert(|| {
1167 calls.fetch_add(1, Ordering::SeqCst);
1168 ConnectionTimeoutMs(7)
1169 });
1170 assert_eq!(missing.0, 7u64);
1171 assert_eq!(calls.load(Ordering::SeqCst), 1);
1172 }
1173
1174 #[test]
1175 fn get_arc_or_insert_uses_existing_or_inserts_once() {
1176 let ext = Extensions::new();
1177 ext.insert_arc(Arc::new(TraceNote(String::from("stored"))));
1178
1179 let calls = AtomicUsize::new(0);
1180 let existing = ext.self_get_arc_or_insert(|| {
1181 calls.fetch_add(1, Ordering::SeqCst);
1182 Arc::new(TraceNote(String::from("new")))
1183 });
1184 assert_eq!(existing.0.as_str(), "stored");
1185 assert_eq!(calls.load(Ordering::SeqCst), 0);
1186
1187 let missing = ext.self_get_arc_or_insert(|| {
1188 calls.fetch_add(1, Ordering::SeqCst);
1189 Arc::new(RetryBudget(11))
1190 });
1191 assert_eq!(missing.0, 11u32);
1192 assert_eq!(calls.load(Ordering::SeqCst), 1);
1193 }
1194
1195 #[test]
1196 fn iter_all_exposes_all_items_in_insert_order() {
1197 let ext = Extensions::new();
1198 ext.insert(HealthSignal(1));
1199 ext.insert(FeatureToggle(true));
1200 ext.insert(HealthSignal(2));
1201
1202 let type_ids: Vec<TypeId> = ext
1203 .self_iter_all()
1204 .map(TypeErasedExtension::type_id)
1205 .collect();
1206 assert_eq!(
1207 type_ids,
1208 vec![
1209 TypeId::of::<HealthSignal>(),
1210 TypeId::of::<FeatureToggle>(),
1211 TypeId::of::<HealthSignal>()
1212 ]
1213 );
1214 }
1215
1216 #[test]
1217 fn iter_for_missing_type_is_empty() {
1218 let ext = Extensions::new();
1219 ext.insert(HealthSignal(1));
1220
1221 assert_eq!(ext.self_iter_ref::<TraceNote>().count(), 0);
1222 assert_eq!(ext.self_iter_arc::<TraceNote>().count(), 0);
1223 }
1224
1225 #[test]
1226 fn iter_ref_returns_items_for_present_type_in_newest_to_oldest_order() {
1227 let ext = Extensions::new();
1228 ext.insert(TraceNote(String::from("first")));
1229 ext.insert(HealthSignal(9));
1230 ext.insert(TraceNote(String::from("second")));
1231
1232 let output: Vec<&str> = ext
1233 .self_iter_ref::<TraceNote>()
1234 .map(|it| it.0.as_str())
1235 .collect();
1236 assert_eq!(output, vec!["second", "first"]);
1237 }
1238
1239 #[test]
1240 fn iter_arc_returns_items_for_present_type_in_newest_to_oldest_order() {
1241 let ext = Extensions::new();
1242 ext.insert(TraceNote(String::from("first")));
1243 ext.insert(HealthSignal(9));
1244 ext.insert(TraceNote(String::from("second")));
1245
1246 let output: Vec<String> = ext
1247 .self_iter_arc::<TraceNote>()
1248 .map(|arc| arc.0.clone())
1249 .collect();
1250 assert_eq!(output, vec!["second".to_owned(), "first".to_owned()]);
1251 }
1252
1253 #[test]
1254 fn type_erased_new_supports_downcast_ref_and_cloned_downcast() {
1255 let ext = TypeErasedExtension::new(TraceNote(String::from("hello")));
1256
1257 assert_eq!(ext.type_id(), TypeId::of::<TraceNote>());
1258 assert_eq!(
1259 ext.downcast_ref::<TraceNote>().map(|it| it.0.as_str()),
1260 Some("hello")
1261 );
1262 assert_eq!(
1263 ext.cloned_downcast::<TraceNote>()
1264 .as_deref()
1265 .map(|it| it.0.as_str()),
1266 Some("hello")
1267 );
1268 assert!(ext.downcast_ref::<RetryBudget>().is_none());
1269 assert!(ext.cloned_downcast::<RetryBudget>().is_none());
1270 }
1271
1272 #[test]
1273 fn type_erased_new_arc_supports_all_downcasts() {
1274 let ext = TypeErasedExtension::new_arc(Arc::new(TraceNote(String::from("hello"))));
1275
1276 assert_eq!(ext.type_id(), TypeId::of::<TraceNote>());
1277 assert_eq!(
1278 ext.downcast_ref::<TraceNote>().map(|it| it.0.as_str()),
1279 Some("hello")
1280 );
1281 assert_eq!(
1282 ext.cloned_downcast::<TraceNote>()
1283 .as_deref()
1284 .map(|it| it.0.as_str()),
1285 Some("hello")
1286 );
1287 assert!(ext.downcast_ref::<RetryBudget>().is_none());
1288 assert!(ext.cloned_downcast::<RetryBudget>().is_none());
1289 }
1290
1291 #[test]
1292 fn extensions_ref_blanket_impls_forward_to_underlying_extensions() {
1293 let base = Extensions::new();
1294 base.insert(RetryBudget(7));
1295
1296 let by_ref: &Extensions = &base;
1297 assert_eq!(
1298 by_ref.extensions().get_ref::<RetryBudget>(),
1299 Some(&RetryBudget(7))
1300 );
1301
1302 let mut base_for_mut = base.clone();
1303 let by_mut_ref: &mut Extensions = &mut base_for_mut;
1304 assert_eq!(
1305 by_mut_ref.extensions().get_ref::<RetryBudget>(),
1306 Some(&RetryBudget(7))
1307 );
1308
1309 let boxed = Box::new(base.clone());
1310 assert_eq!(
1311 boxed.extensions().get_ref::<RetryBudget>(),
1312 Some(&RetryBudget(7))
1313 );
1314
1315 let pinned = Pin::new(Box::new(base.clone()));
1316 assert_eq!(
1317 pinned.extensions().get_ref::<RetryBudget>(),
1318 Some(&RetryBudget(7))
1319 );
1320
1321 let arced = Arc::new(base);
1322 assert_eq!(
1323 arced.extensions().get_ref::<RetryBudget>(),
1324 Some(&RetryBudget(7))
1325 );
1326 }
1327
1328 #[derive(Debug, Clone, PartialEq, Eq, Extension)]
1329 struct ConnSocketInfo(&'static str);
1330
1331 #[derive(Debug, Clone, PartialEq, Eq, Extension)]
1332 struct RequestId(u64);
1333
1334 #[test]
1335 fn get_finds_local() {
1336 let req = Extensions::new();
1337 req.insert(RequestId(42));
1338 assert_eq!(req.get_ref::<RequestId>(), Some(&RequestId(42)));
1339 }
1340
1341 #[test]
1342 fn get_walks_parent_chain() {
1343 let req = Extensions::new();
1344 req.insert(RequestId(7));
1345
1346 let resp = req.fork();
1347 assert_eq!(resp.get_ref::<RequestId>(), Some(&RequestId(7)));
1348 }
1349
1350 #[test]
1351 fn local_shadows_parent() {
1352 let req = Extensions::new();
1353 req.insert(RequestId(7));
1354
1355 let attempt = req.fork();
1356 attempt.insert(RequestId(99));
1357
1358 assert_eq!(attempt.get_ref::<RequestId>(), Some(&RequestId(99)));
1359 }
1360
1361 #[test]
1362 fn fork_isolates_writes() {
1363 let req = Extensions::new();
1364 req.insert(RequestId(1));
1365
1366 let attempt = req.fork();
1367 attempt.insert(RequestId(2));
1368
1369 assert_eq!(req.get_ref::<RequestId>(), Some(&RequestId(1)));
1370 }
1371
1372 #[test]
1373 fn ingress_view_walks_parent() {
1374 let conn_ext = Extensions::new();
1375 conn_ext.insert(ConnSocketInfo("client-in"));
1376
1377 let req = Extensions::new();
1378 req.insert(Ingress(conn_ext));
1379
1380 assert_eq!(
1381 req.ingress().and_then(|i| i.get_ref::<ConnSocketInfo>()),
1382 Some(&ConnSocketInfo("client-in"))
1383 );
1384 }
1385
1386 #[test]
1387 fn egress_view_walks_parent() {
1388 let conn_ext = Extensions::new();
1389 conn_ext.insert(ConnSocketInfo("egress-side"));
1390
1391 let req = Extensions::new();
1392 req.insert(Egress(conn_ext));
1393
1394 assert_eq!(
1395 req.egress().and_then(|e| e.get_ref::<ConnSocketInfo>()),
1396 Some(&ConnSocketInfo("egress-side"))
1397 );
1398 }
1399
1400 #[test]
1401 fn ingress_egress_disambiguate_in_mitm() {
1402 let in_conn = Extensions::new();
1403 in_conn.insert(ConnSocketInfo("in"));
1404 let out_conn = Extensions::new();
1405 out_conn.insert(ConnSocketInfo("out"));
1406
1407 let req = Extensions::new();
1408 req.insert(Ingress(in_conn));
1409 req.insert(Egress(out_conn));
1410
1411 assert_eq!(
1412 req.ingress().and_then(|i| i.get_ref::<ConnSocketInfo>()),
1413 Some(&ConnSocketInfo("in"))
1414 );
1415 assert_eq!(
1416 req.egress().and_then(|e| e.get_ref::<ConnSocketInfo>()),
1417 Some(&ConnSocketInfo("out"))
1418 );
1419 }
1420
1421 #[test]
1422 fn egress_view_walks_through_parent_to_find_wrapper() {
1423 let conn_ext = Extensions::new();
1424 conn_ext.insert(ConnSocketInfo("inside-parent"));
1425 let req = Extensions::new();
1426 req.insert(Egress(conn_ext));
1427
1428 let resp = req.fork();
1429 assert_eq!(
1430 resp.egress().and_then(|e| e.get_ref::<ConnSocketInfo>()),
1431 Some(&ConnSocketInfo("inside-parent"))
1432 );
1433 }
1434
1435 #[test]
1436 fn ingress_egress_return_none_when_absent() {
1437 let req = Extensions::new();
1438 assert!(req.ingress().is_none());
1439 assert!(req.egress().is_none());
1440 }
1441
1442 #[test]
1443 fn iter_ref_yields_local_then_parent_newest_to_oldest() {
1444 let parent = Extensions::new();
1445 parent.insert(RequestId(1));
1446 parent.insert(RequestId(2));
1447
1448 let child = parent.fork();
1449 child.insert(RequestId(3));
1450 child.insert(RequestId(4));
1451
1452 let ids: Vec<_> = child.iter_ref::<RequestId>().map(|r| r.0).collect();
1453 assert_eq!(ids, vec![4, 3, 2, 1]);
1454 }
1455
1456 #[test]
1457 fn iter_ref_walks_egress_and_ingress_wrappers_inline() {
1458 let conn_in = Extensions::new();
1459 conn_in.insert(RequestId(10));
1460 conn_in.insert(RequestId(11));
1461 let conn_out = Extensions::new();
1462 conn_out.insert(RequestId(20));
1463
1464 let req = Extensions::new();
1465 req.insert(RequestId(1));
1466 req.insert(Ingress(conn_in));
1467 req.insert(Egress(conn_out));
1468
1469 let ids: Vec<_> = req.iter_ref::<RequestId>().map(|r| r.0).collect();
1470 assert_eq!(ids, vec![20, 11, 10, 1]);
1471 }
1472
1473 #[test]
1474 fn local_direct_after_wrapper_shadows_wrapper() {
1475 let conn = Extensions::new();
1476 conn.insert(RequestId(99));
1477 let req = Extensions::new();
1478 req.insert(Ingress(conn));
1479 req.insert(RequestId(1));
1480
1481 assert_eq!(req.get_ref::<RequestId>(), Some(&RequestId(1)));
1482 }
1483
1484 #[test]
1485 fn wrapper_after_local_direct_shadows_direct() {
1486 let conn = Extensions::new();
1487 conn.insert(RequestId(99));
1488 let req = Extensions::new();
1489 req.insert(RequestId(1));
1490 req.insert(Ingress(conn));
1491
1492 assert_eq!(req.get_ref::<RequestId>(), Some(&RequestId(99)));
1493 }
1494
1495 #[test]
1496 fn iter_ref_first_matches_get_ref() {
1497 let parent = Extensions::new();
1498 parent.insert(RequestId(1));
1499 let child = parent.fork();
1500 child.insert(RequestId(2));
1501
1502 assert_eq!(
1503 child.iter_ref::<RequestId>().next(),
1504 child.get_ref::<RequestId>()
1505 );
1506 }
1507
1508 #[test]
1509 fn get_many_present_and_absent() {
1510 let ext = Extensions::new();
1511 ext.insert(RequestId(7));
1512 ext.insert(ConnSocketInfo("a"));
1513
1514 let (id, sock, toggle) = ext.get_many_ref::<(RequestId, ConnSocketInfo, FeatureToggle)>();
1515 assert_eq!(id, Some(&RequestId(7)));
1516 assert_eq!(sock, Some(&ConnSocketInfo("a")));
1517 assert_eq!(toggle, None);
1518 }
1519
1520 #[test]
1521 fn get_many_each_slot_matches_get_ref() {
1522 let ext = Extensions::new();
1523 ext.insert(RequestId(1));
1524 ext.insert(RequestId(2)); ext.insert(ConnSocketInfo("x"));
1526
1527 let (id, sock) = ext.get_many_ref::<(RequestId, ConnSocketInfo)>();
1528 assert_eq!(id, ext.get_ref::<RequestId>());
1529 assert_eq!(sock, ext.get_ref::<ConnSocketInfo>());
1530 assert_eq!(id, Some(&RequestId(2)));
1531 }
1532
1533 #[test]
1534 fn get_many_walks_parent_chain() {
1535 let parent = Extensions::new();
1536 parent.insert(RequestId(1));
1537 let child = parent.fork();
1538 child.insert(ConnSocketInfo("x"));
1539
1540 let (id, sock) = child.get_many_ref::<(RequestId, ConnSocketInfo)>();
1541 assert_eq!(id, Some(&RequestId(1)));
1542 assert_eq!(sock, Some(&ConnSocketInfo("x")));
1543 }
1544
1545 #[test]
1546 fn with_base_and_chain() {
1547 let base = Extensions::new();
1548 base.insert(RequestId(1));
1549 base.insert(ConnSocketInfo("base"));
1550
1551 let req = Extensions::new();
1552 req.insert(RequestId(2));
1553 req.insert(TraceNote("mid".to_owned()));
1554 let req_retry = req.fork();
1555 req_retry.insert(RequestId(3));
1556
1557 let combined = req_retry.with_base(&base);
1558
1559 assert_eq!(combined.get_ref::<RequestId>(), Some(&RequestId(3)));
1560 assert_eq!(
1561 combined.get_ref::<TraceNote>(),
1562 Some(&TraceNote("mid".to_owned())),
1563 );
1564
1565 assert_eq!(
1566 combined.get_ref::<ConnSocketInfo>(),
1567 Some(&ConnSocketInfo("base")),
1568 );
1569
1570 assert_eq!(base.get_ref::<RequestId>(), Some(&RequestId(1)));
1571 assert!(req_retry.get_ref::<ConnSocketInfo>().is_none());
1572 }
1573
1574 #[test]
1575 fn get_many_walks_wrappers() {
1576 let conn = Extensions::new();
1577 conn.insert(ConnSocketInfo("in"));
1578 let req = Extensions::new();
1579 req.insert(RequestId(7));
1580 req.insert(Ingress(conn));
1581
1582 let (id, sock) = req.get_many_ref::<(RequestId, ConnSocketInfo)>();
1583 assert_eq!(id, Some(&RequestId(7)));
1584 assert_eq!(sock, Some(&ConnSocketInfo("in")));
1585 }
1586
1587 #[derive(FromExtensions)]
1588 struct GatherView<'a> {
1589 id: Option<&'a RequestId>,
1590 sock: Option<&'a ConnSocketInfo>,
1591 toggle: Option<&'a FeatureToggle>,
1592 }
1593
1594 #[test]
1595 fn derive_from_extensions_gathers_pieces() {
1596 let ext = Extensions::new();
1597 ext.insert(RequestId(7));
1598 ext.insert(ConnSocketInfo("a"));
1599
1600 let view = GatherView::from_extensions(&ext);
1601 assert_eq!(view.id, Some(&RequestId(7)));
1602 assert_eq!(view.sock, Some(&ConnSocketInfo("a")));
1603 assert_eq!(view.toggle, None);
1604 assert_eq!(view.id, ext.get_ref::<RequestId>());
1605 }
1606
1607 #[test]
1608 fn derive_from_extensions_walks_parent() {
1609 let parent = Extensions::new();
1610 parent.insert(RequestId(1));
1611 let child = parent.fork();
1612 child.insert(ConnSocketInfo("x"));
1613
1614 let view = GatherView::from_extensions(&child);
1615 assert_eq!(view.id, Some(&RequestId(1)));
1616 assert_eq!(view.sock, Some(&ConnSocketInfo("x")));
1617 assert_eq!(view.toggle, None);
1618 }
1619
1620 #[test]
1621 fn get_many_arc_returns_owned_arcs() {
1622 let ext = Extensions::new();
1623 ext.insert(RequestId(7));
1624
1625 let (id, sock) = ext.get_many_arc::<(RequestId, ConnSocketInfo)>();
1626 assert_eq!(id.as_deref(), Some(&RequestId(7)));
1627 assert_eq!(sock, None);
1628 }
1629
1630 #[derive(FromExtensions)]
1631 struct MixedView<'a> {
1632 id_ref: Option<&'a RequestId>,
1633 sock_arc: Option<Arc<ConnSocketInfo>>,
1634 }
1635
1636 #[test]
1637 fn derive_from_extensions_mixed_ref_and_arc() {
1638 let ext = Extensions::new();
1639 ext.insert(RequestId(7));
1640 ext.insert(ConnSocketInfo("a"));
1641
1642 let view = MixedView::from_extensions(&ext);
1643 assert_eq!(view.id_ref, Some(&RequestId(7)));
1644 assert_eq!(view.sock_arc.as_deref(), Some(&ConnSocketInfo("a")));
1645 }
1646
1647 #[derive(FromExtensions)]
1648 struct AllArc {
1649 id_ref: Option<Arc<RequestId>>,
1650 sock_arc: Option<Arc<ConnSocketInfo>>,
1651 }
1652
1653 #[test]
1654 fn derive_from_extensions_all_arc() {
1655 let ext = Extensions::new();
1656 ext.insert(RequestId(7));
1657 ext.insert(ConnSocketInfo("a"));
1658
1659 let view = AllArc::from_extensions(&ext);
1660 assert_eq!(view.id_ref.as_deref(), Some(&RequestId(7)));
1661 assert_eq!(view.sock_arc.as_deref(), Some(&ConnSocketInfo("a")));
1662 }
1663
1664 #[derive(FromExtensions)]
1665 struct RankedView<'a> {
1666 id: Option<(&'a RequestId, usize)>,
1667 sock: Option<(&'a ConnSocketInfo, usize)>,
1668 toggle: Option<(&'a FeatureToggle, usize)>,
1669 }
1670
1671 #[test]
1672 fn derive_from_extensions_captures_rank() {
1673 let ext = Extensions::new();
1674 ext.insert(RequestId(7)); ext.insert(ConnSocketInfo("a")); let view = RankedView::from_extensions(&ext);
1678
1679 assert_eq!(view.sock, Some((&ConnSocketInfo("a"), 0)));
1680 assert_eq!(view.id, Some((&RequestId(7), 1)));
1681 assert_eq!(view.toggle, None);
1682
1683 assert!(view.sock.unwrap().1 < view.id.unwrap().1);
1684 }
1685
1686 #[test]
1687 fn derive_from_extensions_rank_arc_variant() {
1688 #[derive(FromExtensions)]
1689 struct RankedArc {
1690 id: Option<(Arc<RequestId>, usize)>,
1691 }
1692
1693 let ext = Extensions::new();
1694 ext.insert(ConnSocketInfo("a"));
1695 ext.insert(RequestId(7));
1696
1697 let view = RankedArc::from_extensions(&ext);
1698 let (id, rank) = view.id.expect("present");
1699 assert_eq!(&*id, &RequestId(7));
1700 assert_eq!(rank, 0);
1701 }
1702
1703 #[derive(Debug, PartialEq, Eq, FromExtensions)]
1704 enum AnyOf<'a> {
1705 Req(&'a RequestId),
1706 Sock(&'a ConnSocketInfo),
1707 }
1708
1709 #[test]
1710 fn derive_from_extensions_enum_newest_wins() {
1711 let ext = Extensions::new();
1712 ext.insert(ConnSocketInfo("a"));
1713 ext.insert(RequestId(7));
1714 assert_eq!(
1715 AnyOf::from_extensions(&ext),
1716 Some(AnyOf::Req(&RequestId(7)))
1717 );
1718
1719 let ext = Extensions::new();
1720 ext.insert(RequestId(7));
1721 ext.insert(ConnSocketInfo("a"));
1722 assert_eq!(
1723 AnyOf::from_extensions(&ext),
1724 Some(AnyOf::Sock(&ConnSocketInfo("a")))
1725 );
1726
1727 let ext = Extensions::new();
1728 ext.insert(RequestId(7));
1729 assert_eq!(
1730 AnyOf::from_extensions(&ext),
1731 Some(AnyOf::Req(&RequestId(7)))
1732 );
1733
1734 let ext = Extensions::new();
1735 ext.insert(FeatureToggle(true));
1736 assert_eq!(AnyOf::from_extensions(&ext), None);
1737 }
1738
1739 #[derive(FromExtensions)]
1740 struct ConfigView<'a> {
1741 toggle: Option<&'a FeatureToggle>,
1742 either: Option<AnyOf<'a>>,
1743 }
1744
1745 #[derive(Debug, PartialEq, Eq, FromExtensions)]
1746 enum SameType<'a> {
1747 First(&'a RequestId),
1748 Second(&'a RequestId),
1749 }
1750
1751 #[test]
1752 fn derive_from_extensions_enum_same_type_ties_to_earlier_variant() {
1753 let ext = Extensions::new();
1757 ext.insert(RequestId(7));
1758 assert_eq!(
1759 SameType::from_extensions(&ext),
1760 Some(SameType::First(&RequestId(7)))
1761 );
1762 }
1763
1764 #[test]
1765 fn derive_from_extensions_nested_group_field() {
1766 let ext = Extensions::new();
1767 ext.insert(FeatureToggle(true));
1768 ext.insert(RequestId(7));
1769 ext.insert(ConnSocketInfo("a"));
1770
1771 let view = ConfigView::from_extensions(&ext);
1772 assert_eq!(view.toggle, Some(&FeatureToggle(true)));
1773 assert_eq!(view.either, Some(AnyOf::Sock(&ConnSocketInfo("a"))));
1774
1775 let ext = Extensions::new();
1776 ext.insert(FeatureToggle(false));
1777 let view = ConfigView::from_extensions(&ext);
1778 assert_eq!(view.toggle, Some(&FeatureToggle(false)));
1779 assert_eq!(view.either, None);
1780 }
1781
1782 #[test]
1783 fn derive_from_extensions_enum_newest_wins_across_parent() {
1784 let parent = Extensions::new();
1785 parent.insert(RequestId(7));
1786 let child = parent.fork();
1787 child.insert(ConnSocketInfo("a"));
1788
1789 assert_eq!(
1790 AnyOf::from_extensions(&child),
1791 Some(AnyOf::Sock(&ConnSocketInfo("a")))
1792 );
1793
1794 let parent = Extensions::new();
1795 parent.insert(ConnSocketInfo("a"));
1796 let child = parent.fork();
1797 child.insert(RequestId(7));
1798
1799 assert_eq!(
1800 AnyOf::from_extensions(&child),
1801 Some(AnyOf::Req(&RequestId(7)))
1802 );
1803 }
1804}