251 lines
6.3 KiB
Rust
251 lines
6.3 KiB
Rust
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<NomoValue>,
|
|
},
|
|
Bool {
|
|
value: bool,
|
|
},
|
|
Object {
|
|
value: BTreeMap<String, NomoValue>,
|
|
},
|
|
Integer {
|
|
value: u64,
|
|
},
|
|
SignedInteger {
|
|
value: i64,
|
|
},
|
|
Float {
|
|
value: f64,
|
|
},
|
|
Iterator {
|
|
value: Box<dyn CloneIterator<Item = NomoValue>>,
|
|
},
|
|
}
|
|
|
|
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<bool> {
|
|
if let Self::Bool { value } = self {
|
|
Some(*value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn as_object(&self) -> Option<&BTreeMap<String, NomoValue>> {
|
|
if let Self::Object { value } = self {
|
|
Some(value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn as_integer(&self) -> Option<u64> {
|
|
if let Self::Integer { value } = self {
|
|
Some(*value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn as_float(&self) -> Option<f64> {
|
|
if let Self::Float { value } = self {
|
|
Some(*value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn as_iterator(&self) -> Option<&dyn CloneIterator<Item = NomoValue>> {
|
|
if let Self::Iterator { value } = self {
|
|
Some(value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn as_iterator_mut(&mut self) -> Option<&mut dyn CloneIterator<Item = NomoValue>> {
|
|
if let Self::Iterator { value } = self {
|
|
Some(value)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait CloneIterator: Iterator<Item = NomoValue> {
|
|
fn clone_box(&self) -> Box<dyn CloneIterator<Item = NomoValue>>;
|
|
}
|
|
|
|
impl<I> CloneIterator for I
|
|
where
|
|
I: Iterator<Item = NomoValue> + Clone + 'static,
|
|
{
|
|
fn clone_box(&self) -> Box<dyn CloneIterator<Item = NomoValue>> {
|
|
Box::new(Clone::clone(self))
|
|
}
|
|
}
|
|
|
|
impl Clone for Box<dyn CloneIterator> {
|
|
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<R> From<&R> for NomoValue
|
|
where
|
|
R: Into<NomoValue> + Clone,
|
|
{
|
|
fn from(value: &R) -> Self {
|
|
value.clone().into()
|
|
}
|
|
}
|
|
|
|
impl From<String> 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<V> From<Vec<V>> for NomoValue
|
|
where
|
|
V: Into<NomoValue>,
|
|
{
|
|
fn from(val: Vec<V>) -> Self {
|
|
NomoValue::Array {
|
|
value: val.into_iter().map(Into::into).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<V> From<std::collections::VecDeque<V>> for NomoValue
|
|
where
|
|
V: Into<NomoValue>,
|
|
{
|
|
fn from(val: std::collections::VecDeque<V>) -> Self {
|
|
NomoValue::Array {
|
|
value: val.into_iter().map(Into::into).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<V> From<&[V]> for NomoValue
|
|
where
|
|
V: Into<NomoValue> + Clone,
|
|
{
|
|
fn from(value: &[V]) -> Self {
|
|
NomoValue::Array {
|
|
value: value.iter().cloned().map(Into::into).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<K, V> From<std::collections::HashMap<K, V>> for NomoValue
|
|
where
|
|
K: Into<String>,
|
|
V: Into<NomoValue>,
|
|
{
|
|
fn from(val: std::collections::HashMap<K, V>) -> 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<serde_json::Value> for NomoValue {
|
|
type Error = NomoValueError;
|
|
fn try_from(value: serde_json::Value) -> Result<Self, NomoValueError> {
|
|
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::<Result<_, _>>()?,
|
|
}),
|
|
serde_json::Value::Object(_map) => todo!(),
|
|
}
|
|
}
|
|
}
|