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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
use super::ValidatedWrapper;

use std::error::Error;
use std::str::Utf8Error;
use std::fmt::{self, Display, Debug, Formatter};
use std::hash::Hash;
use std::collections::HashSet;

#[derive(Debug, PartialEq, Clone)]
pub enum ValidatedCustomizedHashSetError {
    Overflow,
    Underflow,
    NotSupport,
    UTF8Error(Utf8Error),
}

impl Display for ValidatedCustomizedHashSetError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

impl Error for ValidatedCustomizedHashSetError {}

pub trait ValidatedHashSetWrapper<T: ValidatedWrapper + Eq + Hash>: ValidatedWrapper {
    fn from_hash_set(s: HashSet<T>) -> Result<Self, ValidatedCustomizedHashSetError>;
}

#[cfg(feature = "serdely")]
pub struct HashSetVisitor<V, T>(pub Vec<V>, pub Vec<T>);

#[cfg(feature = "serdely")]
impl<'de, V: ValidatedHashSetWrapper<T>, T: ValidatedWrapper + Eq + Hash + serde::Deserialize<'de>> serde::de::Visitor<'de> for HashSetVisitor<V, T> {
    type Value = V;

    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("an array({})", stringify!($name)))
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: serde::de::SeqAccess<'de> {
        let mut v = HashSet::<T>::new();

        loop {
            match seq.next_element()? {
                Some(e) => {
                    v.insert(e);
                }
                None => { break; }
            }
        }

        Ok(V::from_hash_set(v).map_err(|err| {
            serde::de::Error::custom(err.to_string())
        })?)
    }
}

