utoipa_gen/component/features/
validators.rs

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
use crate::component::{GenericType, TypeTree};
use crate::schema_type::SchemaType;

use super::validation::NumberValue;

pub trait Validator {
    fn is_valid(&self) -> Result<(), &'static str>;
}

pub struct IsNumber<'a>(pub &'a SchemaType<'a>);

impl Validator for IsNumber<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        if self.0.is_number() {
            Ok(())
        } else {
            Err("can only be used with `number` type")
        }
    }
}

pub struct IsString<'a>(pub(super) &'a SchemaType<'a>);

impl Validator for IsString<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        if self.0.is_string() {
            Ok(())
        } else {
            Err("can only be used with `string` type")
        }
    }
}

pub struct IsInteger<'a>(&'a SchemaType<'a>);

impl Validator for IsInteger<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        if self.0.is_integer() {
            Ok(())
        } else {
            Err("can only be used with `integer` type")
        }
    }
}

pub struct IsVec<'a>(pub(super) &'a TypeTree<'a>);

impl Validator for IsVec<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        if self.0.generic_type == Some(GenericType::Vec) {
            Ok(())
        } else {
            Err("can only be used with `Vec`, `array` or `slice` types")
        }
    }
}

pub struct AboveZeroUsize<'a>(pub(super) &'a NumberValue);

impl Validator for AboveZeroUsize<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        let usize: usize = self
            .0
            .try_from_str()
            .map_err(|_| "invalid type, expected `usize`")?;

        if usize != 0 {
            Ok(())
        } else {
            Err("can only be above zero value")
        }
    }
}

pub struct AboveZeroF64<'a>(pub(super) &'a NumberValue);

impl Validator for AboveZeroF64<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        let float: f64 = self
            .0
            .try_from_str()
            .map_err(|_| "invalid type, expected `f64`")?;
        if float > 0.0 {
            Ok(())
        } else {
            Err("can only be above zero value")
        }
    }
}

pub struct ValidatorChain<'c> {
    inner: &'c dyn Validator,
    next: Option<&'c dyn Validator>,
}

impl Validator for ValidatorChain<'_> {
    fn is_valid(&self) -> Result<(), &'static str> {
        self.inner.is_valid().and_then(|_| {
            if let Some(validator) = self.next.as_ref() {
                validator.is_valid()
            } else {
                // if there is no next validator consider it valid
                Ok(())
            }
        })
    }
}

impl<'c> ValidatorChain<'c> {
    pub fn new(validator: &'c dyn Validator) -> Self {
        Self {
            inner: validator,
            next: None,
        }
    }

    pub fn next(mut self, validator: &'c dyn Validator) -> Self {
        self.next = Some(validator);

        self
    }
}