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}