simd_json_derive/impls/
array.rs

1use crate::{de, io, Deserialize, Node, Serialize, Tape, Write};
2use std::mem::MaybeUninit;
3use std::ptr;
4
5// taken from https://github.com/rust-lang/rust/blob/95f6a01e8f8fb121ded7d0eaa86906437cb08652/library/core/src/array/mod.rs#L843
6struct Guard<'a, T, const N: usize> {
7    pub array: &'a mut [MaybeUninit<T>; N], // we include size for a small optimization of pointer size
8    pub initialized: usize,
9}
10
11impl<T, const N: usize> Guard<'_, T, N> {
12    #[inline]
13    pub unsafe fn push_unchecked(&mut self, item: T) {
14        // SAFETY: If `initialized` was correct before and the caller does not
15        // invoke this method more than N times then writes will be in-bounds
16        // and slots will not be initialized more than once.
17        unsafe {
18            self.array.get_unchecked_mut(self.initialized).write(item);
19            self.initialized = self.initialized.wrapping_add(1); // unchecked_add is unstable
20        }
21    }
22}
23
24impl<T, const N: usize> Drop for Guard<'_, T, N> {
25    fn drop(&mut self) {
26        debug_assert!(self.initialized <= N);
27
28        // SAFETY: this slice will contain only initialized objects.
29        unsafe {
30            let slice = ptr::slice_from_raw_parts_mut(
31                self.array.as_mut_ptr().cast::<T>(),
32                self.initialized,
33            );
34            ptr::drop_in_place(slice);
35        }
36    }
37}
38
39impl<'input, T, const N: usize> Deserialize<'input> for [T; N]
40where
41    T: Deserialize<'input>,
42{
43    #[inline]
44    fn from_tape(tape: &mut Tape<'input>) -> de::Result<Self>
45    where
46        Self: Sized + 'input,
47    {
48        if let Some(Node::Array { len, .. }) = tape.next() {
49            if len != N {
50                return Err(de::Error::custom(
51                    "expected array of len {N} found array of len {len}",
52                ));
53            }
54
55            if N == 0 {
56                // Safety: N is 0, and so *const [T; N] is *const [T; 0]
57                #[allow(clippy::ref_as_ptr)]
58                return Ok(unsafe { ptr::read((&[]) as *const [T; N]) });
59            }
60
61            // Safety: elements are still MaybeUninit
62            let mut array: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
63
64            // Guard is here to make sure we drop
65            let mut guard = Guard {
66                array: &mut array,
67                initialized: 0,
68            };
69
70            // taken from https://github.com/rust-lang/rust/blob/95f6a01e8f8fb121ded7d0eaa86906437cb08652/library/core/src/array/mod.rs#L812
71            while guard.initialized < N {
72                let item = T::from_tape(tape)?;
73
74                // SAFETY: The loop condition ensures we have space to push the item
75                unsafe { guard.push_unchecked(item) };
76            }
77            core::mem::forget(guard);
78
79            // all elements initialized
80            Ok(unsafe { array.map(|x| x.assume_init()) })
81        } else {
82            Err(de::Error::expected_array())
83        }
84    }
85}
86
87impl<T, const N: usize> Serialize for [T; N]
88where
89    T: Serialize,
90{
91    #[inline]
92    fn json_write<W>(&self, writer: &mut W) -> io::Result<()>
93    where
94        W: Write,
95    {
96        // N is a compile time constant, this wont be checked at runtime
97        if N == 0 {
98            return writer.write_all(b"[]");
99        }
100
101        let mut i = self.iter();
102        if let Some(first) = i.next() {
103            writer.write_all(b"[")?;
104            first.json_write(writer)?;
105            for e in i {
106                writer.write_all(b",")?;
107                e.json_write(writer)?;
108            }
109            writer.write_all(b"]")
110        } else {
111            unreachable!()
112        }
113    }
114}
115
116#[cfg(test)]
117mod test {
118    use crate::*;
119    #[test]
120    fn arr() {
121        let s: [u8; 0] = [];
122        assert_eq!(s.json_string().expect("invalid "), "[]");
123        assert_eq!([1].json_string().expect("invalid "), "[1]");
124        assert_eq!([1, 2].json_string().expect("invalid "), "[1,2]");
125        assert_eq!([1, 2, 3].json_string().expect("invalid "), "[1,2,3]");
126    }
127    #[test]
128    fn arr2() {
129        assert_eq!(
130            <[u8; 0] as Deserialize<'_>>::from_slice(&mut b"[]".to_vec()),
131            Ok([])
132        );
133        assert_eq!(
134            <[u8; 1] as Deserialize<'_>>::from_slice(&mut b"[1]".to_vec()),
135            Ok([1])
136        );
137        assert_eq!(
138            <[u8; 2] as Deserialize<'_>>::from_slice(&mut b"[1, 2]".to_vec()),
139            Ok([1, 2])
140        );
141        assert_eq!(
142            <[u8; 3] as Deserialize<'_>>::from_slice(&mut b"[1, 2, 3]".to_vec()),
143            Ok([1, 2, 3])
144        );
145    }
146    #[test]
147    fn slice() {
148        let s: [u8; 0] = [];
149        assert_eq!(s.json_string().expect("invalid data"), "[]");
150        assert_eq!([1].json_string().expect("invalid data"), "[1]");
151        assert_eq!([1, 2].json_string().expect("invalid data"), "[1,2]");
152        assert_eq!([1, 2, 3].json_string().expect("invalid data"), "[1,2,3]");
153    }
154}