ghee_lang/
value.rs

1use nom::bytes::complete::is_not;
2use nom::combinator::{all_consuming, map};
3use nom::multi::many0;
4use nom::number::complete::double;
5
6use nom::bytes::complete::take_while1;
7
8use nom::character::{is_alphanumeric, is_space};
9
10use nom::bytes::complete::tag;
11
12use nom::sequence::delimited;
13
14use nom::branch::alt;
15
16use nom::IResult;
17use serde::Serialize;
18use thiserror::Error;
19
20use std;
21
22//FIXME Enforce types statically; don't let String be compared with f64
23#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize)]
24pub enum Value {
25    Number(f64),
26    String(String),
27    Bytes(Vec<u8>),
28}
29
30#[derive(Error, Debug)]
31pub enum ValueErr {
32    #[error("JSON value was not supported: {0}")]
33    UnsupportedJsonValue(serde_json::Value),
34}
35
36fn is_not_space(chr: u8) -> bool {
37    !is_space(chr)
38}
39
40fn is_alphanumeric_or_dash(chr: u8) -> bool {
41    is_alphanumeric(chr) || chr == '-' as u8
42}
43
44impl Value {
45    pub fn as_bytes(&self) -> Vec<u8> {
46        match self {
47            Self::Number(x) => format!("{}", x).into_bytes(),
48            Self::String(s) => {
49                let mut bytes = s.clone().into_bytes();
50
51                let alphanum = bytes.iter().copied().all(is_not_space);
52
53                if !alphanum {
54                    bytes.insert(0, b'"');
55                    bytes.push(b'"');
56                }
57
58                bytes
59            }
60            Self::Bytes(b) => b.clone(),
61        }
62    }
63}
64
65impl std::fmt::Display for Value {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
67        match self {
68            Self::Number(x) => write!(f, "{}", x),
69            Self::String(s) => write!(f, "{}", s),
70            Self::Bytes(b) => write!(f, "{}", String::from_utf8_lossy(b)),
71        }
72    }
73}
74
75impl From<f64> for Value {
76    fn from(x: f64) -> Self {
77        Self::Number(x)
78    }
79}
80
81impl From<String> for Value {
82    fn from(s: String) -> Self {
83        Self::String(s)
84    }
85}
86
87impl From<&str> for Value {
88    fn from(s: &str) -> Self {
89        Self::String(s.to_string())
90    }
91}
92
93impl From<&[u8]> for Value {
94    fn from(b: &[u8]) -> Self {
95        parse_value(b).unwrap().1
96    }
97}
98
99impl TryFrom<serde_json::Value> for Value {
100    type Error = ValueErr;
101    fn try_from(v: serde_json::Value) -> Result<Self, Self::Error> {
102        match v {
103            serde_json::Value::Number(x) => {
104                Ok(Value::Number(x.as_f64().unwrap_or_else(|| {
105                    panic!("Could not convert json number {} to ghee number", x)
106                })))
107            }
108            serde_json::Value::String(s) => Ok(Value::String(s)),
109            x => Err(ValueErr::UnsupportedJsonValue(x)),
110        }
111    }
112}
113
114pub fn string(i: &[u8]) -> IResult<&[u8], String> {
115    alt((
116        delimited(tag("'"), is_not("'"), tag("'")),
117        delimited(tag("\""), is_not("\""), tag("\"")),
118        take_while1(is_alphanumeric_or_dash),
119    ))(i)
120    .map(|(i, b)| (i, String::from_utf8_lossy(b).to_string()))
121}
122
123pub fn parse_value_not_all_consuming(i: &[u8]) -> IResult<&[u8], Value> {
124    alt((
125        map(double, Value::Number),
126        map(string, Value::String),
127        map(many0(nom::number::complete::u8), Value::Bytes),
128    ))(i)
129}
130
131pub fn parse_value(i: &[u8]) -> IResult<&[u8], Value> {
132    alt((
133        map(all_consuming(double), Value::Number),
134        map(all_consuming(string), Value::String),
135        map(
136            all_consuming(many0(nom::number::complete::u8)),
137            Value::Bytes,
138        ),
139    ))(i)
140}
141
142#[cfg(test)]
143mod test {
144    use crate::parser::value::{parse_value, Value};
145
146    #[test]
147    fn test_parse_value() {
148        assert_eq!(
149            parse_value(b"5.5"),
150            Ok((b"".as_slice(), Value::Number(5.5f64)))
151        );
152        assert_eq!(
153            parse_value(b"Abcdefg"),
154            Ok((b"".as_slice(), Value::String(String::from("Abcdefg"))))
155        );
156        assert_eq!(
157            parse_value(b"\x00"),
158            Ok((b"".as_slice(), Value::Bytes(b"\x00".to_vec())))
159        );
160        assert_eq!(
161            parse_value(b"59b49924-d34f-3e43-b645-d3d2b1c4f51"),
162            Ok((
163                b"".as_slice(),
164                Value::String(String::from("59b49924-d34f-3e43-b645-d3d2b1c4f51"))
165            ))
166        );
167    }
168}