use std::collections::BTreeMap;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Value {
String(String),
Double(f64),
Bytes(Vec<u8>),
U16(u16),
U32(u32),
Map(BTreeMap<String, Value>),
I32(i32),
U64(u64),
U128(u128),
Array(Vec<Value>),
Bool(bool),
Float(f32),
}
impl Value {
pub fn map<K, V, I>(entries: I) -> Self
where
K: Into<String>,
V: Into<Value>,
I: IntoIterator<Item = (K, V)>,
{
Self::Map(
entries
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
)
}
pub fn array<V, I>(items: I) -> Self
where
V: Into<Value>,
I: IntoIterator<Item = V>,
{
Self::Array(items.into_iter().map(Into::into).collect())
}
#[must_use]
pub fn merge_top_level(existing: &Value, new: &Value) -> Value {
match (existing, new) {
(Value::Map(old), Value::Map(new_map)) => {
let mut merged = old.clone();
for (k, v) in new_map {
merged.insert(k.clone(), v.clone());
}
Value::Map(merged)
}
_ => new.clone(),
}
}
#[must_use]
pub fn merge_deep(existing: &Value, new: &Value) -> Value {
match (existing, new) {
(Value::Map(old), Value::Map(new_map)) => {
let mut merged = old.clone();
for (k, v) in new_map {
let combined = match merged.get(k) {
Some(prev) => Value::merge_deep(prev, v),
None => v.clone(),
};
merged.insert(k.clone(), combined);
}
Value::Map(merged)
}
(Value::Array(old), Value::Array(new_arr)) => {
let mut merged = old.clone();
merged.extend(new_arr.iter().cloned());
Value::Array(merged)
}
_ => new.clone(),
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::String(a), Self::String(b)) => a == b,
(Self::Double(a), Self::Double(b)) => a.to_bits() == b.to_bits(),
(Self::Bytes(a), Self::Bytes(b)) => a == b,
(Self::U16(a), Self::U16(b)) => a == b,
(Self::U32(a), Self::U32(b)) => a == b,
(Self::Map(a), Self::Map(b)) => a == b,
(Self::I32(a), Self::I32(b)) => a == b,
(Self::U64(a), Self::U64(b)) => a == b,
(Self::U128(a), Self::U128(b)) => a == b,
(Self::Array(a), Self::Array(b)) => a == b,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
_ => false,
}
}
}
impl Eq for Value {}
impl std::hash::Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Self::String(v) => v.hash(state),
Self::Double(v) => v.to_bits().hash(state),
Self::Bytes(v) => v.hash(state),
Self::U16(v) => v.hash(state),
Self::U32(v) => v.hash(state),
Self::Map(v) => v.hash(state),
Self::I32(v) => v.hash(state),
Self::U64(v) => v.hash(state),
Self::U128(v) => v.hash(state),
Self::Array(v) => v.hash(state),
Self::Bool(v) => v.hash(state),
Self::Float(v) => v.to_bits().hash(state),
}
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Self::String(v.to_owned())
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Self::String(v)
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Self::Bool(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Self::Float(v)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Self::Double(v)
}
}
impl From<u8> for Value {
fn from(v: u8) -> Self {
Self::U16(u16::from(v))
}
}
impl From<u16> for Value {
fn from(v: u16) -> Self {
Self::U16(v)
}
}
impl From<u32> for Value {
fn from(v: u32) -> Self {
Self::U32(v)
}
}
impl From<u64> for Value {
fn from(v: u64) -> Self {
Self::U64(v)
}
}
impl From<u128> for Value {
fn from(v: u128) -> Self {
Self::U128(v)
}
}
impl From<i8> for Value {
fn from(v: i8) -> Self {
Self::I32(i32::from(v))
}
}
impl From<i16> for Value {
fn from(v: i16) -> Self {
Self::I32(i32::from(v))
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Self::I32(v)
}
}
impl From<Vec<u8>> for Value {
fn from(v: Vec<u8>) -> Self {
Self::Bytes(v)
}
}
impl From<Vec<Value>> for Value {
fn from(v: Vec<Value>) -> Self {
Self::Array(v)
}
}
impl From<BTreeMap<String, Value>> for Value {
fn from(v: BTreeMap<String, Value>) -> Self {
Self::Map(v)
}
}
impl FromIterator<Value> for Value {
fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
Self::Array(iter.into_iter().collect())
}
}
impl FromIterator<(String, Value)> for Value {
fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
Self::Map(iter.into_iter().collect())
}
}
#[cfg(feature = "serde")]
mod serde_impls;