serde_json_borrow/
owned.rs

1use std::io;
2use std::ops::Deref;
3
4use crate::Value;
5
6/// Parses a `String` into `Value`, by taking ownership of `String` and reference slices from it in
7/// contrast to copying the contents.
8///
9/// This is done to mitigate lifetime issues.
10#[derive(Clone, Debug, Eq, PartialEq, Hash)]
11pub struct OwnedValue {
12    /// Keep owned data, to be able to safely reference it from Value<'static>
13    _data: String,
14    value: Value<'static>,
15}
16
17impl OwnedValue {
18    /// Validates `&[u8]` for utf-8 and parses it into a [crate::Value].
19    pub fn from_slice(data: &[u8]) -> io::Result<Self> {
20        let data = String::from_utf8(data.to_vec())
21            .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8"))?;
22        Self::from_string(data)
23    }
24
25    /// Takes serialized JSON `&str` and parses it into a [crate::Value].
26    ///
27    /// Clones the passed str.
28    #[allow(clippy::should_implement_trait)]
29    pub fn from_str(json_str: &str) -> io::Result<Self> {
30        let json_str = json_str.to_string();
31        Self::from_string(json_str)
32    }
33
34    /// Takes serialized JSON `String` and parses it into a [crate::Value].
35    pub fn from_string(json_str: String) -> io::Result<Self> {
36        let value: Value = serde_json::from_str(&json_str)?;
37        let value = unsafe { extend_lifetime(value) };
38        Ok(Self {
39            _data: json_str,
40            value,
41        })
42    }
43
44    /// Takes serialized JSON `String` and parses it into a [crate::Value].
45    pub fn parse_from(json_str: String) -> io::Result<Self> {
46        Self::from_string(json_str)
47    }
48
49    /// Returns the `Value` reference.
50    pub fn get_value(&self) -> &Value<'_> {
51        &self.value
52    }
53}
54
55impl Deref for OwnedValue {
56    type Target = Value<'static>;
57
58    fn deref(&self) -> &Self::Target {
59        &self.value
60    }
61}
62
63unsafe fn extend_lifetime<'b>(r: Value<'b>) -> Value<'static> {
64    std::mem::transmute::<Value<'b>, Value<'static>>(r)
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    /// Test reading from the internal Value via Deref.
72    #[test]
73    fn test_deref_access() {
74        let raw_json = r#"{"name": "John", "age": 30}"#;
75        let owned_value = OwnedValue::from_string(raw_json.to_string()).unwrap();
76
77        assert_eq!(owned_value.get("name"), &Value::Str("John".into()));
78        assert_eq!(owned_value.get("age"), &Value::Number(30_u64.into()));
79    }
80
81    /// Test that clone clones OwnedValue
82    #[test]
83    fn test_deref_clone() {
84        let raw_json = r#"{"name": "John", "age": 30}"#;
85        let owned_value = OwnedValue::from_string(raw_json.to_string()).unwrap();
86        let owned_value = owned_value.clone();
87
88        assert_eq!(owned_value.get("name"), &Value::Str("John".into()));
89        assert_eq!(owned_value.get("age"), &Value::Number(30_u64.into()));
90    }
91}