use std::collections::BTreeMap;
use std::fmt;
use serde_json::value::RawValue;
pub type Object = BTreeMap<String, Value>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Number(String);
impl Number {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
self.as_str().parse().ok()
}
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
self.as_str().parse().ok()
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NotANumber;
impl fmt::Display for NotANumber {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("not a JSON number")
}
}
impl std::error::Error for NotANumber {}
impl std::str::FromStr for Number {
type Err = NotANumber;
fn from_str(text: &str) -> Result<Self, Self::Err> {
let numeric = matches!(text.as_bytes().first(), Some(b'-' | b'0'..=b'9'))
&& matches!(text.as_bytes().last(), Some(b'0'..=b'9'));
if !numeric {
return Err(NotANumber);
}
serde_json::from_str::<&RawValue>(text).map_err(|_| NotANumber)?;
Ok(Self(String::from(text)))
}
}
impl From<i64> for Number {
fn from(value: i64) -> Self {
Self(value.to_string())
}
}
impl From<i32> for Number {
fn from(value: i32) -> Self {
Self::from(i64::from(value))
}
}
impl From<u32> for Number {
fn from(value: u32) -> Self {
Self::from(i64::from(value))
}
}
impl serde::Serialize for Number {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self.as_i64() {
Some(whole) if self.as_str() != "-0" => serializer.serialize_i64(whole),
_ => {
let raw = serde_json::from_str::<&RawValue>(self.as_str())
.map_err(serde::ser::Error::custom)?;
serde::Serialize::serialize(raw, serializer)
}
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Value {
#[default]
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Object),
}
impl Value {
#[must_use]
pub fn get(&self, key: &str) -> Option<&Self> {
match self {
Self::Object(object) => object.get(key),
_ => None,
}
}
#[must_use]
pub const fn as_object(&self) -> Option<&Object> {
match self {
Self::Object(object) => Some(object),
_ => None,
}
}
#[must_use]
pub fn as_array(&self) -> Option<&[Self]> {
match self {
Self::Array(items) => Some(items),
_ => None,
}
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(text) => Some(text),
_ => None,
}
}
#[must_use]
pub const fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Self::Number(Number::from(value))
}
}
impl From<u32> for Value {
fn from(value: u32) -> Self {
Self::Number(Number::from(value))
}
}
impl serde::Serialize for Value {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Null => serializer.serialize_unit(),
Self::Bool(flag) => serializer.serialize_bool(*flag),
Self::Number(number) => serde::Serialize::serialize(number, serializer),
Self::String(text) => serializer.serialize_str(text),
Self::Array(items) => serde::Serialize::serialize(items, serializer),
Self::Object(object) => serde::Serialize::serialize(object, serializer),
}
}
}
impl<'de> serde::Deserialize<'de> for Value {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let raw = <Box<RawValue> as serde::Deserialize>::deserialize(deserializer)?;
read_raw(raw.get(), 0).map_err(serde::de::Error::custom)
}
}
const NESTING_LIMIT: usize = 128;
fn read_raw(raw: &str, depth: usize) -> Result<Value, serde_json::Error> {
let text = raw.trim();
if depth > NESTING_LIMIT {
return Err(serde::de::Error::custom("recursion limit exceeded"));
}
match text.as_bytes().first() {
Some(b'{') => {
let members: BTreeMap<String, Box<RawValue>> = serde_json::from_str(text)?;
let mut object = Object::new();
for (key, member) in members {
object.insert(key, read_raw(member.get(), depth + 1)?);
}
Ok(Value::Object(object))
}
Some(b'[') => {
let members: Vec<Box<RawValue>> = serde_json::from_str(text)?;
let mut items = Vec::with_capacity(members.len());
for member in members {
items.push(read_raw(member.get(), depth + 1)?);
}
Ok(Value::Array(items))
}
Some(b'"') => Ok(Value::String(serde_json::from_str(text)?)),
Some(b't' | b'f') => Ok(Value::Bool(serde_json::from_str(text)?)),
Some(b'n') => Ok(Value::Null),
_ => Ok(Value::Number(Number(String::from(text)))),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecodeErrorKind {
UnknownProperty,
MissingProperty,
WrongType {
expected: &'static str,
},
WrongCardinality,
Empty,
BadNumber,
BadValue,
DuplicateChoice,
ResourceType,
UnknownElement,
UnexpectedText,
WrongRoot,
MalformedXml {
reason: String,
},
}
impl fmt::Display for DecodeErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownProperty => f.write_str("unknown property"),
Self::MissingProperty => f.write_str("required property is missing"),
Self::WrongType { expected } => write!(f, "expected {expected}"),
Self::WrongCardinality => f.write_str("cardinality mismatch"),
Self::Empty => f.write_str("empty object or array"),
Self::BadNumber => f.write_str("number out of range"),
Self::BadValue => f.write_str("invalid value"),
Self::DuplicateChoice => f.write_str("more than one form of a choice element"),
Self::ResourceType => f.write_str("resourceType is missing or does not match"),
Self::UnknownElement => f.write_str("unknown element"),
Self::UnexpectedText => f.write_str("text where an element belongs"),
Self::WrongRoot => f.write_str("the root element is no resource of this version"),
Self::MalformedXml { reason } => write!(f, "malformed XML: {reason}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecodeError {
pub path: String,
pub kind: DecodeErrorKind,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.path, self.kind)
}
}
impl std::error::Error for DecodeError {}
#[derive(Debug, Default, Clone)]
pub struct Path {
segments: Vec<String>,
lenient: bool,
}
impl Path {
#[must_use]
pub fn root(root: &str) -> Self {
Self {
segments: vec![root.to_owned()],
lenient: false,
}
}
#[must_use]
pub fn lenient(root: &str) -> Self {
Self {
segments: vec![root.to_owned()],
lenient: true,
}
}
#[must_use]
pub const fn is_lenient(&self) -> bool {
self.lenient
}
pub fn with<T>(
&mut self,
name: &str,
f: impl FnOnce(&mut Self) -> Result<T, DecodeError>,
) -> Result<T, DecodeError> {
self.segments.push(name.to_owned());
let out = f(self);
self.segments.pop();
out
}
pub fn with_index<T>(
&mut self,
name: &str,
index: usize,
f: impl FnOnce(&mut Self) -> Result<T, DecodeError>,
) -> Result<T, DecodeError> {
self.segments.push(format!("{name}[{index}]"));
let out = f(self);
self.segments.pop();
out
}
#[must_use]
pub fn error(&self, kind: DecodeErrorKind) -> DecodeError {
DecodeError {
path: self.segments.join("."),
kind,
}
}
}
pub trait Json: Sized {
fn to_json(&self) -> Result<Object, EncodeError>;
fn from_json(object: &Object, path: &mut Path) -> Result<Self, DecodeError>;
}
pub trait Primitive: Sized {
fn value_json(&self) -> Result<Option<Value>, EncodeError>;
fn element_json(&self) -> Result<Option<Value>, EncodeError>;
fn from_json_parts(
value: Option<&Value>,
element: Option<&Value>,
path: &mut Path,
) -> Result<Self, DecodeError>;
fn has_value(&self) -> bool;
fn has_element(&self) -> bool;
fn serialize_value<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
fn serialize_element<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
}
#[derive(Debug)]
pub struct PrimitiveValue<'a, P: Primitive>(pub &'a P);
impl<P: Primitive> serde::Serialize for PrimitiveValue<'_, P> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize_value(serializer)
}
}
#[derive(Debug)]
pub struct PrimitiveElement<'a, P: Primitive>(pub &'a P);
impl<P: Primitive> serde::Serialize for PrimitiveElement<'_, P> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize_element(serializer)
}
}
#[derive(Debug)]
pub struct PrimitiveValues<'a, P: Primitive>(pub &'a [P]);
impl<P: Primitive> serde::Serialize for PrimitiveValues<'_, P> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serde::Serializer::serialize_seq(serializer, Some(self.0.len()))?;
for item in self.0 {
serde::ser::SerializeSeq::serialize_element(&mut seq, &PrimitiveValue(item))?;
}
serde::ser::SerializeSeq::end(seq)
}
}
#[derive(Debug)]
pub struct PrimitiveElements<'a, P: Primitive>(pub &'a [P]);
impl<P: Primitive> serde::Serialize for PrimitiveElements<'_, P> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serde::Serializer::serialize_seq(serializer, Some(self.0.len()))?;
for item in self.0 {
serde::ser::SerializeSeq::serialize_element(&mut seq, &PrimitiveElement(item))?;
}
serde::ser::SerializeSeq::end(seq)
}
}
pub fn value_entry<M: serde::ser::SerializeMap, P: Primitive>(
map: &mut M,
key: &str,
primitive: &P,
) -> Result<(), M::Error> {
if primitive.has_value() {
map.serialize_entry(key, &PrimitiveValue(primitive))?;
}
Ok(())
}
pub fn element_entry<M: serde::ser::SerializeMap, P: Primitive>(
map: &mut M,
key: &str,
primitive: &P,
) -> Result<(), M::Error> {
if primitive.has_element() {
map.serialize_entry(key, &PrimitiveElement(primitive))?;
}
Ok(())
}
pub fn value_list_entry<M: serde::ser::SerializeMap, P: Primitive>(
map: &mut M,
key: &str,
items: &[P],
) -> Result<(), M::Error> {
if !items.is_empty() {
map.serialize_entry(key, &PrimitiveValues(items))?;
}
Ok(())
}
pub fn element_list_entry<M: serde::ser::SerializeMap, P: Primitive>(
map: &mut M,
key: &str,
items: &[P],
) -> Result<(), M::Error> {
if items.iter().any(Primitive::has_element) {
map.serialize_entry(key, &PrimitiveElements(items))?;
}
Ok(())
}
pub fn expect_object<'a>(value: &'a Value, path: &Path) -> Result<&'a Object, DecodeError> {
match value {
Value::Object(object) if object.is_empty() => Err(path.error(DecodeErrorKind::Empty)),
Value::Object(object) => Ok(object),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "an object",
})),
}
}
pub fn expect_array<'a>(value: &'a Value, path: &Path) -> Result<&'a [Value], DecodeError> {
match value {
Value::Array(items) if items.is_empty() => Err(path.error(DecodeErrorKind::Empty)),
Value::Array(items) => Ok(items),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "an array",
})),
}
}
pub fn expect_single<'a>(value: &'a Value, path: &Path) -> Result<&'a Value, DecodeError> {
match value {
Value::Array(_) => Err(path.error(DecodeErrorKind::WrongCardinality)),
other => Ok(other),
}
}
pub fn expect_string(value: &Value, path: &Path) -> Result<String, DecodeError> {
match value {
Value::String(s) => Ok(s.clone()),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a string",
})),
}
}
pub fn expect_bool(value: &Value, path: &Path) -> Result<bool, DecodeError> {
match value {
Value::Bool(b) => Ok(*b),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a boolean",
})),
}
}
pub fn expect_i32(value: &Value, path: &Path) -> Result<i32, DecodeError> {
match value {
Value::Number(n) => n
.as_i64()
.and_then(|i| i32::try_from(i).ok())
.ok_or_else(|| path.error(DecodeErrorKind::BadNumber)),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a number",
})),
}
}
pub fn expect_u32(value: &Value, min: u32, path: &Path) -> Result<u32, DecodeError> {
match value {
Value::Number(n) => n
.as_u64()
.and_then(|u| u32::try_from(u).ok())
.filter(|u| *u >= min)
.ok_or_else(|| path.error(DecodeErrorKind::BadNumber)),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a number",
})),
}
}
pub fn expect_i64_string(value: &Value, path: &Path) -> Result<i64, DecodeError> {
match value {
Value::String(s) => s
.parse()
.map_err(|_| path.error(DecodeErrorKind::BadNumber)),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a string holding an integer",
})),
}
}
pub fn expect_decimal(value: &Value, path: &Path) -> Result<String, DecodeError> {
match value {
Value::Number(n) => Ok(String::from(n.as_str())),
_ => Err(path.error(DecodeErrorKind::WrongType {
expected: "a number",
})),
}
}
pub fn decimal_value(text: &str, path: &Path) -> Result<Value, DecodeError> {
text.parse::<Number>()
.map(Value::Number)
.map_err(|_| path.error(DecodeErrorKind::BadValue))
}
pub type ValuePair<'a> = (Option<&'a Value>, Option<&'a Value>);
pub fn pair_arrays<'a>(
values: Option<&'a Value>,
elements: Option<&'a Value>,
path: &Path,
) -> Result<Vec<ValuePair<'a>>, DecodeError> {
let values = values.map(|v| expect_array(v, path)).transpose()?;
let elements = elements.map(|v| expect_array(v, path)).transpose()?;
let len = match (values, elements) {
(Some(v), Some(e)) if v.len() != e.len() => {
return Err(path.error(DecodeErrorKind::WrongCardinality));
}
(Some(v), _) => v.len(),
(None, Some(e)) => e.len(),
(None, None) => 0,
};
Ok((0..len)
.map(|i| {
let value = values.and_then(|v| v.get(i)).filter(|v| !v.is_null());
let element = elements.and_then(|e| e.get(i)).filter(|e| !e.is_null());
(value, element)
})
.collect())
}
pub fn primitive_arrays<P: Primitive>(items: &[P]) -> Result<(Value, Option<Value>), EncodeError> {
let mut values = Vec::with_capacity(items.len());
let mut elements = Vec::with_capacity(items.len());
for item in items {
values.push(item.value_json()?.unwrap_or(Value::Null));
elements.push(item.element_json()?.unwrap_or(Value::Null));
}
let any_element = elements.iter().any(|e| !e.is_null());
Ok((
Value::Array(values),
any_element.then_some(Value::Array(elements)),
))
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EncodeError {
BadDecimal {
text: String,
},
UnknownResourceBody,
Xml {
reason: String,
},
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadDecimal { text } => write!(f, "decimal {text:?} is not a JSON number"),
Self::UnknownResourceBody => f.write_str("an unknown resource's body is not an object"),
Self::Xml { reason } => write!(f, "no XML form: {reason}"),
}
}
}
impl std::error::Error for EncodeError {}
#[derive(Debug, Default)]
pub struct ChoiceSlot<'a> {
pub suffix: Option<&'static str>,
pub value: Option<&'a Value>,
pub element: Option<&'a Value>,
}
impl<'a> ChoiceSlot<'a> {
fn claim(&mut self, suffix: &'static str, path: &Path) -> Result<(), DecodeError> {
match self.suffix {
Some(seen) if seen != suffix => Err(path.error(DecodeErrorKind::DuplicateChoice)),
_ => {
self.suffix = Some(suffix);
Ok(())
}
}
}
pub fn value(
&mut self,
suffix: &'static str,
value: &'a Value,
path: &Path,
) -> Result<(), DecodeError> {
self.claim(suffix, path)?;
self.value = Some(value);
Ok(())
}
pub fn element(
&mut self,
suffix: &'static str,
element: &'a Value,
path: &Path,
) -> Result<(), DecodeError> {
self.claim(suffix, path)?;
self.element = Some(element);
Ok(())
}
}
pub fn resource_type<'a>(object: &'a Object, path: &Path) -> Result<&'a str, DecodeError> {
match object.get("resourceType") {
Some(Value::String(name)) => Ok(name),
_ => Err(path.error(DecodeErrorKind::ResourceType)),
}
}