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
/// A placeholder concrete type in cases where no validator is necessary
pub use brane_shr::input::NoValidator;
use dialoguer::InputValidator;

/// A validator that solely validates that there if *some* input was provided
#[derive(Default)]
pub struct NotEmptyValidator;

impl InputValidator<String> for NotEmptyValidator {
    type Err = String;

    fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
        if input.is_empty() { Err(String::from("Value may not be empty")) } else { Ok(()) }
    }
}

/// A validator  that validates whether the provided number is a valid port number
/// Yes this is basically a check if something fits in a u16
#[derive(Default)]
pub struct PortValidator;

impl InputValidator<String> for PortValidator {
    type Err = String;

    fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
        match input.parse::<u16>() {
            Ok(_) => Ok(()),
            Err(err) => Err(format!("Entered port is not valid: {err}")),
        }
    }
}

/// A validator that checks whether the provided input is a valid range. It by default uses a `-`
/// as range seperator, but this is configurable using the seperator field. It allows whitespace
/// around the range values. The segment validator validates the separate parts of the range using
/// the same instance.
pub struct RangeValidator<V>
where
    V: InputValidator<String>,
{
    pub separator: String,
    pub segment_validator: V,
    pub allow_empty: bool,
}

impl<V> Default for RangeValidator<V>
where
    V: Default,
    V: dialoguer::InputValidator<String>,
{
    fn default() -> Self { Self { separator: String::from("-"), segment_validator: Default::default(), allow_empty: false } }
}

impl<V> InputValidator<String> for RangeValidator<V>
where
    V: InputValidator<String>,
    V::Err: ToString,
{
    type Err = String;

    fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
        if self.allow_empty && input.trim().is_empty() {
            return Ok(());
        }

        let Some((start, end)) = input.split_once(&self.separator) else {
            return Err(format!("No range separator {} found", self.separator));
        };

        self.segment_validator.validate(&String::from(start.trim())).map_err(|err| err.to_string())?;
        self.segment_validator.validate(&String::from(end.trim())).map_err(|err| err.to_string())?;

        Ok(())
    }
}

/// The map validator can validate mappings from between different types of values. By default
/// these values are separated by a `:`, but this is configurable using the `separator` field.
pub struct MapValidator<V1, V2>
where
    V1: InputValidator<String>,
    V2: InputValidator<String>,
{
    pub separator: String,
    pub left_validator: V1,
    pub right_validator: V2,
    pub allow_empty: bool,
}

impl<V1, V2> Default for MapValidator<V1, V2>
where
    V1: Default,
    V1: dialoguer::InputValidator<String>,
    V2: Default,
    V2: dialoguer::InputValidator<String>,
{
    fn default() -> Self {
        Self { separator: String::from(":"), left_validator: Default::default(), right_validator: Default::default(), allow_empty: false }
    }
}

impl<V1, V2> InputValidator<String> for MapValidator<V1, V2>
where
    V1: InputValidator<String>,
    V1::Err: ToString,
    V2: InputValidator<String>,
    V2::Err: ToString,
{
    type Err = String;

    fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
        if self.allow_empty && input.is_empty() {
            return Ok(());
        }

        let Some((left, right)) = input.split_once(&self.separator) else {
            return Err(format!("No separator {} found", self.separator));
        };

        self.left_validator.validate(&String::from(left.trim())).map_err(|err| err.to_string())?;
        self.right_validator.validate(&String::from(right.trim())).map_err(|err| err.to_string())?;

        Ok(())
    }
}

/// The validator is a wrapper for all types that implement [`std::str::FromStr`], it uses `FromStr` to validate if
/// the provided input is correct. This assumes that the `Result` that `FromStr` provides correctly
/// distinguishes correct from incorrect inputs. If your `FromStr` implementation is expensive,
/// this might come at a performance hit.
pub struct FromStrValidator<T>
where
    T: std::str::FromStr,
{
    pub field_name: &'static str,
    _fd: std::marker::PhantomData<T>,
}

impl<T> Default for FromStrValidator<T>
where
    T: std::str::FromStr,
{
    fn default() -> Self {
        let field_name_raw = std::any::type_name::<T>();
        let field_name = match field_name_raw.rsplit_once("::") {
            Some((_, segment)) => segment,
            None => field_name_raw,
        };
        Self { _fd: std::marker::PhantomData, field_name }
    }
}

impl<T> InputValidator<String> for FromStrValidator<T>
where
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Display,
{
    type Err = String;

    fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
        match T::from_str(input) {
            Ok(_) => Ok(()),
            Err(err) => Err(format!("Input is not a legal {}: {err}", self.field_name)),
        }
    }
}