drasi_core/models/
element_value.rs

1#![allow(clippy::unwrap_used)]
2// Copyright 2024 The Drasi Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::ConversionError;
17
18use std::{
19    collections::BTreeMap,
20    ops::{Index, IndexMut},
21};
22
23use crate::evaluation::variable_value::{float::Float, integer::Integer, VariableValue};
24
25use std::sync::Arc;
26
27use ordered_float::OrderedFloat;
28
29#[derive(Debug, Clone, Hash, Eq, PartialEq, Default)]
30pub enum ElementValue {
31    #[default]
32    Null,
33    Bool(bool),
34    Float(OrderedFloat<f64>),
35    Integer(i64),
36    String(Arc<str>),
37    List(Vec<ElementValue>),
38    Object(ElementPropertyMap),
39}
40
41impl From<&ElementPropertyMap> for VariableValue {
42    fn from(val: &ElementPropertyMap) -> Self {
43        let mut map = BTreeMap::new();
44        for (key, value) in val.values.iter() {
45            map.insert(key.to_string(), value.into());
46        }
47        VariableValue::Object(map)
48    }
49}
50
51impl From<&ElementValue> for VariableValue {
52    fn from(val: &ElementValue) -> Self {
53        match val {
54            ElementValue::Null => VariableValue::Null,
55            ElementValue::Bool(b) => VariableValue::Bool(*b),
56            ElementValue::Float(f) => VariableValue::Float(Float::from(f.0)),
57            ElementValue::Integer(i) => VariableValue::Integer(Integer::from(*i)),
58            ElementValue::String(s) => VariableValue::String(s.to_string()),
59            ElementValue::List(l) => VariableValue::List(l.iter().map(|x| x.into()).collect()),
60            ElementValue::Object(o) => o.into(),
61        }
62    }
63}
64
65impl TryInto<ElementValue> for &VariableValue {
66    type Error = ConversionError;
67
68    fn try_into(self) -> Result<ElementValue, ConversionError> {
69        match self {
70            VariableValue::Null => Ok(ElementValue::Null),
71            VariableValue::Bool(b) => Ok(ElementValue::Bool(*b)),
72            VariableValue::Float(f) => Ok(ElementValue::Float(OrderedFloat(
73                f.as_f64().unwrap_or_default(),
74            ))),
75            VariableValue::Integer(i) => Ok(ElementValue::Integer(i.as_i64().unwrap_or_default())),
76            VariableValue::String(s) => Ok(ElementValue::String(Arc::from(s.as_str()))),
77            VariableValue::List(l) => Ok(ElementValue::List(
78                l.iter().map(|x| x.try_into().unwrap_or_default()).collect(),
79            )),
80            VariableValue::Object(o) => Ok(ElementValue::Object(o.into())),
81            _ => Err(ConversionError {}),
82        }
83    }
84}
85
86impl From<&ElementValue> for serde_json::Value {
87    fn from(val: &ElementValue) -> Self {
88        match val {
89            ElementValue::Null => serde_json::Value::Null,
90            ElementValue::Bool(b) => serde_json::Value::Bool(*b),
91            ElementValue::Float(f) => {
92                serde_json::Value::Number(serde_json::Number::from_f64(f.into_inner()).unwrap())
93            }
94            ElementValue::Integer(i) => serde_json::Value::Number(serde_json::Number::from(*i)),
95            ElementValue::String(s) => serde_json::Value::String(s.to_string()),
96            ElementValue::List(l) => serde_json::Value::Array(l.iter().map(|x| x.into()).collect()),
97            ElementValue::Object(o) => serde_json::Value::Object(o.into()),
98        }
99    }
100}
101
102impl From<&serde_json::Value> for ElementValue {
103    fn from(value: &serde_json::Value) -> Self {
104        match value {
105            serde_json::Value::Null => ElementValue::Null,
106            serde_json::Value::Bool(b) => ElementValue::Bool(*b),
107            serde_json::Value::Number(n) => {
108                if let Some(i) = n.as_i64() {
109                    ElementValue::Integer(i)
110                } else if let Some(f) = n.as_f64() {
111                    ElementValue::Float(OrderedFloat(f))
112                } else {
113                    ElementValue::Null
114                }
115            }
116            serde_json::Value::String(s) => ElementValue::String(Arc::from(s.as_str())),
117            serde_json::Value::Array(a) => ElementValue::List(a.iter().map(|x| x.into()).collect()),
118            serde_json::Value::Object(o) => ElementValue::Object(o.into()),
119        }
120    }
121}
122
123impl TryInto<ElementPropertyMap> for &VariableValue {
124    type Error = ConversionError;
125
126    fn try_into(self) -> Result<ElementPropertyMap, ConversionError> {
127        match self {
128            VariableValue::Object(o) => {
129                let mut values = BTreeMap::new();
130                for (key, value) in o.iter() {
131                    values.insert(Arc::from(key.as_str()), value.try_into()?);
132                }
133                Ok(ElementPropertyMap { values })
134            }
135            _ => Err(ConversionError {}),
136        }
137    }
138}
139
140#[derive(Debug, Clone, Hash, Eq, PartialEq)]
141pub struct ElementPropertyMap {
142    values: BTreeMap<Arc<str>, ElementValue>,
143}
144
145impl Default for ElementPropertyMap {
146    fn default() -> Self {
147        Self::new()
148    }
149}
150
151impl ElementPropertyMap {
152    pub fn new() -> Self {
153        ElementPropertyMap {
154            values: BTreeMap::new(),
155        }
156    }
157
158    pub fn get(&self, key: &str) -> Option<&ElementValue> {
159        self.values.get(key)
160    }
161
162    pub fn insert(&mut self, key: &str, value: ElementValue) {
163        self.values.insert(Arc::from(key), value);
164    }
165
166    pub fn merge(&mut self, other: &ElementPropertyMap) {
167        for (key, value) in other.values.iter() {
168            self.values
169                .entry(key.clone())
170                .or_insert_with(|| value.clone());
171        }
172    }
173
174    pub fn map_iter<T>(
175        &self,
176        f: impl Fn(&Arc<str>, &ElementValue) -> T + 'static,
177    ) -> impl Iterator<Item = T> + '_ {
178        self.values.iter().map(move |(k, v)| f(k, v))
179    }
180}
181
182impl Index<&str> for ElementPropertyMap {
183    type Output = ElementValue;
184
185    fn index(&self, key: &str) -> &Self::Output {
186        static NULL: ElementValue = ElementValue::Null;
187        match self.values.get(key) {
188            Some(value) => value,
189            None => &NULL,
190        }
191    }
192}
193
194impl IndexMut<&str> for ElementPropertyMap {
195    fn index_mut(&mut self, key: &str) -> &mut Self::Output {
196        self.values
197            .entry(Arc::from(key))
198            .or_insert_with(|| ElementValue::Null)
199    }
200}
201
202impl From<&BTreeMap<String, VariableValue>> for ElementPropertyMap {
203    fn from(map: &BTreeMap<String, VariableValue>) -> Self {
204        let mut values = BTreeMap::new();
205        for (key, value) in map.iter() {
206            values.insert(Arc::from(key.as_str()), value.try_into().unwrap());
207        }
208        ElementPropertyMap { values }
209    }
210}
211
212impl From<&ElementPropertyMap> for serde_json::Map<String, serde_json::Value> {
213    fn from(val: &ElementPropertyMap) -> Self {
214        val.values
215            .iter()
216            .map(|(k, v)| (k.to_string(), v.into()))
217            .collect()
218    }
219}
220
221impl From<&serde_json::Map<String, serde_json::Value>> for ElementPropertyMap {
222    fn from(map: &serde_json::Map<String, serde_json::Value>) -> Self {
223        let mut values = BTreeMap::new();
224        for (key, value) in map.iter() {
225            values.insert(Arc::from(key.as_str()), value.into());
226        }
227        ElementPropertyMap { values }
228    }
229}
230
231impl From<serde_json::Value> for ElementPropertyMap {
232    fn from(value: serde_json::Value) -> Self {
233        match value {
234            serde_json::Value::Object(o) => (&o).into(),
235            _ => ElementPropertyMap::new(),
236        }
237    }
238}