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: JsonBackend>(self, backend: &mut B) -> Result<()>;
18}
19
20impl WriteVal for &str {
21    #[inline]
22    fn write_to<B: JsonBackend>(self, backend: &mut B) -> Result<()> {
23        backend.write_string(self)
24    }
25}
26
27impl WriteVal for bool {
28    #[inline]
29    fn write_to<B: JsonBackend>(self, backend: &mut B) -> Result<()> {
30        backend.write_bool(self)
31    }
32}
33
34impl WriteVal for u8 {
35    #[inline]
36    fn write_to<B: JsonBackend>(self, backend: &mut B) -> Result<()> {
37        backend.write_number(u32::from(self))
38    }
39}
40
41impl WriteVal for u32 {
42    #[inline]
43    fn write_to<B: JsonBackend>(self, backend: &mut B) -> Result<()> {
44        backend.write_number(self)
45    }
46}
47
48impl WriteVal for Null {
49    #[inline]
50    fn write_to<B: JsonBackend>(self, backend: &mut B) -> Result<()> {
51        backend.write_null()
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use docspec_core::Error;
59
60    #[derive(Default)]
61    struct MockBackend {
62        fail: bool,
63        last_bool: Option<bool>,
64        last_call: &'static str,
65        last_number: Option<u32>,
66        last_string: Option<String>,
67    }
68
69    impl crate::JsonBackend for MockBackend {
70        type Output = ();
71
72        fn begin_array(&mut self) -> docspec_core::Result<()> {
73            Ok(())
74        }
75
76        fn begin_object(&mut self) -> docspec_core::Result<()> {
77            Ok(())
78        }
79
80        fn end_array(&mut self) -> docspec_core::Result<()> {
81            Ok(())
82        }
83
84        fn end_object(&mut self) -> docspec_core::Result<()> {
85            Ok(())
86        }
87
88        fn finish(self) -> docspec_core::Result<()> {
89            Ok(())
90        }
91
92        fn write_bool(&mut self, b: bool) -> docspec_core::Result<()> {
93            self.last_call = "write_bool";
94            self.last_bool = Some(b);
95            Ok(())
96        }
97
98        fn write_name(&mut self, _: &str) -> docspec_core::Result<()> {
99            Ok(())
100        }
101
102        fn write_null(&mut self) -> docspec_core::Result<()> {
103            self.last_call = "write_null";
104            Ok(())
105        }
106
107        fn write_number(&mut self, n: u32) -> docspec_core::Result<()> {
108            self.last_call = "write_number";
109            self.last_number = Some(n);
110            Ok(())
111        }
112
113        fn write_string(&mut self, s: &str) -> docspec_core::Result<()> {
114            self.last_call = "write_string";
115            self.last_string = Some(s.to_string());
116            if self.fail {
117                Err(Error::Other {
118                    message: "mock error".to_string(),
119                })
120            } else {
121                Ok(())
122            }
123        }
124    }
125
126    #[test]
127    fn mock_backend_container_methods_callable() {
128        let mut b = MockBackend::default();
129        assert!(b.begin_array().is_ok());
130        assert!(b.begin_object().is_ok());
131        assert!(b.end_array().is_ok());
132        assert!(b.end_object().is_ok());
133        assert!(b.write_name("k").is_ok());
134    }
135
136    #[test]
137    fn mock_backend_finish_callable() {
138        let b = MockBackend::default();
139        assert!(b.finish().is_ok());
140    }
141
142    #[test]
143    fn write_val_bool_false_calls_write_bool_with_false() {
144        let mut b = MockBackend::default();
145        assert!(false.write_to(&mut b).is_ok());
146        assert_eq!(b.last_call, "write_bool");
147        assert_eq!(b.last_bool, Some(false));
148    }
149
150    #[test]
151    fn write_val_bool_true_calls_write_bool_with_true() {
152        let mut b = MockBackend::default();
153        assert!(true.write_to(&mut b).is_ok());
154        assert_eq!(b.last_call, "write_bool");
155        assert_eq!(b.last_bool, Some(true));
156    }
157
158    #[test]
159    fn write_val_null_calls_write_null() {
160        let mut b = MockBackend::default();
161        assert!(Null.write_to(&mut b).is_ok());
162        assert_eq!(b.last_call, "write_null");
163    }
164
165    #[test]
166    fn write_val_propagates_backend_error() {
167        let mut b = MockBackend {
168            fail: true,
169            ..MockBackend::default()
170        };
171        assert!("hello".write_to(&mut b).is_err());
172    }
173
174    #[test]
175    fn write_val_str_calls_write_string() {
176        let mut b = MockBackend::default();
177        assert!("hello".write_to(&mut b).is_ok());
178        assert_eq!(b.last_call, "write_string");
179        assert_eq!(b.last_string.as_deref(), Some("hello"));
180    }
181
182    #[test]
183    fn write_val_u8_calls_write_number() {
184        let mut b = MockBackend::default();
185        let n: u8 = 42;
186        assert!(n.write_to(&mut b).is_ok());
187        assert_eq!(b.last_call, "write_number");
188        assert_eq!(b.last_number, Some(42));
189    }
190
191    #[test]
192    fn write_val_u32_calls_write_number() {
193        let mut b = MockBackend::default();
194        let n: u32 = 42;
195        assert!(n.write_to(&mut b).is_ok());
196        assert_eq!(b.last_call, "write_number");
197        assert_eq!(b.last_number, Some(42));
198    }
199}