1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/*!
Field-accessor-related error types and traits
*/

use std_::fmt::{self, Display};

use core_extensions::collection_traits::Cloned;

mod sealed {
    pub trait Sealed {}
}
use self::sealed::Sealed;

/// Marker trait for the errors that can be returned from the `RevGetField` trait and subtraits.
///
/// The errors can be:
///
/// - [InfallibleAccess](./enum.InfallibleAccess.html):
///     For `Rev*` accessors that return a field that always exists,
///     most often in a struct.
///     Because the field always exists this error is never actually returned.
///
/// - [FailedAccess](./struct.FailedAccess.html):
///     For `Rev*` accessors that failed to return a field that may not exist,
///     most often inside an enum.
///
/// This trait is sealed,and cannot be implemented outside of the `structural` crate.
pub trait IsFieldErr: Sealed + 'static + Copy + Cloned {}

/// The error type for accesses to fields that always exist,most often in a struct.
///
/// Because the fields always exist,this error is never actually returned,
/// and `Result<T, InfallibleAccess>` has the same size as `T` (as of Rust 1.42).
///
/// This is used as the `Err` associated type for `Rev*Field*` implementors,
/// which return a `Result<_,InfallibleAccess>`,
/// then [StructuralExt](../../trait.StructuralExt.html) methods use
/// [NormalizeFields](../trait.NormalizeFields.html) to turn
/// `Ok(foo)` into `foo` (which can be safely done,since this type can't be constructed).
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum InfallibleAccess {}

/// The error type for accesses to fields that may not exist,most often inside an enum.
///
/// This is used as the `Err` associated type for `Rev*Field*` implementors,
/// which return a `Result<_,FailedAccess>`,
/// then [StructuralExt](../../trait.StructuralExt.html) methods use
/// [NormalizeFields](../trait.NormalizeFields.html) to turn
/// `Ok(foo)` into `Some(foo)`,and `Err(FailedAccess)` into `None`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FailedAccess;

impl Cloned for FailedAccess {
    type Cloned = Self;

    #[inline(always)]
    fn cloned_(&self) -> Self {
        *self
    }
}

impl Cloned for InfallibleAccess {
    type Cloned = Self;

    #[inline(always)]
    fn cloned_(&self) -> Self {
        *self
    }
}

impl Sealed for FailedAccess {}
impl IsFieldErr for FailedAccess {}

impl Sealed for InfallibleAccess {}
impl IsFieldErr for InfallibleAccess {}

#[cfg(feature = "std")]
mod std_impls {
    use super::{FailedAccess, InfallibleAccess};

    use std::error::Error;

