tesap_std/
chunks.rs

1use std::alloc;
2use std::ptr;
3use std::mem;
4use std::fmt;
5use core::slice;
6use std::ops::{Index, IndexMut};
7use std::fmt::Display;
8
9type Layout = alloc::Layout;
10
11fn array_layout<T>(count: usize) -> Layout {
12    let layout = alloc::Layout::array::<T>(count).unwrap();
13    assert_ne!(layout.size(), 0);
14    assert_eq!(layout.size(), count * mem::size_of::<T>());
15    layout
16}
17
18// TODO Add Option for error case
19fn array_alloc<T>(count: usize) -> *mut T {
20    let layout = array_layout::<T>(count);
21
22    unsafe {
23        alloc::alloc(layout) as *mut T
24    }
25}
26
27fn array_realloc<T>(ptr: *mut T, count: usize, new_count: usize) -> *mut T {
28    if new_count == count {
29        return ptr;
30    }
31
32    let layout = array_layout::<T>(count);
33
34    unsafe {
35        alloc::realloc(
36            ptr as *mut u8,
37            layout,
38            array_layout::<T>(new_count).size()
39        ) as *mut T
40    }
41}
42
43fn array_dealloc<T>(ptr: *mut T, count: usize) {
44    // Safety: memory was allocated with same pointer and layout alignment
45    unsafe {
46        alloc::dealloc(
47            ptr as *mut u8,
48            array_layout::<T>(count)
49        )
50    }
51}
52
53
54pub struct Chunks<T: Clone, const BOUNDS_CHECK: bool = true>
55{
56    pub ptr: *mut T,
57    pub count: usize,
58}
59
60impl<
61    T: Copy + Clone,
62    const BC: bool,
63> Chunks<T, BC> {
64
65    pub fn memset_copy(&mut self, value: T) {
66        for i in 0..self.count {
67            // ptr::write(self.ptr.add(i), value);
68            self[i] = value;
69        }
70    }
71
72    // Constructor
73    pub fn filled_copy(value: T, count: usize) -> Self {
74        let mut c: Self = Self::alloc(count);
75        c.memset_copy(value);
76        c
77    }
78
79    pub fn from_slice_copy(from: &[T]) -> Self {
80        let count: usize = from.len();
81        let c = Self::alloc(count);
82
83        // --> Would work, but only for Copy types
84        if count > 0 {
85            unsafe {
86                ptr::copy(from.as_ptr(), c.ptr, count)
87            }
88        }
89
90        c
91    }
92}
93
94impl<
95    T: Clone + Display,
96    const BC: bool,
97> Chunks<T, BC> {
98    pub fn memset_clone(&mut self, value: T) {
99        for i in 0..self.count {
100            // Err: invalid memory reference
101            // self[i] = value.clone();
102
103            self.write_index(i, value.clone());
104        }
105    }
106
107    // Constructor
108    // TODO Can we reuse one by another
109    pub fn filled_clone(value: T, count: usize) -> Self {
110        let mut c: Self = Self::alloc(count);
111        c.memset_clone(value);
112        c
113    }
114
115}
116
117impl<
118    T: Clone + Display,
119    const BC: bool,
120> Chunks<T, BC> {
121    pub fn from_slice_clone(from: &[T]) -> Self {
122        let count: usize = from.len();
123        let mut c = Self::alloc(count);
124
125        // --> Doesn't work: String-like structs gets double freed
126        //if count > 0 {
127        //    unsafe {
128        //        ptr::copy(from.as_ptr(), c.ptr, count)
129        //    }
130        //}
131        // std::mem::forget(from.as_ptr());
132
133        for i in 0..count {
134            // We are obliged to clone
135            // Using write_index because memory is zeroed
136            c.write_index(i, from[i].clone())
137        }
138
139        c
140    }
141}
142
143
144impl<
145    T: Clone,
146    const BC: bool,
147> Chunks<T, BC> {
148    // Constructor
149    pub fn alloc(count: usize) -> Self {
150        Self {
151            ptr: array_alloc::<T>(count),
152            count,
153        }
154    }
155
156    pub fn dealloc(&mut self) {
157        if self.allocated() {
158            array_dealloc(self.ptr, self.count);
159        }
160
161        self.ptr = ptr::null::<T>() as *mut T;
162        self.count = 0;
163    }
164
165    pub fn realloc(&mut self, new_count: usize) {
166        if self.allocated() {
167            self.ptr = array_realloc(self.ptr, self.count, new_count);
168        } else {
169            self.ptr = array_alloc(new_count);
170        }
171        self.count = new_count;
172    }
173
174    pub fn grow(&mut self, delta: usize) {
175        if !self.allocated() {
176            // Copy is in action? How efficiently?
177            // self = Self::alloc(delta);
178            return;
179        }
180        self.realloc(self.count + delta);
181    }
182
183    pub fn allocated(&self) -> bool {
184        !self.ptr.is_null() && self.count > 0
185    }
186
187    pub fn as_ptr(&self) -> *const T {
188        self.ptr as *const T
189    }
190
191    pub fn as_mut_ptr(&self) -> *mut T {
192        self.ptr
193    }
194
195    pub fn as_array<const N: usize>(&self) -> Option<&[T; N]> {
196        if N != self.count {
197            None
198        } else {
199            // Doesnt work
200            // &self.ptr as &[T; N]
201            let ptr = self.as_ptr() as *const [T; N];
202            unsafe {
203                Some(&*ptr)
204            }
205        }
206    }
207
208    pub fn as_slice(&self) -> &[T] {
209        unsafe {
210            slice::from_raw_parts(self.ptr, self.count)
211        }
212    }
213
214    pub fn as_mut_slice(&mut self) -> &mut [T] {
215        unsafe {
216            std::slice::from_raw_parts_mut(self.ptr, self.count)
217        }
218    }
219
220    pub fn indices(&self) -> std::ops::Range<usize> {
221        0..self.count
222    }
223
224    // Private
225    fn bounds(&self, index: usize) -> bool {
226        match BC {
227            false => true,
228            true => 0 <= index && index < self.count,
229        }
230    }
231
232    /// Replaces mutable acces via index like `self.data[self.len] = elem`
233    /// by providing an access to an element via pointer `*mut T`
234    /// rather than reference `&mut T`
235    ///
236    /// This is made for objects with custom Drop trait (such as String):
237    /// Trying to overwrite memory location by `&T` reference (returned by index_mut)
238    /// causes invokation of drop().
239    /// But this is unwanted behaviour for memory without an actual object
240    /// and will lead to "invalid memory reference" error in this case.
241    pub fn write_index(&mut self, index: usize, value: T) {
242        // TODO match
243        let p: *mut T = self.get_mut_ptr(index).unwrap();
244        unsafe {
245            p.write(value);
246        }
247    }
248
249    // === PRIVATE ===
250    fn get_ptr(&self, index: usize) -> Result<*const T, &'static str> {
251        // Safety: Out-of-bounds is checked
252        if self.bounds(index) {
253            unsafe {
254                Ok(self.ptr.add(index) as *const T)
255            }
256        } else {
257            Err("Index out of bounds")
258        }
259    }
260
261    fn get_mut_ptr(&mut self, index: usize) -> Result<*mut T, &'static str> {
262        // Safety: Out-of-bounds is checked
263        if self.bounds(index) {
264            unsafe {
265                Ok(self.ptr.add(index))
266            }
267        } else {
268            Err("Index out of bounds")
269        }
270    }
271
272    //
273    //fn get(&self, index: usize) -> Result<&T, &'static str> {
274    //    // Safety: Out-of-bounds is checked
275    //    if self.bounds(index) {
276    //        unsafe {
277    //            // TODO Maybe return by reference?
278    //            // Does &mut *... is a borrowing, i.e. moving?
279    //            // Looks like overhead of moving twice
280    //            Ok(&*self.ptr.add(index))
281    //        }
282    //    } else {
283    //        Err("Index out of bounds")
284    //    }
285    //}
286
287    fn get_mut(&mut self, index: usize) -> Result<&mut T, &'static str> {
288        // TODO Check overheads of such solution
289        // May it be done better?
290        //match self.get(index) {
291        //    // === Error: [E0605]: non-primitive cast: `&T` as `&mut T`
292        //    Ok(value) => Ok(value as &mut T),
293        //    Err(err) => panic!("{}", err),
294        //}
295
296        if self.bounds(index) {
297            // Safety: Out-of-bounds is checked
298            unsafe {
299                Ok(&mut *self.ptr.add(index))
300            }
301        } else {
302            Err("Index out of bounds")
303        }
304    }
305    // TODO is it right approach in Rust to have mut & const function's duplicates?
306}
307
308// ================== INDEX & INDEX_MUT ==================
309// TODO Seems that cannot use self[i] = string1; // (String)
310// Because returning a reference to a non-existing type value
311
312impl<
313    T: Clone,
314    const BC: bool,
315> Index<usize> for Chunks<T, BC> {
316    type Output = T;
317
318    fn index(&self, index: usize) -> &Self::Output {
319        unsafe {
320            &*self.get_ptr(index).unwrap()
321        }
322    }
323}
324
325impl<
326    T: Clone,
327    const BC: bool,
328> IndexMut<usize> for Chunks<T, BC> {
329    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
330        unsafe {
331            &mut *self.get_mut_ptr(index).unwrap()
332        }
333    }
334}
335
336// ================== FMT ==================
337
338impl<
339    T: Display + Clone,
340    const BC: bool,
341> fmt::Debug for Chunks<T, BC> {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(f, "Chunks: [").unwrap();
344        for i in 0..self.count {
345            if i > 0 {
346                write!(f, ", ").unwrap();
347            }
348            // --> Works improperly; Seems that it frees a pointer obtained, and this cuases an
349            // --> issue for Clone types
350            // unsafe {
351            //     write!(f, "{:}", self.get_ptr(i).unwrap().read()).unwrap();
352            // }
353
354            // --> Also doesn't work, because data may be zeroed
355            // write!(f, "{}", self[i]).unwrap();
356            // --> TODO Add check for whether current memory is assigned with values or not
357
358            let val: T = unsafe {
359                self.ptr.add(i).read()
360            };
361            write!(f, "{}", val).unwrap();
362
363            // --> We don't wont to drop a value
364            std::mem::forget(val);
365        }
366        write!(f, "]")
367    }
368}
369
370// ================== DROP ==================
371
372impl<
373    T: Clone,
374    const BC: bool,
375> Drop for Chunks<T, BC> {
376    fn drop(&mut self) {
377        if self.allocated() && false {
378            self.dealloc();
379        }
380    }
381}