summaryrefslogtreecommitdiff
path: root/crates/tor-config/src/setter_traits.rs
blob: e84f904d59478450ae234b677cfa12fe4678600a (plain)
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
//! Traits to allow the setter functions on our builders
//! to accept the specific set of types we want.

use std::num::NonZero;

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

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

impl StringOrStr for String {
    fn to_string(self) -> String {
        self
    }
}
impl<'a> StringOrStr for &'a str {
    fn to_string(self) -> String {
        self.to_owned()
    }
}

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

impl<S> OptionStringOrStr for S
where
    S: StringOrStr,
{
    fn to_option_string(self) -> Option<String> {
        Some(self.to_string())
    }
}
impl<S> seal::Sealed for Option<S> where S: StringOrStr {}
impl<S> OptionStringOrStr for Option<S>
where
    S: StringOrStr,
{
    fn to_option_string(self) -> Option<String> {
        self.map(StringOrStr::to_string)
    }
}

/// A trait implemented by `N` and `NonZero<N>`, where N is an integer type.
pub trait PossiblyBoundsChecked<N>: seal::Sealed {
    /// Convert this object to an instance of `N`.
    fn to_unchecked(self) -> N;
}
/// A trait implemented by `N`, `NonZero<N>`, `Option<N>`, and `Option<NonZero<N>>`, where N is an
/// integer type.
pub trait OptionPossiblyBoundsChecked<N>: seal::Sealed {
    /// Convert this object to an instance of `Option<N>`.
    fn to_option_unchecked(self) -> Option<N>;
}

/// Implement [`PossiblyBoundsChecked`] and [`OptionPossiblyBoundsChecked`]
/// for a space-separated list of integer types.
macro_rules! impl_possibly_bounds_checked {
    { $($num:ty)+ } => {
        $(
            impl seal::Sealed for $num {}
            impl seal::Sealed for NonZero<$num> {}
            impl seal::Sealed for Option<$num> {}
            impl seal::Sealed for Option<NonZero<$num>> {}

            impl PossiblyBoundsChecked<$num> for $num {
                fn to_unchecked(self) -> $num {
                    self
                }
            }
            impl PossiblyBoundsChecked<$num> for NonZero<$num> {
                fn to_unchecked(self) -> $num {
                    self.get()
                }
            }
            impl OptionPossiblyBoundsChecked<$num> for $num {
                fn to_option_unchecked(self) -> Option<$num> {
                    Some(self)
                }
            }
            impl OptionPossiblyBoundsChecked<$num> for Option<$num> {
                fn to_option_unchecked(self) -> Option<$num> {
                    self
                }
            }
            impl OptionPossiblyBoundsChecked<$num> for NonZero<$num> {
                fn to_option_unchecked(self) -> Option<$num> {
                    Some(self.get())
                }
            }
            impl OptionPossiblyBoundsChecked<$num> for Option<NonZero<$num>> {
                fn to_option_unchecked(self) -> Option<$num> {
                    self.map(|v| v.get())
                }
            }
         )+
    }
}
impl_possibly_bounds_checked! { u8 u16 u32 u64 u128 }

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

impl<T> PossiblyOption<T> for T {
    fn to_option(self) -> Option<T> {
        Some(self)
    }
}
impl<T> PossiblyOption<T> for Option<T> {
    fn to_option(self) -> Option<T> {
        self
    }
}