online_dsl_forge/
value.rs1use std::collections::BTreeMap;
2use std::convert::TryFrom;
3use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
8#[serde(tag = "type", content = "value", rename_all = "snake_case")]
9pub enum Value {
10 Null,
11 Bool(bool),
12 Int(i64),
13 Float(f64),
14 String(String),
15 Array(Vec<Value>),
16 Object(BTreeMap<String, Value>),
17}
18
19#[derive(Debug, Clone, Eq, PartialEq)]
20pub struct ValueConversionError {
21 message: String,
22}
23
24impl ValueConversionError {
25 fn new(message: impl Into<String>) -> Self {
26 Self {
27 message: message.into(),
28 }
29 }
30}
31
32impl fmt::Display for ValueConversionError {
33 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34 formatter.write_str(&self.message)
35 }
36}
37
38impl std::error::Error for ValueConversionError {}
39
40impl Value {
41 pub fn type_name(&self) -> &'static str {
42 match self {
43 Self::Null => "null",
44 Self::Bool(_) => "bool",
45 Self::Int(_) => "int",
46 Self::Float(_) => "float",
47 Self::String(_) => "string",
48 Self::Array(_) => "array",
49 Self::Object(_) => "object",
50 }
51 }
52
53 pub fn as_bool(&self) -> Option<bool> {
54 match self {
55 Self::Bool(value) => Some(*value),
56 _ => None,
57 }
58 }
59
60 pub fn is_number(&self) -> bool {
61 matches!(self, Self::Int(_) | Self::Float(_))
62 }
63}
64
65impl TryFrom<serde_json::Value> for Value {
66 type Error = ValueConversionError;
67
68 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
69 match value {
70 serde_json::Value::Null => Ok(Self::Null),
71 serde_json::Value::Bool(value) => Ok(Self::Bool(value)),
72 serde_json::Value::Number(number) => {
73 if let Some(value) = number.as_i64() {
74 Ok(Self::Int(value))
75 } else if let Some(value) = number.as_f64() {
76 Ok(Self::Float(value))
77 } else {
78 Err(ValueConversionError::new("unsupported JSON number"))
79 }
80 }
81 serde_json::Value::String(value) => Ok(Self::String(value)),
82 serde_json::Value::Array(values) => values
83 .into_iter()
84 .map(Value::try_from)
85 .collect::<Result<Vec<_>, _>>()
86 .map(Self::Array),
87 serde_json::Value::Object(values) => values
88 .into_iter()
89 .map(|(key, value)| Value::try_from(value).map(|value| (key, value)))
90 .collect::<Result<BTreeMap<_, _>, _>>()
91 .map(Self::Object),
92 }
93 }
94}
95
96impl From<Value> for serde_json::Value {
97 fn from(value: Value) -> Self {
98 match value {
99 Value::Null => Self::Null,
100 Value::Bool(value) => Self::Bool(value),
101 Value::Int(value) => Self::Number(value.into()),
102 Value::Float(value) => serde_json::Number::from_f64(value)
103 .map(Self::Number)
104 .unwrap_or(Self::Null),
105 Value::String(value) => Self::String(value),
106 Value::Array(values) => Self::Array(values.into_iter().map(Self::from).collect()),
107 Value::Object(values) => Self::Object(
108 values
109 .into_iter()
110 .map(|(key, value)| (key, Self::from(value)))
111 .collect(),
112 ),
113 }
114 }
115}