use std::collections::BTreeMap;
use std::fmt;
use serde::de::{IgnoredAny, MapAccess, SeqAccess, Visitor};
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, PartialEq)]
pub enum ExtensionValue {
Null,
Bool(bool),
UnsignedInteger(u64),
SignedInteger(i64),
Float(f64),
String(String),
Array(Vec<ExtensionValue>),
Object(BTreeMap<String, ExtensionValue>),
}
impl ExtensionValue {
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(text) => Some(text),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(flag) => Some(*flag),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Self::UnsignedInteger(value) => Some(*value as f64),
Self::SignedInteger(value) => Some(*value as f64),
Self::Float(value) => Some(*value),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[ExtensionValue]> {
match self {
Self::Array(items) => Some(items),
_ => None,
}
}
pub fn as_object(&self) -> Option<&BTreeMap<String, ExtensionValue>> {
match self {
Self::Object(members) => Some(members),
_ => None,
}
}
}
impl From<&str> for ExtensionValue {
fn from(text: &str) -> Self {
Self::String(text.to_string())
}
}
impl From<String> for ExtensionValue {
fn from(text: String) -> Self {
Self::String(text)
}
}
impl Serialize for ExtensionValue {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Null => serializer.serialize_unit(),
Self::Bool(flag) => serializer.serialize_bool(*flag),
Self::UnsignedInteger(value) => serializer.serialize_u64(*value),
Self::SignedInteger(value) => serializer.serialize_i64(*value),
Self::Float(value) => serializer.serialize_f64(*value),
Self::String(text) => serializer.serialize_str(text),
Self::Array(items) => {
let mut seq = serializer.serialize_seq(Some(items.len()))?;
for item in items {
seq.serialize_element(item)?;
}
seq.end()
}
Self::Object(members) => {
let mut map = serializer.serialize_map(Some(members.len()))?;
for (name, value) in members {
map.serialize_entry(name, value)?;
}
map.end()
}
}
}
}
impl<'de> Deserialize<'de> for ExtensionValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_any(ExtensionValueVisitor)
}
}
struct ExtensionValueVisitor;
impl<'de> Visitor<'de> for ExtensionValueVisitor {
type Value = ExtensionValue;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("any JSON value")
}
fn visit_unit<E>(self) -> Result<Self::Value, E> {
Ok(ExtensionValue::Null)
}
fn visit_none<E>(self) -> Result<Self::Value, E> {
Ok(ExtensionValue::Null)
}
fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
deserializer.deserialize_any(self)
}
fn visit_bool<E>(self, flag: bool) -> Result<Self::Value, E> {
Ok(ExtensionValue::Bool(flag))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
Ok(ExtensionValue::UnsignedInteger(value))
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
Ok(match u64::try_from(value) {
Ok(unsigned) => ExtensionValue::UnsignedInteger(unsigned),
Err(_) => ExtensionValue::SignedInteger(value),
})
}
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
Ok(ExtensionValue::Float(value))
}
fn visit_str<E>(self, text: &str) -> Result<Self::Value, E> {
Ok(ExtensionValue::String(text.to_string()))
}
fn visit_string<E>(self, text: String) -> Result<Self::Value, E> {
Ok(ExtensionValue::String(text))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut items = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(item) = seq.next_element()? {
items.push(item);
}
Ok(ExtensionValue::Array(items))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut members = BTreeMap::new();
while let Some(name) = map.next_key::<String>()? {
members.insert(name, map.next_value()?);
}
Ok(ExtensionValue::Object(members))
}
}
pub(crate) fn take_or_ignore<'de, A: MapAccess<'de>>(
map: &mut A,
keep: bool,
) -> Result<Option<ExtensionValue>, A::Error> {
if keep {
map.next_value().map(Some)
} else {
map.next_value::<IgnoredAny>().map(|_| None)
}
}