nstd_sys/core/
slice.rs

1//! A view into a sequence of values in memory.
2use crate::{
3    core::{
4        mem::{nstd_core_mem_copy, nstd_core_mem_is_aligned},
5        optional::{gen_optional, NSTDOptional},
6    },
7    NSTDAny, NSTDAnyMut, NSTDUInt, NSTD_INT_MAX, NSTD_NULL,
8};
9use nstdapi::nstdapi;
10
11/// An immutable view into a sequence of values in memory.
12#[nstdapi]
13#[derive(Clone, Copy)]
14pub struct NSTDSlice {
15    /// A pointer to the first element in the slice.
16    ptr: NSTDAny,
17    /// The number of elements in the slice.
18    len: NSTDUInt,
19    /// The slice's stride.
20    stride: NSTDUInt,
21    /// The slice's align.
22    align: NSTDUInt,
23}
24impl NSTDSlice {
25    /// Creates a new [`NSTDSlice`] from a Rust slice.
26    #[inline]
27    #[allow(dead_code)]
28    pub(crate) const fn from_slice<T>(s: &[T]) -> Self {
29        Self {
30            ptr: s.as_ptr().cast(),
31            len: s.len(),
32            stride: core::mem::size_of::<T>(),
33            align: core::mem::align_of::<T>(),
34        }
35    }
36
37    /// Returns the number of bytes that this slice covers.
38    #[inline]
39    #[allow(clippy::arithmetic_side_effects)]
40    pub(crate) const fn byte_len(&self) -> usize {
41        self.len * self.stride
42    }
43
44    /// Creates a Rust slice from this `NSTDSlice`.
45    ///
46    /// Returns [`None`] if `size_of::<T>()` does not match the slice's stride.
47    ///
48    /// # Safety
49    ///
50    /// - The `NSTDSlice`'s data must remain valid and unmodified while the returned slice is in
51    /// use.
52    ///
53    /// - The slice's data must be properly aligned.
54    #[inline]
55    pub(crate) const unsafe fn as_slice<T>(&self) -> Option<&[T]> {
56        match self.stride == core::mem::size_of::<T>() {
57            true => Some(core::slice::from_raw_parts(self.ptr.cast(), self.len)),
58            false => None,
59        }
60    }
61}
62gen_optional!(NSTDOptionalSlice, NSTDSlice);
63
64/// Creates a new slice from raw data.
65///
66/// # Parameters:
67///
68/// - `NSTDAny ptr` - A pointer to the first element in the sequence.
69///
70/// - `NSTDUInt stride` - The number of bytes each element occupies.
71///
72/// - `NSTDUInt align` - The alignment of each element in the slice.
73///
74/// - `NSTDUInt len` - The number of elements in the sequence.
75///
76/// # Returns
77///
78/// `NSTDOptionalSlice slice` - The new slice on success, or an uninitialized "none" variant if
79/// `ptr` is null, `align` is not a power of two, `stride` is not a multiple of `align`, `ptr` is
80/// not a multiple of `align`, or the slice's length in bytes would exceed `NSTDInt`'s max value.
81#[nstdapi]
82pub fn nstd_core_slice_new(
83    ptr: NSTDAny,
84    stride: NSTDUInt,
85    align: NSTDUInt,
86    len: NSTDUInt,
87) -> NSTDOptionalSlice {
88    if let Some(size) = len.checked_mul(stride) {
89        #[allow(clippy::arithmetic_side_effects)]
90        if size <= NSTD_INT_MAX
91            && crate::core::mem::is_power_of_two(align)
92            && stride % align == 0
93            && !ptr.is_null()
94            && nstd_core_mem_is_aligned(ptr, align)
95        {
96            return NSTDOptional::Some(NSTDSlice {
97                ptr,
98                len,
99                stride,
100                align,
101            });
102        }
103    }
104    NSTDOptional::None
105}
106
107/// Creates a new slice from raw data without checking if `ptr` is null.
108///
109/// # Parameters:
110///
111/// - `NSTDAny ptr` - A pointer to the first element in the sequence.
112///
113/// - `NSTDUInt stride` - The number of bytes each element occupies.
114///
115/// - `NSTDUInt align` - The alignment of each element in the slice.
116///
117/// - `NSTDUInt len` - The number of elements in the sequence.
118///
119/// # Returns
120///
121/// `NSTDSlice slice` - The new slice.
122///
123/// # Safety
124///
125/// - `ptr` must be non-null.
126///
127/// - `align` must be a nonzero power of two.
128///
129/// - `stride` must be a multiple of `align`.
130///
131/// - `ptr` must be a multiple of `align`.
132///
133/// - The slice's total length in bytes will not exceed `NSTDInt`'s max value.
134#[inline]
135#[nstdapi]
136pub const unsafe fn nstd_core_slice_new_unchecked(
137    ptr: NSTDAny,
138    stride: NSTDUInt,
139    align: NSTDUInt,
140    len: NSTDUInt,
141) -> NSTDSlice {
142    NSTDSlice {
143        ptr,
144        len,
145        stride,
146        align,
147    }
148}
149
150/// Creates a new empty slice with a given `stride`.
151///
152/// # Parameters:
153///
154/// - `NSTDUInt stride` - The number of bytes each element occupies.
155///
156/// - `NSTDUInt align` - The alignment of each element in the slice.
157///
158/// # Returns
159///
160/// `NSTDSlice slice` - The new empty slice.
161///
162/// # Panics
163///
164/// This operation will panic if either `align` is not a power of two or `stride` is not a multiple
165/// of `align`.
166#[inline]
167#[nstdapi]
168#[allow(clippy::arithmetic_side_effects)]
169pub const fn nstd_core_slice_empty(stride: NSTDUInt, align: NSTDUInt) -> NSTDSlice {
170    assert!(crate::core::mem::is_power_of_two(align) && stride % align == 0);
171    NSTDSlice {
172        ptr: align as NSTDAny,
173        len: 0,
174        stride,
175        align,
176    }
177}
178
179/// Returns a raw pointer to the slice's memory.
180///
181/// # Parameters:
182///
183/// - `const NSTDSlice *slice` - The slice.
184///
185/// # Returns
186///
187/// `AnyConst ptr` - A raw pointer to the slice's memory.
188///
189/// # Example
190///
191/// ```
192/// use nstd_sys::core::slice::{nstd_core_slice_as_ptr, nstd_core_slice_new};
193///
194/// unsafe {
195///     let bytes = "Hello, world!".as_bytes();
196///     let bytes_ptr = bytes.as_ptr().cast();
197///     let slice = nstd_core_slice_new(bytes_ptr, 1, 1, bytes.len()).unwrap();
198///     assert!(nstd_core_slice_as_ptr(&slice) == bytes_ptr);
199/// }
200/// ```
201#[inline]
202#[nstdapi]
203pub const fn nstd_core_slice_as_ptr(slice: &NSTDSlice) -> NSTDAny {
204    slice.ptr
205}
206
207/// Returns the number of elements in an immutable slice.
208///
209/// # Parameters:
210///
211/// - `const NSTDSlice *slice` - The immutable slice.
212///
213/// # Returns
214///
215/// `NSTDUInt len` - The length of the slice.
216///
217/// # Example
218///
219/// ```
220/// use nstd_sys::core::slice::{nstd_core_slice_len, nstd_core_slice_new};
221///
222/// unsafe {
223///     let bytes = "Goodbye, world!".as_bytes();
224///     let len = bytes.len();
225///     let slice = nstd_core_slice_new(bytes.as_ptr().cast(), 1, 1, len).unwrap();
226///     assert!(nstd_core_slice_len(&slice) == len);
227/// }
228/// ```
229#[inline]
230#[nstdapi]
231pub const fn nstd_core_slice_len(slice: &NSTDSlice) -> NSTDUInt {
232    slice.len
233}
234
235/// Returns the amount of bytes each value in a slice occupies.
236///
237/// # Parameters:
238///
239/// - `const NSTDSlice *slice` - The slice.
240///
241/// # Returns
242///
243/// `NSTDUInt stride` - The size of each value in the slice.
244///
245/// # Example
246///
247/// ```
248/// use nstd_sys::core::slice::{nstd_core_slice_stride, nstd_core_slice_new};
249///
250/// unsafe {
251///     let bytes = "Hello, world!".as_bytes();
252///     let slice = nstd_core_slice_new(bytes.as_ptr().cast(), 1, 1, bytes.len()).unwrap();
253///     assert!(nstd_core_slice_stride(&slice) == 1);
254/// }
255/// ```
256#[inline]
257#[nstdapi]
258pub const fn nstd_core_slice_stride(slice: &NSTDSlice) -> NSTDUInt {
259    slice.stride
260}
261
262/// Returns the alignment of each value in a slice.
263///
264/// # Parameters:
265///
266/// - `const NSTDSlice *slice` - The slice.
267///
268/// # Returns
269///
270/// `NSTDUInt align` - The alignment of each value in the slice.
271///
272/// # Example
273///
274/// ```
275/// use nstd_sys::core::slice::{nstd_core_slice_align, nstd_core_slice_new};
276///
277/// unsafe {
278///     let bytes = "Hello, world!".as_bytes();
279///     let slice = nstd_core_slice_new(bytes.as_ptr().cast(), 1, 1, bytes.len()).unwrap();
280///     assert!(nstd_core_slice_align(&slice) == 1);
281/// }
282/// ```
283#[inline]
284#[nstdapi]
285pub const fn nstd_core_slice_align(slice: &NSTDSlice) -> NSTDUInt {
286    slice.align
287}
288
289/// Returns an immutable pointer to the element at index `pos` in `slice`.
290///
291/// # Parameters:
292///
293/// - `const NSTDSlice *slice` - The slice to read an element from.
294///
295/// - `NSTDUInt pos` - The position of the element to get, starting at 0.
296///
297/// # Returns
298///
299/// `NSTDAny element` - A pointer to the element at `pos` or `NSTD_NULL` if `pos` is out
300/// of the slice's boundaries.
301///
302/// # Example
303///
304/// ```
305/// use nstd_sys::core::slice::{nstd_core_slice_get, nstd_core_slice_new};
306///
307/// const STRIDE: usize = core::mem::size_of::<i32>();
308/// const ALIGN: usize = core::mem::align_of::<i32>();
309///
310/// unsafe {
311///     let numbers: [i32; 3] = [33, 103, 45];
312///     let slice =
313///         nstd_core_slice_new(numbers.as_ptr().cast(), STRIDE, ALIGN, numbers.len()).unwrap();
314///
315///     assert!(*nstd_core_slice_get(&slice, 0).cast::<i32>() == 33);
316///     assert!(*nstd_core_slice_get(&slice, 1).cast::<i32>() == 103);
317///     assert!(*nstd_core_slice_get(&slice, 2).cast::<i32>() == 45);
318///     assert!(nstd_core_slice_get(&slice, 3).is_null());
319/// }
320/// ```
321#[inline]
322#[nstdapi]
323pub const fn nstd_core_slice_get(slice: &NSTDSlice, mut pos: NSTDUInt) -> NSTDAny {
324    #[allow(clippy::arithmetic_side_effects)]
325    if pos < slice.len {
326        pos *= slice.stride;
327        // SAFETY: We've checked `pos`.
328        return unsafe { slice.ptr.add(pos) };
329    }
330    NSTD_NULL
331}
332
333/// Returns an immutable pointer to the first element in the slice.
334///
335/// # Parameters:
336///
337/// - `const NSTDSlice *slice` - The slice to get the first element of.
338///
339/// # Returns
340///
341/// `NSTDAny element` - A pointer to the first element in `slice` or `NSTD_NULL` if the
342/// slice is empty.
343///
344/// # Example
345///
346/// ```
347/// use nstd_sys::core::slice::{nstd_core_slice_first, nstd_core_slice_new};
348///
349/// const STRIDE: usize = core::mem::size_of::<u64>();
350/// const ALIGN: usize = core::mem::align_of::<u64>();
351///
352/// unsafe {
353///     let numbers: [u64; 3] = [707, 23043, 8008];
354///     let numbers_ptr = numbers.as_ptr().cast();
355///     let slice = nstd_core_slice_new(numbers_ptr, STRIDE, ALIGN, numbers.len()).unwrap();
356///     let empty = nstd_core_slice_new(numbers_ptr, STRIDE, ALIGN, 0).unwrap();
357///
358///     assert!(nstd_core_slice_first(&slice) == numbers_ptr);
359///     assert!(*nstd_core_slice_first(&slice).cast::<u64>() == 707);
360///     assert!(nstd_core_slice_first(&empty).is_null());
361/// }
362/// ```
363#[inline]
364#[nstdapi]
365pub const fn nstd_core_slice_first(slice: &NSTDSlice) -> NSTDAny {
366    match slice.len > 0 {
367        true => slice.ptr,
368        false => NSTD_NULL,
369    }
370}
371
372/// Returns an immutable pointer to the last element in the slice.
373///
374/// # Parameters:
375///
376/// - `const NSTDSlice *slice` - The slice to get the last element of.
377///
378/// # Returns
379///
380/// `NSTDAny element` - A pointer to the last element in `slice` or `NSTD_NULL` if the
381/// slice is empty.
382///
383/// # Example
384///
385/// ```
386/// use nstd_sys::core::slice::{nstd_core_slice_last, nstd_core_slice_new};
387///
388/// const STRIDE: usize = core::mem::size_of::<u64>();
389/// const ALIGN: usize = core::mem::align_of::<u64>();
390///
391/// unsafe {
392///     let numbers: [u64; 3] = [717, 421, 4317];
393///     let numbers_ptr = numbers.as_ptr().cast();
394///     let slice = nstd_core_slice_new(numbers_ptr, STRIDE, ALIGN, numbers.len()).unwrap();
395///     let empty = nstd_core_slice_new(numbers_ptr, STRIDE, ALIGN, 0).unwrap();
396///
397///     assert!(*nstd_core_slice_last(&slice).cast::<u64>() == 4317);
398///     assert!(nstd_core_slice_last(&empty).is_null());
399/// }
400/// ```
401#[inline]
402#[nstdapi]
403pub const fn nstd_core_slice_last(slice: &NSTDSlice) -> NSTDAny {
404    match slice.len > 0 {
405        #[allow(clippy::arithmetic_side_effects)]
406        true => nstd_core_slice_get(slice, slice.len - 1),
407        false => NSTD_NULL,
408    }
409}
410
411/// A view into a sequence of values in memory.
412#[nstdapi]
413pub struct NSTDSliceMut {
414    /// A pointer to the first element in the slice.
415    ptr: NSTDAnyMut,
416    /// The number of elements in the slice.
417    len: NSTDUInt,
418    /// The slice's stride.
419    stride: NSTDUInt,
420    /// The slice's align.
421    align: NSTDUInt,
422}
423impl NSTDSliceMut {
424    /// Creates a mutable Rust slice from this `NSTDSliceMut`.
425    ///
426    /// Returns [`None`] if `size_of::<T>()` does not match the slice's stride.
427    ///
428    /// # Safety
429    ///
430    /// - The `NSTDSliceMut`'s data must remain valid and unmodified while the returned slice is in
431    /// use.
432    ///
433    /// - The slice's data must be properly aligned.
434    #[inline]
435    #[allow(dead_code)]
436    pub(crate) unsafe fn as_slice_mut<T>(&mut self) -> Option<&mut [T]> {
437        match self.stride == core::mem::size_of::<T>() {
438            true => Some(core::slice::from_raw_parts_mut(self.ptr.cast(), self.len)),
439            false => None,
440        }
441    }
442}
443gen_optional!(NSTDOptionalSliceMut, NSTDSliceMut);
444
445/// Creates a new slice from raw data.
446///
447/// # Parameters:
448///
449/// - `NSTDAnyMut ptr` - A pointer to the first element in the sequence.
450///
451/// - `NSTDUInt stride` - The number of bytes each element occupies.
452///
453/// - `NSTDUInt align` - The alignment of each element in the slice.
454///
455/// - `NSTDUInt len` - The number of elements in the sequence.
456///
457/// # Returns
458///
459/// `NSTDOptionalSliceMut slice` - The new slice on success, or an uninitialized "none" variant if
460/// `ptr` is null, `align` is not a power of two, `stride` is not a multiple of `align`, `ptr` is
461/// not a multiple of `align`, or the slice's length in bytes would exceed `NSTDInt`'s max value.
462#[nstdapi]
463pub fn nstd_core_slice_mut_new(
464    ptr: NSTDAnyMut,
465    stride: NSTDUInt,
466    align: NSTDUInt,
467    len: NSTDUInt,
468) -> NSTDOptionalSliceMut {
469    if let Some(size) = len.checked_mul(stride) {
470        #[allow(clippy::arithmetic_side_effects)]
471        if size <= NSTD_INT_MAX
472            && crate::core::mem::is_power_of_two(align)
473            && stride % align == 0
474            && !ptr.is_null()
475            && nstd_core_mem_is_aligned(ptr, align)
476        {
477            return NSTDOptional::Some(NSTDSliceMut {
478                ptr,
479                len,
480                stride,
481                align,
482            });
483        }
484    }
485    NSTDOptional::None
486}
487
488/// Creates a new slice from raw data without checking if `ptr` is null.
489///
490/// # Parameters:
491///
492/// - `NSTDAnyMut ptr` - A pointer to the first element in the sequence.
493///
494/// - `NSTDUInt stride` - The number of bytes each element occupies.
495///
496/// - `NSTDUInt align` - The alignment of each element in the slice.
497///
498/// - `NSTDUInt len` - The number of elements in the sequence.
499///
500/// # Returns
501///
502/// `NSTDSliceMut slice` - The new slice.
503///
504/// # Safety
505///
506/// - `ptr` must be non-null.
507///
508/// - `align` must be a nonzero power of two.
509///
510/// - `stride` must be a multiple of `align`.
511///
512/// - `ptr` must be a multiple of `align`.
513///
514/// - The slice's total length in bytes will not exceed `NSTDInt`'s max value.
515#[inline]
516#[nstdapi]
517pub const unsafe fn nstd_core_slice_mut_new_unchecked(
518    ptr: NSTDAnyMut,
519    stride: NSTDUInt,
520    align: NSTDUInt,
521    len: NSTDUInt,
522) -> NSTDSliceMut {
523    NSTDSliceMut {
524        ptr,
525        len,
526        stride,
527        align,
528    }
529}
530
531/// Creates a new empty slice with a given `stride`.
532///
533/// # Parameters:
534///
535/// - `NSTDUInt stride` - The number of bytes each element occupies.
536///
537/// - `NSTDUInt align` - The alignment of each element in the slice.
538///
539/// # Returns
540///
541/// `NSTDSliceMut slice` - The new empty slice.
542///
543/// # Panics
544///
545/// This operation will panic if either `align` is not a power of two or `stride` is not a multiple
546/// of `align`.
547#[inline]
548#[nstdapi]
549#[allow(clippy::arithmetic_side_effects)]
550pub const fn nstd_core_slice_mut_empty(stride: NSTDUInt, align: NSTDUInt) -> NSTDSliceMut {
551    assert!(crate::core::mem::is_power_of_two(align) && stride % align == 0);
552    NSTDSliceMut {
553        ptr: align as NSTDAnyMut,
554        len: 0,
555        stride,
556        align,
557    }
558}
559
560/// Creates an immutable version of a mutable slice.
561///
562/// # Parameters:
563///
564/// - `const NSTDSliceMut *slice` - The mutable slice.
565///
566/// # Returns
567///
568/// `NSTDSlice slice_const` - The immutable copy of `slice`.
569#[inline]
570#[nstdapi]
571pub const fn nstd_core_slice_mut_as_const(slice: &NSTDSliceMut) -> NSTDSlice {
572    let ptr = nstd_core_slice_mut_as_ptr_const(slice);
573    let stride = nstd_core_slice_mut_stride(slice);
574    // SAFETY: `ptr` is never null.
575    unsafe { nstd_core_slice_new_unchecked(ptr, stride, slice.align, slice.len) }
576}
577
578/// Returns a raw pointer to the slice's memory.
579///
580/// # Parameters:
581///
582/// - `NSTDSliceMut *slice` - The slice.
583///
584/// # Returns
585///
586/// `NSTDAnyMut ptr` - A raw pointer to the slice's memory.
587///
588/// # Example
589///
590/// ```
591/// use nstd_sys::core::slice::{
592///     nstd_core_slice_mut_as_ptr, nstd_core_slice_mut_get_const, nstd_core_slice_mut_new,
593/// };
594///
595/// const STRIDE: usize = core::mem::size_of::<u16>();
596/// const ALIGN: usize = core::mem::align_of::<u16>();
597///
598/// unsafe {
599///     let mut buf: [u16; 3] = [3, 5, 7];
600///     let ptr = buf.as_mut_ptr().cast();
601///     let mut slice = nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, buf.len()).unwrap();
602///
603///     *nstd_core_slice_mut_as_ptr(&mut slice).cast::<u16>() = 1;
604///     assert!(*nstd_core_slice_mut_get_const(&slice, 0).cast::<u16>() == 1);
605/// }
606/// ```
607#[inline]
608#[nstdapi]
609pub fn nstd_core_slice_mut_as_ptr(slice: &mut NSTDSliceMut) -> NSTDAnyMut {
610    slice.ptr
611}
612
613/// Returns an immutable raw pointer to the slice's memory.
614///
615/// # Parameters:
616///
617/// - `const NSTDSliceMut *slice` - The slice.
618///
619/// # Returns
620///
621/// `NSTDAny ptr` - A raw pointer to the slice's memory.
622///
623/// # Example
624///
625/// ```
626/// use nstd_sys::core::slice::{nstd_core_slice_mut_as_ptr_const, nstd_core_slice_mut_new};
627///
628/// unsafe {
629///     let mut m33 = String::from("33marrow");
630///     let raw_ptr = m33.as_mut_ptr().cast();
631///     let slice = nstd_core_slice_mut_new(raw_ptr, 1, 1, m33.len()).unwrap();
632///     assert!(nstd_core_slice_mut_as_ptr_const(&slice) == raw_ptr);
633/// }
634/// ```
635#[inline]
636#[nstdapi]
637pub const fn nstd_core_slice_mut_as_ptr_const(slice: &NSTDSliceMut) -> NSTDAny {
638    slice.ptr
639}
640
641/// Returns the number of elements in a slice.
642///
643/// # Parameters:
644///
645/// - `const NSTDSliceMut *slice` - The slice.
646///
647/// # Returns
648///
649/// `NSTDUInt len` - The length of the slice.
650///
651/// # Example
652///
653/// ```
654/// use nstd_sys::core::slice::{nstd_core_slice_mut_len, nstd_core_slice_mut_new};
655///
656/// unsafe {
657///     let mut bye = String::from("Goodbye, cruel world!");
658///     let len = bye.len();
659///     let slice = nstd_core_slice_mut_new(bye.as_mut_ptr().cast(), 1, 1, len).unwrap();
660///     assert!(nstd_core_slice_mut_len(&slice) == len);
661/// }
662/// ```
663#[inline]
664#[nstdapi]
665pub const fn nstd_core_slice_mut_len(slice: &NSTDSliceMut) -> NSTDUInt {
666    slice.len
667}
668
669/// Returns the amount of bytes each value in a slice occupies.
670///
671/// # Parameters:
672///
673/// - `const NSTDSliceMut *slice` - The slice.
674///
675/// # Returns
676///
677/// `NSTDUInt stride` - The size of each value in the slice.
678///
679/// # Example
680///
681/// ```
682/// use nstd_sys::core::slice::{nstd_core_slice_mut_stride, nstd_core_slice_mut_new};
683///
684/// unsafe {
685///     let mut hw = String::from("Hello, world!");
686///     let slice = nstd_core_slice_mut_new(hw.as_mut_ptr().cast(), 1, 1, hw.len()).unwrap();
687///     assert!(nstd_core_slice_mut_stride(&slice) == 1);
688/// }
689/// ```
690#[inline]
691#[nstdapi]
692pub const fn nstd_core_slice_mut_stride(slice: &NSTDSliceMut) -> NSTDUInt {
693    slice.stride
694}
695
696/// Returns the alignment of each value in a slice.
697///
698/// # Parameters:
699///
700/// - `const NSTDSliceMut *slice` - The slice.
701///
702/// # Returns
703///
704/// `NSTDUInt align` - The alignment of each value in the slice.
705///
706/// # Example
707///
708/// ```
709/// use nstd_sys::core::slice::{nstd_core_slice_mut_align, nstd_core_slice_mut_new};
710///
711/// unsafe {
712///     let mut bytes = b"Hello, world!".to_vec();
713///     let slice = nstd_core_slice_mut_new(bytes.as_mut_ptr().cast(), 1, 1, bytes.len()).unwrap();
714///     assert!(nstd_core_slice_mut_align(&slice) == 1);
715/// }
716/// ```
717#[inline]
718#[nstdapi]
719pub const fn nstd_core_slice_mut_align(slice: &NSTDSliceMut) -> NSTDUInt {
720    slice.align
721}
722
723/// Returns a pointer to the element at index `pos` in `slice`.
724///
725/// # Parameters:
726///
727/// - `NSTDSliceMut *slice` - The slice to read an element from.
728///
729/// - `NSTDUInt pos` - The position of the element to get, starting at 0.
730///
731/// # Returns
732///
733/// `NSTDAnyMut element` - A pointer to the element at `pos` or `NSTD_NULL` if `pos` is out of
734/// the slice's boundaries.
735///
736/// # Example
737///
738/// ```
739/// use nstd_sys::core::slice::{nstd_core_slice_mut_get, nstd_core_slice_mut_new};
740///
741/// const STRIDE: usize = core::mem::size_of::<i32>();
742/// const ALIGN: usize = core::mem::align_of::<i32>();
743///
744/// unsafe {
745///     let mut numbers = [0i32; 3];
746///     let ptr = numbers.as_mut_ptr().cast();
747///     let mut slice = nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, numbers.len()).unwrap();
748///
749///     *nstd_core_slice_mut_get(&mut slice, 0).cast::<i32>() = 33;
750///     *nstd_core_slice_mut_get(&mut slice, 1).cast::<i32>() = 103;
751///     *nstd_core_slice_mut_get(&mut slice, 2).cast::<i32>() = 45;
752///     assert!(numbers == [33, 103, 45]);
753/// }
754/// ```
755#[inline]
756#[nstdapi]
757pub fn nstd_core_slice_mut_get(slice: &mut NSTDSliceMut, pos: NSTDUInt) -> NSTDAnyMut {
758    nstd_core_slice_mut_get_const(slice, pos).cast_mut()
759}
760
761/// Returns an immutable pointer to the element at index `pos` in `slice`.
762///
763/// # Parameters:
764///
765/// - `const NSTDSliceMut *slice` - The slice to read an element from.
766///
767/// - `NSTDUInt pos` - The position of the element to get, starting at 0.
768///
769/// # Returns
770///
771/// `NSTDAny element` - A pointer to the element at `pos` or `NSTD_NULL` if `pos` is out
772/// of the slice's boundaries.
773///
774/// # Example
775///
776/// ```
777/// use nstd_sys::core::slice::{nstd_core_slice_mut_get_const, nstd_core_slice_mut_new};
778///
779/// const STRIDE: usize = core::mem::size_of::<i32>();
780/// const ALIGN: usize = core::mem::align_of::<i32>();
781///
782/// unsafe {
783///     let mut numbers: [i32; 3] = [33, 103, 45];
784///     let ptr = numbers.as_mut_ptr().cast();
785///     let slice = nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, numbers.len()).unwrap();
786///
787///     assert!(*nstd_core_slice_mut_get_const(&slice, 0).cast::<i32>() == 33);
788///     assert!(*nstd_core_slice_mut_get_const(&slice, 1).cast::<i32>() == 103);
789///     assert!(*nstd_core_slice_mut_get_const(&slice, 2).cast::<i32>() == 45);
790///     assert!(nstd_core_slice_mut_get_const(&slice, 3).is_null());
791/// }
792/// ```
793#[inline]
794#[nstdapi]
795pub const fn nstd_core_slice_mut_get_const(slice: &NSTDSliceMut, mut pos: NSTDUInt) -> NSTDAny {
796    #[allow(clippy::arithmetic_side_effects)]
797    if pos < slice.len {
798        pos *= slice.stride;
799        // SAFETY: We've checked `pos`.
800        return unsafe { slice.ptr.add(pos) };
801    }
802    NSTD_NULL
803}
804
805/// Returns a pointer to the first element in the slice.
806///
807/// # Parameters:
808///
809/// - `NSTDSliceMut *slice` - The slice to get the first element of.
810///
811/// # Returns
812///
813/// `NSTDAnyMut element` - A pointer to the first element in `slice` or `NSTD_NULL` if the slice
814/// is empty.
815///
816/// # Example
817///
818/// ```
819/// use nstd_sys::core::slice::{nstd_core_slice_mut_first, nstd_core_slice_mut_new};
820///
821/// const STRIDE: usize = core::mem::size_of::<u64>();
822/// const ALIGN: usize = core::mem::align_of::<u64>();
823///
824/// let mut numbers: [u64; 3] = [707, 23043, 8008];
825/// let ptr = numbers.as_mut_ptr().cast();
826/// let mut slice = unsafe { nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, numbers.len()).unwrap() };
827///
828/// unsafe { *nstd_core_slice_mut_first(&mut slice).cast::<u64>() = 101 };
829/// assert!(numbers[0] == 101);
830/// ```
831#[inline]
832#[nstdapi]
833pub fn nstd_core_slice_mut_first(slice: &mut NSTDSliceMut) -> NSTDAnyMut {
834    nstd_core_slice_mut_first_const(slice).cast_mut()
835}
836
837/// Returns an immutable pointer to the first element in the slice.
838///
839/// # Parameters:
840///
841/// - `const NSTDSliceMut *slice` - The slice to get the first element of.
842///
843/// # Returns
844///
845/// `NSTDAny element` - A pointer to the first element in `slice` or `NSTD_NULL` if the
846/// slice is empty.
847///
848/// # Example
849///
850/// ```
851/// use nstd_sys::core::slice::{nstd_core_slice_mut_first_const, nstd_core_slice_mut_new};
852///
853/// const STRIDE: usize = core::mem::size_of::<u64>();
854/// const ALIGN: usize = core::mem::align_of::<u64>();
855///
856/// unsafe {
857///     let mut numbers: [u64; 3] = [707, 23043, 8008];
858///     let numbers_ptr = numbers.as_mut_ptr().cast();
859///     let slice = nstd_core_slice_mut_new(numbers_ptr, STRIDE, ALIGN, numbers.len()).unwrap();
860///     let empty = nstd_core_slice_mut_new(numbers_ptr, STRIDE, ALIGN, 0).unwrap();
861///
862///     assert!(nstd_core_slice_mut_first_const(&slice) == numbers_ptr);
863///     assert!(*nstd_core_slice_mut_first_const(&slice).cast::<u64>() == 707);
864///     assert!(nstd_core_slice_mut_first_const(&empty).is_null());
865/// }
866/// ```
867#[inline]
868#[nstdapi]
869pub const fn nstd_core_slice_mut_first_const(slice: &NSTDSliceMut) -> NSTDAny {
870    match slice.len > 0 {
871        true => nstd_core_slice_mut_as_ptr_const(slice),
872        false => NSTD_NULL,
873    }
874}
875
876/// Returns a pointer to the last element in the slice.
877///
878/// # Parameters:
879///
880/// - `NSTDSliceMut *slice` - The slice to get the last element of.
881///
882/// # Returns
883///
884/// `NSTDAnyMut element` - A pointer to the last element in `slice` or `NSTD_NULL` if the slice
885/// is empty.
886///
887/// # Example
888///
889/// ```
890/// use nstd_sys::core::slice::{nstd_core_slice_mut_last, nstd_core_slice_mut_new};
891///
892/// const STRIDE: usize = core::mem::size_of::<u64>();
893/// const ALIGN: usize = core::mem::align_of::<u64>();
894///
895/// unsafe {
896///     let mut numbers: [u64; 3] = [717, 421, 4317];
897///     let ptr = numbers.as_mut_ptr().cast();
898///     let mut slice = nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, numbers.len()).unwrap();
899///
900///     *nstd_core_slice_mut_last(&mut slice).cast::<u64>() = 1738;
901///     assert!(numbers[2] == 1738);
902/// }
903/// ```
904#[inline]
905#[nstdapi]
906pub fn nstd_core_slice_mut_last(slice: &mut NSTDSliceMut) -> NSTDAnyMut {
907    nstd_core_slice_mut_last_const(slice).cast_mut()
908}
909
910/// Returns an immutable pointer to the last element in the slice.
911///
912/// # Parameters:
913///
914/// - `const NSTDSliceMut *slice` - The slice to get the last element of.
915///
916/// # Returns
917///
918/// `NSTDAny element` - A pointer to the last element in `slice` or `NSTD_NULL` if the
919/// slice is empty.
920///
921/// # Example
922///
923/// ```
924/// use nstd_sys::core::slice::{nstd_core_slice_mut_last_const, nstd_core_slice_mut_new};
925///
926/// const STRIDE: usize = core::mem::size_of::<u64>();
927/// const ALIGN: usize = core::mem::align_of::<u64>();
928///
929/// unsafe {
930///     let mut numbers: [u64; 3] = [717, 421, 4317];
931///     let numbers_ptr = numbers.as_mut_ptr().cast();
932///     let slice = nstd_core_slice_mut_new(numbers_ptr, STRIDE, ALIGN, numbers.len()).unwrap();
933///     let empty = nstd_core_slice_mut_new(numbers_ptr, STRIDE, ALIGN, 0).unwrap();
934///
935///     assert!(*nstd_core_slice_mut_last_const(&slice).cast::<u64>() == 4317);
936///     assert!(nstd_core_slice_mut_last_const(&empty).is_null());
937/// }
938/// ```
939#[inline]
940#[nstdapi]
941pub const fn nstd_core_slice_mut_last_const(slice: &NSTDSliceMut) -> NSTDAny {
942    match slice.len > 0 {
943        #[allow(clippy::arithmetic_side_effects)]
944        true => nstd_core_slice_mut_get_const(slice, slice.len - 1),
945        false => NSTD_NULL,
946    }
947}
948
949/// Copies data into `dest` from `src`. The number of bytes copied is determined by `src`.
950///
951/// # Parameters:
952///
953/// - `NSTDSliceMut *dest` - The slice to copy data to.
954///
955/// - `const NSTDSlice *src` - The slice to copy data from.
956///
957/// # Panics
958///
959/// This operation will panic in the following situations:
960///
961/// - The two buffer's lengths do not match.
962///
963/// - The two buffer's strides do not match.
964///
965/// # Safety
966///
967/// This function can cause undefined behavior if either `dest` or `src`'s data is invalid.
968///
969/// # Example
970///
971/// ```
972/// use nstd_sys::core::slice::{
973///     nstd_core_slice_mut_copy, nstd_core_slice_mut_new, nstd_core_slice_new,
974/// };
975///
976/// const STRIDE: usize = core::mem::size_of::<u32>();
977/// const ALIGN: usize = core::mem::align_of::<u32>();
978///
979/// let mut dest_arr = [0u32; 5];
980/// let src_arr: [u32; 5] = [7, 43, 32, 90, 15];
981///
982/// unsafe {
983///     let ptr = dest_arr.as_mut_ptr().cast();
984///     let mut dest = nstd_core_slice_mut_new(ptr, STRIDE, ALIGN, dest_arr.len()).unwrap();
985///     let src =
986///         nstd_core_slice_new(src_arr.as_ptr().cast(), STRIDE, ALIGN, src_arr.len()).unwrap();
987///
988///     nstd_core_slice_mut_copy(&mut dest, &src);
989///     assert!(dest_arr == src_arr);
990/// }
991/// ```
992#[nstdapi]
993pub unsafe fn nstd_core_slice_mut_copy(dest: &mut NSTDSliceMut, src: &NSTDSlice) {
994    assert!(dest.len == src.len && dest.stride == src.stride);
995    let len = src.byte_len();
996    let dest = nstd_core_slice_mut_as_ptr(dest).cast();
997    let src = nstd_core_slice_as_ptr(src).cast();
998    nstd_core_mem_copy(dest, src, len);
999}