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#[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}