1
//! Traits to allow the setter functions on our builders
2
//! to accept the specific set of types we want.
3

            
4
use std::num::NonZero;
5

            
6
/// Module used to seal the traits declared here.
7
mod seal {
8
    /// A type to seal most of the traits here.
9
    pub trait Sealed {}
10
    /// A type to seal `PossiblyOption<T>`. (This one has to be generic.)
11
    pub trait SealedPossiblyOption<T> {}
12
}
13

            
14
/// A trait implemented by `String` and `&str`.
15
///
16
/// This is more specific than `AsRef<str>`, which can accidentally include
17
/// many other undesired types.
18
pub trait StringOrStr: seal::Sealed {
19
    /// Convert this object to a String.
20
    fn to_string(self) -> String;
21
}
22
impl seal::Sealed for String {}
23
impl<'a> seal::Sealed for &'a str {}
24

            
25
impl StringOrStr for String {
26
2
    fn to_string(self) -> String {
27
2
        self
28
2
    }
29
}
30
impl<'a> StringOrStr for &'a str {
31
12
    fn to_string(self) -> String {
32
12
        self.to_owned()
33
12
    }
34
}
35

            
36
/// A trait implemented by `String`, `&str`, `Option<String>`, and `Option<&str>`
37
pub trait OptionStringOrStr: seal::Sealed {
38
    /// Convert this object to an `Option<String>`.
39
    fn to_option_string(self) -> Option<String>;
40
}
41

            
42
impl<S> OptionStringOrStr for S
43
where
44
    S: StringOrStr,
45
{
46
4
    fn to_option_string(self) -> Option<String> {
47
4
        Some(self.to_string())
48
4
    }
49
}
50
impl<S> seal::Sealed for Option<S> where S: StringOrStr {}
51
impl<S> OptionStringOrStr for Option<S>
52
where
53
    S: StringOrStr,
54
{
55
2
    fn to_option_string(self) -> Option<String> {
56
2
        self.map(StringOrStr::to_string)
57
2
    }
58
}
59

            
60
/// A trait implemented by `N` and `NonZero<N>`, where N is an integer type.
61
pub trait PossiblyBoundsChecked<N>: seal::Sealed {
62
    /// Convert this object to an instance of `N`.
63
    fn to_unchecked(self) -> N;
64
}
65
/// A trait implemented by `N`, `NonZero<N>`, `Option<N>`, and `Option<NonZero<N>>`, where N is an
66
/// integer type.
67
pub trait OptionPossiblyBoundsChecked<N>: seal::Sealed {
68
    /// Convert this object to an instance of `Option<N>`.
69
    fn to_option_unchecked(self) -> Option<N>;
70
}
71

            
72
/// Implement [`PossiblyBoundsChecked`] and [`OptionPossiblyBoundsChecked`]
73
/// for a space-separated list of integer types.
74
macro_rules! impl_possibly_bounds_checked {
75
    { $($num:ty)+ } => {
76
        $(
77
            impl seal::Sealed for $num {}
78
            impl seal::Sealed for NonZero<$num> {}
79
            impl seal::Sealed for Option<$num> {}
80
            impl seal::Sealed for Option<NonZero<$num>> {}
81

            
82
            impl PossiblyBoundsChecked<$num> for $num {
83
48
                fn to_unchecked(self) -> $num {
84
48
                    self
85
48
                }
86
            }
87
            impl PossiblyBoundsChecked<$num> for NonZero<$num> {
88
                fn to_unchecked(self) -> $num {
89
                    self.get()
90
                }
91
            }
92
            impl OptionPossiblyBoundsChecked<$num> for $num {
93
2
                fn to_option_unchecked(self) -> Option<$num> {
94
2
                    Some(self)
95
2
                }
96
            }
97
            impl OptionPossiblyBoundsChecked<$num> for Option<$num> {
98
                fn to_option_unchecked(self) -> Option<$num> {
99
                    self
100
                }
101
            }
102
            impl OptionPossiblyBoundsChecked<$num> for NonZero<$num> {
103
                fn to_option_unchecked(self) -> Option<$num> {
104
                    Some(self.get())
105
                }
106
            }
107
            impl OptionPossiblyBoundsChecked<$num> for Option<NonZero<$num>> {
108
2
                fn to_option_unchecked(self) -> Option<$num> {
109
3
                    self.map(|v| v.get())
110
2
                }
111
            }
112
         )+
113
    }
114
}
115
impl_possibly_bounds_checked! { u8 u16 u32 u64 u128 }
116

            
117
/// A trait implemented by `T` and `Option<T>`.
118
pub trait PossiblyOption<T>: seal::SealedPossiblyOption<T> {
119
    /// Convert this object into an `Option<T>`
120
    fn to_option(self) -> Option<T>;
121
}
122
impl<T> seal::SealedPossiblyOption<T> for T {}
123
impl<T> seal::SealedPossiblyOption<T> for Option<T> {}
124

            
125
impl<T> PossiblyOption<T> for T {
126
4
    fn to_option(self) -> Option<T> {
127
4
        Some(self)
128
4
    }
129
}
130
impl<T> PossiblyOption<T> for Option<T> {
131
14
    fn to_option(self) -> Option<T> {
132
14
        self
133
14
    }
134
}