light_zero_copy/
slice.rs

1use core::{fmt, mem::size_of, ops::Index, slice};
2#[cfg(feature = "std")]
3use std::vec::Vec;
4
5use zerocopy::{little_endian::U32, Ref};
6
7use crate::{add_padding, errors::ZeroCopyError, ZeroCopyTraits};
8
9pub type ZeroCopySliceU64<'a, T> = ZeroCopySlice<'a, u64, T>;
10pub type ZeroCopySliceU32<'a, T> = ZeroCopySlice<'a, u32, T>;
11pub type ZeroCopySliceU16<'a, T> = ZeroCopySlice<'a, u16, T>;
12pub type ZeroCopySliceU8<'a, T> = ZeroCopySlice<'a, u8, T>;
13pub type ZeroCopySliceBorsh<'a, T> = ZeroCopySlice<'a, U32, T, false>;
14
15#[derive(Clone)]
16pub struct ZeroCopySlice<'a, L, T, const PAD: bool = true>
17where
18    L: ZeroCopyTraits,
19    T: ZeroCopyTraits,
20{
21    length: Ref<&'a [u8], L>,
22    bytes: Ref<&'a [u8], [T]>,
23}
24
25impl<'a, L, T, const PAD: bool> ZeroCopySlice<'a, L, T, PAD>
26where
27    L: ZeroCopyTraits,
28    T: ZeroCopyTraits,
29    u64: From<L>,
30{
31    #[inline]
32    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, ZeroCopyError> {
33        Ok(Self::from_bytes_at(bytes)?.0)
34    }
35
36    #[inline]
37    pub fn from_bytes_at(
38        bytes: &'a [u8],
39    ) -> Result<(ZeroCopySlice<'a, L, T, PAD>, &'a [u8]), ZeroCopyError> {
40        let metadata_size = Self::metadata_size();
41        if bytes.len() < metadata_size {
42            return Err(ZeroCopyError::InsufficientMemoryAllocated(
43                bytes.len(),
44                metadata_size,
45            ));
46        }
47
48        let (meta_data, bytes) = bytes.split_at(metadata_size);
49        let (length, _padding) = Ref::<&[u8], L>::from_prefix(meta_data)?;
50        let usize_len: usize = u64::from(*length) as usize;
51        let full_vector_size = Self::data_size(*length);
52        if bytes.len() < full_vector_size {
53            return Err(ZeroCopyError::InsufficientMemoryAllocated(
54                bytes.len() + metadata_size,
55                full_vector_size + metadata_size,
56            ));
57        }
58        let (bytes, remaining_bytes) = Ref::<&[u8], [T]>::from_prefix_with_elems(bytes, usize_len)?;
59        Ok((ZeroCopySlice { length, bytes }, remaining_bytes))
60    }
61
62    #[cfg(feature = "std")]
63    pub fn try_into_array<const N: usize>(&self) -> Result<[T; N], ZeroCopyError> {
64        if self.len() != N {
65            return Err(ZeroCopyError::ArraySize(N, self.len()));
66        }
67        Ok(core::array::from_fn(|i| *self.get(i).unwrap()))
68    }
69
70    #[inline]
71    pub fn metadata_size() -> usize {
72        let mut size = size_of::<L>();
73        if PAD {
74            add_padding::<L, T>(&mut size);
75        }
76        size
77    }
78
79    #[inline]
80    pub fn data_size(length: L) -> usize {
81        let usize_len: usize = u64::from(length) as usize;
82        usize_len.saturating_mul(size_of::<T>())
83    }
84
85    #[inline]
86    pub fn required_size_for_capacity(capacity: L) -> usize {
87        Self::metadata_size().saturating_add(Self::data_size(capacity))
88    }
89
90    #[inline]
91    pub fn len(&self) -> usize {
92        let usize_len: usize = u64::from(*self.length) as usize;
93        usize_len
94    }
95
96    #[inline]
97    pub fn is_empty(&self) -> bool {
98        self.len() == 0
99    }
100
101    #[inline]
102    pub fn first(&self) -> Option<&T> {
103        self.get(0)
104    }
105
106    #[inline]
107    pub fn last(&self) -> Option<&T> {
108        self.get(self.len().saturating_sub(1))
109    }
110
111    #[inline]
112    pub fn as_slice(&self) -> &[T] {
113        self.bytes.as_ref()
114    }
115
116    #[inline]
117    pub fn data_as_ptr(&self) -> *const T {
118        self.as_slice().as_ptr()
119    }
120
121    #[inline]
122    pub fn get(&self, index: usize) -> Option<&T> {
123        self.as_slice().get(index)
124    }
125
126    #[cfg(feature = "std")]
127    #[inline]
128    pub fn to_vec(&self) -> Vec<T> {
129        self.as_slice().to_vec()
130    }
131}
132
133impl<L, T, const PAD: bool> Index<usize> for ZeroCopySlice<'_, L, T, PAD>
134where
135    L: ZeroCopyTraits,
136    T: ZeroCopyTraits,
137    u64: From<L>,
138{
139    type Output = T;
140
141    #[inline]
142    fn index(&self, index: usize) -> &Self::Output {
143        &self.as_slice()[index]
144    }
145}
146
147impl<'a, L, T, const PAD: bool> IntoIterator for &'a ZeroCopySlice<'_, L, T, PAD>
148where
149    L: ZeroCopyTraits,
150    T: ZeroCopyTraits,
151    u64: From<L>,
152{
153    type Item = &'a T;
154    type IntoIter = slice::Iter<'a, T>;
155
156    #[inline]
157    fn into_iter(self) -> Self::IntoIter {
158        self.iter()
159    }
160}
161
162impl<'a, L, T, const PAD: bool> ZeroCopySlice<'_, L, T, PAD>
163where
164    L: ZeroCopyTraits,
165    T: ZeroCopyTraits,
166    u64: From<L>,
167{
168    #[inline]
169    pub fn iter(&'a self) -> slice::Iter<'a, T> {
170        self.as_slice().iter()
171    }
172}
173
174impl<L, T, const PAD: bool> PartialEq for ZeroCopySlice<'_, L, T, PAD>
175where
176    L: ZeroCopyTraits,
177    T: ZeroCopyTraits + PartialEq,
178    u64: From<L>,
179{
180    #[inline]
181    fn eq(&self, other: &Self) -> bool {
182        self.as_slice() == other.as_slice()
183    }
184}
185
186impl<L, T, const PAD: bool> fmt::Debug for ZeroCopySlice<'_, L, T, PAD>
187where
188    T: ZeroCopyTraits + fmt::Debug,
189    L: ZeroCopyTraits,
190    u64: From<L>,
191{
192    #[inline]
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        write!(f, "{:?}", self.as_slice())
195    }
196}
197
198#[cfg(feature = "std")]
199impl<'a, T: ZeroCopyTraits + crate::traits::ZeroCopyAt<'a>> crate::traits::ZeroCopyAt<'a>
200    for ZeroCopySliceBorsh<'a, T>
201{
202    type ZeroCopyAt = Self;
203
204    fn zero_copy_at(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ZeroCopyError> {
205        ZeroCopySliceBorsh::from_bytes_at(bytes)
206    }
207}