1#![allow(clippy::module_name_repetitions)]
2
3use crate::tagged_box::TaggedBox;
4
5pub trait TaggableContainer {
14 type Inner;
16
17 fn into_inner(self) -> Self::Inner;
19}
20
21pub trait TaggableInner: Sized {
30 fn into_tagged_box(self) -> TaggedBox<Self>;
37
38 fn from_tagged_box(tagged: TaggedBox<Self>) -> Self;
42
43 unsafe fn ref_from_tagged_box<F>(tagged: &TaggedBox<Self>, callback: F)
50 where
51 F: FnOnce(&Self);
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use crate::tagged_box;
58
59 tagged_box! {
60 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
61 struct Container, enum Item {
62 Int(usize),
63 Bool(bool),
64 Float(f32),
65 }
66 }
67
68 #[test]
69 fn container_into_inner() {
70 let int = Container::from(usize::max_value());
71 assert_eq!(int.into_inner(), Item::Int(usize::max_value()));
72
73 let boolean = Container::from(true);
74 assert_eq!(boolean.into_inner(), Item::Bool(true));
75
76 let float = Container::from(core::f32::MAX);
77 assert_eq!(float.into_inner(), Item::Float(core::f32::MAX));
78 }
79
80 #[test]
81 fn inner_into_tagged_box() {
82 assert_eq!(
83 Item::Int(usize::max_value()),
84 Container {
85 value: Item::Int(usize::max_value()).into_tagged_box()
86 }
87 .into_inner()
88 );
89
90 assert_eq!(
91 Item::Bool(false),
92 Container {
93 value: Item::Bool(false).into_tagged_box()
94 }
95 .into_inner()
96 );
97
98 assert_eq!(
99 Item::Float(core::f32::MIN),
100 Container {
101 value: Item::Float(core::f32::MIN).into_tagged_box()
102 }
103 .into_inner()
104 );
105 }
106
107 #[test]
108 fn inner_from_tagged_box() {
109 assert_eq!(
110 Item::Int(usize::max_value()),
111 Item::from_tagged_box(Item::Int(usize::max_value()).into_tagged_box())
112 );
113
114 assert_eq!(
115 Item::Bool(true),
116 Item::from_tagged_box(Item::Bool(true).into_tagged_box())
117 );
118
119 assert_eq!(
120 Item::Float(core::f32::MAX),
121 Item::from_tagged_box(Item::Float(core::f32::MAX).into_tagged_box())
122 );
123 }
124
125 #[test]
126 fn inner_ref_from_tagged_box() {
127 unsafe {
128 let int = Item::Int(usize::max_value());
129 let boolean = Item::Bool(false);
130 let float = Item::Float(core::f32::MIN);
131
132 Item::ref_from_tagged_box(&Item::Int(usize::max_value()).into_tagged_box(), |item| {
133 assert_eq!(item, &int);
134 assert_ne!(item, &boolean);
135 assert_ne!(item, &float);
136 });
137
138 Item::ref_from_tagged_box(&Item::Bool(false).into_tagged_box(), |item| {
139 assert_eq!(item, &boolean);
140 assert_ne!(item, &int);
141 assert_ne!(item, &float);
142 });
143
144 Item::ref_from_tagged_box(&Item::Float(core::f32::MIN).into_tagged_box(), |item| {
145 assert_eq!(item, &float);
146 assert_ne!(item, &int);
147 assert_ne!(item, &boolean);
148 });
149 }
150 }
151
152 #[test]
153 fn wrapped_refs_from_tagged_box() {
154 let big = Item::Int(10_000).into_tagged_box();
155 let small = Item::Int(100).into_tagged_box();
156
157 unsafe {
158 Item::ref_from_tagged_box(&big, |big| {
159 Item::ref_from_tagged_box(&small, |small| {
160 assert_ne!(big, small);
161 assert!(big > small);
162 assert!(small < big);
163 });
164 });
165 }
166
167 assert_eq!(Item::from_tagged_box(big), Item::Int(10_000));
168 assert_eq!(Item::from_tagged_box(small), Item::Int(100));
169 }
170}