Skip to main content

docspec_json/
value.rs

1//! Trait and impls for values writable through a [`JsonBackend`].
2
3use crate::JsonBackend;
4use docspec_core::Result;
5
6/// Marker type representing a JSON `null` value.
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
8pub struct Null;
9
10/// A value that can be written through a [`JsonBackend`].
11pub trait WriteVal {
12    /// Write `self` to `backend`.
13    ///
14    /// # Errors
15    ///
16    /// Returns any error produced while writing the value.
17    fn write_to<B>(self, backend: &mut B) -> Result<()>
18    where
19        B: JsonBackend;
20}
21
22impl WriteVal for &str {
23    #[inline]
24    fn write_to<B>(self, backend: &mut B) -> Result<()>
25    where
26        B: JsonBackend,
27    {
28        backend.write_string(self)
29    }
30}
31
32impl WriteVal for bool {
33    #[inline]
34    fn write_to<B>(self, backend: &mut B) -> Result<()>
35    where
36        B: JsonBackend,
37    {
38        backend.write_bool(self)
39    }
40}
41
42impl WriteVal for u8 {
43    #[inline]
44    fn write_to<B>(self, backend: &mut B) -> Result<()>
45    where
46        B: JsonBackend,
47    {
48        backend.write_number(u32::from(self))
49    }
50}
51
52impl WriteVal for u32 {
53    #[inline]
54    fn write_to<B>(self, backend: &mut B) -> Result<()>
55    where
56        B: JsonBackend,
57    {
58        backend.write_number(self)
59    }
60}
61
62impl WriteVal for Null {
63    #[inline]
64    fn write_to<B>(self, backend: &mut B) -> Result<()>
65    where
66        B: JsonBackend,
67    {
68        backend.write_null()
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use docspec_core::Error;
76
77    #[derive(Default)]
78    struct MockBackend {
79        fail: bool,
80        last_bool: Option<bool>,
81        last_call: &'static str,
82        last_number: Option<u32>,
83        last_string: Option<String>,
84    }
85
86    impl crate::JsonBackend for MockBackend {
87        type Output = ();
88
89        fn begin_array(&mut self) -> docspec_core::Result<()> {
90            Ok(())
91        }
92
93        fn begin_object(&mut self) -> docspec_core::Result<()> {
94            Ok(())
95        }
96
97        fn end_array(&mut self) -> docspec_core::Result<()> {
98            Ok(())
99        }
100
101        fn end_object(&mut self) -> docspec_core::Result<()> {
102            Ok(())
103        }
104
105        fn finish(self) -> docspec_core::Result<()> {
106            Ok(())
107        }
108
109        fn write_bool(&mut self, b: bool) -> docspec_core::Result<()> {
110            self.last_call = "write_bool";
111            self.last_bool = Some(b);
112            Ok(())
113        }
114
115        fn write_name(&mut self, _: &str) -> docspec_core::Result<()> {
116            Ok(())
117        }
118
119        fn write_null(&mut self) -> docspec_core::Result<()> {
120            self.last_call = "write_null";
121            Ok(())
122        }
123
124        fn write_number(&mut self, n: u32) -> docspec_core::Result<()> {
125            self.last_call = "write_number";
126            self.last_number = Some(n);
127            Ok(())
128        }
129
130        fn write_string(&mut self, s: &str) -> docspec_core::Result<()> {
131            self.last_call = "write_string";
132            self.last_string = Some(s.to_string());
133            if self.fail {
134                Err(Error::Other {
135                    message: "mock error".to_string(),
136                })
137            } else {
138                Ok(())
139            }
140        }
141    }
142
143    #[test]
144    fn mock_backend_container_methods_callable() {
145        let mut b = MockBackend::default();
146        assert!(b.begin_array().is_ok());
147        assert!(b.begin_object().is_ok());
148        assert!(b.end_array().is_ok());
149        assert!(b.end_object().is_ok());
150        assert!(b.write_name("k").is_ok());
151    }
152
153    #[test]
154    fn mock_backend_finish_callable() {
155        let b = MockBackend::default();
156        assert!(b.finish().is_ok());
157    }
158
159    #[test]
160    fn write_val_bool_false_calls_write_bool_with_false() {
161        let mut b = MockBackend::default();
162        assert!(false.write_to(&mut b).is_ok());
163        assert_eq!(b.last_call, "write_bool");
164        assert_eq!(b.last_bool, Some(false));
165    }
166
167    #[test]
168    fn write_val_bool_true_calls_write_bool_with_true() {
169        let mut b = MockBackend::default();
170        assert!(true.write_to(&mut b).is_ok());
171        assert_eq!(b.last_call, "write_bool");
172        assert_eq!(b.last_bool, Some(true));
173    }
174
175    #[test]
176    fn write_val_null_calls_write_null() {
177        let mut b = MockBackend::default();
178        assert!(Null.write_to(&mut b).is_ok());
179        assert_eq!(b.last_call, "write_null");
180    }
181
182    #[test]
183    fn write_val_propagates_backend_error() {
184        let mut b = MockBackend {
185            fail: true,
186            ..MockBackend::default()
187        };
188        assert!("hello".write_to(&mut b).is_err());
189    }
190
191    #[test]
192    fn write_val_str_calls_write_string() {
193        let mut b = MockBackend::default();
194        assert!("hello".write_to(&mut b).is_ok());
195        assert_eq!(b.last_call, "write_string");
196        assert_eq!(b.last_string.as_deref(), Some("hello"));
197    }
198
199    #[test]
200    fn write_val_u8_calls_write_number() {
201        let mut b = MockBackend::default();
202        let n: u8 = 42;
203        assert!(n.write_to(&mut b).is_ok());
204        assert_eq!(b.last_call, "write_number");
205        assert_eq!(b.last_number, Some(42));
206    }
207
208    #[test]
209    fn write_val_u32_calls_write_number() {
210        let mut b = MockBackend::default();
211        let n: u32 = 42;
212        assert!(n.write_to(&mut b).is_ok());
213        assert_eq!(b.last_call, "write_number");
214        assert_eq!(b.last_number, Some(42));
215    }
216}