typed_index_collections/slice/
boxed.rs

1use alloc::boxed::Box;
2use alloc::vec;
3use core::iter::FromIterator;
4use core::mem::transmute;
5
6#[cfg(feature = "bincode")]
7use bincode::de::{BorrowDecode, BorrowDecoder, Decode, Decoder};
8#[cfg(feature = "bincode")]
9use bincode::error::DecodeError;
10#[cfg(all(feature = "alloc", feature = "serde"))]
11use serde::de::{Deserialize, Deserializer};
12
13use crate::{TiSlice, TiVec};
14
15impl<K, V> From<Box<TiSlice<K, V>>> for Box<[V]> {
16    #[inline]
17    fn from(slice: Box<TiSlice<K, V>>) -> Self {
18        // SAFETY: `TiSlice<K, V>` is `repr(transparent)` over a `[V]` type.
19        unsafe { transmute::<Box<TiSlice<K, V>>, Self>(slice) }
20    }
21}
22
23impl<K, V> From<Box<[V]>> for Box<TiSlice<K, V>> {
24    #[inline]
25    fn from(slice: Box<[V]>) -> Self {
26        // SAFETY: `TiSlice<K, V>` is `repr(transparent)` over a `[V]` type.
27        unsafe { transmute::<Box<[V]>, Self>(slice) }
28    }
29}
30
31impl<K, V: Clone> Clone for Box<TiSlice<K, V>> {
32    #[inline]
33    fn clone(&self) -> Self {
34        self.to_vec().into_boxed_slice()
35    }
36}
37
38impl<K, V> IntoIterator for Box<TiSlice<K, V>> {
39    type Item = V;
40    type IntoIter = vec::IntoIter<V>;
41
42    #[inline]
43    fn into_iter(self) -> Self::IntoIter {
44        self.into_vec().into_iter()
45    }
46}
47
48impl<K, V> Default for Box<TiSlice<K, V>> {
49    #[inline]
50    fn default() -> Self {
51        TiVec::new().into()
52    }
53}
54
55impl<K, V: Copy> From<&TiSlice<K, V>> for Box<TiSlice<K, V>> {
56    #[inline]
57    fn from(slice: &TiSlice<K, V>) -> Self {
58        Box::<[V]>::from(&slice.raw).into()
59    }
60}
61
62impl<K, V> From<Box<TiSlice<K, V>>> for TiVec<K, V> {
63    #[inline]
64    fn from(s: Box<TiSlice<K, V>>) -> Self {
65        s.into_vec()
66    }
67}
68
69impl<K, V> From<TiVec<K, V>> for Box<TiSlice<K, V>> {
70    #[inline]
71    fn from(v: TiVec<K, V>) -> Self {
72        v.into_boxed_slice()
73    }
74}
75
76impl<K, V> FromIterator<V> for Box<TiSlice<K, V>> {
77    #[inline]
78    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
79        iter.into_iter().collect::<TiVec<K, V>>().into_boxed_slice()
80    }
81}
82
83#[cfg(feature = "serde")]
84#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "serde"))))]
85impl<'de, K, V> Deserialize<'de> for Box<TiSlice<K, V>>
86where
87    V: Deserialize<'de>,
88{
89    #[inline]
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: Deserializer<'de>,
93    {
94        Box::<[V]>::deserialize(deserializer).map(Into::into)
95    }
96}
97
98#[cfg(feature = "bincode")]
99#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "bincode"))))]
100impl<K, V, Context> Decode<Context> for Box<TiSlice<K, V>>
101where
102    V: 'static + Decode<Context>,
103{
104    #[inline]
105    fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
106    where
107        D: Decoder<Context = Context>,
108    {
109        Box::<[V]>::decode(decoder).map(Into::into)
110    }
111}
112
113#[cfg(feature = "bincode")]
114#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "bincode"))))]
115impl<'de, K, V, Context> BorrowDecode<'de, Context> for Box<TiSlice<K, V>>
116where
117    V: 'de + BorrowDecode<'de, Context>,
118{
119    #[inline]
120    fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
121    where
122        D: BorrowDecoder<'de, Context = Context>,
123    {
124        Box::<[V]>::borrow_decode(decoder).map(Into::into)
125    }
126}
127
128#[expect(dead_code, unused_imports, unused_mut, reason = "okay in tests")]
129#[cfg(test)]
130mod test {
131    use alloc::borrow::{Cow, ToOwned};
132    use alloc::boxed::Box;
133    use alloc::ffi::CString;
134    use alloc::string::ToString;
135    use alloc::vec::Vec;
136    use core::borrow::{Borrow, BorrowMut};
137    use core::hash::{Hash, Hasher};
138    use core::ops::Bound;
139    #[cfg(feature = "std")]
140    use std::hash::DefaultHasher;
141    #[cfg(feature = "std")]
142    use std::io::{IoSlice, Write};
143
144    use crate::test_util::{AsSliceAndCapacity, Id};
145    use crate::{TiSlice, TiVec};
146
147    #[test]
148    fn test_boxed_slice_api_compatibility() {
149        for v in [
150            &[0_u32; 0][..],
151            &[1],
152            &[1, 1234],
153            &[1, 2, 4],
154            &[1, 5, 3, 2],
155            &[1, 1, 9, 2, 4, 1, 12345, 12],
156        ] {
157            let mut cv = (v, TiSlice::from_ref(v));
158            assert_eq_api!(
159                cv, v => Box::<TheSlice<u32>>::from(v) == <Box<TheSlice<u32>>>::default()
160            );
161            assert_eq_api!(cv, v => Box::<TheSlice<_>>::from(v).into_std());
162            assert_eq_api!(cv, v => Box::<TheSlice<_>>::from(v).clone().into_std());
163            assert_eq_api!(
164                cv, v => IntoIterator::into_iter(Box::<TheSlice<u32>>::from(v)).collect::<Vec<_>>()
165            );
166            assert_eq_api!(cv, v => TheVec::from(Box::<TheSlice<_>>::from(v)).into_std());
167            assert_eq_api!(cv, v => Box::<TheSlice<_>>::from(TheVec::from(v)).into_std());
168            assert_eq_api!(cv, v => v.iter().copied().collect::<Box<TheSlice<_>>>().into_std());
169        }
170    }
171
172    #[expect(clippy::unwrap_used, reason = "okay in tests")]
173    #[cfg(feature = "serde")]
174    #[test]
175    fn test_boxed_slice_deserialize() {
176        let s0: Box<TiSlice<Id, u32>> = serde_json::from_str("[]").unwrap();
177        let s1: Box<TiSlice<Id, u32>> = serde_json::from_str("[12]").unwrap();
178        let s2: Box<TiSlice<Id, u32>> = serde_json::from_str("[23, 34]").unwrap();
179        assert_eq!(s0.as_ref().raw, [0; 0][..]);
180        assert_eq!(s1.as_ref().raw, [12][..]);
181        assert_eq!(s2.as_ref().raw, [23, 34][..]);
182    }
183
184    #[expect(clippy::unwrap_used, reason = "okay in tests")]
185    #[cfg(feature = "bincode")]
186    #[test]
187    fn test_boxed_slice_decode() {
188        fn decode_whole(bytes: &[u8]) -> Box<TiSlice<Id, u32>> {
189            let config = bincode::config::standard();
190            let (decoded, len) = bincode::decode_from_slice(bytes, config).unwrap();
191            assert_eq!(len, bytes.len());
192            decoded
193        }
194
195        let s0: Box<TiSlice<Id, u32>> = decode_whole(&[0]);
196        let s1: Box<TiSlice<Id, u32>> = decode_whole(&[1, 12]);
197        let s2: Box<TiSlice<Id, u32>> = decode_whole(&[2, 23, 34]);
198        let s3: Box<TiSlice<Id, u32>> =
199            decode_whole(&[2, 252, 0x78, 0x56, 0x34, 0x12, 252, 0x89, 0x67, 0x45, 0x23]);
200        assert_eq!(s0.as_ref().raw, [0; 0][..]);
201        assert_eq!(s1.as_ref().raw, [12][..]);
202        assert_eq!(s2.as_ref().raw, [23, 34][..]);
203        assert_eq!(s3.as_ref().raw, [0x1234_5678, 0x2345_6789][..]);
204    }
205
206    #[expect(clippy::unwrap_used, reason = "okay in tests")]
207    #[cfg(feature = "bincode")]
208    #[test]
209    fn test_boxed_slice_borrow_decode() {
210        fn decode_whole(bytes: &[u8]) -> Box<TiSlice<Id, &str>> {
211            let config = bincode::config::standard();
212            let (decoded, len) = bincode::borrow_decode_from_slice(bytes, config).unwrap();
213            assert_eq!(len, bytes.len());
214            decoded
215        }
216
217        let s0: Box<TiSlice<Id, &str>> = decode_whole(&[0]);
218        let s1: Box<TiSlice<Id, &str>> = decode_whole(&[1, 1, b'a']);
219        let s2: Box<TiSlice<Id, &str>> = decode_whole(&[2, 2, b'b', b'c', 3, b'd', b'e', b'f']);
220        assert_eq!(s0.as_ref().raw, [""; 0][..]);
221        assert_eq!(s1.as_ref().raw, ["a"][..]);
222        assert_eq!(s2.as_ref().raw, ["bc", "def"][..]);
223    }
224}