use std::{collections::HashMap, fmt};
#[cfg(feature = "with-json")]
use serde_json::Value as JsonValue;
#[cfg(feature = "with-toml")]
use toml::Value as TomlValue;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
String(String),
Array(Vec<Value>),
Object(HashMap<String, Value>),
}
impl Value {
#[cfg(feature = "with-json")]
fn from_value(value: JsonValue) -> anyhow::Result<Self> {
if value.is_string() {
return Ok(Self::String(String::from(value.as_str().unwrap())));
} else if value.is_array() {
return Ok(Self::Array(
value
.as_array()
.unwrap()
.iter()
.map(|e| Self::from_value(e.clone()).expect("Invalid format."))
.collect(),
));
} else if value.is_object() {
let mut new_data: HashMap<String, Value> = HashMap::new();
for (key, value) in value.as_object().unwrap().iter() {
new_data.insert(key.clone(), Self::from_value(value.clone())?);
}
return Ok(Self::Object(new_data));
}
Err(anyhow::Error::msg(format!(
"Cannot parse `{}` as a language text value.",
value
)))
}
#[cfg(feature = "with-toml")]
pub fn from_value(value: TomlValue) -> anyhow::Result<Self> {
if value.is_str() {
return Ok(Self::String(String::from(value.as_str().unwrap())));
} else if value.is_array() {
return Ok(Self::Array(
value
.as_array()
.unwrap()
.iter()
.map(|e| Self::from_value(e.clone()).expect("Invalid format."))
.collect(),
));
} else if value.is_table() {
let mut new_data: HashMap<String, Value> = HashMap::new();
for (key, value) in value.as_table().unwrap().iter() {
new_data.insert(key.clone(), Self::from_value(value.clone())?);
}
return Ok(Self::Object(new_data));
}
Err(anyhow::Error::msg(format!(
"Cannot parse `{}` as a language text value.",
value
)))
}
#[cfg(feature = "with-json")]
pub fn from_string(text: String) -> anyhow::Result<Self> {
Self::from_value(serde_json::from_str(&text)?)
}
#[cfg(feature = "with-toml")]
pub fn from_string(text: String) -> anyhow::Result<Self> {
Self::from_value(text.parse()?)
}
#[cfg(all(not(feature = "with-json"), not(feature = "with-toml")))]
pub fn from_string(_text: String) -> anyhow::Result<Self> {
Err(anyhow::Error::msg("You must define the parse feature."))
}
pub fn is_string(&self) -> bool {
matches!(self, Self::String(_))
}
pub fn get_string(&self) -> Option<String> {
match self {
Self::String(value) => Some(value.clone()),
_ => None,
}
}
pub fn is_array(&self) -> bool {
matches!(self, Self::Array(_))
}
pub fn get_array(&self) -> Option<Vec<Value>> {
match self {
Self::Array(data) => Some(data.clone()),
_ => None,
}
}
pub fn is_object(&self) -> bool {
matches!(self, Self::Object(_))
}
pub fn get_object(&self) -> Option<HashMap<String, Value>> {
match self {
Self::Object(data) => Some(data.clone()),
_ => None,
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::String(value) => write!(f, "{}", value),
Self::Array(value) => write!(
f,
"[{}]",
value
.iter()
.map(|e| format!("{}", e))
.collect::<Vec<String>>()
.join(", ")
),
Self::Object(value) => {
write!(
f,
"{{ {} }}",
value
.iter()
.map(|(key, value)| format!("{}: {}", key, value))
.collect::<Vec<String>>()
.join(", ")
)
}
}
}
}