gistools/parsers/wkt/
object.rs

1use super::clean_string;
2use alloc::{
3    string::{String, ToString},
4    vec,
5    vec::Vec,
6};
7
8/// WKT value or array of values
9#[derive(Debug, Clone, PartialEq)]
10pub enum WKTValue {
11    /// A string
12    String(String),
13    /// A collection of sub WKT values
14    Array(Vec<WKTValue>),
15}
16impl WKTValue {
17    /// Pull out the string if it exists
18    #[allow(clippy::inherent_to_string)]
19    pub fn to_string(&self) -> String {
20        match self {
21            WKTValue::String(s) => s.clone(),
22            WKTValue::Array(_) => "".into(),
23        }
24    }
25    /// To Float
26    pub fn to_float(&self) -> f64 {
27        match self {
28            WKTValue::String(s) => s.parse().unwrap_or_default(),
29            WKTValue::Array(_) => 0.,
30        }
31    }
32    /// Get the Array if it exists
33    pub fn to_arr(&self) -> Option<&Vec<WKTValue>> {
34        match self {
35            WKTValue::Array(arr) => Some(arr),
36            WKTValue::String(_) => None,
37        }
38    }
39    /// Check if it is an array
40    pub fn is_array(&self) -> bool {
41        matches!(self, WKTValue::Array(_))
42    }
43}
44/// WKT object is a collection of WKT values or even nested WKT objects
45pub type WKTObject = Vec<WKTValue>;
46
47/// A trait for converting from WKT string (pre-parsed as an object)
48pub trait WKTParser: Default {
49    /// Converts from WKT
50    fn from_wkt(wkt: &WKTValue) -> Self;
51}
52
53/// Parses a WKT object
54pub fn parse_wkt_object(wkt_str: &str) -> WKTValue {
55    let wkt_str = clean_string(wkt_str);
56    let mut res: WKTObject = vec![];
57    _parse_wkt_object(wkt_str, &mut res);
58
59    // convert to WKTValue
60    WKTValue::Array(res)
61}
62
63/// # Parse a WKT object
64///
65/// ## Arguments
66/// - `wkt_str` - WKT string
67/// - `res` - collection to store the values
68///
69/// ## Returns
70/// - A sliced WKT string with the parsed values
71fn _parse_wkt_object(wkt_str: String, res: &mut WKTObject) -> String {
72    let mut wkt_str = wkt_str;
73
74    while !wkt_str.is_empty() {
75        // Find indices
76        let comma_index = wkt_str.find(',').unwrap_or(usize::MAX);
77        let start_bracket_index = wkt_str.find('[').unwrap_or(usize::MAX);
78        let end_bracket_index = wkt_str.find(']').unwrap_or(usize::MAX);
79
80        if comma_index < start_bracket_index.min(end_bracket_index) {
81            // Store the value before the comma
82            let key = wkt_str[..comma_index].to_string();
83            if !key.is_empty() {
84                res.push(WKTValue::String(clean_string(&key)));
85            }
86            wkt_str = wkt_str[comma_index + 1..].to_string();
87        } else if start_bracket_index < end_bracket_index {
88            // Store the object inside brackets
89            let key = wkt_str[..start_bracket_index].to_string();
90            let mut arr = WKTObject::new();
91            wkt_str = _parse_wkt_object(wkt_str[start_bracket_index + 1..].to_string(), &mut arr);
92            res.push(WKTValue::String(clean_string(&key)));
93            res.push(WKTValue::Array(arr));
94        } else {
95            // Store the last value if it exists
96            if end_bracket_index > 0 {
97                let key = clean_string(&wkt_str[..end_bracket_index]);
98                if !key.is_empty() {
99                    res.push(WKTValue::String(key));
100                }
101                wkt_str = wkt_str[end_bracket_index + 1..].to_string();
102            } else {
103                // If no closing bracket, just skip one character
104                wkt_str = wkt_str[1..].to_string();
105            }
106            return wkt_str;
107        }
108    }
109
110    // Return the remaining string after parsing
111    wkt_str
112}