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
use crate::JsonSchemaDefinition;

macro_rules! impl_json_schema_definition {
    ($rt:ty, "integer", $min:expr, $max:expr) => {
        impl JsonSchemaDefinition for $rt {
            fn get_json_schema_definition() -> serde_json::Value {
                json!({
                    "type": "integer",
                    "minimum": $min,
                    "maximum": $max,
                })
            }
        }
    };
    ($rt:ty, "number", $min:expr, $max:expr) => {
        impl JsonSchemaDefinition for $rt {
            fn get_json_schema_definition() -> serde_json::Value {
                json!({
                    "type": "number",
                    "minimum": $min,
                    "maximum": $max,
                })
            }
        }
    };
    ($rt:ty, "boolean") => {
        impl JsonSchemaDefinition for $rt {
            fn get_json_schema_definition() -> serde_json::Value {
                json!({
                    "type": "boolean"
                })
            }
        }
    };
    ($rt:ty, "string") => {
        impl JsonSchemaDefinition for $rt {
            fn get_json_schema_definition() -> serde_json::Value {
                json!({
                    "type": "string",
                })
            }
        }
    };
    ($rt:ty, "array", "integer", $min:expr, $max:expr) => {
        impl JsonSchemaDefinition for $rt {
            fn get_json_schema_definition() -> serde_json::Value {
                json!({
                    "type": "array",
                    "items": {
                        "type": "integer",
                        "minimum": $min,
                        "maximum": $max,
                    },
                })
            }
        }
    };
}
impl_json_schema_definition!(i8, "integer", std::i8::MIN, std::i8::MAX);
impl_json_schema_definition!(i16, "integer", std::i16::MIN, std::i16::MAX);
impl_json_schema_definition!(i32, "integer", std::i32::MIN, std::i32::MAX);
impl_json_schema_definition!(i64, "integer", std::i64::MIN, std::i64::MAX);
impl_json_schema_definition!(i128, "integer", std::i128::MIN, std::i128::MAX);
impl_json_schema_definition!(u8, "integer", std::u8::MIN, std::u8::MAX);
impl_json_schema_definition!(u16, "integer", std::u16::MIN, std::u16::MAX);
impl_json_schema_definition!(u32, "integer", std::u32::MIN, std::u32::MAX);
impl_json_schema_definition!(u64, "integer", std::u64::MIN, std::u64::MAX);
impl_json_schema_definition!(u128, "integer", std::u128::MIN, std::u128::MAX);
impl_json_schema_definition!(isize, "integer", std::isize::MIN, std::isize::MAX);
impl_json_schema_definition!(usize, "integer", std::usize::MIN, std::usize::MAX);

impl_json_schema_definition!(f32, "number", std::f32::MIN, std::f32::MAX);
impl_json_schema_definition!(f64, "number", std::f64::MIN, std::f64::MAX);

impl_json_schema_definition!(bool, "boolean");

impl_json_schema_definition!(String, "string");
impl_json_schema_definition!(&str, "string");

impl_json_schema_definition!([i8], "array", "integer", std::i8::MIN, std::i8::MAX);
impl_json_schema_definition!([i16], "array", "integer", std::i16::MIN, std::i16::MAX);
impl_json_schema_definition!([i32], "array", "integer", std::i32::MIN, std::i32::MAX);
impl_json_schema_definition!([i64], "array", "integer", std::i64::MIN, std::i64::MAX);
impl_json_schema_definition!([i128], "array", "integer", std::i128::MIN, std::i128::MAX);
impl_json_schema_definition!([u8], "array", "integer", std::u8::MIN, std::u8::MAX);
impl_json_schema_definition!([u16], "array", "integer", std::u16::MIN, std::u16::MAX);
impl_json_schema_definition!([u32], "array", "integer", std::u32::MIN, std::u32::MAX);
impl_json_schema_definition!([u64], "array", "integer", std::u64::MIN, std::u64::MAX);
impl_json_schema_definition!([u128], "array", "integer", std::u128::MIN, std::u128::MAX);
impl_json_schema_definition!(
    [isize],
    "array",
    "integer",
    std::isize::MIN,
    std::isize::MAX
);
impl_json_schema_definition!(
    [usize],
    "array",
    "integer",
    std::usize::MIN,
    std::usize::MAX
);

impl<T: JsonSchemaDefinition> JsonSchemaDefinition for Option<T> {
    fn get_json_schema_definition() -> serde_json::Value {
        <T>::get_json_schema_definition()
    }
}

impl<T: JsonSchemaDefinition> JsonSchemaDefinition for Vec<T> {
    fn get_json_schema_definition() -> serde_json::Value {
        json!({
            "type": "array",
            "items": T::get_json_schema_definition(),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Field;

    impl PartialEq for Field {
        fn eq(&self, other: &Self) -> bool {
            self.name == other.name
        }
    }

    macro_rules! test {
        ($rt:ty, $expected: expr) => {
            let actual = <$rt>::get_json_schema_definition();
            assert_eq!(actual, $expected);
        };
    }

    #[test]
    fn get_json_schema_definition_u8() {
        test!(
            u8,
            json!({
                "type": "integer",
                "minimum": 0,
                "maximum": 255,
            })
        );
    }

    #[test]
    fn get_json_schema_definition_i8() {
        test!(
            i8,
            json!({
                "type": "integer",
                "minimum": -128,
                "maximum": 127,
            })
        );
    }

    #[test]
    fn get_json_schema_definition_f32() {
        test!(
            f32,
            json!({
                "type": "number",
                "minimum": -340_282_346_638_528_860_000_000_000_000_000_000_000.0,
                "maximum": 340_282_346_638_528_860_000_000_000_000_000_000_000.0,
            })
        );
    }

    #[test]
    fn get_json_schema_definition_f64() {
        test!(
            f64,
            json!({
                "type": "number",
                "minimum": -179_769_313_486_231_570_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000.0,
                "maximum": 179_769_313_486_231_570_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000.0,
            })
        );
    }

    #[test]
    fn get_json_schema_definition_boolean() {
        test!(
            bool,
            json!({
                "type": "boolean",
            })
        );
    }

    #[test]
    fn get_json_schema_definition_string() {
        test!(
            String,
            json!({
                "type": "string",
            })
        );
    }

    #[test]
    fn get_json_schema_definition_str() {
        test!(
            &str,
            json!({
                "type": "string",
            })
        );
    }

    #[test]
    fn get_json_schema_definition_option() {
        test!(
            Option<String>,
            json!({
                "type": "string",
            })
        );
    }
}