#[cfg(feature = "serdely")]
#[doc(hidden)]
#[macro_export]
macro_rules! validated_customized_hash_set_struct_implement_se_de {
     ( $name:ident ) => {
        impl<'de, T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash + ::validators::serde::Deserialize<'de>> ::validators::serde::Deserialize<'de> for $name<T> {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: ::validators::serde::Deserializer<'de> {
                deserializer.deserialize_seq(::validators::HashSetVisitor(Vec::<$name<T>>::new(), Vec::<T>::new()))
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash + ::validators::serde::Serialize> ::validators::serde::Serialize for $name<T> {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ::validators::serde::Serializer {
                serializer.collect_seq(self.as_hash_set().iter())
            }
        }
     }
}

#[cfg(not(feature = "serdely"))]
#[doc(hidden)]
#[macro_export]
macro_rules! validated_customized_hash_set_struct_implement_se_de {
    ( $name:ident ) => {

    }
}

#[cfg(feature = "rocketly")]
#[doc(hidden)]
#[macro_export]
macro_rules! validated_customized_hash_set_struct_implement_from_form_value {
    ( $name:ident ) => {
        impl<'a, T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::validators::rocket::request::FromFormValue<'a> for $name<T> {
            type Error = ::validators::ValidatedCustomizedHashSetError;

            fn from_form_value(form_value: &'a ::validators::rocket::http::RawStr) -> Result<Self, Self::Error>{
                $name::from_string(form_value.url_decode().map_err(|err| ::validators::ValidatedCustomizedHashSetError::UTF8Error(err))?)
            }
        }

        impl<'a, T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::validators::rocket::request::FromParam<'a> for $name<T> {
            type Error = ::validators::ValidatedCustomizedHashSetError;

            fn from_param(param: &'a ::validators::rocket::http::RawStr) -> Result<Self, Self::Error> {
                $name::from_string(param.url_decode().map_err(|err| ::validators::ValidatedCustomizedHashSetError::UTF8Error(err))?)
            }
        }

    }
}

#[cfg(not(feature = "rocketly"))]
#[doc(hidden)]
#[macro_export]
macro_rules! validated_customized_hash_set_struct_implement_from_form_value {
    ( $name:ident ) => {

    }
}

#[macro_export]
macro_rules! validated_customized_hash_set_struct {
    ( $name:ident, $field:ident, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block, $from_hash_set_input:ident $from_hash_set:block ) => {
        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::std::fmt::Debug for $name<T> {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.write_fmt(format_args!("{}[", stringify!($name)))?;

                let len = self.$field.len();

                if len > 0 {
                     for n in self.$field.iter().take(1) {
                        ::std::fmt::Display::fmt(n, f)?;
                    }

                    for n in self.$field.iter().skip(1) {
                        f.write_str(", ")?;
                        ::std::fmt::Display::fmt(n, f)?;
                    }
                }

                f.write_str("]")?;

                Ok(())
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::std::fmt::Display for $name<T> {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.write_str("[")?;

                let len = self.$field.len();

                if len > 0 {
                    for n in self.$field.iter().take(1) {
                        ::std::fmt::Display::fmt(n, f)?;
                    }

                    for n in self.$field.iter().skip(1) {
                        f.write_str(", ")?;
                        ::std::fmt::Display::fmt(n, f)?;
                    }
                }

                f.write_str("]")?;

                Ok(())
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::std::hash::Hash for $name<T>{
            fn hash<H: ::std::hash::Hasher>(&self, state: &mut H){
                for e in &self.$field {
                    e.hash(state)
                }
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::std::ops::Deref for $name<T> {
            type Target = ::std::collections::HashSet<T>;

            fn deref(&self) -> &Self::Target {
                &self.$field
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::validators::Validated for $name<T> {}

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::validators::ValidatedWrapper for $name<T> {
            type Error = ::validators::ValidatedCustomizedHashSetError;

            fn from_string($from_string_input: String) -> Result<Self, Self::Error>{
                $name::from_string($from_string_input)
            }

            fn from_str($from_str_input: &str) -> Result<Self, Self::Error>{
                $name::from_str($from_str_input)
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> ::validators::ValidatedHashSetWrapper<T> for $name<T> {
            fn from_hash_set($from_hash_set_input: ::std::collections::HashSet<T>) -> Result<Self, ::validators::ValidatedCustomizedHashSetError>{
                $name::from_hash_set($from_hash_set_input)
            }
        }

        impl<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> $name<T> {
            pub fn as_hash_set(&self) -> &::std::collections::HashSet<T> {
                &self.$field
            }

            pub fn into_hash_set(self) -> ::std::collections::HashSet<T> {
                self.$field
            }

            pub fn from_string($from_string_input: String) -> Result<Self, ::validators::ValidatedCustomizedHashSetError>{
                let $field = match $from_string {
                    Ok(s)=> s,
                    Err(e)=> return Err(e)
                };

                Ok($name{$field})
            }

            pub fn from_str($from_str_input: &str) -> Result<Self, ::validators::ValidatedCustomizedHashSetError>{
                let $field = match $from_str {
                    Ok(s)=> s,
                    Err(e)=> return Err(e)
                };

                Ok($name{$field})
            }

            pub fn from_hash_set($from_hash_set_input: ::std::collections::HashSet<T>) -> Result<Self, ::validators::ValidatedCustomizedHashSetError>{
                let $field = match $from_hash_set {
                    Ok(s)=> s,
                    Err(e)=> return Err(e)
                };

                Ok($name{$field})
            }

            pub unsafe fn from_hash_set_unchecked($from_hash_set_input: ::std::collections::HashSet<T>) -> Self{
                $name{$field:$from_hash_set_input}
            }
        }

         validated_customized_hash_set_struct_implement_from_form_value!($name);
         validated_customized_hash_set_struct_implement_se_de!($name);
    };
}

#[macro_export]
macro_rules! validated_customized_hash_set {
    ( $name:ident, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block, $from_hash_set_input:ident $from_hash_set:block ) => {
        #[derive(Clone, PartialEq, Eq)]
        struct $name<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> {
            v: ::std::collections::HashSet<T>
        }

        validated_customized_hash_set_struct!($name, v, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_string $from_string_input:ident $from_string:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_str $from_str_input:ident $from_str:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( $name:ident, from_str $from_str_input:ident $from_str:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_string $from_string_input:ident $from_string:block ) => {
        validated_customized_hash_set!($name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block, $from_hash_set_input:ident $from_hash_set:block ) => {
        #[derive(Clone, PartialEq, Eq)]
        pub struct $name<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> {
            v: ::std::collections::HashSet<T>
        }

        validated_customized_hash_set_struct!($name, v, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_string $from_string_input:ident $from_string:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_str $from_str_input:ident $from_str:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
    ( pub $name:ident, from_str $from_str_input:ident $from_str:block, from_hash_set $from_hash_set_input:ident $from_hash_set:block, from_string $from_string_input:ident $from_string:block ) => {
        validated_customized_hash_set!(pub $name, $from_string_input $from_string, $from_str_input $from_str, $from_hash_set_input $from_hash_set);
    };
}

#[macro_export]
macro_rules! validated_customized_ranged_length_hash_set_struct {
    ( $name:ident, $field:expr, $min:expr, $max:expr, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block) => {
        validated_customized_hash_set_struct!($name, v,
        $from_string_input $from_string,
        $from_str_input $from_str,
        input {
            let len = input.len();

            if len > $max {
                Err(::validators::ValidatedCustomizedHashSetError::Overflow)
            } else if len < $min {
                Err(::validators::ValidatedCustomizedHashSetError::Underflow)
            } else {
                Ok(input)
            }
        });
    };
}

#[macro_export]
macro_rules! validated_customized_ranged_length_hash_set {
    ( $name:ident, $min:expr, $max:expr, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block) => {
        #[derive(Clone, PartialEq, Eq)]
        struct $name<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> {
            v: ::std::collections::HashSet<T>
        }

        validated_customized_ranged_length_hash_set_struct!($name, v, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( $name:ident, $min:expr, $max:expr, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block) => {
        validated_customized_ranged_length_hash_set!($name, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( $name:ident, $min:expr, $max:expr, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block) => {
        validated_customized_ranged_length_hash_set!($name, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( $name:ident, $min:expr, $max:expr) => {
        validated_customized_ranged_length_hash_set!($name, $min, $max,
        _input {Err(::validators::ValidatedCustomizedHashSetError::NotSupport)},
        _input {Err(::validators::ValidatedCustomizedHashSetError::NotSupport)});
    };
    ( $name:ident, $equal:expr, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block) => {
        validated_customized_ranged_length_hash_set!($name, $equal, $equal, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( $name:ident, $equal:expr) => {
        validated_customized_ranged_length_hash_set!($name, $equal, $equal);
    };
    ( pub $name:ident, $min:expr, $max:expr, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block) => {
        #[derive(Clone, PartialEq, Eq)]
        pub struct $name<T: ::validators::ValidatedWrapper + Eq + ::std::hash::Hash> {
            v: ::std::collections::HashSet<T>
        }

        validated_customized_ranged_length_hash_set_struct!($name, v, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( pub $name:ident, $min:expr, $max:expr, from_string $from_string_input:ident $from_string:block, from_str $from_str_input:ident $from_str:block) => {
        validated_customized_ranged_length_hash_set!(pub $name, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( pub $name:ident, $min:expr, $max:expr, from_str $from_str_input:ident $from_str:block, from_string $from_string_input:ident $from_string:block) => {
        validated_customized_ranged_length_hash_set!(pub $name, $min, $max, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( pub $name:ident, $min:expr, $max:expr) => {
        validated_customized_ranged_length_hash_set!(pub $name, $min, $max,
        _input {Err(::validators::ValidatedCustomizedHashSetError::NotSupport)},
        _input {Err(::validators::ValidatedCustomizedHashSetError::NotSupport)});
    };
    ( pub $name:ident, $equal:expr, $from_string_input:ident $from_string:block, $from_str_input:ident $from_str:block) => {
        validated_customized_ranged_length_hash_set!(pub $name, $equal, $equal, $from_string_input $from_string, $from_str_input $from_str);
    };
    ( pub $name:ident, $equal:expr) => {
        validated_customized_ranged_length_hash_set!(pub $name, $equal, $equal);
    };
}