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}