1_data_value_impl_oneof!();
7
8#[macro_export]
10#[cfg_attr(cargo_primary_package, doc(hidden))]
11#[allow(clippy::crate_in_macro_def, reason = "impl_const_init arm")]
12macro_rules! _data_value_impl_oneof {
13 () => { $crate::_data_value_impl_oneof!(%canonical); };
18 ($($T:ident : $idx:literal + $nth:literal : $suf:literal),* $(,)?) => {
21 $crate::_data_value_impl_oneof!(define_enum: $($T:$nth:$suf),+);
22 $crate::_data_value_impl_oneof!(impl_default: $($T),+);
23 $crate::_data_value_impl_oneof!(impl_const_init: $($T),+);
24 $crate::_data_value_impl_oneof!(methods_general: $($T:$idx+$nth:$suf),+);
25 $crate::_data_value_impl_oneof!(methods_individ: $($T:$idx+$nth:$suf),+);
26 };
27
28 (impl_const_init) => {
30 $crate::_data_value_impl_oneof!(%canonical %map_ident impl_const_init:);
31 };
32 (impl_const_init: $_0:ident $(, $rest:ident)*) => {
34 impl<const LEN: usize, $_0: crate::ConstInit, $($rest),*> crate::ConstInit
35 for Oneof<LEN, $_0, $($rest),*> {
36 const INIT: Self = Oneof::$_0($_0::INIT);
37 }
38 };
39
40 (%canonical $($prefix:tt)*) => { $crate::_data_value_impl_oneof! { $($prefix)*
44 _0:0+1:"st", _1:1+2:"nd", _2:2+3:"rd", _3:3+4:"th", _4:4+5:"th", _5:5+6:"th",
45 _6:6+7:"th", _7:7+8:"th", _8:8+9:"th", _9:9+10:"th", _10:10+11:"th", _11:11+12:"th",
46 }};
47 (%map_ident $prefix:ident:
49 $($T:ident : $idx:literal + $nth:literal : $suf:literal),* $(,)?) => {
50 $crate::_data_value_impl_oneof!($prefix: $($T),*);
51 };
52 (%map_ident_nth_suf $prefix:ident:
54 $($T:ident : $idx:literal + $nth:literal : $suf:literal),* $(,)?) => {
55 $crate::_data_value_impl_oneof!($prefix: $($T:$nth:$suf),+);
56 };
57
58 (define_enum: $($variant:ident : $nth:literal : $suf:literal),+) => { $crate::paste! {
61 #[doc = crate::_tags!(code)]
62 #[doc = crate::_doc_meta!{location("data/value")}]
64 #[non_exhaustive]
71 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
72 pub enum Oneof<const LEN: usize, $($variant = ()),+> {
73 $(
74 #[doc = "The " $nth $suf " variant."]
75 $variant($variant)
76 ),+
77 }
78 }};
79 (impl_default: $_0:ident $(, $rest:ident)*) => {
80 impl<const LEN: usize, $_0: Default, $($rest),*> Default for Oneof<LEN, $_0, $($rest),*> {
81 fn default() -> Self { Oneof::$_0($_0::default()) }
82 }
83 };
84 (
85 methods_general: $($T:ident : $idx:literal + $nth:literal : $suf:literal),+) => {
97 impl<const LEN:usize, $($T),+ > Oneof<LEN, $($T),+> {
99 pub const LEN: usize = {
101 assert![LEN <= Self::MAX_ARITY, "LEN must be <= MAX_ARITY"];
102 LEN
103 };
104 pub const MAX_ARITY: usize = $crate::ident_total!($($T),+);
106 pub const fn variant_index(&self) -> usize {
110 match self { $( Oneof::$T(_) => $idx ),+ }
111 }
112 pub const fn is_variant_index(&self, index: usize) -> bool {
114 self.variant_index() == index
115 }
116 }
117 impl<const LEN: usize, $($T: 'static),+ > Oneof<LEN, $($T),+> {
118 #[allow(unused_assignments, reason = "wont be read in all cases")]
121 pub fn validate() -> bool {
123 let mut non_unit_count = 0;
124 let mut unit_found = false;
125 $(
126 if $crate::TypeId::of::<$T>() == $crate::TypeId::of::<()>() {
127 unit_found = true;
128 } else {
129 if unit_found { return false; }
130 non_unit_count += 1;
131 }
132 )+
133 LEN == non_unit_count
134 }
135 }
136 impl<const LEN: usize, $($T: Clone),+ > Oneof<LEN, $($T),+> {
139 pub fn into_tuple_options(self) -> ($(Option<$T>),+) { $crate::paste! {
141 let index = self.variant_index();
142 ( $(
143 if $idx == index {
144 self.clone().[<into $T>]()
145 } else {
146 None::<$T>
147 }
148 ),+ )
149 }}
150
151 pub fn into_tuple_defaults(self) -> ($($T),+) where $($T: Default),+ { $crate::paste! {
154 let index = self.variant_index();
155 ( $(
156 if $idx == index {
157 self.clone().[<into $T>]().unwrap()
158 } else {
159 Default::default()
160 }
161 ),+ )
162 }}
163 }
164 impl<const LEN: usize, $($T),+ > Oneof<LEN, $($T),+> {
165 pub const fn as_tuple_ref_options(&self) -> ($(Option<&$T>),+) { $crate::paste! {
168 ( $(
169 if $idx == self.variant_index() {
170 self.[<as_ref $T>]()
171 } else {
172 None::<&$T>
173 }
174 ),+ )
175 }}
176 }
177 };
178 (
179 methods_individ: $($T:ident : $idx:literal + $nth:literal : $suf:literal),+) => {
181 impl<const LEN: usize, $($T),+> Oneof<LEN, $($T),+> {
183 $crate::_data_value_impl_oneof!(methods_field_access: $($T:$idx+$nth:$suf),+);
185 $crate::_data_value_impl_oneof!(methods_map: $($T),+);
186 }
188 };
189 (
190 methods_field_access: $($T:ident : $idx:literal + $nth:literal : $suf:literal),+) => {
196 $( $crate::_data_value_impl_oneof! { @methods_field_access: $T : $idx + $nth : $suf} )+
197 };
198 (@methods_field_access: $T:ident : $idx:literal + $nth:literal : $suf:literal
199 ) => { $crate::paste! {
200 #[doc = "Returns `true` if there's a value in variant [`"
201 $T "`](#variant." $T ") (The " $nth $suf ")."]
202 pub const fn [<is $T>](&self) -> bool { matches!(self, Oneof::$T(_)) }
203
204 #[doc = "Returns a shared reference to the inner value in variant `" $T "`, if present."]
205 pub const fn [<as_ref $T>](&self) -> Option<&$T> {
206 $crate::is![let Self::$T($T) = self, Some($T), None]
207 }
208 #[doc = "Returns an exclusive reference to the inner value in variant`" $T "`, if present."]
209 pub const fn [<as_mut $T>](&mut self) -> Option<&mut $T> {
210 $crate::is![let Self::$T($T) = self, Some($T), None]
211 }
212 #[doc = "Returns a copy of the value in variant `" $T "`, if present."]
213 pub const fn [<copy $T >](self) -> Option<$T> where Self: Copy {
214 $crate::is![let Self::$T($T) = self, Some($T), None]
215 }
216 #[doc = "Returns the owned value in variant `" $T "`, if present."]
217 #[doc = "<hr/>"] pub fn [<into $T>](self) -> Option<$T> {
219 $crate::is![let Self::$T($T) = self, Some($T), None]
220 }
221 }};
222 (
223 methods_map: $first:ident $(, $rest:ident)*) => {
226 $crate::_data_value_impl_oneof!(@methods_map: $first, (), ($($rest),*));
228 $crate::_data_value_impl_oneof!(@methods_map_helper: ($first), ($($rest),*));
230
231 };
240 (
241 @methods_map: $T:ident, ( $($before:ident),* ), ( $($after:ident),* )) => { $crate::paste! {
242 #[doc = "Transforms the inner value in variant`" $T
243 "` using `f`, leaving other variants unchanged."]
244 pub fn [<map $T>]<NEW>(self, f: impl FnOnce($T) -> NEW)
245 -> Oneof<LEN, $($before,)* NEW, $($after,)* > {
246 match self {
247 $( Self::$before(val) => Oneof::$before(val), )*
248 Self::$T(val) => Oneof::$T(f(val)),
249 $( Self::$after(val) => Oneof::$after(val), )*
250 }
251 }
252 }};
265 (@methods_map_helper: ($($before:ident),*), ()) => {};
267 (@methods_map_helper: ($($before:ident),*), ($first:ident $(, $rest:ident)*)) => {
269 $crate::_data_value_impl_oneof!(@methods_map: $first, ($($before),*), ($($rest),*));
270 $crate::_data_value_impl_oneof!(@methods_map_helper: ($($before,)* $first), ($($rest),*));
272 };
273}
274#[doc(hidden)]
275pub use _data_value_impl_oneof;
276
277#[cfg(test)]
278mod tests {
279 use super::Oneof;
280
281 type Bytes = Oneof<2, u8, i8>;
282 type Unums = Oneof<4, u8, u16, u32, u64>;
283
284 #[test]
285 fn validate() {
286 assert![Bytes::validate()];
287 assert![Unums::validate()];
288 assert![Oneof::<0, (), (), ()>::validate()];
289 assert![Oneof::<1, i8, (), ()>::validate()];
290 assert![!Oneof::<0, i8, (), ()>::validate()];
291 assert![!Oneof::<2, i8, (), ()>::validate()];
292 assert![!Oneof::<1, (), i8, ()>::validate()];
294 assert![!Oneof::<2, i32, (), i8>::validate()];
295 assert![!Oneof::<1, (), (), i8, ()>::validate()];
296 }
297 #[test]
298 fn map() {
299 let a: Oneof<2, i32, f64> = Oneof::_0(10);
300 assert_eq![Oneof::_0(20), a.map_0(|v| v * 2)];
301 assert_eq![Oneof::_0(10), a.map_1(|v| v * 2.0)];
302 let b: Oneof<2, i32, f64> = Oneof::_1(3.14);
303 assert_eq![Oneof::_1(3.14), b.map_0(|v| v * 2)];
304 assert_eq![Oneof::_1(6.28), b.map_1(|v| v * 2.0)];
305 }
306 #[test]
307 fn field_access() {
308 let mut u = Unums::_2(32);
309 assert_eq![u.is_2(), true];
310 assert_eq![u.into_2(), Some(32)];
311 assert_eq![u.as_ref_2(), Some(&32)];
312 assert_eq![u.as_mut_2(), Some(&mut 32)];
313 assert_eq![u.is_0(), false];
315 assert_eq![u.into_0(), None];
316 assert_eq![u.as_ref_0(), None];
317 assert_eq![u.as_mut_0(), None];
318 }
319 #[test]
320 fn positioning() {
321 let u = Unums::_2(32);
322 assert_eq![u.variant_index(), 2];
323 assert_eq![u.is_variant_index(2), true];
324 assert_eq![u.is_variant_index(3), false];
325 let u = Unums::_0(32);
330 assert_eq![u.variant_index(), 0];
331 assert_eq![u.is_variant_index(0), true];
332 assert_eq![u.is_variant_index(1), false];
333 }
337 #[test]
338 fn tuple() {
339 let u = Unums::_2(32);
340 assert_eq![
341 u.into_tuple_options(),
342 (None, None, Some(32), None, None, None, None, None, None, None, None, None)
343 ];
344 assert_eq![
345 u.as_tuple_ref_options(),
346 (None, None, Some(&32), None, None, None, None, None, None, None, None, None)
347 ];
348 assert_eq![u.into_tuple_defaults(), (0, 0, 32, 0, (), (), (), (), (), (), (), ())];
349 }
350}