sudachi/util/
cow_array.rs1use std::array::TryFromSliceError;
18use std::convert::TryInto;
19use std::ops::Deref;
20
21pub trait ReadLE {
22 fn from_le_bytes(bytes: &[u8]) -> Result<Self, TryFromSliceError>
23 where
24 Self: Sized;
25}
26
27impl ReadLE for i16 {
28 fn from_le_bytes(bytes: &[u8]) -> Result<Self, TryFromSliceError> {
29 bytes.try_into().map(Self::from_le_bytes)
30 }
31}
32
33impl ReadLE for u32 {
34 fn from_le_bytes(bytes: &[u8]) -> Result<Self, TryFromSliceError>
35 where
36 Self: Sized,
37 {
38 bytes.try_into().map(Self::from_le_bytes)
39 }
40}
41
42pub struct CowArray<'a, T> {
51 slice: &'a [T],
52 storage: Option<Vec<T>>,
53}
54
55impl<T: ReadLE + Clone> CowArray<'static, T> {
56 pub fn from_owned<D: Into<Vec<T>>>(data: D) -> Self {
58 let data = data.into();
59 let slice1: &[T] = &data;
60 let slice: &'static [T] = unsafe { std::mem::transmute(slice1) };
61 Self {
62 storage: Some(data),
63 slice,
64 }
65 }
66}
67
68impl<'a, T: ReadLE + Clone> CowArray<'a, T> {
69 pub fn from_bytes(data: &'a [u8], offset: usize, size: usize) -> Self {
74 let align = std::mem::align_of::<T>();
75
76 let real_size = size * std::mem::size_of::<T>();
77 let real_slice = &data[offset..offset + real_size];
78 let ptr = real_slice.as_ptr() as *const T;
79 if is_aligned(ptr as usize, align) {
80 let reslice = unsafe { std::slice::from_raw_parts(ptr, size) };
82 Self {
83 slice: reslice,
84 storage: None,
85 }
86 } else {
87 let data = copy_of_bytes::<T>(real_slice);
88 let slice_1: &[T] = data.as_slice();
89 let slice: &'a [T] = unsafe { std::mem::transmute(slice_1) };
93 Self {
94 storage: Some(data),
95 slice,
96 }
97 }
98 }
99
100 pub fn set(&mut self, offset: usize, value: T) {
108 if self.storage.is_none() {
109 self.storage = Some(self.slice.to_vec());
110 let slice: &[T] = self.storage.as_ref().unwrap().as_slice();
112 self.slice = unsafe { std::mem::transmute(slice) };
113 }
114 if let Some(s) = self.storage.as_mut() {
115 s[offset] = value;
116 }
117 }
118}
119
120impl<'a, T> Deref for CowArray<'a, T> {
121 type Target = [T];
122
123 fn deref(&self) -> &Self::Target {
124 self.slice
125 }
126}
127
128fn is_aligned(offset: usize, alignment: usize) -> bool {
129 debug_assert!(alignment.is_power_of_two());
130 offset % alignment == 0
131}
132
133fn copy_of_bytes<T: ReadLE>(data: &[u8]) -> Vec<T> {
134 let size_t = std::mem::size_of::<T>();
135 assert_eq!(data.len() % size_t, 0);
136 let nelems = data.len() / size_t;
137 let mut result = Vec::with_capacity(nelems);
138 for i in (0..data.len()).step_by(size_t) {
139 let sl = &data[i..i + size_t];
140 result.push(T::from_le_bytes(sl).unwrap());
141 }
142 result
143}
144
145#[cfg(test)]
146mod test {
147 use super::*;
148
149 #[test]
150 fn aligned_1() {
151 assert!(is_aligned(0, 1));
152 assert!(is_aligned(1, 1));
153 assert!(is_aligned(2, 1));
154 assert!(is_aligned(3, 1));
155 assert!(is_aligned(4, 1));
156 assert!(is_aligned(5, 1));
157 assert!(is_aligned(6, 1));
158 assert!(is_aligned(7, 1));
159 assert!(is_aligned(8, 1));
160 }
161
162 #[test]
163 fn aligned_2() {
164 assert!(is_aligned(0, 2));
165 assert!(!is_aligned(1, 2));
166 assert!(is_aligned(2, 2));
167 assert!(!is_aligned(3, 2));
168 assert!(is_aligned(4, 2));
169 assert!(!is_aligned(5, 2));
170 assert!(is_aligned(6, 2));
171 assert!(!is_aligned(7, 2));
172 assert!(is_aligned(8, 2));
173 }
174
175 #[test]
176 fn aligned_4() {
177 assert!(is_aligned(0, 4));
178 assert!(!is_aligned(1, 4));
179 assert!(!is_aligned(2, 4));
180 assert!(!is_aligned(3, 4));
181 assert!(is_aligned(4, 4));
182 assert!(!is_aligned(5, 4));
183 assert!(!is_aligned(6, 4));
184 assert!(!is_aligned(7, 4));
185 assert!(is_aligned(8, 4));
186 }
187}