#[derive(Debug, Clone)]
pub enum Value {
Boolean(bool),
Integer(i64),
Decimal(f64),
String(String),
List(Vec<Value>),
Map(indexmap::IndexMap<String, Value>),
}
impl Value {
pub fn as_boolean(&self) -> Option<bool> {
match self {
Value::Boolean(value) => Some(*value),
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
Value::Integer(value) => Some(*value),
_ => None,
}
}
pub fn as_decimal(&self) -> Option<f64> {
match self {
Value::Decimal(value) => Some(*value),
Value::Integer(value) => Some(*value as f64),
_ => None,
}
}
pub fn as_string(&self) -> Option<&String> {
match self {
Value::String(value) => Some(value),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(value) => Some(value),
_ => None,
}
}
pub fn to_string(&self) -> Option<String> {
match self {
Value::String(value) => Some(value.clone()),
Value::Integer(value) => Some(value.to_string()),
Value::Decimal(value) => Some(value.to_string()),
_ => None,
}
}
pub(crate) fn as_map(&self) -> Option<&indexmap::IndexMap<String, Value>> {
match self {
Value::Map(value) => Some(value),
_ => None,
}
}
pub fn kind(&self) -> ValueKind {
self.into()
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Boolean(a), Value::Boolean(b)) => a == b,
(Value::Integer(a), Value::Integer(b)) => a == b,
(Value::Decimal(a), Value::Decimal(b)) => a == b,
(Value::String(a), Value::String(b)) => a == b,
(Value::List(a), Value::List(b)) => a == b,
(Value::Map(a), Value::Map(b)) => a == b,
(&Value::Decimal(d), &Value::Integer(i)) | (&Value::Integer(i), &Value::Decimal(d)) => {
i as f64 == d
}
_ => false,
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::Integer(value as i64)
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value::Integer(value)
}
}
impl From<usize> for Value {
fn from(value: usize) -> Self {
Value::Integer(value as i64)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::Decimal(value)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(value)
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::String(value.to_string())
}
}
impl From<indexmap::IndexMap<String, Value>> for Value {
fn from(value: indexmap::IndexMap<String, Value>) -> Self {
Value::Map(value)
}
}
impl From<Value> for ValueKind {
fn from(value: Value) -> Self {
(&value).into()
}
}
impl From<&Value> for ValueKind {
fn from(value: &Value) -> Self {
match value {
Value::Boolean(_) => ValueKind::Boolean,
Value::Integer(_) => ValueKind::Integer,
Value::Decimal(_) => ValueKind::Decimal,
Value::String(_) => ValueKind::String,
Value::List(_) => ValueKind::Array,
Value::Map(_) => ValueKind::Object,
}
}
}
impl<T: Into<Value>> From<Vec<T>> for Value {
fn from(value: Vec<T>) -> Self {
Value::List(value.into_iter().map(Into::into).collect())
}
}
impl serde::ser::Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::{SerializeMap, SerializeSeq};
match self {
Value::Boolean(value) => serializer.serialize_bool(*value),
Value::Integer(value) => serializer.serialize_i64(*value),
Value::Decimal(value) => serializer.serialize_f64(*value),
Value::String(value) => serializer.serialize_str(value),
Value::List(value) => {
let mut ser = serializer.serialize_seq(Some(value.len()))?;
for element in value {
ser.serialize_element(element)?;
}
ser.end()
}
Value::Map(value) => {
let mut ser = serializer.serialize_map(Some(value.len()))?;
for (element_key, element_value) in value {
ser.serialize_entry(element_key, element_value)?;
}
ser.end()
}
}
}
}
impl<'de> serde::de::Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(ValueVisitor)
}
}
struct ValueVisitor;
impl<'de> serde::de::Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("any valid JSON/YAML value")
}
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Boolean(value))
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(value))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if value <= i64::MAX as u64 {
Ok(Value::Integer(value as i64))
} else {
Err(serde::de::Error::custom(format!(
"integer {value} is too large"
)))
}
}
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Decimal(value))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(value.to_string()))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(value))
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(String::new()))
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
serde::Deserialize::deserialize(deserializer)
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(String::new()))
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut values = Vec::new();
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(Value::List(values))
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut values = indexmap::IndexMap::new();
while let Some((key, value)) = map.next_entry()? {
values.insert(key, value);
}
Ok(Value::Map(values))
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ValueKind {
Boolean,
Integer,
Decimal,
String,
Array,
Object,
}
impl std::fmt::Display for ValueKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ValueKind::Boolean => write!(f, "boolean"),
ValueKind::Integer => write!(f, "integer"),
ValueKind::Decimal => write!(f, "decimal"),
ValueKind::String => write!(f, "string"),
ValueKind::Array => write!(f, "array"),
ValueKind::Object => write!(f, "object"),
}
}
}