1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! This library provides an extension object for [serde_json](crates.io/crates/serde_json) crate.

use serde::{de, ser};
use serde_json::value::RawValue;

/// Represents a custom JSON object.
#[derive(Debug, Clone)]
pub struct Ext<'a>(&'a RawValue);

impl<'a> Ext<'a> {
    /// Convert a `&RawValue` to an `Ext` object.
    pub fn try_from<'b>(raw: &'b RawValue) -> serde_json::Result<Ext<'a>>
    where
        'b: 'a,
    {
        check_raw(raw).map(Self).map_err(ser::Error::custom)
    }

    /// Access the JSON text.
    pub fn get(&'a self) -> &'a str {
        self.0.get()
    }
}

impl<'a> PartialEq for Ext<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.0.get() == other.0.get()
    }
}

impl<'a> ser::Serialize for Ext<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<'de: 'a, 'a> de::Deserialize<'de> for Ext<'a> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let raw: &'a RawValue = de::Deserialize::deserialize(deserializer)?;
        check_raw(raw).map(Self).map_err(de::Error::custom)
    }
}

fn check_raw(raw: &RawValue) -> Result<&RawValue, &'static str> {
    match raw.get().as_bytes().get(0) {
        Some(b'{') | Some(b'n') => Ok(raw),
        _ => Err("invalid value: expected null or object"),
    }
}

#[cfg(test)]
mod test {
    use super::*;

    use serde::{Deserialize, Serialize};
    use serde_json::{from_str, value::to_raw_value, Map, Value};

    #[derive(Serialize, Deserialize, Debug, PartialEq)]
    struct Object<'a> {
        #[serde(borrow)]
        ext: Ext<'a>,
    }

    #[derive(Serialize, Deserialize, Debug, PartialEq)]
    struct Extension<'a> {
        f1: &'a str,
        f2: i32,
    }

    #[test]
    fn try_from_and_get() -> serde_json::Result<()> {
        let object = Value::Object({
            let mut m = Map::new();
            m.insert("f1".into(), Value::String("abc".into()));
            m.insert("f2".into(), Value::Number(123.into()));
            m
        });
        let raw = to_raw_value(&object)?;
        let ext = Ext::try_from(raw.as_ref())?;
        let ext2 = from_str::<Extension>(ext.get())?;
        assert_eq!(ext2, Extension { f1: "abc", f2: 123 });

        Ok(())
    }

    #[test]
    fn json() -> serde_json::Result<()> {
        assert!(from_str::<Object>(r#"{"ext":null}"#).is_ok());
        assert!(from_str::<Object>(r#"{"ext":true}"#).is_err());
        assert!(from_str::<Object>(r#"{"ext":1}"#).is_err());
        assert!(from_str::<Object>(r#"{"ext":"1"}"#).is_err());
        assert!(from_str::<Object>(r#"{"ext":[1]}"#).is_err());
        assert!(from_str::<Object>(r#"{"ext":{}}"#).is_ok());

        let s1 = r#"{"ext": 	
null}"#;
        let o1 = from_str::<Object>(s1)?;
        assert_eq!(
            o1,
            Object {
                ext: Ext::try_from(to_raw_value(&Value::Null)?.as_ref())?,
            }
        );
        assert_eq!(serde_json::to_string(&o1)?, r#"{"ext":null}"#);

        let s2 = r#"{"ext": 	
{}
 	}"#;
        let o2 = serde_json::from_str::<Object>(s2)?;
        assert_eq!(
            o2,
            Object {
                ext: Ext::try_from(to_raw_value(&Value::Object(Default::default()))?.as_ref())?,
            }
        );
        assert_eq!(serde_json::to_string(&o2)?, r#"{"ext":{}}"#);

        Ok(())
    }
}