structural/enums/enum_ext.rs
1use crate::{
2 enums::{IsVariant, VariantProxy},
3 path::TStr,
4};
5
6/// Extension trait for enums.
7///
8/// This trait has these methods:
9///
10/// - `*_variant`: For fallibly converting an enum to a VariantProxy of a passed variant.
11/// As opposed to calling StructuralExt methods with a `fp!(::Foo)` argument,
12/// this allows recovering the enum when it's not the passed variant.
13///
14pub trait EnumExt {
15 /// Fallibly converts a reference to an enum into
16 /// a reference of a VariantProxy of some variant.
17 ///
18 /// # Example
19 ///
20 /// ```
21 /// use structural::{ts,TS,StructuralExt};
22 /// use structural::for_examples::Variants;
23 /// use structural::enums::{EnumExt,VariantProxy};
24 ///
25 /// let this=Variants::Foo(11,22);
26 /// {
27 /// let proxy: &VariantProxy<Variants,TS!(Foo)>=
28 /// this.as_variant(ts!(Foo)).unwrap();
29 ///
30 /// assert_eq!( proxy.field_(ts!(0)), &11);
31 /// assert_eq!( proxy.field_(ts!(1)), &22);
32 /// }
33 /// {
34 /// assert_eq!( this.as_variant(ts!(Bar)), Err(&this) );
35 /// }
36 /// ```
37 #[inline(always)]
38 fn as_variant<V>(&self, vari: TStr<V>) -> Result<&VariantProxy<Self, TStr<V>>, &Self>
39 where
40 Self: IsVariant<TStr<V>>,
41 {
42 if IsVariant::is_variant_(self, vari) {
43 unsafe { Ok(VariantProxy::from_ref(self, vari)) }
44 } else {
45 Err(self)
46 }
47 }
48
49 /// Fallibly converts a mutable reference to an enum into
50 /// a mutable reference of a VariantProxy of some variant.
51 ///
52 /// # Example
53 ///
54 /// ```
55 /// use structural::{ts,TS,StructuralExt};
56 /// use structural::for_examples::Variants;
57 /// use structural::enums::{EnumExt,VariantProxy};
58 ///
59 /// let mut this=Variants::Bar("hello");
60 /// let mut other=this.clone();
61 ///
62 /// {
63 /// let proxy: &mut VariantProxy<Variants,TS!(Bar)>=
64 /// this.as_mut_variant(ts!(Bar)).unwrap();
65 ///
66 /// assert_eq!( proxy.field_(ts!(0)), &"hello");
67 /// assert_eq!( proxy.field_mut(ts!(0)), &mut"hello");
68 /// }
69 /// {
70 /// assert_eq!( this.as_mut_variant(ts!(Foo)), Err(&mut other) );
71 /// assert_eq!( this.as_mut_variant(ts!(Baz)), Err(&mut other) );
72 /// assert_eq!( this.as_mut_variant(ts!(Boom)), Err(&mut other) );
73 /// }
74 /// ```
75 #[inline(always)]
76 fn as_mut_variant<V>(
77 &mut self,
78 vari: TStr<V>,
79 ) -> Result<&mut VariantProxy<Self, TStr<V>>, &mut Self>
80 where
81 Self: IsVariant<TStr<V>>,
82 {
83 if IsVariant::is_variant_(&*self, vari) {
84 unsafe { Ok(VariantProxy::from_mut(self, vari)) }
85 } else {
86 Err(self)
87 }
88 }
89
90 /// Fallibly converts a raw pointer to an enum into
91 /// a raw pointer of a VariantProxy of some variant.
92 ///
93 /// # Example
94 ///
95 /// ```
96 /// use structural::{ts,TS,StructuralExt};
97 /// use structural::for_examples::Variants;
98 /// use structural::enums::{EnumExt,VariantProxy};
99 ///
100 /// let mut this=Variants::Baz(None);
101 ///
102 /// unsafe{
103 /// let proxy: *mut VariantProxy<Variants,TS!(Baz)>=
104 /// Variants::as_raw_mut_variant(&mut this,ts!(Baz)).unwrap();
105 ///
106 /// assert_eq!( (*proxy).field_(ts!(0)), &None);;
107 /// assert_eq!( (*proxy).field_mut(ts!(0)), &None);;
108 /// }
109 /// unsafe{
110 /// assert_eq!(
111 /// Variants::as_raw_mut_variant(&mut this,ts!(Foo)),
112 /// Err(&mut this as *mut Variants)
113 /// );
114 /// assert_eq!(
115 /// Variants::as_raw_mut_variant(&mut this,ts!(Bar)),
116 /// Err(&mut this as *mut Variants)
117 /// );
118 /// assert_eq!(
119 /// Variants::as_raw_mut_variant(&mut this,ts!(Boom)),
120 /// Err(&mut this as *mut Variants)
121 /// );
122 /// }
123 ///
124 /// ```
125 ///
126 /// # Safety
127 ///
128 /// You must pass a pointer to a fully initialized instance of `Self`.
129 #[inline(always)]
130 unsafe fn as_raw_mut_variant<V>(
131 this: *mut Self,
132 vari: TStr<V>,
133 ) -> Result<*mut VariantProxy<Self, TStr<V>>, *mut Self>
134 where
135 Self: IsVariant<TStr<V>>,
136 {
137 if IsVariant::is_variant_(&*this, vari) {
138 Ok(VariantProxy::from_raw_mut(this, vari))
139 } else {
140 Err(this)
141 }
142 }
143
144 /// Fallibly converts an enum into a VariantProxy of some variant.
145 ///
146 /// # Example
147 ///
148 /// ```
149 /// use structural::{ts,TS,StructuralExt};
150 /// use structural::for_examples::Variants;
151 /// use structural::enums::{EnumExt,VariantProxy};
152 ///
153 /// use std::cmp::Ordering;
154 ///
155 /// let this=Variants::Baz(Some(Ordering::Less));
156 ///
157 /// {
158 /// let mut proxy: VariantProxy<Variants,TS!(Baz)>=
159 /// this.into_variant(ts!(Baz)).unwrap();
160 ///
161 /// assert_eq!( proxy.field_(ts!(0)), &Some(Ordering::Less));
162 /// assert_eq!( proxy.field_mut(ts!(0)), &mut Some(Ordering::Less));
163 /// assert_eq!( proxy.into_field(ts!(0)), Some(Ordering::Less));
164 /// }
165 /// {
166 /// assert_eq!(this.into_variant(ts!(Foo)), Err(this));
167 /// assert_eq!(this.into_variant(ts!(Bar)), Err(this));
168 /// assert_eq!(this.into_variant(ts!(Boom)), Err(this));
169 /// }
170 ///
171 /// ```
172 #[inline(always)]
173 fn into_variant<V>(self, vari: TStr<V>) -> Result<VariantProxy<Self, TStr<V>>, Self>
174 where
175 Self: IsVariant<TStr<V>> + Sized,
176 {
177 if IsVariant::is_variant_(&self, vari) {
178 unsafe { Ok(VariantProxy::new(self, vari)) }
179 } else {
180 Err(self)
181 }
182 }
183}
184
185impl<This: ?Sized> EnumExt for This {}