structural/field/
errors.rs

1/*!
2Field-accessor-related error types and traits
3*/
4
5use std_::fmt::{self, Display};
6
7use core_extensions::collection_traits::Cloned;
8
9mod sealed {
10    pub trait Sealed {}
11}
12use self::sealed::Sealed;
13
14/// Marker trait for the errors that can be returned from the `RevGetField` trait and subtraits.
15///
16/// The errors can be:
17///
18/// - [InfallibleAccess](./enum.InfallibleAccess.html):
19///     For `Rev*` accessors that return a field that always exists,
20///     most often in a struct.
21///     Because the field always exists this error is never actually returned.
22///
23/// - [FailedAccess](./struct.FailedAccess.html):
24///     For `Rev*` accessors that failed to return a field that may not exist,
25///     most often inside an enum.
26///
27/// This trait is sealed,and cannot be implemented outside of the `structural` crate.
28pub trait IsFieldErr: Sealed + 'static + Copy + Cloned {}
29
30/// The error type for accesses to fields that always exist,most often in a struct.
31///
32/// Because the fields always exist,this error is never actually returned,
33/// and `Result<T, InfallibleAccess>` has the same size as `T` (as of Rust 1.42).
34///
35/// This is used as the `Err` associated type for `Rev*Field*` implementors,
36/// which return a `Result<_,InfallibleAccess>`,
37/// then [StructuralExt](../../trait.StructuralExt.html) methods use
38/// [NormalizeFields](../trait.NormalizeFields.html) to turn
39/// `Ok(foo)` into `foo` (which can be safely done,since this type can't be constructed).
40#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub enum InfallibleAccess {}
42
43/// The error type for accesses to fields that may not exist,most often inside an enum.
44///
45/// This is used as the `Err` associated type for `Rev*Field*` implementors,
46/// which return a `Result<_,FailedAccess>`,
47/// then [StructuralExt](../../trait.StructuralExt.html) methods use
48/// [NormalizeFields](../trait.NormalizeFields.html) to turn
49/// `Ok(foo)` into `Some(foo)`,and `Err(FailedAccess)` into `None`.
50#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct FailedAccess;
52
53impl Cloned for FailedAccess {
54    type Cloned = Self;
55
56    #[inline(always)]
57    fn cloned_(&self) -> Self {
58        *self
59    }
60}
61
62impl Cloned for InfallibleAccess {
63    type Cloned = Self;
64
65    #[inline(always)]
66    fn cloned_(&self) -> Self {
67        *self
68    }
69}
70
71impl Sealed for FailedAccess {}
72impl IsFieldErr for FailedAccess {}
73
74impl Sealed for InfallibleAccess {}
75impl IsFieldErr for InfallibleAccess {}
76
77#[cfg(feature = "std")]
78mod std_impls {
79    use super::{FailedAccess, InfallibleAccess};
80
81    use std::error::Error;
82
83    impl Error for FailedAccess {
84        #[inline(always)]
85        fn description(&self) -> &str {
86            "Some field could not be accessed"
87        }
88    }
89    impl Error for InfallibleAccess {
90        #[inline(always)]
91        fn description(&self) -> &str {
92            "The field isn't optional,this function is uncallable"
93        }
94    }
95}
96
97////////////////////////////////////////////////////////////////////////////////
98
99impl Display for FailedAccess {
100    #[inline(always)]
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        f.write_str("Some field could not be accessed")
103    }
104}
105
106impl From<InfallibleAccess> for FailedAccess {
107    #[inline(always)]
108    fn from(_: InfallibleAccess) -> Self {
109        FailedAccess
110    }
111}
112
113////////////////////////////////////////////////////////////////////////////////
114
115impl Display for InfallibleAccess {
116    #[inline(always)]
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.write_str("This field can always be accessed.")
119    }
120}
121
122////////////////////////////////////////////////////////////////////////////////
123
124/// A specialized conversion trait,to convert field accessor error types to other
125/// field accessor error types.
126pub trait IntoFieldErr<T>: IsFieldErr {
127    /// Performs the conversion
128    fn into_field_err(self) -> T
129    where
130        T: IsFieldErr;
131}
132
133impl<T> IntoFieldErr<T> for T
134where
135    T: IsFieldErr,
136{
137    #[inline(always)]
138    fn into_field_err(self) -> T {
139        self
140    }
141}
142
143impl IntoFieldErr<FailedAccess> for InfallibleAccess {
144    #[inline(always)]
145    fn into_field_err(self) -> FailedAccess {
146        match self {}
147    }
148}
149
150////////////////////////////////////////////////////////////////////////////////
151
152/// Combines multiple error types into one.
153///
154/// A tuple of errors is combined into a `InfallibleAccess` so long as all of them are,
155/// otherwise they're combined into an `FailedAccess` .
156///
157/// This is used by the `Rev*Field*` impls for [NestedFieldPath](../../struct.NestedFieldPath.html) to
158/// determine whether a nested field access is optional or not.
159pub trait CombinedErrs {
160    /// The error type after combining all errors.
161    ///
162    /// In the impls from the structural crate,
163    /// if all errors are `InfallibleAccess`,then `Combined` is `InfallibleAccess`,
164    /// otherwise `Combined` is `FailedAccess`.
165    type Combined: IsFieldErr;
166}
167
168/// The combination of all the error types in `This`.
169///
170/// A tuple of errors is combined into a `InfallibleAccess` so long as all of them are,
171/// otherwise they're combined into an `FailedAccess` .
172pub type CombinedErrsOut<This> = <This as CombinedErrs>::Combined;
173
174mod impl_combine_errs {
175    use super::{
176        CombinedErrs, CombinedErrsOut, FailedAccess as OF, InfallibleAccess as IF, IsFieldErr,
177    };
178
179    macro_rules! combined_err_impls {
180        (small=>
181            $( $ty:ty = $output:ty ,)*
182        ) => {
183            $(
184                impl CombinedErrs for $ty {
185                    type Combined=$output;
186                }
187            )*
188        };
189        (large=>
190            $((
191                $( ($t0:ident,$t1:ident,$t2:ident,$t3:ident,), )*
192                $($trailing:ident,)*
193            ))*
194        )=>{
195            $(
196                #[allow(non_camel_case_types)]
197                impl< $($t0,$t1,$t2,$t3,)* $($trailing,)* CombTuples,CombTrail >
198                    CombinedErrs
199                for ($($t0,$t1,$t2,$t3,)* $($trailing,)*)
200                where
201                    $( ($t0,$t1,$t2,$t3): CombinedErrs, )*
202                    (
203                        $( CombinedErrsOut<($t0,$t1,$t2,$t3)>, )*
204                    ):CombinedErrs<Combined=CombTuples>,
205                    CombTuples:IsFieldErr,
206                    ($($trailing,)*):CombinedErrs<Combined=CombTrail>,
207                    CombTrail:IsFieldErr,
208                    (CombTuples,CombTrail):CombinedErrs,
209                {
210                    type Combined=CombinedErrsOut<(CombTuples,CombTrail)>;
211                }
212            )*
213        };
214    }
215
216    /*
217    fn main() {
218        fn as_ty(b:bool)->&'static str{
219            if b {"OF"}else{"IF"}
220        }
221
222        for elem_count in 0..=4 {
223            for bits in 0..1<<elem_count {
224                let is_optional=(0..elem_count)
225                    .map(|i| (bits>>i)&1!=0 )
226                    .collect::<Vec<bool>>();
227
228                let tup=is_optional.iter().copied().map(as_ty).collect::<Vec<_>>();
229                let any_optional=is_optional.iter().cloned().any(|x|x);
230
231                println!(
232                    "({tup})={output},",
233                    tup=tup.join(","),
234                    output=as_ty(any_optional),
235                )
236            }
237        }
238    }
239    */
240
241    combined_err_impls! {
242        small=>
243        ()=IF,
244        (IF,)=IF,
245        (OF,)=OF,
246        (IF,IF)=IF,
247        (OF,IF)=OF,
248        (IF,OF)=OF,
249        (OF,OF)=OF,
250        (IF,IF,IF)=IF,
251        (OF,IF,IF)=OF,
252        (IF,OF,IF)=OF,
253        (OF,OF,IF)=OF,
254        (IF,IF,OF)=OF,
255        (OF,IF,OF)=OF,
256        (IF,OF,OF)=OF,
257        (OF,OF,OF)=OF,
258        (IF,IF,IF,IF)=IF,
259        (OF,IF,IF,IF)=OF,
260        (IF,OF,IF,IF)=OF,
261        (OF,OF,IF,IF)=OF,
262        (IF,IF,OF,IF)=OF,
263        (OF,IF,OF,IF)=OF,
264        (IF,OF,OF,IF)=OF,
265        (OF,OF,OF,IF)=OF,
266        (IF,IF,IF,OF)=OF,
267        (OF,IF,IF,OF)=OF,
268        (IF,OF,IF,OF)=OF,
269        (OF,OF,IF,OF)=OF,
270        (IF,IF,OF,OF)=OF,
271        (OF,IF,OF,OF)=OF,
272        (IF,OF,OF,OF)=OF,
273        (OF,OF,OF,OF)=OF,
274    }
275
276    /*
277    fn main() {
278        fn as_ty(b:bool)->&'static str{
279            if b {"OF"}else{"IF"}
280        }
281        let tup_size=4;
282
283        for elem_count in 5..=12 {
284            print!("(");
285            for which_tup in 0..elem_count/tup_size {
286                let start=which_tup*tup_size;
287                print!("(");
288                for e in start..start+tup_size{
289                    print!("e{},",e);
290                }
291                print!("),");
292            }
293            for e in elem_count/tup_size*tup_size..elem_count{
294                print!("e{},",e);
295            }
296            println!(")");
297        }
298    }
299
300    */
301
302    combined_err_impls! {
303        large=>
304        ((e0,e1,e2,e3,),e4,)
305        ((e0,e1,e2,e3,),e4,e5,)
306        ((e0,e1,e2,e3,),e4,e5,e6,)
307        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),)
308        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,)
309        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,e9,)
310        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,e9,e10,)
311        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),(e8,e9,e10,e11,),)
312    }
313}