    impl Error for FailedAccess {
        #[inline(always)]
        fn description(&self) -> &str {
            "Some field could not be accessed"
        }
    }
    impl Error for InfallibleAccess {
        #[inline(always)]
        fn description(&self) -> &str {
            "The field isn't optional,this function is uncallable"
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

impl Display for FailedAccess {
    #[inline(always)]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Some field could not be accessed")
    }
}

impl From<InfallibleAccess> for FailedAccess {
    #[inline(always)]
    fn from(_: InfallibleAccess) -> Self {
        FailedAccess
    }
}

////////////////////////////////////////////////////////////////////////////////

impl Display for InfallibleAccess {
    #[inline(always)]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("This field can always be accessed.")
    }
}

////////////////////////////////////////////////////////////////////////////////

/// A specialized conversion trait,to convert field accessor error types to other
/// field accessor error types.
pub trait IntoFieldErr<T>: IsFieldErr {
    fn into_field_err(self) -> T
    where
        T: IsFieldErr;
}

impl<T> IntoFieldErr<T> for T
where
    T: IsFieldErr,
{
    #[inline(always)]
    fn into_field_err(self) -> T {
        self
    }
}

impl IntoFieldErr<FailedAccess> for InfallibleAccess {
    #[inline(always)]
    fn into_field_err(self) -> FailedAccess {
        match self {}
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Combines multiple error types into one.
///
/// A tuple of errors is combined into a `InfallibleAccess` so long as all of them are,
/// otherwise they're combined into an `FailedAccess` .
///
/// This is used by the `Rev*Field*` impls for [NestedFieldPath](../../struct.NestedFieldPath.html) to
/// determine whether a nested field access is optional or not.
pub trait CombinedErrs {
    type Combined: IsFieldErr;
}

/// The combination of all the error types in `This`.
///
/// A tuple of errors is combined into a `InfallibleAccess` so long as all of them are,
/// otherwise they're combined into an `FailedAccess` .
pub type CombinedErrsOut<This> = <This as CombinedErrs>::Combined;

mod impl_combine_errs {
    use super::{
        CombinedErrs, CombinedErrsOut, FailedAccess as OF, InfallibleAccess as IF, IsFieldErr,
    };

    macro_rules! combined_err_impls {
        (small=>
            $( $ty:ty = $output:ty ,)*
        ) => {
            $(
                impl CombinedErrs for $ty {
                    type Combined=$output;
                }
            )*
        };
        (large=>
            $((
                $( ($t0:ident,$t1:ident,$t2:ident,$t3:ident,), )*
                $($trailing:ident,)*
            ))*
        )=>{
            $(
                #[allow(non_camel_case_types)]
                impl< $($t0,$t1,$t2,$t3,)* $($trailing,)* CombTuples,CombTrail >
                    CombinedErrs
                for ($($t0,$t1,$t2,$t3,)* $($trailing,)*)
                where
                    $( ($t0,$t1,$t2,$t3): CombinedErrs, )*
                    (
                        $( CombinedErrsOut<($t0,$t1,$t2,$t3)>, )*
                    ):CombinedErrs<Combined=CombTuples>,
                    CombTuples:IsFieldErr,
                    ($($trailing,)*):CombinedErrs<Combined=CombTrail>,
                    CombTrail:IsFieldErr,
                    (CombTuples,CombTrail):CombinedErrs,
                {
                    type Combined=CombinedErrsOut<(CombTuples,CombTrail)>;
                }
            )*
        };
    }

    /*
    fn main() {
        fn as_ty(b:bool)->&'static str{
            if b {"OF"}else{"IF"}
        }

        for elem_count in 0..=4 {
            for bits in 0..1<<elem_count {
                let is_optional=(0..elem_count)
                    .map(|i| (bits>>i)&1!=0 )
                    .collect::<Vec<bool>>();

                let tup=is_optional.iter().copied().map(as_ty).collect::<Vec<_>>();
                let any_optional=is_optional.iter().cloned().any(|x|x);

                println!(
                    "({tup})={output},",
                    tup=tup.join(","),
                    output=as_ty(any_optional),
                )
            }
        }
    }
    */

    combined_err_impls! {
        small=>
        ()=IF,
        (IF,)=IF,
        (OF,)=OF,
        (IF,IF)=IF,
        (OF,IF)=OF,
        (IF,OF)=OF,
        (OF,OF)=OF,
        (IF,IF,IF)=IF,
        (OF,IF,IF)=OF,
        (IF,OF,IF)=OF,
        (OF,OF,IF)=OF,
        (IF,IF,OF)=OF,
        (OF,IF,OF)=OF,
        (IF,OF,OF)=OF,
        (OF,OF,OF)=OF,
        (IF,IF,IF,IF)=IF,
        (OF,IF,IF,IF)=OF,
        (IF,OF,IF,IF)=OF,
        (OF,OF,IF,IF)=OF,
        (IF,IF,OF,IF)=OF,
        (OF,IF,OF,IF)=OF,
        (IF,OF,OF,IF)=OF,
        (OF,OF,OF,IF)=OF,
        (IF,IF,IF,OF)=OF,
        (OF,IF,IF,OF)=OF,
        (IF,OF,IF,OF)=OF,
        (OF,OF,IF,OF)=OF,
        (IF,IF,OF,OF)=OF,
        (OF,IF,OF,OF)=OF,
        (IF,OF,OF,OF)=OF,
        (OF,OF,OF,OF)=OF,
    }

    /*
    fn main() {
        fn as_ty(b:bool)->&'static str{
            if b {"OF"}else{"IF"}
        }
        let tup_size=4;

        for elem_count in 5..=12 {
            print!("(");
            for which_tup in 0..elem_count/tup_size {
                let start=which_tup*tup_size;
                print!("(");
                for e in start..start+tup_size{
                    print!("e{},",e);
                }
                print!("),");
            }
            for e in elem_count/tup_size*tup_size..elem_count{
                print!("e{},",e);
            }
            println!(")");
        }
    }

    */

    combined_err_impls! {
        large=>
        ((e0,e1,e2,e3,),e4,)
        ((e0,e1,e2,e3,),e4,e5,)
        ((e0,e1,e2,e3,),e4,e5,e6,)
        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),)
        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,)
        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,e9,)
        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),e8,e9,e10,)
        ((e0,e1,e2,e3,),(e4,e5,e6,e7,),(e8,e9,e10,e11,),)
    }
}