use std::fmt::Display;
use serde::de::{self, Deserialize, EnumAccess, MapAccess, SeqAccess, Visitor};
use serde::ser::{Serialize, Serializer};
use serde::ser::{SerializeMap as _, SerializeSeq as _, SerializeTupleVariant as _};
use crate::base64::Bytes;
use crate::error::Error;
#[derive(Debug, PartialEq, Clone)]
pub enum RawValue {
Null,
Integer(i64),
Bytes(Bytes),
Float(f64),
String(String),
Bool(bool),
Array(Vec<RawValue>),
Map(Vec<(RawValue, RawValue)>),
Tagged(u64, Box<RawValue>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum RawValueKind {
Null,
Bool,
String,
Bytes,
Integer,
Float,
Array,
Map,
Tagged,
}
impl RawValue {
pub fn kind(&self) -> RawValueKind {
match self {
RawValue::Null => RawValueKind::Null,
RawValue::Bool(_) => RawValueKind::Bool,
RawValue::String(_) => RawValueKind::String,
RawValue::Bytes(_) => RawValueKind::Bytes,
RawValue::Integer(_) => RawValueKind::Integer,
RawValue::Float(_) => RawValueKind::Float,
RawValue::Array(_) => RawValueKind::Array,
RawValue::Map(_) => RawValueKind::Map,
RawValue::Tagged(_, _) => RawValueKind::Tagged,
}
}
pub fn is(&self, kind: &RawValueKind) -> bool {
self.kind() == *kind
}
pub fn can_convert(&self, kind: &RawValueKind) -> bool {
matches!(
(self.kind(), kind),
(RawValueKind::String, RawValueKind::Bytes)
| (RawValueKind::Bytes, RawValueKind::String)
)
}
pub fn convert(&self, kind: &RawValueKind) -> Result<RawValue, Error> {
match kind {
RawValueKind::Bytes => match self {
RawValue::String(s) => Ok(RawValue::Bytes(Bytes::try_from(s as &str)?)),
other => Err(Error::ValueError(format!(
"cannot convert into {kind:?} from {other:?}",
))),
},
_ => Err(Error::ValueError(format!(
"cannot convert into {kind:?} from any other variant",
))),
}
}
}
impl Serialize for RawValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Null => serializer.serialize_unit(),
Self::Integer(i) => serializer.serialize_i64(*i),
Self::Bytes(b) => b.serialize(serializer),
Self::Float(f) => serializer.serialize_f64(*f),
Self::String(s) => serializer.serialize_str(s),
Self::Bool(b) => serializer.serialize_bool(*b),
Self::Array(vs) => {
let mut seq = serializer.serialize_seq(Some(vs.len()))?;
for v in vs.iter() {
seq.serialize_element(v)?;
}
seq.end()
}
Self::Map(vs) => {
let mut map = serializer.serialize_map(Some(vs.len()))?;
for (k, v) in vs.iter() {
map.serialize_entry(k, v)?;
}
map.end()
}
Self::Tagged(t, v) => {
if serializer.is_human_readable() {
v.serialize(serializer)
} else {
let mut acc =
serializer.serialize_tuple_variant("@@TAG@@", 0, "@@TAGGED@@", 2)?;
acc.serialize_field(t)?;
acc.serialize_field(v)?;
acc.end()
}
}
}
}
}
impl<'de> Deserialize<'de> for RawValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(RawValueVisitor {})
}
}
struct RawValueVisitor;
impl<'de> Visitor<'de> for RawValueVisitor {
type Value = RawValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an arbitrary JSON or CBOR structure")
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(RawValue::Null)
}
fn visit_i8<E: de::Error>(self, v: i8) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_i16<E: de::Error>(self, v: i16) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_i32<E: de::Error>(self, v: i32) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v))
}
fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_u16<E: de::Error>(self, v: u16) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_u32<E: de::Error>(self, v: u32) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.into()))
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
Ok(RawValue::Integer(v.try_into().map_err(E::custom)?))
}
fn visit_f32<E: de::Error>(self, v: f32) -> Result<Self::Value, E> {
Ok(RawValue::Float(v.into()))
}
fn visit_f64<E: de::Error>(self, v: f64) -> Result<Self::Value, E> {
Ok(RawValue::Float(v))
}
fn visit_bool<E: de::Error>(self, v: bool) -> Result<Self::Value, E> {
Ok(RawValue::Bool(v))
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(RawValue::String(v.to_string()))
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(RawValue::Bytes(Bytes::from(v)))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut ret = Vec::new();
while let Some(v) = seq.next_element::<RawValue>()? {
ret.push(v);
}
Ok(RawValue::Array(ret))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut ret = Vec::new();
while let Some((key, val)) = map.next_entry::<RawValue, RawValue>()? {
ret.push((key, val));
}
Ok(RawValue::Map(ret))
}
fn visit_enum<A: EnumAccess<'de>>(self, acc: A) -> Result<Self::Value, A::Error> {
use serde::de::VariantAccess;
struct Inner;
impl<'de> serde::de::Visitor<'de> for Inner {
type Value = RawValue;
fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(formatter, "a CBOR tagged value")
}
#[inline]
fn visit_seq<A: de::SeqAccess<'de>>(self, mut acc: A) -> Result<Self::Value, A::Error> {
let tag: u64 = acc
.next_element()?
.ok_or_else(|| de::Error::custom("expected tag"))?;
let val = acc
.next_element()?
.ok_or_else(|| de::Error::custom("expected val"))?;
Ok(RawValue::Tagged(tag, Box::new(val)))
}
}
let (name, data): (String, _) = acc.variant()?;
assert_eq!("@@TAGGED@@", name);
data.tuple_variant(2, Inner)
}
}
impl Display for RawValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Null => "Null".to_string(),
Self::Integer(v) => v.to_string(),
Self::Float(v) => v.to_string(),
Self::Bool(v) => v.to_string(),
Self::Bytes(b) => b.to_string(),
Self::String(s) => format!(r#""{}""#, s),
Self::Array(vs) => format!(
r#"[{}]"#,
vs.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
),
Self::Map(vs) => format!(
r#"{{{}}}"#,
vs.iter()
.map(|(k, v)| format!("{0}: {1}", k, v))
.collect::<Vec<_>>()
.join(", ")
),
Self::Tagged(t, v) => format!("#6.{0}({1})", t, v),
}
.fmt(f)
}
}
#[cfg(test)]
mod test {
use super::*;
use ciborium::{de::from_reader, ser::into_writer};
#[test]
fn serde() {
let rv = RawValue::Integer(7);
let val = serde_json::to_string(&rv).unwrap();
assert_eq!("7", val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, rv);
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(vec![0x07], buf);
let rv2: RawValue = from_reader(buf.as_slice()).unwrap();
assert_eq!(rv2, rv);
let rv = RawValue::Bytes(Bytes::from(vec![0xde, 0xad, 0xbe, 0xef].as_slice()));
let val = serde_json::to_string(&rv).unwrap();
assert_eq!(r#""3q2-7w""#, val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, RawValue::String("3q2-7w".to_string()));
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(
vec![
0x44, 0xde, 0xad, 0xbe, 0xef,
],
buf
);
let rv2: RawValue = from_reader(buf.as_slice()).unwrap();
assert_eq!(rv2, rv);
let rv = RawValue::Map(vec![
(
RawValue::String("field one".to_string()),
RawValue::Float(7.0),
),
(
RawValue::String("field two".to_string()),
RawValue::Bool(true),
),
]);
let val = serde_json::to_string(&rv).unwrap();
assert_eq!(r#"{"field one":7.0,"field two":true}"#, val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, rv);
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(
vec![
0xa2, 0x69, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x6f, 0x6e, 0x65, 0xf9, 0x47, 0x00, 0x69, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x74, 0x77, 0x6f, 0xf5, ],
buf
);
let rv2: RawValue = from_reader(buf.as_slice()).unwrap();
assert_eq!(rv2, rv);
let rv = RawValue::Array(vec![
RawValue::String("foo".to_string()),
RawValue::Integer(-1337),
]);
let val = serde_json::to_string(&rv).unwrap();
assert_eq!(r#"["foo",-1337]"#, val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, rv);
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(
vec![
0x82, 0x63, 0x66, 0x6f, 0x6f, 0x39, 0x05, 0x38, ],
buf
);
let rv2: RawValue = from_reader(buf.as_slice()).unwrap();
assert_eq!(rv2, rv);
let rv = RawValue::Tagged(1, Box::new(RawValue::String("foo".to_string())));
let val = serde_json::to_string(&rv).unwrap();
assert_eq!(r#""foo""#, val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, RawValue::String("foo".to_string()));
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(
vec![
0xc1, 0x63, 0x66, 0x6f, 0x6f,
],
buf
);
let rv2: RawValue = from_reader(buf.as_slice()).unwrap();
assert_eq!(rv2, rv);
let rv = RawValue::Null;
let val = serde_json::to_string(&rv).unwrap();
assert_eq!("null", val);
let rv2: RawValue = serde_json::from_str(&val).unwrap();
assert_eq!(rv2, RawValue::Null);
let mut buf: Vec<u8> = Vec::new();
into_writer(&rv, &mut buf).unwrap();
assert_eq!(
vec![
0xf6, ],
buf
);
}
#[test]
fn to_string() {
assert_eq!(RawValue::Null.to_string(), "Null".to_string());
assert_eq!(RawValue::Integer(234).to_string(), "234".to_string());
assert_eq!(RawValue::Float(1.5).to_string(), "1.5".to_string());
assert_eq!(
RawValue::String("foo".to_string()).to_string(),
r#""foo""#.to_string()
);
assert_eq!(
RawValue::Tagged(7, Box::new(RawValue::Bool(true))).to_string(),
"#6.7(true)".to_string()
);
assert_eq!(
RawValue::Bytes(Bytes(vec![222u8, 173u8, 190u8, 239u8])).to_string(),
"deadbeef".to_string()
);
assert_eq!(
RawValue::Array(vec![
RawValue::String("foo".to_string()),
RawValue::String("bar".to_string())
])
.to_string(),
r#"["foo", "bar"]"#.to_string()
);
assert_eq!(
RawValue::Map(vec![
(RawValue::String("foo".to_string()), RawValue::Integer(1)),
(RawValue::String("bar".to_string()), RawValue::Integer(2)),
])
.to_string(),
r#"{"foo": 1, "bar": 2}"#,
)
}
}