use std::fmt;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;
#[derive(Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RawJson(pub Box<RawValue>);
impl RawJson {
pub fn parse(text: impl Into<String>) -> Result<Self, serde_json::Error> {
RawValue::from_string(text.into()).map(Self)
}
pub fn from_value<T: Serialize + ?Sized>(value: &T) -> Result<Self, serde_json::Error> {
serde_json::value::to_raw_value(value).map(Self)
}
#[must_use]
pub fn null() -> Self {
Self::from_json_value(&serde_json::Value::Null)
}
#[must_use]
pub fn from_json_value(value: &serde_json::Value) -> Self {
serde_json::value::to_raw_value(value)
.map_or_else(|_| Self(RawValue::NULL.to_owned()), Self)
}
#[must_use]
pub fn as_str(&self) -> &str {
self.0.get()
}
#[must_use]
pub fn into_string(self) -> String {
self.0.get().to_owned()
}
pub fn decode<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
serde_json::from_str(self.as_str())
}
#[must_use]
pub fn to_value(&self) -> serde_json::Value {
serde_json::from_str(self.as_str()).unwrap_or(serde_json::Value::Null)
}
}
impl fmt::Debug for RawJson {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Display for RawJson {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl PartialEq for RawJson {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str() || self.to_value() == other.to_value()
}
}
impl From<serde_json::Value> for RawJson {
fn from(value: serde_json::Value) -> Self {
Self::from_json_value(&value)
}
}
impl From<&serde_json::Value> for RawJson {
fn from(value: &serde_json::Value) -> Self {
Self::from_json_value(value)
}
}
#[cfg(test)]
mod tests {
use super::RawJson;
#[test]
fn round_trips_and_compares_semantically() {
let a = RawJson::parse(r#"{"a":1,"b":[true]}"#).unwrap();
let b = RawJson::parse(r#"{ "b": [true], "a": 1 }"#).unwrap();
assert_eq!(a, b);
assert_eq!(a.to_value()["a"], 1);
assert!(RawJson::parse("{").is_err());
assert_eq!(RawJson::null().as_str(), "null");
}
}