sel4_abstract_ptr/abstract_ptr/
slice_operations.rs

1//
2// Copyright 2024, Colias Group, LLC
3// Copyright (c) 2020 Philipp Oppermann
4//
5// SPDX-License-Identifier: MIT OR Apache-2.0
6//
7
8use core::{
9    ops::{Range, RangeBounds},
10    ptr::{self, NonNull},
11    slice::SliceIndex,
12};
13
14use crate::{
15    access::{Access, Readable, Writable},
16    core_ext::{
17        non_null_index, non_null_slice_as_mut_ptr, non_null_slice_len, range, AbstractPtrSliceIndex,
18    },
19    memory_type::BulkOps,
20    AbstractPtr,
21};
22
23impl<'a, M, T, A> AbstractPtr<'a, M, [T], A> {
24    pub fn len(self) -> usize {
25        non_null_slice_len(self.pointer)
26    }
27
28    pub fn is_empty(self) -> bool {
29        self.len() == 0
30    }
31
32    pub fn index<I>(self, index: I) -> AbstractPtr<'a, M, <I as SliceIndex<[T]>>::Output, A>
33    where
34        I: AbstractPtrSliceIndex<[T]> + SliceIndex<[()]> + Clone,
35        A: Access,
36    {
37        unsafe { self.map(|slice| non_null_index(slice, index)) }
38    }
39
40    pub fn iter(self) -> impl Iterator<Item = AbstractPtr<'a, M, T, A>>
41    where
42        A: Access,
43    {
44        let ptr = non_null_slice_as_mut_ptr(self.pointer);
45        let len = self.len();
46        (0..len)
47            .map(move |i| unsafe { AbstractPtr::new_generic(NonNull::new_unchecked(ptr.add(i))) })
48    }
49
50    pub fn copy_into_slice(self, dst: &mut [T])
51    where
52        M: BulkOps<T>,
53        A: Readable,
54    {
55        let len = self.len();
56        assert_eq!(
57            len,
58            dst.len(),
59            "destination and source slices have different lengths"
60        );
61        unsafe {
62            M::memcpy_from(
63                dst.as_mut_ptr(),
64                non_null_slice_as_mut_ptr(self.pointer),
65                len,
66            );
67        }
68    }
69
70    pub fn copy_from_slice(self, src: &[T])
71    where
72        M: BulkOps<T>,
73        A: Writable,
74    {
75        let len = self.len();
76        assert_eq!(
77            len,
78            src.len(),
79            "destination and source slices have different lengths"
80        );
81        unsafe {
82            M::memcpy_into(non_null_slice_as_mut_ptr(self.pointer), src.as_ptr(), len);
83        }
84    }
85
86    pub fn copy_within(self, src: impl RangeBounds<usize>, dest: usize)
87    where
88        M: BulkOps<T>,
89        A: Readable + Writable,
90    {
91        let len = self.pointer.len();
92        // implementation taken from https://github.com/rust-lang/rust/blob/683d1bcd405727fcc9209f64845bd3b9104878b8/library/core/src/slice/mod.rs#L2726-L2738
93        let Range {
94            start: src_start,
95            end: src_end,
96        } = range(src, ..len);
97        let count = src_end - src_start;
98        assert!(dest <= len - count, "dest is out of bounds");
99        unsafe {
100            M::memmove(
101                non_null_slice_as_mut_ptr(self.pointer).add(dest),
102                non_null_slice_as_mut_ptr(self.pointer).add(src_start),
103                count,
104            );
105        }
106    }
107
108    #[allow(clippy::type_complexity)]
109    pub fn split_at(self, mid: usize) -> (AbstractPtr<'a, M, [T], A>, AbstractPtr<'a, M, [T], A>)
110    where
111        A: Access,
112    {
113        assert!(mid <= self.pointer.len());
114        // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
115        // fulfills the requirements of `from_raw_parts_mut`.
116        unsafe { self.split_at_unchecked(mid) }
117    }
118
119    #[allow(clippy::type_complexity)]
120    unsafe fn split_at_unchecked(
121        self,
122        mid: usize,
123    ) -> (AbstractPtr<'a, M, [T], A>, AbstractPtr<'a, M, [T], A>)
124    where
125        A: Access,
126    {
127        // SAFETY: Caller has to check that `0 <= mid <= self.len()`
128        unsafe {
129            (
130                AbstractPtr::new_generic(non_null_index(self.pointer, ..mid)),
131                AbstractPtr::new_generic(non_null_index(self.pointer, mid..)),
132            )
133        }
134    }
135
136    #[allow(clippy::type_complexity)]
137    pub fn as_chunks<const N: usize>(
138        self,
139    ) -> (AbstractPtr<'a, M, [[T; N]], A>, AbstractPtr<'a, M, [T], A>)
140    where
141        A: Access,
142    {
143        assert_ne!(N, 0);
144        let len = self.pointer.len() / N;
145        let (multiple_of_n, remainder) = self.split_at(len * N);
146        // SAFETY: We already panicked for zero, and ensured by construction
147        // that the length of the subslice is a multiple of N.
148        let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() };
149        (array_slice, remainder)
150    }
151
152    pub unsafe fn as_chunks_unchecked<const N: usize>(self) -> AbstractPtr<'a, M, [[T; N]], A>
153    where
154        A: Access,
155    {
156        debug_assert_ne!(N, 0);
157        debug_assert_eq!(self.pointer.len() % N, 0);
158        let new_len = self.pointer.len() / N;
159        // SAFETY: We cast a slice of `new_len * N` elements into
160        // a slice of `new_len` many `N` elements chunks.
161        let pointer = NonNull::new(ptr::slice_from_raw_parts_mut(
162            non_null_slice_as_mut_ptr(self.pointer).cast(),
163            new_len,
164        ))
165        .unwrap();
166        unsafe { AbstractPtr::new_generic(pointer) }
167    }
168}
169
170impl<M, A> AbstractPtr<'_, M, [u8], A> {
171    pub fn fill(self, value: u8)
172    where
173        M: BulkOps<u8>,
174        A: Writable,
175    {
176        unsafe {
177            M::memset(
178                non_null_slice_as_mut_ptr(self.pointer),
179                value,
180                non_null_slice_len(self.pointer),
181            );
182        }
183    }
184}
185
186/// Methods for converting arrays to slices
187impl<'a, M, T, A, const N: usize> AbstractPtr<'a, M, [T; N], A> {
188    pub fn as_slice(self) -> AbstractPtr<'a, M, [T], A>
189    where
190        A: Access,
191    {
192        unsafe {
193            self.map(|array| {
194                NonNull::new(ptr::slice_from_raw_parts_mut(array.as_ptr() as *mut T, N)).unwrap()
195            })
196        }
197    }
198}