Skip to main content

gen_analyzer/parse/value/
struct.rs

1use std::{collections::BTreeMap, fmt::Display};
2
3use gen_utils::{
4    error::{Error, ParseError},
5    parser::{parse_value, trim},
6};
7use nom::{bytes::complete::take_till1, character::complete::char, multi::many0, IResult};
8
9
10use crate::PropKeyType;
11
12use super::Value;
13
14/// # Struct Value
15/// struct value used in style (seldom used now)
16/// ## Test
17/// See [test_struct](tests/src/parser/value/struct.rs)
18#[derive(Debug, Clone, PartialEq)]
19pub struct Struct {
20    pub name: Option<String>,
21    pub fields: BTreeMap<String, Value>,
22    pub is_anonymous: bool,
23}
24
25impl Struct {
26    pub fn new(name: &str) -> Self {
27        Struct {
28            name: Some(name.to_string()),
29            fields: BTreeMap::new(),
30            is_anonymous: false,
31        }
32    }
33    pub fn insert(&mut self, key: &str, value: Value) {
34        self.fields.insert(key.to_string(), value);
35    }
36    pub fn get(&self, key: &str) -> Option<&Value> {
37        self.fields.get(key)
38    }
39    pub fn set_name(&mut self, name: &str) {
40        self.name.replace(name.to_string());
41        self.is_anonymous = false;
42    }
43    pub fn parse_style(s: &str) -> Result<Self, Error> {
44        match parse_struct_style(s) {
45            Ok((_, res)) => Ok(res),
46            Err(_) => Err(ParseError::template("parse style struct failed").into()),
47        }
48    }
49    pub fn parse_template(s: &str) -> Result<Self, Error> {
50        Self::parse_style(s)
51    }
52}
53
54impl TryFrom<serde_json::Value> for Struct {
55    type Error = Error;
56
57    fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
58        let mut fields = BTreeMap::new();
59        if let serde_json::Value::Object(obj) = value {
60            for (k, v) in obj {
61                fields.insert(k, Value::try_from(v)?);
62            }
63        }
64        Ok(Struct {
65            name: None,
66            fields,
67            is_anonymous: true,
68        })
69    }
70}
71
72impl From<Vec<(&str, &str)>> for Struct {
73    fn from(value: Vec<(&str, &str)>) -> Self {
74        let mut fields = BTreeMap::new();
75        for (k, v) in value {
76            fields.insert(k.to_string(), Value::from(v));
77        }
78        Struct {
79            name: None,
80            fields,
81            is_anonymous: true,
82        }
83    }
84}
85
86impl From<Vec<(&str, (Value, PropKeyType))>> for Struct {
87    fn from(value: Vec<(&str, (Value, PropKeyType))>) -> Self {
88        let mut fields = BTreeMap::new();
89        for (k, (v, _)) in value {
90            fields.insert(k.to_string(), v);
91        }
92        Struct {
93            name: None,
94            fields,
95            is_anonymous: true,
96        }
97    }
98}
99
100impl Display for Struct {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        let mut fields = String::new();
103        for (k, v) in &self.fields {
104            fields.push_str(&format!("{}: {}, ", k, v));
105        }
106        if self.is_anonymous {
107            write!(f, "{{{}}}", fields)
108        } else {
109            write!(
110                f,
111                "{} {{{}}}",
112                self.name.as_ref().unwrap_or(&String::new()),
113                fields
114            )
115        }
116    }
117}
118
119fn parse_kv(input: &str) -> IResult<&str, (&str, Value)> {
120    let mut res = Struct {
121        name: None,
122        fields: BTreeMap::new(),
123        is_anonymous: true,
124    };
125
126    let (input, k) = trim(parse_value)(input)?;
127    let (input, _) = trim(char(':'))(input)?;
128
129    if input.trim().starts_with('{') {
130        let (input, _) = char('{')(input)?;
131        let (input, fields) = many0(parse_kv)(input)?;
132        let (input, _) = char('}')(input)?;
133        for (k, v) in fields {
134            res.fields.insert(k.to_string(), v);
135        }
136        return Ok((input, (k, Value::Struct(res))));
137    } else {
138        let (input, v) = trim(take_till1(|c| c == ',' || c == '}'))(input)?;
139        let input = if input.starts_with(',') {
140            let (input, _) = trim(char(','))(input)?;
141            input
142        } else {
143            input
144        };
145        let v = Value::parse_style(v).map_err(|_| {
146            nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Fail))
147        })?;
148        return Ok((input, (k, v)));
149    }
150}
151/// parse struct in <style>
152fn parse_struct_style(s: &str) -> IResult<&str, Struct> {
153    // let mut map = BTreeMap::new();
154    let mut res = Struct {
155        name: None,
156        fields: BTreeMap::new(),
157        is_anonymous: true,
158    };
159    // let input = s.trim().trim_matches(|c| c == '{' || c == '}');
160    let (input, _) = char('{')(s.trim())?;
161    let (input, fields) = match trim(char('}'))(input) {
162        Ok((input, _)) => (input, vec![]),
163        Err(_) => {
164            let (input, fields) = many0(parse_kv)(input)?;
165
166            // let (input, children) = many0(parse_struct_style)(input)?;
167            // let (input, _) = trim(char('}'))(input)?;
168            (input, fields)
169        }
170    };
171
172    if !fields.is_empty() {
173        for (k, v) in fields {
174            res.fields.insert(k.to_string(), v);
175        }
176    }
177
178    // if !children.is_empty() {
179    //     for child in children {
180    //         dbg!(child);
181    //         // res.fields.insert(k.to_string(), Value::from(v));
182    //     }
183    // }
184
185    Ok((input, res))
186}
187