Skip to main content

qubit_io/util/
unchecked_slice.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5// =============================================================================
6//! Low-level unchecked slice helpers in a dedicated namespace.
7//!
8//! These helpers avoid bound checks and are intended for call sites that
9//! already validate bounds in their own protocol.
10
11use core::mem;
12use std::io::{
13    Error,
14    ErrorKind,
15    Result,
16};
17
18/// Namespace for low-level slice operations without bound checks.
19///
20/// All functions are unsafe and assume the caller has already validated their
21/// preconditions. Safety requirements in each method are explicit.
22pub enum UncheckedSlice {}
23
24impl UncheckedSlice {
25    /// Returns the exclusive end index of a checked slice range.
26    ///
27    /// # Parameters
28    ///
29    /// - `len`: Slice length.
30    /// - `start`: Start index in the slice.
31    /// - `count`: Number of requested items after `start`.
32    ///
33    /// # Returns
34    ///
35    /// `Some(end)` if `start + count <= len` and no overflow occurs, or
36    /// `None` when the requested range does not fit inside the slice.
37    #[inline(always)]
38    pub const fn range_end(
39        len: usize,
40        start: usize,
41        count: usize,
42    ) -> Option<usize> {
43        match start.checked_add(count) {
44            Some(end) if len >= end => Some(end),
45            _ => None,
46        }
47    }
48
49    /// Returns whether a slice has at least `count` readable/writable items
50    /// from `start`.
51    ///
52    /// # Parameters
53    ///
54    /// - `len`: Slice length.
55    /// - `start`: Start index in the slice.
56    /// - `count`: Number of requested items after `start`.
57    ///
58    /// # Returns
59    ///
60    /// `true` if `start + count <= len` and no overflow occurs.
61    #[inline(always)]
62    pub const fn range_fits(len: usize, start: usize, count: usize) -> bool {
63        Self::range_end(len, start, count).is_some()
64    }
65
66    /// Returns the exclusive end index of a checked slice range as an I/O
67    /// result.
68    ///
69    /// # Parameters
70    ///
71    /// - `len`: Slice length.
72    /// - `start`: Start index in the slice.
73    /// - `count`: Number of requested items after `start`.
74    /// - `message`: Error message used when the requested range is invalid.
75    ///
76    /// # Returns
77    ///
78    /// Returns the exclusive end index when the range fits inside the slice.
79    ///
80    /// # Errors
81    ///
82    /// Returns [`ErrorKind::InvalidInput`] with `message` when
83    /// `start + count` overflows or exceeds `len`.
84    #[inline]
85    pub fn checked_range_end(
86        len: usize,
87        start: usize,
88        count: usize,
89        message: &'static str,
90    ) -> Result<usize> {
91        Self::range_end(len, start, count)
92            .ok_or_else(|| Error::new(ErrorKind::InvalidInput, message))
93    }
94
95    /// Reads one value from an unchecked slice index.
96    ///
97    /// # Parameters
98    ///
99    /// - `input`: Source slice.
100    /// - `index`: Start index that must be valid for reading one item.
101    ///
102    /// # Safety
103    ///
104    /// The caller must guarantee that `index < input.len()`.
105    #[inline(always)]
106    pub unsafe fn read<T: Copy>(input: &[T], index: usize) -> T {
107        // SAFETY: The caller guarantees that `index` is in-bounds.
108        unsafe { *input.as_ptr().add(index) }
109    }
110
111    /// Writes one value to an unchecked mutable slice index.
112    ///
113    /// This replaces the existing initialized element at `index`. The previous
114    /// value is dropped before `value` is moved into the slot.
115    ///
116    /// # Parameters
117    ///
118    /// - `output`: Destination slice.
119    /// - `index`: Start index that must be valid for writing one item.
120    /// - `value`: Value to write.
121    ///
122    /// # Safety
123    ///
124    /// The caller must guarantee that `index < output.len()`.
125    #[inline(always)]
126    pub unsafe fn write<T>(output: &mut [T], index: usize, value: T) {
127        // SAFETY: The caller guarantees that `index` is in-bounds.
128        unsafe {
129            *output.as_mut_ptr().add(index) = value;
130        }
131    }
132
133    /// Returns an immutable reference to one value at an unchecked slice index.
134    ///
135    /// # Parameters
136    ///
137    /// - `input`: Source slice.
138    /// - `index`: Start index that must be valid for reading one item.
139    ///
140    /// # Safety
141    ///
142    /// The caller must guarantee that `index < input.len()`.
143    #[inline(always)]
144    pub unsafe fn get<T>(input: &[T], index: usize) -> &T {
145        // SAFETY: The caller guarantees that `index` is in-bounds.
146        unsafe { &*input.as_ptr().add(index) }
147    }
148
149    /// Returns a mutable reference to one value at an unchecked mutable slice
150    /// index.
151    ///
152    /// # Parameters
153    ///
154    /// - `output`: Destination slice.
155    /// - `index`: Start index that must be valid for writing one item.
156    ///
157    /// # Safety
158    ///
159    /// The caller must guarantee that `index < output.len()`.
160    #[inline(always)]
161    pub unsafe fn get_mut<T>(output: &mut [T], index: usize) -> &mut T {
162        // SAFETY: The caller guarantees that `index` is in-bounds.
163        unsafe { &mut *output.as_mut_ptr().add(index) }
164    }
165
166    /// Returns an immutable subslice at an unchecked offset and length.
167    ///
168    /// # Parameters
169    ///
170    /// - `input`: Source slice.
171    /// - `start`: Start index in `input`.
172    /// - `count`: Number of items in the returned subslice.
173    ///
174    /// # Safety
175    ///
176    /// The caller must guarantee that `start + count <= input.len()` and that
177    /// the addition does not overflow.
178    #[inline(always)]
179    pub unsafe fn subslice<T>(input: &[T], start: usize, count: usize) -> &[T] {
180        debug_assert!(
181            Self::range_fits(input.len(), start, count),
182            "subslice range exceeds input buffer"
183        );
184        // SAFETY: The caller guarantees that the range is valid inside `input`.
185        unsafe { core::slice::from_raw_parts(input.as_ptr().add(start), count) }
186    }
187
188    /// Returns a mutable subslice at an unchecked offset and length.
189    ///
190    /// # Parameters
191    ///
192    /// - `output`: Destination slice.
193    /// - `start`: Start index in `output`.
194    /// - `count`: Number of items in the returned subslice.
195    ///
196    /// # Safety
197    ///
198    /// The caller must guarantee that `start + count <= output.len()` and that
199    /// the addition does not overflow.
200    #[inline(always)]
201    pub unsafe fn subslice_mut<T>(
202        output: &mut [T],
203        start: usize,
204        count: usize,
205    ) -> &mut [T] {
206        debug_assert!(
207            Self::range_fits(output.len(), start, count),
208            "subslice range exceeds output buffer"
209        );
210        // SAFETY: The caller guarantees that the range is valid inside
211        // `output`.
212        unsafe {
213            core::slice::from_raw_parts_mut(
214                output.as_mut_ptr().add(start),
215                count,
216            )
217        }
218    }
219
220    /// Copies `count` values between unchecked slice offsets.
221    ///
222    /// # Parameters
223    ///
224    /// - `source`: Source slice.
225    /// - `source_index`: Source offset, must be valid for `count` items.
226    /// - `destination`: Destination slice.
227    /// - `destination_index`: Destination offset, must be valid for `count`
228    ///   items.
229    /// - `count`: Number of items to copy.
230    ///
231    /// # Safety
232    ///
233    /// The caller must guarantee that both source and destination ranges are
234    /// valid for `count` elements, the copy does not overflow pointer
235    /// arithmetic, and the two memory regions do not overlap.
236    #[inline(always)]
237    pub unsafe fn copy_nonoverlapping<T: Copy>(
238        source: &[T],
239        source_index: usize,
240        destination: &mut [T],
241        destination_index: usize,
242        count: usize,
243    ) {
244        debug_assert!(
245            Self::range_fits(source.len(), source_index, count),
246            "unchecked source range exceeds source buffer"
247        );
248        debug_assert!(
249            Self::range_fits(destination.len(), destination_index, count),
250            "unchecked destination range exceeds destination buffer"
251        );
252        // SAFETY: The caller guarantees both ranges are valid and
253        // non-overlapping.
254        unsafe {
255            let src = source.as_ptr().add(source_index);
256            let dst = destination.as_mut_ptr().add(destination_index);
257            core::ptr::copy_nonoverlapping(src, dst, count);
258        }
259    }
260
261    /// Copies `count` values between unchecked offsets in one buffer.
262    ///
263    /// Overlapping source and destination ranges are supported.
264    ///
265    /// # Parameters
266    ///
267    /// - `buffer`: Buffer containing both ranges.
268    /// - `source_index`: Source offset, must be valid for `count` items.
269    /// - `destination_index`: Destination offset, must be valid for `count`
270    ///   items.
271    /// - `count`: Number of values to copy.
272    ///
273    /// # Safety
274    ///
275    /// The caller must guarantee that both ranges lie within `buffer` and that
276    /// `source_index + count` and `destination_index + count` do not overflow
277    /// `usize`.
278    #[inline(always)]
279    pub unsafe fn copy_within<T: Copy>(
280        buffer: &mut [T],
281        source_index: usize,
282        destination_index: usize,
283        count: usize,
284    ) {
285        debug_assert!(
286            Self::range_fits(buffer.len(), source_index, count),
287            "unchecked source range exceeds buffer"
288        );
289        debug_assert!(
290            Self::range_fits(buffer.len(), destination_index, count),
291            "unchecked destination range exceeds buffer"
292        );
293        // SAFETY: The caller guarantees both ranges are valid; `copy` supports
294        // overlapping regions within the same allocation.
295        unsafe {
296            let source = buffer.as_ptr().add(source_index);
297            let destination = buffer.as_mut_ptr().add(destination_index);
298            core::ptr::copy(source, destination, count);
299        }
300    }
301
302    /// Reads one value from an unchecked unaligned byte slice offset.
303    ///
304    /// # Parameters
305    ///
306    /// - `input`: Source byte buffer.
307    /// - `index`: Byte offset in `input`.
308    ///
309    /// # Safety
310    ///
311    /// The caller must guarantee that `index..index + size_of::<T>()` is a
312    /// valid readable range inside `input` and that the addition does not
313    /// overflow. Every byte in that range must be initialized and together
314    /// form a valid value of `T`, including all bit-validity and pointer
315    /// provenance requirements imposed by `T`.
316    ///
317    /// `T: Copy` does not guarantee that an arbitrary byte sequence is a valid
318    /// `T`. Primitive integer and floating-point types satisfy this
319    /// representation requirement; types with restricted bit patterns,
320    /// references, or pointers require additional justification from the
321    /// caller.
322    #[inline(always)]
323    pub unsafe fn read_ne_unaligned<T: Copy>(input: &[u8], index: usize) -> T {
324        debug_assert!(
325            Self::range_fits(input.len(), index, mem::size_of::<T>()),
326            "unchecked input range exceeds source buffer"
327        );
328        // SAFETY: The caller guarantees byte-level validity for this unaligned
329        // load.
330        unsafe {
331            let src = input.as_ptr().add(index).cast::<T>();
332            core::ptr::read_unaligned(src)
333        }
334    }
335
336    /// Writes one value to an unchecked unaligned byte slice offset.
337    ///
338    /// # Parameters
339    ///
340    /// - `output`: Destination byte buffer.
341    /// - `index`: Byte offset in `output`.
342    /// - `value`: Value to write.
343    ///
344    /// # Safety
345    ///
346    /// The caller must guarantee that `index..index + size_of::<T>()` is a
347    /// valid writable range inside `output` and that the addition does not
348    /// overflow. The complete object representation of `value`, including any
349    /// padding bytes, must be initialized and valid to store in and later
350    /// observe through the destination byte slice.
351    ///
352    /// `T: Copy` does not guarantee initialized padding or unrestricted
353    /// bytewise representation. Types containing padding, references, or
354    /// pointers require additional justification from the caller.
355    #[inline(always)]
356    pub unsafe fn write_ne_unaligned<T: Copy>(
357        output: &mut [u8],
358        index: usize,
359        value: T,
360    ) {
361        debug_assert!(
362            Self::range_fits(output.len(), index, mem::size_of::<T>()),
363            "unchecked output range exceeds destination buffer"
364        );
365        // SAFETY: The caller guarantees byte-level validity for this unaligned
366        // store.
367        unsafe {
368            let dst = output.as_mut_ptr().add(index).cast::<T>();
369            core::ptr::write_unaligned(dst, value);
370        }
371    }
372}