1use {
4 crate::list_trait::List,
5 bytemuck::Pod,
6 core::ops::Deref,
7 spl_pod::{pod_length::PodLength, primitives::PodU32},
8};
9
10#[derive(Debug)]
11pub struct ListViewReadOnly<'data, T: Pod, L: PodLength = PodU32> {
12 pub(crate) length: &'data L,
13 pub(crate) data: &'data [T],
14 pub(crate) capacity: usize,
15}
16
17impl<T: Pod, L: PodLength> List for ListViewReadOnly<'_, T, L> {
18 type Item = T;
19 type Length = L;
20
21 fn capacity(&self) -> usize {
22 self.capacity
23 }
24}
25
26impl<T: Pod, L: PodLength> Deref for ListViewReadOnly<'_, T, L> {
27 type Target = [T];
28
29 fn deref(&self) -> &Self::Target {
30 let len = (*self.length).into();
31 &self.data[..len]
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use {
38 super::*,
39 crate::ListView,
40 bytemuck_derive::{Pod as DerivePod, Zeroable},
41 core::mem::size_of,
42 spl_pod::{
43 pod_length::PodLength,
44 primitives::{PodU32, PodU64},
45 },
46 };
47
48 #[repr(C, align(16))]
49 #[derive(DerivePod, Zeroable, Copy, Clone, Debug, PartialEq)]
50 struct TestStruct(u128);
51
52 fn build_test_buffer<T: Pod, L: PodLength>(
54 length: usize,
55 capacity: usize,
56 items: &[T],
57 ) -> Vec<u8> {
58 let size = ListView::<T, L>::size_of(capacity).unwrap();
59 let mut buffer = vec![0u8; size];
60
61 let pod_len = L::try_from(length).unwrap();
63 let len_bytes = bytemuck::bytes_of(&pod_len);
64 buffer[0..size_of::<L>()].copy_from_slice(len_bytes);
65
66 if !items.is_empty() {
68 let data_start = ListView::<T, L>::size_of(0).unwrap();
69 let items_bytes = bytemuck::cast_slice(items);
70 buffer[data_start..data_start.saturating_add(items_bytes.len())]
71 .copy_from_slice(items_bytes);
72 }
73
74 buffer
75 }
76
77 #[test]
78 fn test_len_and_capacity() {
79 let items = [10u32, 20, 30];
80 let buffer = build_test_buffer::<u32, PodU32>(items.len(), 5, &items);
81 let view = ListView::<u32>::unpack(&buffer).unwrap();
82
83 assert_eq!(view.len(), 3);
84 assert_eq!(view.capacity(), 5);
85 }
86
87 #[test]
88 fn test_as_slice() {
89 let items = [10u32, 20, 30];
90 let buffer = build_test_buffer::<u32, PodU32>(items.len(), 5, &items);
92 let view = ListView::<u32, PodU32>::unpack(&buffer).unwrap();
93
94 assert_eq!(*view, items[..]);
96 }
97
98 #[test]
99 fn test_is_empty() {
100 let buffer_full = build_test_buffer::<u32, PodU32>(1, 2, &[10]);
102 let view_full = ListView::<u32>::unpack(&buffer_full).unwrap();
103 assert!(!view_full.is_empty());
104
105 let buffer_empty = build_test_buffer::<u32, PodU32>(0, 2, &[]);
107 let view_empty = ListView::<u32>::unpack(&buffer_empty).unwrap();
108 assert!(view_empty.is_empty());
109 }
110
111 #[test]
112 fn test_iter() {
113 let items = [TestStruct(1), TestStruct(2)];
114 let buffer = build_test_buffer::<TestStruct, PodU64>(items.len(), 3, &items);
115 let view = ListView::<TestStruct, PodU64>::unpack(&buffer).unwrap();
116
117 let mut iter = view.iter();
118 assert_eq!(iter.next(), Some(&items[0]));
119 assert_eq!(iter.next(), Some(&items[1]));
120 assert_eq!(iter.next(), None);
121 let collected: Vec<_> = view.iter().collect();
122 assert_eq!(collected, vec![&items[0], &items[1]]);
123 }
124
125 #[test]
126 fn test_iter_on_empty_list() {
127 let buffer = build_test_buffer::<u32, PodU32>(0, 5, &[]);
128 let view = ListView::<u32, PodU32>::unpack(&buffer).unwrap();
129
130 assert_eq!(view.iter().count(), 0);
131 assert_eq!(view.iter().next(), None);
132 }
133
134 #[test]
135 fn test_zero_capacity() {
136 let buffer = build_test_buffer::<TestStruct, PodU32>(0, 0, &[]);
138 let view = ListView::<TestStruct, PodU32>::unpack(&buffer).unwrap();
139
140 assert_eq!(view.len(), 0);
141 assert_eq!(view.capacity(), 0);
142 assert!(view.is_empty());
143 assert_eq!(*view, []);
144 }
145
146 #[test]
147 fn test_with_padding() {
148 let header_size = ListView::<TestStruct>::size_of(0).unwrap();
152 assert_eq!(header_size, 16);
153
154 let items = [TestStruct(123), TestStruct(456)];
155 let buffer = build_test_buffer::<TestStruct, PodU32>(items.len(), 4, &items);
156 let view = ListView::<TestStruct>::unpack(&buffer).unwrap();
157
158 assert_eq!(view.len(), 2);
160 assert_eq!(view.capacity(), 4);
161 assert_eq!(*view, items[..]);
162 }
163
164 #[test]
165 fn test_bytes_used_and_allocated() {
166 let items = [10u32, 20, 30];
168 let capacity = 5;
169 let buffer = build_test_buffer::<u32, PodU32>(items.len(), capacity, &items);
170 let view = ListView::<u32>::unpack(&buffer).unwrap();
171
172 let expected_used = ListView::<u32>::size_of(view.len()).unwrap();
173 let expected_cap = ListView::<u32>::size_of(view.capacity()).unwrap();
174
175 assert_eq!(view.bytes_used().unwrap(), expected_used);
176 assert_eq!(view.bytes_allocated().unwrap(), expected_cap);
177 }
178
179 #[test]
180 fn test_get() {
181 let items = [10u32, 20, 30];
182 let buffer = build_test_buffer::<u32, PodU32>(items.len(), 5, &items);
183 let view = ListView::<u32>::unpack(&buffer).unwrap();
184
185 assert_eq!(view.first(), Some(&10u32));
187 assert_eq!(view.get(1), Some(&20u32));
188 assert_eq!(view.get(2), Some(&30u32));
189
190 assert_eq!(view.get(3), None);
192
193 assert_eq!(view.get(100), None);
195 }
196
197 #[test]
198 fn test_get_on_empty_list() {
199 let buffer = build_test_buffer::<u32, PodU32>(0, 5, &[]);
200 let view = ListView::<u32, PodU32>::unpack(&buffer).unwrap();
201 assert_eq!(view.first(), None);
202 }
203}