nstd_sys/core/cstr/
raw.rs

1//! Raw C string processing.
2use crate::{NSTDBool, NSTDChar, NSTDUInt};
3use cfg_if::cfg_if;
4use nstdapi::nstdapi;
5
6/// Gets the length of a raw null terminated C string, not counting the C string's null byte.
7///
8/// # Parameters:
9///
10/// - `const NSTDChar *cstr` - The null terminated C string.
11///
12/// # Returns
13///
14/// `NSTDUInt len` - The length of the C string, not counting the C string's null byte.
15///
16/// # Safety
17///
18/// `cstr` must point to a character array that is valid for reads up until and including it's
19/// null-terminating byte.
20///
21/// # Example
22///
23/// ```
24/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_len;
25///
26/// let cstr = b"Hello, world!\0";
27/// assert!(unsafe { nstd_core_cstr_raw_len(cstr.as_ptr().cast()) } == 13);
28/// ```
29#[inline]
30#[nstdapi]
31#[allow(unused_mut, clippy::missing_const_for_fn)]
32pub unsafe fn nstd_core_cstr_raw_len(mut cstr: *const NSTDChar) -> NSTDUInt {
33    cfg_if! {
34        if #[cfg(all(
35            any(
36                unix,
37                windows,
38                any(target_env = "wasi", target_os = "wasi"),
39                target_os = "solid_asp3",
40                target_os = "teeos"
41            ),
42            feature = "libc"
43        ))] {
44            libc::strlen(cstr)
45        } else {
46            let mut i = 0;
47            #[allow(clippy::arithmetic_side_effects)]
48            while *cstr != 0 {
49                cstr = cstr.offset(1);
50                i += 1;
51            }
52            i
53        }
54    }
55}
56
57/// Gets the length of a raw null terminated C string, counting the C string's null byte.
58///
59/// # Parameters:
60///
61/// - `const NSTDChar *cstr` - The null terminated C string.
62///
63/// # Returns
64///
65/// `NSTDUInt len` - The length of the C string, counting the C string's null byte.
66///
67/// # Safety
68///
69/// `cstr` must point to a character array that is valid for reads up until and including it's
70/// null-terminating byte.
71///
72/// # Example
73///
74/// ```
75/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_len_with_null;
76///
77/// let cstr = b"Hello, world!\0";
78/// assert!(unsafe { nstd_core_cstr_raw_len_with_null(cstr.as_ptr().cast()) } == 14);
79/// ```
80#[inline]
81#[nstdapi]
82#[allow(clippy::arithmetic_side_effects)]
83pub unsafe fn nstd_core_cstr_raw_len_with_null(cstr: *const NSTDChar) -> NSTDUInt {
84    nstd_core_cstr_raw_len(cstr) + 1
85}
86
87/// Compares two raw null-terminated C strings, returning `NSTD_TRUE` if they are lexicographically
88/// equal.
89///
90/// # Parameters:
91///
92/// - `const NSTDChar *cstr1` - The first C string.
93///
94/// - `const NSTDChar *cstr2` - The second C string.
95///
96/// # Returns
97///
98/// `NSTDBool is_eq` - `NSTD_TRUE` if the two C strings are lexicographically equal.
99///
100/// # Safety
101///
102/// Both `cstr1` and `cstr2` must point to character arrays that are valid for reads up until and
103/// including their null-terminating bytes.
104///
105/// # Example
106///
107/// ```
108/// use nstd_sys::{core::cstr::raw::nstd_core_cstr_raw_compare, NSTD_FALSE};
109///
110/// let cstr1 = b"Hello, world!\0".as_ptr().cast();
111/// let cstr2 = b"Hello world!\0".as_ptr().cast();
112///
113/// assert!(unsafe { nstd_core_cstr_raw_compare(cstr1, cstr2) } == NSTD_FALSE);
114/// ```
115#[nstdapi]
116#[allow(unused_mut)]
117pub unsafe fn nstd_core_cstr_raw_compare(
118    mut cstr1: *const NSTDChar,
119    mut cstr2: *const NSTDChar,
120) -> NSTDBool {
121    cfg_if! {
122        if #[cfg(all(
123            any(
124                unix,
125                windows,
126                any(target_env = "wasi", target_os = "wasi"),
127                target_os = "solid_asp3",
128                target_os = "teeos"
129            ),
130            feature = "libc"
131        ))] {
132            libc::strcmp(cstr1, cstr2) == 0
133        } else {
134            use crate::{NSTD_FALSE, NSTD_TRUE};
135            // If the C strings point to the same data return true.
136            if cstr1 == cstr2 {
137                return NSTD_TRUE;
138            }
139            // Otherwise compare them lexicographically.
140            while *cstr1 == *cstr2 {
141                if *cstr1 == 0 {
142                    return NSTD_TRUE;
143                }
144                cstr1 = cstr1.offset(1);
145                cstr2 = cstr2.offset(1);
146            }
147            NSTD_FALSE
148        }
149    }
150}
151
152/// Copies the contents of one raw C string to another, excluding the source's null-terminator.
153///
154/// # Note
155///
156/// If you already know how many bytes should be copied, `nstd_core_mem_copy[_overlapped]` should
157/// be used instead as it can minimize execution times.
158///
159/// # Parameters:
160///
161/// - `NSTDChar *dest` - The C string buffer to copy data to.
162///
163/// - `const NSTDChar *src` - The C string to copy data from.
164///
165/// # Safety
166///
167/// - `src` must point to a character array that is valid for reads up until and including it's
168/// null-terminating byte.
169///
170/// - `dest` must point to a character array that is valid for writes.
171///
172/// - `dest`'s buffer must be large enough to contain the contents of `src`.
173///
174/// # Example
175///
176/// ```
177/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_copy;
178///
179/// let cstr = b"Hello, world!\0";
180/// let mut buffer = [0u8; 14];
181///
182/// unsafe { nstd_core_cstr_raw_copy(buffer.as_mut_ptr().cast(), cstr.as_ptr().cast()) };
183/// assert!(&buffer == cstr);
184/// ```
185#[inline]
186#[nstdapi]
187#[allow(clippy::missing_const_for_fn)]
188pub unsafe fn nstd_core_cstr_raw_copy(mut dest: *mut NSTDChar, mut src: *const NSTDChar) {
189    while *src != 0 {
190        *dest = *src;
191        dest = dest.offset(1);
192        src = src.offset(1);
193    }
194}
195
196/// Copies the contents of one raw C string to another, including the source's null-terminator.
197///
198/// # Note
199///
200/// If you already know how many bytes should be copied, `nstd_core_mem_copy[_overlapped]` should
201/// be used instead as it can minimize execution times.
202///
203/// # Parameters:
204///
205/// - `NSTDChar *dest` - The C string buffer to copy data to.
206///
207/// - `const NSTDChar *src` - The C string to copy data from.
208///
209/// # Safety
210///
211/// - `src` must point to a character array that is valid for reads up until and including it's
212/// null-terminating byte.
213///
214/// - `dest` must point to a character array that is valid for writes.
215///
216/// - `dest`'s buffer must be large enough to contain the contents of `src`, including it's
217/// null-terminating byte.
218///
219/// # Example
220///
221/// ```
222/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_copy_with_null;
223///
224/// let cstr = b"Hello, world!\0";
225/// let mut buffer = [u8::MAX; 14];
226///
227/// let buf_ptr = buffer.as_mut_ptr().cast();
228/// unsafe { nstd_core_cstr_raw_copy_with_null(buf_ptr, cstr.as_ptr().cast()) };
229/// assert!(&buffer == cstr);
230/// ```
231#[inline]
232#[nstdapi]
233#[allow(unused_mut, clippy::missing_const_for_fn)]
234pub unsafe fn nstd_core_cstr_raw_copy_with_null(mut dest: *mut NSTDChar, mut src: *const NSTDChar) {
235    cfg_if! {
236        if #[cfg(all(
237            any(
238                unix,
239                windows,
240                any(target_env = "wasi", target_os = "wasi"),
241                target_os = "solid_asp3",
242                target_os = "teeos"
243            ),
244            feature = "libc"
245        ))] {
246            libc::strcpy(dest, src);
247        } else {
248            while {
249                *dest = *src;
250                *src != 0
251            } {
252                dest = dest.offset(1);
253                src = src.offset(1);
254            }
255        }
256    }
257}