geode/parse/
range.rs

1#![allow(unused)]
2use std::str::FromStr;
3use schemars::{schema::{InstanceType, Schema, SchemaObject, SingleOrVec, StringValidation, SubschemaValidation}, JsonSchema};
4
5use thiserror::Error;
6
7use serde::{de::Error, Deserialize, Serialize};
8
9use super::{RawRepr, RANGE_PATTERN};
10
11#[derive(Clone, Debug, PartialEq)]
12pub struct Range<T> {
13    start: T,
14    end: T,
15    raw: String,
16}
17
18impl<T> Serialize for Range<T> {
19    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: serde::Serializer,
22    {
23        serializer.serialize_str(&self.raw)
24    }
25}
26impl<T> JsonSchema for Range<T> {
27    fn schema_name() -> String {
28        String::from("Range")
29    }
30
31    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
32        let mut schema = SchemaObject::default();
33        //schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
34        schema.subschemas = Some(Box::new(SubschemaValidation {
35            one_of: Some(vec![
36                // Schema for string type
37                Schema::Object(SchemaObject {
38                    instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
39                    string: Some(Box::new(StringValidation {
40                        pattern: Some(RANGE_PATTERN.to_string()),
41                        ..Default::default()
42
43                    })),
44                    ..Default::default()
45                }),
46                // Schema for number type
47                Schema::Object(SchemaObject {
48                    instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Number))),
49                    ..Default::default()
50                }),
51            ]),
52            ..Default::default()
53        }));
54        
55        Schema::Object(schema)
56        
57    }
58}
59
60impl<'de, T> Deserialize<'de> for Range<T>
61where
62    T: FromStr,
63    T::Err: std::error::Error + 'static,
64{
65    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
66    where
67        D: serde::Deserializer<'de>,
68    {
69        let raw: String = Deserialize::deserialize(deserializer)?;
70        let range: Range<T> = raw.parse().map_err(|e| D::Error::custom(e))?;
71
72        Ok(range)
73    }
74}
75
76impl<T> RawRepr for Range<T> {
77    /// Returns a raw string representation as written by the user.
78    fn raw(&self) -> &str {
79        &self.raw
80    }
81}
82
83use std::fmt::{Debug, Display};
84#[derive(Debug, Error, PartialEq)]
85pub enum ParseRangeError<T: FromStr>
86where
87    T::Err: std::error::Error + 'static,
88{
89    #[error("Wrong number of elements for a range, it should be 2. Example: 0 .. 1")]
90    WrongArgNumber,
91    #[error("Failed to parse start bound: {0}")]
92    InvalidStart(#[source] T::Err),
93    #[error("Failed to parse end bound: {0}")]
94    InvalidEnd(#[source] T::Err),
95}
96
97use super::quantity;
98
99impl<T> FromStr for Range<T>
100where
101    T: FromStr,
102    T::Err: std::error::Error + 'static,
103{
104    type Err = ParseRangeError<T>;
105
106    fn from_str(s: &str) -> Result<Self, Self::Err> {
107        let parts: Vec<&str> = s.split("..").map(|part| part.trim()).collect();
108
109        if parts.len() != 2 {
110            return Err(ParseRangeError::WrongArgNumber);
111        }
112
113        let start_unit = quantity::get_unit(parts[0]);
114        let end_unit = quantity::get_unit(parts[1]);
115
116        let mut start = parts[0].to_string();
117        let mut end = parts[1].to_string();
118        if start_unit.is_some() && end_unit.is_none() {
119            end += start_unit.expect("already checked")
120        } else if start_unit.is_none() && end_unit.is_some() {
121            start += end_unit.expect("already checked")
122        }
123
124        let start: T = start
125            .parse()
126            .map_err(|e| ParseRangeError::InvalidStart(e))?;
127        let end: T = end.parse().map_err(|e| ParseRangeError::InvalidEnd(e))?;
128
129        Ok(Range {
130            start,
131            end,
132            raw: s.to_string(),
133        })
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use std::num::ParseIntError;
140
141
142    use super::*;
143    
144    use super::quantity::*;
145
146    #[test]
147    fn same_unit_when_only_one() {
148        let raw = "0..1m2";
149        let range: Range<Area> = raw.parse().expect("valid range should be parsed");
150        assert_eq!(
151            range,
152            Range {
153            start: Area::new("0 m²").unwrap(),
154            end: Area::new("1 m^2").unwrap(),
155            raw: raw.to_string()
156            }
157        );
158    }
159
160    #[test]
161    fn different_units() {
162        let raw = "10km^+2..1m2";
163        let range: Range<Area> = raw.parse().expect("valid range should be parsed");
164        assert_eq!(
165            range,
166            Range {
167            start: Area::new("10 km²").unwrap(),
168            end: Area::new("1 m^2").unwrap(),
169            raw: raw.to_string()
170            }
171        );
172    }
173
174    #[test]
175    fn parse_valid_range() {
176        let raw = "0 .. 1";
177        let range: Range<i32> = raw.parse().expect("Valid range should be parsed");
178        assert_eq!(
179            range,
180            Range {
181                start: 0,
182                end: 1,
183                raw: raw.to_string()
184            }
185        )
186    }
187    #[test]
188    fn serialize_range() {
189        let range = Range {
190            start: 0,
191            end: 1,
192            raw: "0 .. 1".to_string(),
193        };
194        let serialized = serde_json::to_string(&range).expect("Serialization should succeed");
195        assert_eq!(serialized, "\"0 .. 1\"");
196    }
197    //
198    //#[test]
199    //fn deserialize_range() {
200    //    let raw = "\"0 .. 1\"";
201    //    let range: Range<i32> = serde_json::from_str(raw).expect("Deserialization should succeed");
202    //    assert_eq!(
203    //        range,
204    //        Range {
205    //            start: 0,
206    //            end: 1,
207    //            raw: "0 .. 1".to_string()
208    //        }
209    //    );
210    //}
211
212    #[test]
213    fn parse_invalid_range_wrong_arg_number() {
214        let raw = "0 .. 1 .. 2";
215        let result: Result<Range<i32>, _> = raw.parse();
216        assert_eq!(result.unwrap_err(), ParseRangeError::WrongArgNumber);
217    }
218
219    #[test]
220    fn parse_invalid_range_invalid_start() {
221        let raw = "a .. 1";
222        let result: Result<Range<i32>, _> = raw.parse();
223        assert_eq!(
224            result.unwrap_err(),
225            ParseRangeError::InvalidStart("a".parse::<i32>().unwrap_err())
226        );
227    }
228
229    #[test]
230    fn parse_invalid_range_invalid_end() {
231        let raw = "0 .. b";
232        let result: Result<Range<i32>, _> = raw.parse();
233        assert_eq!(
234            result.unwrap_err(),
235            ParseRangeError::InvalidEnd("b".parse::<i32>().unwrap_err())
236        );
237    }
238}