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
use core::{borrow::Borrow, fmt};

/**
A string containing encoded JSON.

Streaming a `JsonStr` will embed its contents directly rather
than treating them as a string.
*/
#[repr(transparent)]
#[derive(PartialEq, Eq, Hash)]
pub struct JsonStr(str);

impl JsonStr {
    /**
    Treat a string as native JSON.
    */
    pub const fn new<'a>(json: &'a str) -> &'a Self {
        // SAFETY: `JsonStr` and `str` have the same ABI
        unsafe { &*(json as *const _ as *const JsonStr) }
    }

    /**
    Get a reference to the underlying string.
    */
    pub const fn as_str(&self) -> &str {
        &self.0
    }

    /**
    Get a reference to the bytes of the underlying string.
    */
    pub const fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

impl<'a> From<&'a str> for &'a JsonStr {
    fn from(value: &'a str) -> Self {
        JsonStr::new(value)
    }
}

impl fmt::Debug for JsonStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Display for JsonStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl PartialEq<str> for JsonStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl sval::Value for JsonStr {
    fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
        stream.tagged_begin(Some(&crate::tags::JSON_VALUE), None, None)?;
        stream.value(&self.0)?;
        stream.tagged_end(Some(&crate::tags::JSON_VALUE), None, None)
    }
}

impl AsRef<str> for JsonStr {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl Borrow<str> for JsonStr {
    fn borrow(&self) -> &str {
        &self.0
    }
}

#[cfg(feature = "alloc")]
mod alloc_support {
    use super::*;

    use alloc::boxed::Box;

    impl JsonStr {
        /**
        Treat a string as native JSON.
        */
        pub fn boxed(json: impl Into<Box<str>>) -> Box<Self> {
            let json = json.into();

            // SAFETY: `JsonStr` and `str` have the same ABI
            unsafe { Box::from_raw(Box::into_raw(json) as *mut str as *mut JsonStr) }
        }
    }

    impl From<Box<str>> for Box<JsonStr> {
        fn from(value: Box<str>) -> Self {
            // SAFETY: `JsonStr` and `str` have the same ABI
            unsafe { Box::from_raw(Box::into_raw(value) as *mut JsonStr) }
        }
    }
}