use std::borrow::Cow; use std::collections::BTreeMap; #[cfg(feature = "serde_json")] use displaydoc::Display; use thiserror::Error; #[derive(Clone)] pub enum NomoValue { String { value: Cow<'static, str>, }, Array { value: Vec, }, Bool { value: bool, }, Object { value: BTreeMap, }, Integer { value: u64, }, SignedInteger { value: i64, }, Float { value: f64, }, Iterator { value: Box>, }, } impl NomoValue { pub fn as_str(&self) -> Option<&str> { if let Self::String { value } = self { Some(value) } else { None } } pub fn as_array(&self) -> Option<&[NomoValue]> { if let Self::Array { value } = self { Some(value) } else { None } } pub fn as_bool(&self) -> Option { if let Self::Bool { value } = self { Some(*value) } else { None } } pub fn as_object(&self) -> Option<&BTreeMap> { if let Self::Object { value } = self { Some(value) } else { None } } pub fn as_integer(&self) -> Option { if let Self::Integer { value } = self { Some(*value) } else { None } } pub fn as_float(&self) -> Option { if let Self::Float { value } = self { Some(*value) } else { None } } pub fn as_iterator(&self) -> Option<&dyn CloneIterator> { if let Self::Iterator { value } = self { Some(value) } else { None } } pub fn as_iterator_mut(&mut self) -> Option<&mut dyn CloneIterator> { if let Self::Iterator { value } = self { Some(value) } else { None } } } pub trait CloneIterator: Iterator { fn clone_box(&self) -> Box>; } impl CloneIterator for I where I: Iterator + Clone + 'static, { fn clone_box(&self) -> Box> { Box::new(Clone::clone(self)) } } impl Clone for Box { fn clone(&self) -> Self { self.clone_box() } } impl std::fmt::Debug for NomoValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::String { value } => f.debug_struct("String").field("value", value).finish(), Self::Array { value } => f.debug_struct("Array").field("value", value).finish(), Self::Bool { value } => f.debug_struct("Bool").field("value", value).finish(), Self::Object { value } => f.debug_struct("Object").field("value", value).finish(), Self::Integer { value } => f.debug_struct("Integer").field("value", value).finish(), Self::SignedInteger { value } => f .debug_struct("SignedInteger") .field("value", value) .finish(), Self::Float { value } => f.debug_struct("Float").field("value", value).finish(), Self::Iterator { value: _ } => f .debug_struct("Iterator") .field("value", &"Iterator") .finish(), } } } impl From<&R> for NomoValue where R: Into + Clone, { fn from(value: &R) -> Self { value.clone().into() } } impl From for NomoValue { fn from(val: String) -> Self { NomoValue::String { value: Cow::Owned(val), } } } impl From<&'static str> for NomoValue { fn from(val: &'static str) -> Self { NomoValue::String { value: Cow::Borrowed(val), } } } impl From> for NomoValue where V: Into, { fn from(val: Vec) -> Self { NomoValue::Array { value: val.into_iter().map(Into::into).collect(), } } } impl From> for NomoValue where V: Into, { fn from(val: std::collections::VecDeque) -> Self { NomoValue::Array { value: val.into_iter().map(Into::into).collect(), } } } impl From<&[V]> for NomoValue where V: Into + Clone, { fn from(value: &[V]) -> Self { NomoValue::Array { value: value.iter().cloned().map(Into::into).collect(), } } } impl From> for NomoValue where K: Into, V: Into, { fn from(val: std::collections::HashMap) -> Self { NomoValue::Object { value: val.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), } } } #[cfg(feature = "serde_json")] #[derive(Debug, Error, Display)] /// Could not transform value to [`NomoValue`] pub struct NomoValueError; #[cfg(feature = "serde_json")] impl TryFrom for NomoValue { type Error = NomoValueError; fn try_from(value: serde_json::Value) -> Result { match value { serde_json::Value::Null => todo!(), serde_json::Value::Bool(value) => Ok(NomoValue::Bool { value }), serde_json::Value::Number(number) => { if let Some(value) = number.as_u64() { return Ok(NomoValue::Integer { value }); } if let Some(value) = number.as_f64() { return Ok(NomoValue::Float { value }); } if let Some(value) = number.as_i64() { return Ok(NomoValue::SignedInteger { value }); } Err(NomoValueError) } serde_json::Value::String(str) => Ok(NomoValue::String { value: Cow::Owned(str), }), serde_json::Value::Array(values) => Ok(NomoValue::Array { value: values .into_iter() .map(TryInto::try_into) .collect::>()?, }), serde_json::Value::Object(_map) => todo!(), } } }