nstd_sys/core/
cstr.rs

1//! Unowned C string slices.
2pub mod raw;
3use self::raw::{nstd_core_cstr_raw_len, nstd_core_cstr_raw_len_with_null};
4use crate::{
5    core::{
6        mem::nstd_core_mem_search,
7        optional::{gen_optional, NSTDOptional},
8        slice::{nstd_core_slice_new_unchecked, NSTDSlice},
9    },
10    NSTDBool, NSTDChar, NSTDUInt, NSTD_INT_MAX,
11};
12use nstdapi::nstdapi;
13
14/// An immutable slice of a C string.
15#[nstdapi]
16#[derive(Clone, Copy)]
17pub struct NSTDCStr {
18    /// A pointer to the first character in the C string.
19    ptr: *const NSTDChar,
20    /// The length of the C string slice.
21    len: NSTDUInt,
22}
23impl NSTDCStr {
24    /// Interprets a C string slice as a byte slice.
25    ///
26    /// # Safety
27    ///
28    /// This C string slice's data must remain valid and unmodified while the returned byte slice
29    /// is in use.
30    #[inline]
31    pub(crate) const unsafe fn as_bytes(&self) -> &[u8] {
32        core::slice::from_raw_parts(self.ptr.cast(), self.len)
33    }
34}
35gen_optional!(NSTDOptionalCStr, NSTDCStr);
36
37/// Creates a new C string slice from a raw pointer and a size.
38///
39/// # Parameters:
40///
41/// - `const NSTDChar *raw` - A pointer to the first character to be in the C string slice.
42///
43/// - `NSTDUInt len` - The length of the C string slice.
44///
45/// # Returns
46///
47/// `NSTDOptionalCStr cstr` - The new C string slice referencing `raw`'s data on success, or an
48/// uninitialized "none" variant if `raw` is null or `len` is greater than `NSTDInt`'s max value.
49///
50/// # Example
51///
52/// ```
53/// use nstd_sys::core::cstr::{nstd_core_cstr_is_null_terminated, nstd_core_cstr_new};
54///
55/// unsafe {
56///     let str = "This is a null-terminated C string slice.\0";
57///     let cstr = nstd_core_cstr_new(str.as_ptr().cast(), str.len()).unwrap();
58///     assert!(nstd_core_cstr_is_null_terminated(&cstr));
59/// }
60/// ```
61#[inline]
62#[nstdapi]
63pub fn nstd_core_cstr_new(raw: *const NSTDChar, len: NSTDUInt) -> NSTDOptionalCStr {
64    match !raw.is_null() && len <= NSTD_INT_MAX {
65        true => NSTDOptional::Some(NSTDCStr { ptr: raw, len }),
66        false => NSTDOptional::None,
67    }
68}
69
70/// Creates a new C string slice from a raw pointer and a size without checking if `raw` is null.
71///
72/// # Parameters:
73///
74/// - `const NSTDChar *raw` - A pointer to the first character to be in the C string slice.
75///
76/// - `NSTDUInt len` - The length of the C string slice.
77///
78/// # Returns
79///
80/// `NSTDCStr cstr` - The new C string slice, referencing `raw`'s data.
81///
82/// # Safety
83///
84/// The user of this function must ensure that `raw` is non-null and `len` is not greater than
85/// `NSTDInt`'s max value.
86///
87/// # Example
88///
89/// ```
90/// use nstd_sys::core::cstr::{nstd_core_cstr_is_null_terminated, nstd_core_cstr_new_unchecked};
91///
92/// let str = "This is a null-terminated C string slice.\0";
93/// unsafe {
94///     let cstr = nstd_core_cstr_new_unchecked(str.as_ptr().cast(), str.len());
95///     assert!(nstd_core_cstr_is_null_terminated(&cstr));
96/// }
97/// ```
98#[inline]
99#[nstdapi]
100pub const unsafe fn nstd_core_cstr_new_unchecked(raw: *const NSTDChar, len: NSTDUInt) -> NSTDCStr {
101    NSTDCStr { ptr: raw, len }
102}
103
104/// Creates a new instance of `NSTDCStr` from a raw C string, excluding the null byte.
105///
106/// # Parameters:
107///
108/// - `const NSTDChar *raw` - A raw pointer to the first character in the C string.
109///
110/// # Returns
111///
112/// `NSTDCStr cstr` - The new C string slice, referencing `raw`'s data.
113///
114/// # Safety
115///
116/// - `raw` must point to a character array that is valid for reads up until and including it's
117/// null-terminating byte.
118///
119/// - `raw`'s length must not be greater than `NSTDInt`'s max value.
120///
121/// # Example
122///
123/// ```
124/// use nstd_sys::core::cstr::{nstd_core_cstr_from_raw, nstd_core_cstr_len};
125///
126/// let s_str = "Yo yo dog\0";
127///
128/// unsafe {
129///     let cstr = nstd_core_cstr_from_raw(s_str.as_ptr().cast());
130///     assert!(nstd_core_cstr_len(&cstr) == s_str.len() - 1);
131/// }
132/// ```
133#[inline]
134#[nstdapi]
135pub unsafe fn nstd_core_cstr_from_raw(raw: *const NSTDChar) -> NSTDCStr {
136    let len = nstd_core_cstr_raw_len(raw);
137    nstd_core_cstr_new_unchecked(raw, len)
138}
139
140/// Creates a new instance of `NSTDCStr` from a raw C string, including the null byte.
141///
142/// # Parameters:
143///
144/// - `const NSTDChar *raw` - A raw pointer to the first character in the C string.
145///
146/// # Returns
147///
148/// `NSTDCStr cstr` - The new C string slice, referencing `raw`'s data.
149///
150/// # Safety
151///
152/// - `raw` must point to a character array that is valid for reads up until and including it's
153/// null-terminating byte.
154///
155/// - `raw`'s length must not be greater than `NSTDInt`'s max value.
156///
157/// # Example
158///
159/// ```
160/// use nstd_sys::core::cstr::{nstd_core_cstr_from_raw_with_null, nstd_core_cstr_len};
161///
162/// let s_str = "Yo yo cat\0";
163///
164/// unsafe {
165///     let cstr = nstd_core_cstr_from_raw_with_null(s_str.as_ptr().cast());
166///     assert!(nstd_core_cstr_len(&cstr) == s_str.len());
167/// }
168/// ```
169#[inline]
170#[nstdapi]
171pub unsafe fn nstd_core_cstr_from_raw_with_null(raw: *const NSTDChar) -> NSTDCStr {
172    let len = nstd_core_cstr_raw_len_with_null(raw);
173    nstd_core_cstr_new_unchecked(raw, len)
174}
175
176/// Returns a byte slice of a C string slice's data.
177///
178/// # Parameters:
179///
180/// - `const NSTDCStr *cstr` - The C string slice.
181///
182/// # Returns
183///
184/// `NSTDSlice bytes` - An immutable byte slice of the C string slice's data.
185///
186/// # Example
187///
188/// ```
189/// use nstd_sys::core::{
190///     cstr::{nstd_core_cstr_as_bytes, nstd_core_cstr_from_raw, nstd_core_cstr_len},
191///     slice::nstd_core_slice_len,
192/// };
193///
194/// let s_str = "Rusty 🦀\0";
195///
196/// unsafe {
197///     let cstr = nstd_core_cstr_from_raw(s_str.as_ptr().cast());
198///     let bytes = nstd_core_cstr_as_bytes(&cstr);
199///     assert!(nstd_core_cstr_len(&cstr) == nstd_core_slice_len(&bytes));
200/// }
201/// ```
202#[inline]
203#[nstdapi]
204pub const fn nstd_core_cstr_as_bytes(cstr: &NSTDCStr) -> NSTDSlice {
205    // SAFETY: `cstr.ptr` is never null.
206    unsafe { nstd_core_slice_new_unchecked(cstr.ptr.cast(), 1, 1, cstr.len) }
207}
208
209/// Returns a pointer to the first character in a C string slice.
210///
211/// # Parameters:
212///
213/// - `const NSTDCStr *cstr` - The C string slice.
214///
215/// # Returns
216///
217/// `const NSTDChar *ptr` - A pointer to the first character in the C string.
218///
219/// # Example
220///
221/// ```
222/// use nstd_sys::core::cstr::{nstd_core_cstr_as_ptr, nstd_core_cstr_new};
223///
224/// unsafe {
225///     let str = "assert!(Rust + C >= God)";
226///     let str_ptr = str.as_ptr().cast();
227///     let cstr = nstd_core_cstr_new(str_ptr, str.len()).unwrap();
228///     assert!(str_ptr == nstd_core_cstr_as_ptr(&cstr));
229/// }
230/// ```
231#[inline]
232#[nstdapi]
233pub const fn nstd_core_cstr_as_ptr(cstr: &NSTDCStr) -> *const NSTDChar {
234    cstr.ptr
235}
236
237/// Returns the length of a C string slice.
238///
239/// # Parameters:
240///
241/// - `const NSTDCStr *cstr` - The C string slice.
242///
243/// # Returns
244///
245/// `NSTDUInt len` - The length of the C string slice.
246///
247/// # Example
248///
249/// ```
250/// use nstd_sys::core::cstr::{nstd_core_cstr_from_raw, nstd_core_cstr_len};
251///
252/// unsafe {
253///     let str = "Sunflower seeds yum\0";
254///     let cstr = nstd_core_cstr_from_raw(str.as_ptr().cast());
255///     assert!(nstd_core_cstr_len(&cstr) == 19);
256/// }
257/// ```
258#[inline]
259#[nstdapi]
260pub const fn nstd_core_cstr_len(cstr: &NSTDCStr) -> NSTDUInt {
261    cstr.len
262}
263
264/// Determines whether or not a C string slice is null terminated. This will return false if the C
265/// string slice contains any null bytes before the last byte.
266///
267/// # Parameters:
268///
269/// - `const NSTDCStr *cstr` - The C string slice.
270///
271/// # Returns
272///
273/// `NSTDBool is_null_terminated` - Returns true if the C string slice contains a single null byte
274/// at the end.
275///
276/// # Safety
277///
278/// The caller must ensure that `cstr` is valid for reads.
279///
280/// # Example
281///
282/// ```
283/// use nstd_sys::{
284///     core::cstr::{nstd_core_cstr_is_null_terminated, nstd_core_cstr_new},
285///     NSTD_FALSE, NSTD_TRUE,
286/// };
287///
288/// # unsafe {
289/// let nn_bytes = "Hello, world!";
290/// let nn_cstr = nstd_core_cstr_new(nn_bytes.as_ptr().cast(), nn_bytes.len()).unwrap();
291///
292/// let nt_bytes = "Hello, world!\0";
293/// let nt_cstr = nstd_core_cstr_new(nt_bytes.as_ptr().cast(), nt_bytes.len()).unwrap();
294///
295/// let mn_bytes = "Hello, \0world!";
296/// let mn_cstr = nstd_core_cstr_new(mn_bytes.as_ptr().cast(), mn_bytes.len()).unwrap();
297///
298/// assert!(nstd_core_cstr_is_null_terminated(&nn_cstr) == NSTD_FALSE);
299/// assert!(nstd_core_cstr_is_null_terminated(&nt_cstr) == NSTD_TRUE);
300/// assert!(nstd_core_cstr_is_null_terminated(&mn_cstr) == NSTD_FALSE);
301/// # }
302/// ```
303#[inline]
304#[nstdapi]
305pub unsafe fn nstd_core_cstr_is_null_terminated(cstr: &NSTDCStr) -> NSTDBool {
306    nstd_core_mem_search(cstr.ptr.cast(), cstr.len, 0) == nstd_core_cstr_last(cstr).cast()
307}
308
309/// Returns a pointer to the first null byte in a C string slice if one is present.
310///
311/// # Parameters:
312///
313/// - `const NSTDCStr *cstr` - The C string slice.
314///
315/// # Returns
316///
317/// `const NSTDChar *nul` - A pointer to the first null byte in `cstr`, or null if the C string
318/// slice doesn't contain a null byte.
319///
320/// # Safety
321///
322/// The caller must ensure that `cstr` is valid for reads.
323///
324/// # Example
325///
326/// ```
327/// use nstd_sys::core::cstr::{
328///     nstd_core_cstr_from_raw, nstd_core_cstr_from_raw_with_null, nstd_core_cstr_get,
329///     nstd_core_cstr_get_null, nstd_core_cstr_len,
330/// };
331///
332/// let s_str = "Where is the null byte?\0";
333/// let str_ptr = s_str.as_ptr().cast();
334///
335/// unsafe {
336///     let mut cstr = nstd_core_cstr_from_raw_with_null(str_ptr);
337///     let ptr = nstd_core_cstr_get_null(&cstr);
338///     let last_pos = nstd_core_cstr_len(&cstr) - 1;
339///     assert!(ptr == nstd_core_cstr_get(&cstr, last_pos));
340///
341///     cstr = nstd_core_cstr_from_raw(str_ptr);
342///     assert!(nstd_core_cstr_get_null(&cstr).is_null());
343/// }
344/// ```
345#[inline]
346#[nstdapi]
347pub unsafe fn nstd_core_cstr_get_null(cstr: &NSTDCStr) -> *const NSTDChar {
348    nstd_core_mem_search(cstr.ptr.cast(), cstr.len, 0).cast()
349}
350
351/// Return a pointer to the character at index `pos` in `cstr`.
352///
353/// # Parameters:
354///
355/// - `const NSTDCStr *cstr` - The C string.
356///
357/// - `NSTDUInt pos` - The position of the character to get.
358///
359/// # Returns
360///
361/// `const NSTDChar *chr` - A pointer to the character at `pos`, or null if `pos` is out of the C
362/// string slice's boundaries.
363///
364/// # Example
365///
366/// ```
367/// use nstd_sys::core::cstr::{nstd_core_cstr_from_raw_with_null, nstd_core_cstr_get};
368///
369/// let s_str = "AMP\0";
370///
371/// unsafe {
372///     let cstr = nstd_core_cstr_from_raw_with_null(s_str.as_ptr().cast());
373///     let nb = nstd_core_cstr_get(&cstr, s_str.len() - 1);
374///     assert!(!nb.is_null());
375///     assert!(*nb == 0);
376/// }
377/// ```
378#[inline]
379#[nstdapi]
380pub const fn nstd_core_cstr_get(cstr: &NSTDCStr, pos: NSTDUInt) -> *const NSTDChar {
381    if pos < cstr.len {
382        // SAFETY: We've checked `pos`.
383        return unsafe { cstr.ptr.add(pos) };
384    }
385    core::ptr::null()
386}
387
388/// Returns a pointer to the first character in a C string slice, or null if it is empty.
389///
390/// # Parameters:
391///
392/// - `const NSTDCStr *cstr` - The C string slice.
393///
394/// # Returns
395///
396/// `const NSTDChar *first` - If present, a pointer to the first character in the C string slice.
397///
398/// # Example
399///
400/// ```
401/// use nstd_sys::{
402///     core::cstr::{nstd_core_cstr_first, nstd_core_cstr_from_raw},
403///     NSTDChar,
404/// };
405///
406/// unsafe {
407///     let cstr = nstd_core_cstr_from_raw("Tea\0".as_ptr().cast());
408///     assert!(*nstd_core_cstr_first(&cstr) == b'T' as NSTDChar);
409/// }
410/// ```
411#[inline]
412#[nstdapi]
413pub const fn nstd_core_cstr_first(cstr: &NSTDCStr) -> *const NSTDChar {
414    match cstr.len > 0 {
415        true => cstr.ptr,
416        false => core::ptr::null(),
417    }
418}
419
420/// Returns a pointer to the last character in a C string slice, or null if it is empty.
421///
422/// # Parameters:
423///
424/// - `const NSTDCStr *cstr` - The C string slice.
425///
426/// # Returns
427///
428/// `const NSTDChar *last` - If present, a pointer to the last character in the C string slice.
429///
430/// # Example
431///
432/// ```
433/// use nstd_sys::core::cstr::{nstd_core_cstr_from_raw_with_null, nstd_core_cstr_last};
434///
435/// unsafe {
436///     let cstr = nstd_core_cstr_from_raw_with_null("Tea\0".as_ptr().cast());
437///     assert!(*nstd_core_cstr_last(&cstr) == 0);
438/// }
439/// ```
440#[inline]
441#[nstdapi]
442pub const fn nstd_core_cstr_last(cstr: &NSTDCStr) -> *const NSTDChar {
443    match cstr.len > 0 {
444        #[allow(clippy::arithmetic_side_effects)]
445        true => nstd_core_cstr_get(cstr, cstr.len - 1),
446        false => core::ptr::null(),
447    }
448}
449
450/// A mutable slice of a C string.
451#[nstdapi]
452pub struct NSTDCStrMut {
453    /// A pointer to the first character in the C string.
454    ptr: *mut NSTDChar,
455    /// The length of the C string slice.
456    len: NSTDUInt,
457}
458impl NSTDCStrMut {
459    /// Interprets a C string slice as a byte slice.
460    ///
461    /// # Safety
462    ///
463    /// This C string slice's data must remain valid and unmodified while the returned byte slice
464    /// is in use.
465    #[inline]
466    pub(crate) const unsafe fn as_bytes(&self) -> &[u8] {
467        core::slice::from_raw_parts(self.ptr.cast(), self.len)
468    }
469}
470gen_optional!(NSTDOptionalCStrMut, NSTDCStrMut);
471
472/// Creates a new C string slice from a raw pointer and a size.
473///
474/// # Parameters:
475///
476/// - `NSTDChar *raw` - A pointer to the first character to be in the C string slice.
477///
478/// - `NSTDUInt len` - The length of the C string slice.
479///
480/// # Returns
481///
482/// `NSTDOptionalCStrMut cstr` - The new C string slice referencing `raw`'s data on success, or an
483/// uninitialized "none" variant if `raw` is null or `len` is greater than `NSTDInt`'s max value.
484///
485/// # Example
486///
487/// ```
488/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_is_null_terminated, nstd_core_cstr_mut_new};
489///
490/// unsafe {
491///     let mut str = String::from("This is a null-terminated C string slice.\0");
492///     let cstr = nstd_core_cstr_mut_new(str.as_mut_ptr().cast(), str.len()).unwrap();
493///     assert!(nstd_core_cstr_mut_is_null_terminated(&cstr));
494/// }
495/// ```
496#[inline]
497#[nstdapi]
498pub fn nstd_core_cstr_mut_new(raw: *mut NSTDChar, len: NSTDUInt) -> NSTDOptionalCStrMut {
499    match !raw.is_null() && len <= NSTD_INT_MAX {
500        true => NSTDOptional::Some(NSTDCStrMut { ptr: raw, len }),
501        false => NSTDOptional::None,
502    }
503}
504
505/// Creates a new C string slice from a raw pointer and a size without checking if `raw` is null.
506///
507/// # Parameters:
508///
509/// - `NSTDChar *raw` - A pointer to the first character to be in the C string slice.
510///
511/// - `NSTDUInt len` - The length of the C string slice.
512///
513/// # Returns
514///
515/// `NSTDCStrMut cstr` - The new C string slice, referencing `raw`'s data.
516///
517/// # Safety
518///
519/// The user of this function must ensure that `raw` is non-null and `len` is not greater than
520/// `NSTDInt`'s max value.
521///
522/// # Example
523///
524/// ```
525/// use nstd_sys::core::cstr::{
526///     nstd_core_cstr_mut_is_null_terminated, nstd_core_cstr_mut_new_unchecked,
527/// };
528///
529/// let mut str = String::from("This is a null-terminated C string slice.\0");
530/// unsafe {
531///     let cstr = nstd_core_cstr_mut_new_unchecked(str.as_mut_ptr().cast(), str.len());
532///     assert!(nstd_core_cstr_mut_is_null_terminated(&cstr));
533/// }
534/// ```
535#[inline]
536#[nstdapi]
537pub const unsafe fn nstd_core_cstr_mut_new_unchecked(
538    raw: *mut NSTDChar,
539    len: NSTDUInt,
540) -> NSTDCStrMut {
541    NSTDCStrMut { ptr: raw, len }
542}
543
544/// Creates a new instance of `NSTDCStrMut` from a raw C string, excluding the null byte.
545///
546/// # Parameters:
547///
548/// - `NSTDChar *raw` - A raw pointer to the first character in the C string.
549///
550/// # Returns
551///
552/// `NSTDCStrMut cstr` - The new C string slice, referencing `raw`'s data.
553///
554/// # Safety
555///
556/// - `raw` must point to a character array that is valid for reads up until and including it's
557/// null-terminating byte.
558///
559/// - `raw`'s length must not be greater than `NSTDInt`'s max value.
560///
561/// # Example
562///
563/// ```
564/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_from_raw, nstd_core_cstr_mut_len};
565///
566/// let mut s_str = String::from("Yo yo dog\0");
567///
568/// unsafe {
569///     let cstr = nstd_core_cstr_mut_from_raw(s_str.as_mut_ptr().cast());
570///     assert!(nstd_core_cstr_mut_len(&cstr) == s_str.len() - 1);
571/// }
572/// ```
573#[inline]
574#[nstdapi]
575pub unsafe fn nstd_core_cstr_mut_from_raw(raw: *mut NSTDChar) -> NSTDCStrMut {
576    let len = nstd_core_cstr_raw_len(raw);
577    nstd_core_cstr_mut_new_unchecked(raw, len)
578}
579
580/// Creates a new instance of `NSTDCStrMut` from a raw C string, including the null byte.
581///
582/// # Parameters:
583///
584/// - `NSTDChar *raw` - A raw pointer to the first character in the C string.
585///
586/// # Returns
587///
588/// `NSTDCStrMut cstr` - The new C string slice, referencing `raw`'s data.
589///
590/// # Safety
591///
592/// - `raw` must point to a character array that is valid for reads up until and including it's
593/// null-terminating byte.
594///
595/// - `raw`'s length must not be greater than `NSTDInt`'s max value.
596///
597/// # Example
598///
599/// ```
600/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_from_raw_with_null, nstd_core_cstr_mut_len};
601///
602/// let mut s_str = String::from("Yo yo cat\0");
603///
604/// unsafe {
605///     let cstr = nstd_core_cstr_mut_from_raw_with_null(s_str.as_mut_ptr().cast());
606///     assert!(nstd_core_cstr_mut_len(&cstr) == s_str.len());
607/// }
608/// ```
609#[inline]
610#[nstdapi]
611pub unsafe fn nstd_core_cstr_mut_from_raw_with_null(raw: *mut NSTDChar) -> NSTDCStrMut {
612    let len = nstd_core_cstr_raw_len_with_null(raw);
613    nstd_core_cstr_mut_new_unchecked(raw, len)
614}
615
616/// Creates an immutable version of a mutable C string slice.
617///
618/// # Parameters:
619///
620/// - `const NSTDCStrMut *cstr` - The mutable C string slice.
621///
622/// # Returns
623///
624/// `NSTDCStr cstr_const` - The immutable copy of `cstr`.
625///
626/// # Example
627///
628/// ```
629/// use nstd_sys::core::cstr::{
630///     nstd_core_cstr_len, nstd_core_cstr_mut_as_const, nstd_core_cstr_mut_new,
631/// };
632///
633/// unsafe {
634///     let mut str = String::from("Faded than a ho");
635///     let cstr_mut = nstd_core_cstr_mut_new(str.as_mut_ptr().cast(), str.len()).unwrap();
636///     let cstr = nstd_core_cstr_mut_as_const(&cstr_mut);
637///     assert!(nstd_core_cstr_len(&cstr) == str.len());
638/// }
639/// ```
640#[inline]
641#[nstdapi]
642pub const fn nstd_core_cstr_mut_as_const(cstr: &NSTDCStrMut) -> NSTDCStr {
643    // SAFETY: `cstr.ptr` is never null, C string slices are never longer than `NSTDInt`'s max
644    // value.
645    unsafe { nstd_core_cstr_new_unchecked(cstr.ptr, cstr.len) }
646}
647
648/// Returns a byte slice of a C string slice's data.
649///
650/// # Parameters:
651///
652/// - `const NSTDCStrMut *cstr` - The C string slice.
653///
654/// # Returns
655///
656/// `NSTDSlice bytes` - An immutable byte slice of the C string slice's data.
657///
658/// # Example
659///
660/// ```
661/// use nstd_sys::core::{
662///     cstr::{nstd_core_cstr_mut_as_bytes, nstd_core_cstr_mut_from_raw, nstd_core_cstr_mut_len},
663///     slice::nstd_core_slice_len,
664/// };
665///
666/// let mut s_str = String::from("Rusty 🦀\0");
667///
668/// unsafe {
669///     let cstr = nstd_core_cstr_mut_from_raw(s_str.as_mut_ptr().cast());
670///     let bytes = nstd_core_cstr_mut_as_bytes(&cstr);
671///     assert!(nstd_core_cstr_mut_len(&cstr) == nstd_core_slice_len(&bytes));
672/// }
673/// ```
674#[inline]
675#[nstdapi]
676pub const fn nstd_core_cstr_mut_as_bytes(cstr: &NSTDCStrMut) -> NSTDSlice {
677    // SAFETY: `cstr.ptr` is never null.
678    unsafe { nstd_core_slice_new_unchecked(cstr.ptr.cast(), 1, 1, cstr.len) }
679}
680
681/// Returns a pointer to the first character in a C string slice.
682///
683/// # Parameters:
684///
685/// - `NSTDCStrMut *cstr` - The C string slice.
686///
687/// # Returns
688///
689/// `NSTDChar *ptr` - A pointer to the first character in the C string.
690///
691/// # Example
692///
693/// ```
694/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_as_ptr, nstd_core_cstr_mut_new};
695///
696/// unsafe {
697///     let mut str = String::from("assert!(Rust + C >= God)");
698///     let str_ptr = str.as_mut_ptr().cast();
699///     let mut cstr = nstd_core_cstr_mut_new(str_ptr, str.len()).unwrap();
700///     assert!(str_ptr == nstd_core_cstr_mut_as_ptr(&mut cstr));
701/// }
702/// ```
703#[inline]
704#[nstdapi]
705pub fn nstd_core_cstr_mut_as_ptr(cstr: &mut NSTDCStrMut) -> *mut NSTDChar {
706    cstr.ptr
707}
708
709/// Returns a pointer to the first character in a C string slice.
710///
711/// # Parameters:
712///
713/// - `const NSTDCStrMut *cstr` - The C string slice.
714///
715/// # Returns
716///
717/// `const NSTDChar *ptr` - A pointer to the first character in the C string.
718///
719/// # Example
720///
721/// ```
722/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_as_ptr_const, nstd_core_cstr_mut_new};
723///
724/// unsafe {
725///     let mut str = String::from("assert!(Rust + C >= God)");
726///     let cstr = nstd_core_cstr_mut_new(str.as_mut_ptr().cast(), str.len()).unwrap();
727///     assert!(str.as_ptr().cast() == nstd_core_cstr_mut_as_ptr_const(&cstr));
728/// }
729/// ```
730#[inline]
731#[nstdapi]
732pub const fn nstd_core_cstr_mut_as_ptr_const(cstr: &NSTDCStrMut) -> *const NSTDChar {
733    cstr.ptr
734}
735
736/// Returns the length of a C string slice.
737///
738/// # Parameters:
739///
740/// - `const NSTDCStrMut *cstr` - The C string slice.
741///
742/// # Returns
743///
744/// `NSTDUInt len` - The length of the C string slice.
745///
746/// # Example
747///
748/// ```
749/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_from_raw, nstd_core_cstr_mut_len};
750///
751/// unsafe {
752///     let mut str = String::from("Sunflower seeds yum\0");
753///     let cstr = nstd_core_cstr_mut_from_raw(str.as_mut_ptr().cast());
754///     assert!(nstd_core_cstr_mut_len(&cstr) == 19);
755/// }
756/// ```
757#[inline]
758#[nstdapi]
759pub const fn nstd_core_cstr_mut_len(cstr: &NSTDCStrMut) -> NSTDUInt {
760    cstr.len
761}
762
763/// Determines whether or not a C string slice is null terminated. This will return false if the C
764/// string slice contains any null bytes before the last byte.
765///
766/// # Parameters:
767///
768/// - `const NSTDCStrMut *cstr` - The C string slice.
769///
770/// # Returns
771///
772/// `NSTDBool is_null_terminated` - Returns true if the C string slice contains a single null byte
773/// at the end.
774///
775/// # Safety
776///
777/// The caller must ensure that `cstr` is valid for reads.
778///
779/// # Example
780///
781/// ```
782/// use nstd_sys::{
783///     core::cstr::{nstd_core_cstr_mut_is_null_terminated, nstd_core_cstr_mut_new},
784///     NSTD_FALSE, NSTD_TRUE,
785/// };
786///
787/// # unsafe {
788/// let mut nn_bytes = String::from("Hello, world!");
789/// let nn_cstr = nstd_core_cstr_mut_new(nn_bytes.as_mut_ptr().cast(), nn_bytes.len()).unwrap();
790///
791/// let mut nt_bytes = String::from("Hello, world!\0");
792/// let nt_cstr = nstd_core_cstr_mut_new(nt_bytes.as_mut_ptr().cast(), nt_bytes.len()).unwrap();
793///
794/// let mut mn_bytes = String::from("Hello, \0world!");
795/// let mn_cstr = nstd_core_cstr_mut_new(mn_bytes.as_mut_ptr().cast(), mn_bytes.len()).unwrap();
796///
797/// assert!(nstd_core_cstr_mut_is_null_terminated(&nn_cstr) == NSTD_FALSE);
798/// assert!(nstd_core_cstr_mut_is_null_terminated(&nt_cstr) == NSTD_TRUE);
799/// assert!(nstd_core_cstr_mut_is_null_terminated(&mn_cstr) == NSTD_FALSE);
800/// # }
801/// ```
802#[inline]
803#[nstdapi]
804pub unsafe fn nstd_core_cstr_mut_is_null_terminated(cstr: &NSTDCStrMut) -> NSTDBool {
805    let cstr_const = nstd_core_cstr_mut_as_const(cstr);
806    nstd_core_cstr_is_null_terminated(&cstr_const)
807}
808
809/// Returns a pointer to the first null byte in a C string slice if one is present.
810///
811/// # Parameters:
812///
813/// - `NSTDCStrMut *cstr` - The C string slice.
814///
815/// # Returns
816///
817/// `NSTDChar *nul` - A pointer to the first null byte in `cstr`, or null if the C string
818/// slice doesn't contain a null byte.
819///
820/// # Safety
821///
822/// The caller must ensure that `cstr` is valid for reads.
823///
824/// # Example
825///
826/// ```
827/// use nstd_sys::{
828///     core::cstr::{
829///         nstd_core_cstr_mut_from_raw_with_null, nstd_core_cstr_mut_get_null,
830///         nstd_core_cstr_mut_is_null_terminated,
831///     },
832///     NSTDChar, NSTD_FALSE,
833/// };
834///
835/// let mut s_str = String::from("BMP\0");
836///
837/// unsafe {
838///     let mut cstr = nstd_core_cstr_mut_from_raw_with_null(s_str.as_mut_ptr().cast());
839///     let n = nstd_core_cstr_mut_get_null(&mut cstr);
840///     assert!(!n.is_null());
841///     *n = b'!' as NSTDChar;
842///     assert!(nstd_core_cstr_mut_is_null_terminated(&cstr) == NSTD_FALSE);
843/// }
844/// ```
845#[inline]
846#[nstdapi]
847pub unsafe fn nstd_core_cstr_mut_get_null(cstr: &mut NSTDCStrMut) -> *mut NSTDChar {
848    nstd_core_cstr_mut_get_null_const(cstr).cast_mut()
849}
850
851/// Returns an immutable pointer to the first null byte in a C string slice if one is present.
852///
853/// # Parameters:
854///
855/// - `const NSTDCStrMut *cstr` - The C string slice.
856///
857/// # Returns
858///
859/// `const NSTDChar *nul` - A pointer to the first null byte in `cstr`, or null if the C string
860/// slice doesn't contain a null byte.
861///
862/// # Safety
863///
864/// The caller must ensure that `cstr` is valid for reads.
865///
866/// # Example
867///
868/// ```
869/// use nstd_sys::core::cstr::{
870///     nstd_core_cstr_mut_from_raw, nstd_core_cstr_mut_from_raw_with_null,
871///     nstd_core_cstr_mut_get_const, nstd_core_cstr_mut_get_null_const, nstd_core_cstr_mut_len,
872/// };
873///
874/// let mut s_str = String::from("Where is the null byte?\0");
875/// let str_ptr = s_str.as_mut_ptr().cast();
876///
877/// unsafe {
878///     let mut cstr = nstd_core_cstr_mut_from_raw_with_null(str_ptr);
879///     let ptr = nstd_core_cstr_mut_get_null_const(&cstr);
880///     let last_pos = nstd_core_cstr_mut_len(&cstr) - 1;
881///     assert!(ptr == nstd_core_cstr_mut_get_const(&cstr, last_pos));
882///
883///     cstr = nstd_core_cstr_mut_from_raw(str_ptr);
884///     assert!(nstd_core_cstr_mut_get_null_const(&cstr).is_null());
885/// }
886/// ```
887#[inline]
888#[nstdapi]
889pub unsafe fn nstd_core_cstr_mut_get_null_const(cstr: &NSTDCStrMut) -> *const NSTDChar {
890    let cstr_const = nstd_core_cstr_mut_as_const(cstr);
891    nstd_core_cstr_get_null(&cstr_const)
892}
893
894/// Return a pointer to the character at index `pos` in `cstr`.
895///
896/// # Parameters:
897///
898/// - `NSTDCStrMut *cstr` - The C string.
899///
900/// - `NSTDUInt pos` - The position of the character to get.
901///
902/// # Returns
903///
904/// `NSTDChar *chr` - A pointer to the character at `pos`, or null if `pos` is out of the C
905/// string slice's boundaries.
906///
907/// # Example
908///
909/// ```
910/// use nstd_sys::{
911///     core::cstr::{nstd_core_cstr_mut_from_raw_with_null, nstd_core_cstr_mut_get},
912///     NSTDChar,
913/// };
914///
915/// let mut s_str = String::from("BMP\0");
916///
917/// unsafe {
918///     let mut cstr = nstd_core_cstr_mut_from_raw_with_null(s_str.as_mut_ptr().cast());
919///     let b = nstd_core_cstr_mut_get(&mut cstr, 0);
920///     assert!(!b.is_null());
921///     *b = b'A' as NSTDChar;
922///     assert!(s_str == "AMP\0");
923/// }
924/// ```
925#[inline]
926#[nstdapi]
927pub fn nstd_core_cstr_mut_get(cstr: &mut NSTDCStrMut, pos: NSTDUInt) -> *mut NSTDChar {
928    nstd_core_cstr_mut_get_const(cstr, pos).cast_mut()
929}
930
931/// Return an immutable pointer to the character at index `pos` in `cstr`.
932///
933/// # Parameters:
934///
935/// - `const NSTDCStrMut *cstr` - The C string.
936///
937/// - `NSTDUInt pos` - The position of the character to get.
938///
939/// # Returns
940///
941/// `const NSTDChar *chr` - A pointer to the character at `pos`, or null if `pos` is out of the C
942/// string slice's boundaries.
943///
944/// # Example
945///
946/// ```
947/// use nstd_sys::core::cstr::{nstd_core_cstr_mut_from_raw_with_null, nstd_core_cstr_mut_get_const};
948///
949/// let mut s_str = String::from("AMP\0");
950///
951/// unsafe {
952///     let cstr = nstd_core_cstr_mut_from_raw_with_null(s_str.as_mut_ptr().cast());
953///     let nb = nstd_core_cstr_mut_get_const(&cstr, s_str.len() - 1);
954///     assert!(!nb.is_null());
955///     assert!(*nb == 0);
956/// }
957/// ```
958#[inline]
959#[nstdapi]
960pub const fn nstd_core_cstr_mut_get_const(cstr: &NSTDCStrMut, pos: NSTDUInt) -> *const NSTDChar {
961    if pos < cstr.len {
962        // SAFETY: We've checked `pos`.
963        return unsafe { cstr.ptr.add(pos) };
964    }
965    core::ptr::null_mut()
966}
967
968/// Returns a pointer to the first character in a C string slice, or null if it is empty.
969///
970/// # Parameters:
971///
972/// - `NSTDCStrMut *cstr` - The C string slice.
973///
974/// # Returns
975///
976/// `NSTDChar *first` - If present, a pointer to the first character in the C string slice.
977///
978/// # Example
979///
980/// ```
981/// use nstd_sys::{
982///     core::cstr::{nstd_core_cstr_mut_first, nstd_core_cstr_mut_from_raw},
983///     NSTDChar,
984/// };
985///
986/// let mut s_str = String::from("Bea\0");
987///
988/// unsafe {
989///     let mut cstr = nstd_core_cstr_mut_from_raw(s_str.as_mut_ptr().cast());
990///     *nstd_core_cstr_mut_first(&mut cstr) = b'T' as NSTDChar;
991///     assert!(s_str == "Tea\0");
992/// }
993/// ```
994#[inline]
995#[nstdapi]
996pub fn nstd_core_cstr_mut_first(cstr: &mut NSTDCStrMut) -> *mut NSTDChar {
997    match cstr.len > 0 {
998        true => cstr.ptr,
999        false => core::ptr::null_mut(),
1000    }
1001}
1002
1003/// Returns an immutable pointer to the first character in a C string slice, or null if it is empty.
1004///
1005/// # Parameters:
1006///
1007/// - `const NSTDCStrMut *cstr` - The C string slice.
1008///
1009/// # Returns
1010///
1011/// `const NSTDChar *first` - If present, a pointer to the first character in the C string slice.
1012///
1013/// # Example
1014///
1015/// ```
1016/// use nstd_sys::{
1017///     core::cstr::{nstd_core_cstr_mut_first_const, nstd_core_cstr_mut_from_raw},
1018///     NSTDChar,
1019/// };
1020///
1021/// let mut s_str = String::from("Tea\0");
1022///
1023/// unsafe {
1024///     let cstr = nstd_core_cstr_mut_from_raw(s_str.as_mut_ptr().cast());
1025///     assert!(*nstd_core_cstr_mut_first_const(&cstr) == b'T' as NSTDChar);
1026/// }
1027/// ```
1028#[inline]
1029#[nstdapi]
1030pub const fn nstd_core_cstr_mut_first_const(cstr: &NSTDCStrMut) -> *const NSTDChar {
1031    match cstr.len > 0 {
1032        true => cstr.ptr,
1033        false => core::ptr::null(),
1034    }
1035}
1036
1037/// Returns a pointer to the last character in a C string slice, or null if it is empty.
1038///
1039/// # Parameters:
1040///
1041/// - `NSTDCStrMut *cstr` - The C string slice.
1042///
1043/// # Returns
1044///
1045/// `NSTDChar *last` - If present, a pointer to the last character in the C string slice.
1046///
1047/// # Example
1048///
1049/// ```
1050/// use nstd_sys::{
1051///     core::cstr::{nstd_core_cstr_mut_from_raw, nstd_core_cstr_mut_last},
1052///     NSTDChar,
1053/// };
1054///
1055/// let mut s_str = String::from("Ted\0");
1056///
1057/// unsafe {
1058///     let mut cstr = nstd_core_cstr_mut_from_raw(s_str.as_mut_ptr().cast());
1059///     *nstd_core_cstr_mut_last(&mut cstr) = b'a' as NSTDChar;
1060///     assert!(s_str == "Tea\0");
1061/// }
1062/// ```
1063#[inline]
1064#[nstdapi]
1065pub fn nstd_core_cstr_mut_last(cstr: &mut NSTDCStrMut) -> *mut NSTDChar {
1066    match cstr.len > 0 {
1067        #[allow(clippy::arithmetic_side_effects)]
1068        true => nstd_core_cstr_mut_get(cstr, cstr.len - 1),
1069        false => core::ptr::null_mut(),
1070    }
1071}
1072
1073/// Returns an immutable pointer to the last character in a C string slice, or null if it is empty.
1074///
1075/// # Parameters:
1076///
1077/// - `const NSTDCStrMut *cstr` - The C string slice.
1078///
1079/// # Returns
1080///
1081/// `const NSTDChar *last` - If present, a pointer to the last character in the C string slice.
1082///
1083/// # Example
1084///
1085/// ```
1086/// use nstd_sys::core::cstr::{
1087///     nstd_core_cstr_mut_from_raw_with_null, nstd_core_cstr_mut_last_const,
1088/// };
1089///
1090/// let mut s_str = String::from("Tea\0");
1091///
1092/// unsafe {
1093///     let cstr = nstd_core_cstr_mut_from_raw_with_null(s_str.as_mut_ptr().cast());
1094///     assert!(*nstd_core_cstr_mut_last_const(&cstr) == 0);
1095/// }
1096/// ```
1097#[inline]
1098#[nstdapi]
1099pub const fn nstd_core_cstr_mut_last_const(cstr: &NSTDCStrMut) -> *const NSTDChar {
1100    match cstr.len > 0 {
1101        #[allow(clippy::arithmetic_side_effects)]
1102        true => nstd_core_cstr_mut_get_const(cstr, cstr.len - 1),
1103        false => core::ptr::null(),
1104    }
1105}