1 | //! [`CStr`] and its related types. |
2 | |
3 | use crate::cmp::Ordering; |
4 | use crate::error::Error; |
5 | use crate::ffi::c_char; |
6 | use crate::fmt; |
7 | use crate::intrinsics; |
8 | use crate::iter::FusedIterator; |
9 | use crate::marker::PhantomData; |
10 | use crate::ops; |
11 | use crate::ptr::addr_of; |
12 | use crate::ptr::NonNull; |
13 | use crate::slice; |
14 | use crate::slice::memchr; |
15 | use crate::str; |
16 | |
17 | // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link |
18 | // depends on where the item is being documented. however, since this is libcore, we can't |
19 | // actually reference libstd or liballoc in intra-doc links. so, the best we can do is remove the |
20 | // links to `CString` and `String` for now until a solution is developed |
21 | |
22 | /// Representation of a borrowed C string. |
23 | /// |
24 | /// This type represents a borrowed reference to a nul-terminated |
25 | /// array of bytes. It can be constructed safely from a <code>&[[u8]]</code> |
26 | /// slice, or unsafely from a raw `*const c_char`. It can then be |
27 | /// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or |
28 | /// into an owned `CString`. |
29 | /// |
30 | /// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former |
31 | /// in each pair are borrowed references; the latter are owned |
32 | /// strings. |
33 | /// |
34 | /// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)` |
35 | /// notwithstanding) and is not recommended to be placed in the signatures of FFI functions. |
36 | /// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor |
37 | /// to provide a safe interface to other consumers. |
38 | /// |
39 | /// # Examples |
40 | /// |
41 | /// Inspecting a foreign C string: |
42 | /// |
43 | /// ```ignore (extern-declaration) |
44 | /// use std::ffi::CStr; |
45 | /// use std::os::raw::c_char; |
46 | /// |
47 | /// extern "C" { fn my_string() -> *const c_char; } |
48 | /// |
49 | /// unsafe { |
50 | /// let slice = CStr::from_ptr(my_string()); |
51 | /// println!("string buffer size without nul terminator: {}" , slice.to_bytes().len()); |
52 | /// } |
53 | /// ``` |
54 | /// |
55 | /// Passing a Rust-originating C string: |
56 | /// |
57 | /// ```ignore (extern-declaration) |
58 | /// use std::ffi::{CString, CStr}; |
59 | /// use std::os::raw::c_char; |
60 | /// |
61 | /// fn work(data: &CStr) { |
62 | /// extern "C" { fn work_with(data: *const c_char); } |
63 | /// |
64 | /// unsafe { work_with(data.as_ptr()) } |
65 | /// } |
66 | /// |
67 | /// let s = CString::new("data data data data" ).expect("CString::new failed" ); |
68 | /// work(&s); |
69 | /// ``` |
70 | /// |
71 | /// Converting a foreign C string into a Rust `String`: |
72 | /// |
73 | /// ```ignore (extern-declaration) |
74 | /// use std::ffi::CStr; |
75 | /// use std::os::raw::c_char; |
76 | /// |
77 | /// extern "C" { fn my_string() -> *const c_char; } |
78 | /// |
79 | /// fn my_string_safe() -> String { |
80 | /// let cstr = unsafe { CStr::from_ptr(my_string()) }; |
81 | /// // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation |
82 | /// String::from_utf8_lossy(cstr.to_bytes()).to_string() |
83 | /// } |
84 | /// |
85 | /// println!("string: {}" , my_string_safe()); |
86 | /// ``` |
87 | /// |
88 | /// [str]: prim@str "str" |
89 | #[derive (Hash)] |
90 | #[stable (feature = "core_c_str" , since = "1.64.0" )] |
91 | #[rustc_has_incoherent_inherent_impls ] |
92 | #[lang = "CStr" ] |
93 | // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies |
94 | // on `CStr` being layout-compatible with `[u8]`. |
95 | // However, `CStr` layout is considered an implementation detail and must not be relied upon. We |
96 | // want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under |
97 | // `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. |
98 | #[cfg_attr (not(doc), repr(transparent))] |
99 | #[allow (clippy::derived_hash_with_manual_eq)] |
100 | pub struct CStr { |
101 | // FIXME: this should not be represented with a DST slice but rather with |
102 | // just a raw `c_char` along with some form of marker to make |
103 | // this an unsized type. Essentially `sizeof(&CStr)` should be the |
104 | // same as `sizeof(&c_char)` but `CStr` should be an unsized type. |
105 | inner: [c_char], |
106 | } |
107 | |
108 | /// An error indicating that a nul byte was not in the expected position. |
109 | /// |
110 | /// The slice used to create a [`CStr`] must have one and only one nul byte, |
111 | /// positioned at the end. |
112 | /// |
113 | /// This error is created by the [`CStr::from_bytes_with_nul`] method. |
114 | /// See its documentation for more. |
115 | /// |
116 | /// # Examples |
117 | /// |
118 | /// ``` |
119 | /// use std::ffi::{CStr, FromBytesWithNulError}; |
120 | /// |
121 | /// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f \0oo" ).unwrap_err(); |
122 | /// ``` |
123 | #[derive (Clone, PartialEq, Eq, Debug)] |
124 | #[stable (feature = "core_c_str" , since = "1.64.0" )] |
125 | pub struct FromBytesWithNulError { |
126 | kind: FromBytesWithNulErrorKind, |
127 | } |
128 | |
129 | #[derive (Clone, PartialEq, Eq, Debug)] |
130 | enum FromBytesWithNulErrorKind { |
131 | InteriorNul(usize), |
132 | NotNulTerminated, |
133 | } |
134 | |
135 | // FIXME: const stability attributes should not be required here, I think |
136 | impl FromBytesWithNulError { |
137 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
138 | const fn interior_nul(pos: usize) -> FromBytesWithNulError { |
139 | FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } |
140 | } |
141 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
142 | const fn not_nul_terminated() -> FromBytesWithNulError { |
143 | FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } |
144 | } |
145 | } |
146 | |
147 | #[stable (feature = "frombyteswithnulerror_impls" , since = "1.17.0" )] |
148 | impl Error for FromBytesWithNulError { |
149 | #[allow (deprecated)] |
150 | fn description(&self) -> &str { |
151 | match self.kind { |
152 | FromBytesWithNulErrorKind::InteriorNul(..) => { |
153 | "data provided contains an interior nul byte" |
154 | } |
155 | FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated" , |
156 | } |
157 | } |
158 | } |
159 | |
160 | /// An error indicating that no nul byte was present. |
161 | /// |
162 | /// A slice used to create a [`CStr`] must contain a nul byte somewhere |
163 | /// within the slice. |
164 | /// |
165 | /// This error is created by the [`CStr::from_bytes_until_nul`] method. |
166 | /// |
167 | #[derive (Clone, PartialEq, Eq, Debug)] |
168 | #[stable (feature = "cstr_from_bytes_until_nul" , since = "1.69.0" )] |
169 | pub struct FromBytesUntilNulError(()); |
170 | |
171 | #[stable (feature = "cstr_from_bytes_until_nul" , since = "1.69.0" )] |
172 | impl fmt::Display for FromBytesUntilNulError { |
173 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
174 | write!(f, "data provided does not contain a nul" ) |
175 | } |
176 | } |
177 | |
178 | #[stable (feature = "cstr_debug" , since = "1.3.0" )] |
179 | impl fmt::Debug for CStr { |
180 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
181 | write!(f, " \"{}\"" , self.to_bytes().escape_ascii()) |
182 | } |
183 | } |
184 | |
185 | #[stable (feature = "cstr_default" , since = "1.10.0" )] |
186 | impl Default for &CStr { |
187 | #[inline ] |
188 | fn default() -> Self { |
189 | const SLICE: &[c_char] = &[0]; |
190 | // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string. |
191 | unsafe { CStr::from_ptr(SLICE.as_ptr()) } |
192 | } |
193 | } |
194 | |
195 | #[stable (feature = "frombyteswithnulerror_impls" , since = "1.17.0" )] |
196 | impl fmt::Display for FromBytesWithNulError { |
197 | #[allow (deprecated, deprecated_in_future)] |
198 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
199 | f.write_str(self.description())?; |
200 | if let FromBytesWithNulErrorKind::InteriorNul(pos: usize) = self.kind { |
201 | write!(f, " at byte pos {pos}" )?; |
202 | } |
203 | Ok(()) |
204 | } |
205 | } |
206 | |
207 | impl CStr { |
208 | /// Wraps a raw C string with a safe C string wrapper. |
209 | /// |
210 | /// This function will wrap the provided `ptr` with a `CStr` wrapper, which |
211 | /// allows inspection and interoperation of non-owned C strings. The total |
212 | /// size of the terminated buffer must be smaller than [`isize::MAX`] **bytes** |
213 | /// in memory (a restriction from [`slice::from_raw_parts`]). |
214 | /// |
215 | /// # Safety |
216 | /// |
217 | /// * The memory pointed to by `ptr` must contain a valid nul terminator at the |
218 | /// end of the string. |
219 | /// |
220 | /// * `ptr` must be [valid] for reads of bytes up to and including the nul terminator. |
221 | /// This means in particular: |
222 | /// |
223 | /// * The entire memory range of this `CStr` must be contained within a single allocated object! |
224 | /// * `ptr` must be non-null even for a zero-length cstr. |
225 | /// |
226 | /// * The memory referenced by the returned `CStr` must not be mutated for |
227 | /// the duration of lifetime `'a`. |
228 | /// |
229 | /// * The nul terminator must be within `isize::MAX` from `ptr` |
230 | /// |
231 | /// > **Note**: This operation is intended to be a 0-cost cast but it is |
232 | /// > currently implemented with an up-front calculation of the length of |
233 | /// > the string. This is not guaranteed to always be the case. |
234 | /// |
235 | /// # Caveat |
236 | /// |
237 | /// The lifetime for the returned slice is inferred from its usage. To prevent accidental misuse, |
238 | /// it's suggested to tie the lifetime to whichever source lifetime is safe in the context, |
239 | /// such as by providing a helper function taking the lifetime of a host value for the slice, |
240 | /// or by explicit annotation. |
241 | /// |
242 | /// # Examples |
243 | /// |
244 | /// ```ignore (extern-declaration) |
245 | /// use std::ffi::{c_char, CStr}; |
246 | /// |
247 | /// extern "C" { |
248 | /// fn my_string() -> *const c_char; |
249 | /// } |
250 | /// |
251 | /// unsafe { |
252 | /// let slice = CStr::from_ptr(my_string()); |
253 | /// println!("string returned: {}" , slice.to_str().unwrap()); |
254 | /// } |
255 | /// ``` |
256 | /// |
257 | /// ``` |
258 | /// #![feature(const_cstr_from_ptr)] |
259 | /// |
260 | /// use std::ffi::{c_char, CStr}; |
261 | /// |
262 | /// const HELLO_PTR: *const c_char = { |
263 | /// const BYTES: &[u8] = b"Hello, world! \0" ; |
264 | /// BYTES.as_ptr().cast() |
265 | /// }; |
266 | /// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) }; |
267 | /// ``` |
268 | /// |
269 | /// [valid]: core::ptr#safety |
270 | #[inline ] // inline is necessary for codegen to see strlen. |
271 | #[must_use ] |
272 | #[stable (feature = "rust1" , since = "1.0.0" )] |
273 | #[rustc_const_unstable (feature = "const_cstr_from_ptr" , issue = "113219" )] |
274 | pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { |
275 | // SAFETY: The caller has provided a pointer that points to a valid C |
276 | // string with a NUL terminator less than `isize::MAX` from `ptr`. |
277 | let len = unsafe { const_strlen(ptr) }; |
278 | |
279 | // SAFETY: The caller has provided a valid pointer with length less than |
280 | // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid |
281 | // and doesn't change for the lifetime of the returned `CStr`. This |
282 | // means the call to `from_bytes_with_nul_unchecked` is correct. |
283 | // |
284 | // The cast from c_char to u8 is ok because a c_char is always one byte. |
285 | unsafe { Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1)) } |
286 | } |
287 | |
288 | /// Creates a C string wrapper from a byte slice with any number of nuls. |
289 | /// |
290 | /// This method will create a `CStr` from any byte slice that contains at |
291 | /// least one nul byte. Unlike with [`CStr::from_bytes_with_nul`], the caller |
292 | /// does not need to know where the nul byte is located. |
293 | /// |
294 | /// If the first byte is a nul character, this method will return an |
295 | /// empty `CStr`. If multiple nul characters are present, the `CStr` will |
296 | /// end at the first one. |
297 | /// |
298 | /// If the slice only has a single nul byte at the end, this method is |
299 | /// equivalent to [`CStr::from_bytes_with_nul`]. |
300 | /// |
301 | /// # Examples |
302 | /// ``` |
303 | /// use std::ffi::CStr; |
304 | /// |
305 | /// let mut buffer = [0u8; 16]; |
306 | /// unsafe { |
307 | /// // Here we might call an unsafe C function that writes a string |
308 | /// // into the buffer. |
309 | /// let buf_ptr = buffer.as_mut_ptr(); |
310 | /// buf_ptr.write_bytes(b'A' , 8); |
311 | /// } |
312 | /// // Attempt to extract a C nul-terminated string from the buffer. |
313 | /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap(); |
314 | /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA" ); |
315 | /// ``` |
316 | /// |
317 | #[stable (feature = "cstr_from_bytes_until_nul" , since = "1.69.0" )] |
318 | #[rustc_const_stable (feature = "cstr_from_bytes_until_nul" , since = "1.69.0" )] |
319 | pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { |
320 | let nul_pos = memchr::memchr(0, bytes); |
321 | match nul_pos { |
322 | Some(nul_pos) => { |
323 | // FIXME(const-hack) replace with range index |
324 | // SAFETY: nul_pos + 1 <= bytes.len() |
325 | let subslice = unsafe { crate::slice::from_raw_parts(bytes.as_ptr(), nul_pos + 1) }; |
326 | // SAFETY: We know there is a nul byte at nul_pos, so this slice |
327 | // (ending at the nul byte) is a well-formed C string. |
328 | Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) }) |
329 | } |
330 | None => Err(FromBytesUntilNulError(())), |
331 | } |
332 | } |
333 | |
334 | /// Creates a C string wrapper from a byte slice with exactly one nul |
335 | /// terminator. |
336 | /// |
337 | /// This function will cast the provided `bytes` to a `CStr` |
338 | /// wrapper after ensuring that the byte slice is nul-terminated |
339 | /// and does not contain any interior nul bytes. |
340 | /// |
341 | /// If the nul byte may not be at the end, |
342 | /// [`CStr::from_bytes_until_nul`] can be used instead. |
343 | /// |
344 | /// # Examples |
345 | /// |
346 | /// ``` |
347 | /// use std::ffi::CStr; |
348 | /// |
349 | /// let cstr = CStr::from_bytes_with_nul(b"hello \0" ); |
350 | /// assert!(cstr.is_ok()); |
351 | /// ``` |
352 | /// |
353 | /// Creating a `CStr` without a trailing nul terminator is an error: |
354 | /// |
355 | /// ``` |
356 | /// use std::ffi::CStr; |
357 | /// |
358 | /// let cstr = CStr::from_bytes_with_nul(b"hello" ); |
359 | /// assert!(cstr.is_err()); |
360 | /// ``` |
361 | /// |
362 | /// Creating a `CStr` with an interior nul byte is an error: |
363 | /// |
364 | /// ``` |
365 | /// use std::ffi::CStr; |
366 | /// |
367 | /// let cstr = CStr::from_bytes_with_nul(b"he \0llo \0" ); |
368 | /// assert!(cstr.is_err()); |
369 | /// ``` |
370 | #[stable (feature = "cstr_from_bytes" , since = "1.10.0" )] |
371 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
372 | pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { |
373 | let nul_pos = memchr::memchr(0, bytes); |
374 | match nul_pos { |
375 | Some(nul_pos) if nul_pos + 1 == bytes.len() => { |
376 | // SAFETY: We know there is only one nul byte, at the end |
377 | // of the byte slice. |
378 | Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) |
379 | } |
380 | Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)), |
381 | None => Err(FromBytesWithNulError::not_nul_terminated()), |
382 | } |
383 | } |
384 | |
385 | /// Unsafely creates a C string wrapper from a byte slice. |
386 | /// |
387 | /// This function will cast the provided `bytes` to a `CStr` wrapper without |
388 | /// performing any sanity checks. |
389 | /// |
390 | /// # Safety |
391 | /// The provided slice **must** be nul-terminated and not contain any interior |
392 | /// nul bytes. |
393 | /// |
394 | /// # Examples |
395 | /// |
396 | /// ``` |
397 | /// use std::ffi::{CStr, CString}; |
398 | /// |
399 | /// unsafe { |
400 | /// let cstring = CString::new("hello" ).expect("CString::new failed" ); |
401 | /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); |
402 | /// assert_eq!(cstr, &*cstring); |
403 | /// } |
404 | /// ``` |
405 | #[inline ] |
406 | #[must_use ] |
407 | #[stable (feature = "cstr_from_bytes" , since = "1.10.0" )] |
408 | #[rustc_const_stable (feature = "const_cstr_unchecked" , since = "1.59.0" )] |
409 | #[rustc_allow_const_fn_unstable (const_eval_select)] |
410 | pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { |
411 | #[inline ] |
412 | fn rt_impl(bytes: &[u8]) -> &CStr { |
413 | // Chance at catching some UB at runtime with debug builds. |
414 | debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); |
415 | |
416 | // SAFETY: Casting to CStr is safe because its internal representation |
417 | // is a [u8] too (safe only inside std). |
418 | // Dereferencing the obtained pointer is safe because it comes from a |
419 | // reference. Making a reference is then safe because its lifetime |
420 | // is bound by the lifetime of the given `bytes`. |
421 | unsafe { &*(bytes as *const [u8] as *const CStr) } |
422 | } |
423 | |
424 | const fn const_impl(bytes: &[u8]) -> &CStr { |
425 | // Saturating so that an empty slice panics in the assert with a good |
426 | // message, not here due to underflow. |
427 | let mut i = bytes.len().saturating_sub(1); |
428 | assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated" ); |
429 | |
430 | // Ending nul byte exists, skip to the rest. |
431 | while i != 0 { |
432 | i -= 1; |
433 | let byte = bytes[i]; |
434 | assert!(byte != 0, "input contained interior nul" ); |
435 | } |
436 | |
437 | // SAFETY: See `rt_impl` cast. |
438 | unsafe { &*(bytes as *const [u8] as *const CStr) } |
439 | } |
440 | |
441 | intrinsics::const_eval_select((bytes,), const_impl, rt_impl) |
442 | } |
443 | |
444 | /// Returns the inner pointer to this C string. |
445 | /// |
446 | /// The returned pointer will be valid for as long as `self` is, and points |
447 | /// to a contiguous region of memory terminated with a 0 byte to represent |
448 | /// the end of the string. |
449 | /// |
450 | /// The type of the returned pointer is |
451 | /// [`*const c_char`][crate::ffi::c_char], and whether it's |
452 | /// an alias for `*const i8` or `*const u8` is platform-specific. |
453 | /// |
454 | /// **WARNING** |
455 | /// |
456 | /// The returned pointer is read-only; writing to it (including passing it |
457 | /// to C code that writes to it) causes undefined behavior. |
458 | /// |
459 | /// It is your responsibility to make sure that the underlying memory is not |
460 | /// freed too early. For example, the following code will cause undefined |
461 | /// behavior when `ptr` is used inside the `unsafe` block: |
462 | /// |
463 | /// ```no_run |
464 | /// # #![allow (unused_must_use)] #![allow (temporary_cstring_as_ptr)] |
465 | /// use std::ffi::CString; |
466 | /// |
467 | /// // Do not do this: |
468 | /// let ptr = CString::new("Hello" ).expect("CString::new failed" ).as_ptr(); |
469 | /// unsafe { |
470 | /// // `ptr` is dangling |
471 | /// *ptr; |
472 | /// } |
473 | /// ``` |
474 | /// |
475 | /// This happens because the pointer returned by `as_ptr` does not carry any |
476 | /// lifetime information and the `CString` is deallocated immediately after |
477 | /// the `CString::new("Hello").expect("CString::new failed").as_ptr()` |
478 | /// expression is evaluated. |
479 | /// To fix the problem, bind the `CString` to a local variable: |
480 | /// |
481 | /// ```no_run |
482 | /// # #![allow(unused_must_use)] |
483 | /// use std::ffi::CString; |
484 | /// |
485 | /// let hello = CString::new("Hello" ).expect("CString::new failed" ); |
486 | /// let ptr = hello.as_ptr(); |
487 | /// unsafe { |
488 | /// // `ptr` is valid because `hello` is in scope |
489 | /// *ptr; |
490 | /// } |
491 | /// ``` |
492 | /// |
493 | /// This way, the lifetime of the `CString` in `hello` encompasses |
494 | /// the lifetime of `ptr` and the `unsafe` block. |
495 | #[inline ] |
496 | #[must_use ] |
497 | #[stable (feature = "rust1" , since = "1.0.0" )] |
498 | #[rustc_const_stable (feature = "const_str_as_ptr" , since = "1.32.0" )] |
499 | #[rustc_never_returns_null_ptr ] |
500 | pub const fn as_ptr(&self) -> *const c_char { |
501 | self.inner.as_ptr() |
502 | } |
503 | |
504 | /// We could eventually expose this publicly, if we wanted. |
505 | #[inline ] |
506 | #[must_use ] |
507 | const fn as_non_null_ptr(&self) -> NonNull<c_char> { |
508 | NonNull::from(&self.inner).as_non_null_ptr() |
509 | } |
510 | |
511 | /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator. |
512 | /// |
513 | /// > **Note**: This method is currently implemented as a constant-time |
514 | /// > cast, but it is planned to alter its definition in the future to |
515 | /// > perform the length calculation whenever this method is called. |
516 | /// |
517 | /// # Examples |
518 | /// |
519 | /// ``` |
520 | /// use std::ffi::CStr; |
521 | /// |
522 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" ).unwrap(); |
523 | /// assert_eq!(cstr.count_bytes(), 3); |
524 | /// |
525 | /// let cstr = CStr::from_bytes_with_nul(b" \0" ).unwrap(); |
526 | /// assert_eq!(cstr.count_bytes(), 0); |
527 | /// ``` |
528 | #[inline ] |
529 | #[must_use ] |
530 | #[doc (alias("len" , "strlen" ))] |
531 | #[stable (feature = "cstr_count_bytes" , since = "CURRENT_RUSTC_VERSION" )] |
532 | #[rustc_const_unstable (feature = "const_cstr_from_ptr" , issue = "113219" )] |
533 | pub const fn count_bytes(&self) -> usize { |
534 | self.inner.len() - 1 |
535 | } |
536 | |
537 | /// Returns `true` if `self.to_bytes()` has a length of 0. |
538 | /// |
539 | /// # Examples |
540 | /// |
541 | /// ``` |
542 | /// use std::ffi::CStr; |
543 | /// # use std::ffi::FromBytesWithNulError; |
544 | /// |
545 | /// # fn main() { test().unwrap(); } |
546 | /// # fn test() -> Result<(), FromBytesWithNulError> { |
547 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" )?; |
548 | /// assert!(!cstr.is_empty()); |
549 | /// |
550 | /// let empty_cstr = CStr::from_bytes_with_nul(b" \0" )?; |
551 | /// assert!(empty_cstr.is_empty()); |
552 | /// # Ok(()) |
553 | /// # } |
554 | /// ``` |
555 | #[inline ] |
556 | #[stable (feature = "cstr_is_empty" , since = "1.71.0" )] |
557 | #[rustc_const_stable (feature = "cstr_is_empty" , since = "1.71.0" )] |
558 | pub const fn is_empty(&self) -> bool { |
559 | // SAFETY: We know there is at least one byte; for empty strings it |
560 | // is the NUL terminator. |
561 | // FIXME(const-hack): use get_unchecked |
562 | unsafe { *self.inner.as_ptr() == 0 } |
563 | } |
564 | |
565 | /// Converts this C string to a byte slice. |
566 | /// |
567 | /// The returned slice will **not** contain the trailing nul terminator that this C |
568 | /// string has. |
569 | /// |
570 | /// > **Note**: This method is currently implemented as a constant-time |
571 | /// > cast, but it is planned to alter its definition in the future to |
572 | /// > perform the length calculation whenever this method is called. |
573 | /// |
574 | /// # Examples |
575 | /// |
576 | /// ``` |
577 | /// use std::ffi::CStr; |
578 | /// |
579 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" ).expect("CStr::from_bytes_with_nul failed" ); |
580 | /// assert_eq!(cstr.to_bytes(), b"foo" ); |
581 | /// ``` |
582 | #[inline ] |
583 | #[must_use = "this returns the result of the operation, \ |
584 | without modifying the original" ] |
585 | #[stable (feature = "rust1" , since = "1.0.0" )] |
586 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
587 | pub const fn to_bytes(&self) -> &[u8] { |
588 | let bytes = self.to_bytes_with_nul(); |
589 | // FIXME(const-hack) replace with range index |
590 | // SAFETY: to_bytes_with_nul returns slice with length at least 1 |
591 | unsafe { slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1) } |
592 | } |
593 | |
594 | /// Converts this C string to a byte slice containing the trailing 0 byte. |
595 | /// |
596 | /// This function is the equivalent of [`CStr::to_bytes`] except that it |
597 | /// will retain the trailing nul terminator instead of chopping it off. |
598 | /// |
599 | /// > **Note**: This method is currently implemented as a 0-cost cast, but |
600 | /// > it is planned to alter its definition in the future to perform the |
601 | /// > length calculation whenever this method is called. |
602 | /// |
603 | /// # Examples |
604 | /// |
605 | /// ``` |
606 | /// use std::ffi::CStr; |
607 | /// |
608 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" ).expect("CStr::from_bytes_with_nul failed" ); |
609 | /// assert_eq!(cstr.to_bytes_with_nul(), b"foo \0" ); |
610 | /// ``` |
611 | #[inline ] |
612 | #[must_use = "this returns the result of the operation, \ |
613 | without modifying the original" ] |
614 | #[stable (feature = "rust1" , since = "1.0.0" )] |
615 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
616 | pub const fn to_bytes_with_nul(&self) -> &[u8] { |
617 | // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s |
618 | // is safe on all supported targets. |
619 | unsafe { &*(addr_of!(self.inner) as *const [u8]) } |
620 | } |
621 | |
622 | /// Iterates over the bytes in this C string. |
623 | /// |
624 | /// The returned iterator will **not** contain the trailing nul terminator |
625 | /// that this C string has. |
626 | /// |
627 | /// # Examples |
628 | /// |
629 | /// ``` |
630 | /// #![feature(cstr_bytes)] |
631 | /// use std::ffi::CStr; |
632 | /// |
633 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" ).expect("CStr::from_bytes_with_nul failed" ); |
634 | /// assert!(cstr.bytes().eq(*b"foo" )); |
635 | /// ``` |
636 | #[inline ] |
637 | #[unstable (feature = "cstr_bytes" , issue = "112115" )] |
638 | pub fn bytes(&self) -> Bytes<'_> { |
639 | Bytes::new(self) |
640 | } |
641 | |
642 | /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8. |
643 | /// |
644 | /// If the contents of the `CStr` are valid UTF-8 data, this |
645 | /// function will return the corresponding <code>&[str]</code> slice. Otherwise, |
646 | /// it will return an error with details of where UTF-8 validation failed. |
647 | /// |
648 | /// [str]: prim@str "str" |
649 | /// |
650 | /// # Examples |
651 | /// |
652 | /// ``` |
653 | /// use std::ffi::CStr; |
654 | /// |
655 | /// let cstr = CStr::from_bytes_with_nul(b"foo \0" ).expect("CStr::from_bytes_with_nul failed" ); |
656 | /// assert_eq!(cstr.to_str(), Ok("foo" )); |
657 | /// ``` |
658 | #[stable (feature = "cstr_to_str" , since = "1.4.0" )] |
659 | #[rustc_const_stable (feature = "const_cstr_methods" , since = "1.72.0" )] |
660 | pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { |
661 | // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` |
662 | // instead of in `from_ptr()`, it may be worth considering if this should |
663 | // be rewritten to do the UTF-8 check inline with the length calculation |
664 | // instead of doing it afterwards. |
665 | str::from_utf8(self.to_bytes()) |
666 | } |
667 | } |
668 | |
669 | #[stable (feature = "rust1" , since = "1.0.0" )] |
670 | impl PartialEq for CStr { |
671 | #[inline ] |
672 | fn eq(&self, other: &CStr) -> bool { |
673 | self.to_bytes().eq(other.to_bytes()) |
674 | } |
675 | } |
676 | #[stable (feature = "rust1" , since = "1.0.0" )] |
677 | impl Eq for CStr {} |
678 | #[stable (feature = "rust1" , since = "1.0.0" )] |
679 | impl PartialOrd for CStr { |
680 | #[inline ] |
681 | fn partial_cmp(&self, other: &CStr) -> Option<Ordering> { |
682 | self.to_bytes().partial_cmp(&other.to_bytes()) |
683 | } |
684 | } |
685 | #[stable (feature = "rust1" , since = "1.0.0" )] |
686 | impl Ord for CStr { |
687 | #[inline ] |
688 | fn cmp(&self, other: &CStr) -> Ordering { |
689 | self.to_bytes().cmp(&other.to_bytes()) |
690 | } |
691 | } |
692 | |
693 | #[stable (feature = "cstr_range_from" , since = "1.47.0" )] |
694 | impl ops::Index<ops::RangeFrom<usize>> for CStr { |
695 | type Output = CStr; |
696 | |
697 | #[inline ] |
698 | fn index(&self, index: ops::RangeFrom<usize>) -> &CStr { |
699 | let bytes: &[u8] = self.to_bytes_with_nul(); |
700 | // we need to manually check the starting index to account for the null |
701 | // byte, since otherwise we could get an empty string that doesn't end |
702 | // in a null. |
703 | if index.start < bytes.len() { |
704 | // SAFETY: Non-empty tail of a valid `CStr` is still a valid `CStr`. |
705 | unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) } |
706 | } else { |
707 | panic!( |
708 | "index out of bounds: the len is {} but the index is {}" , |
709 | bytes.len(), |
710 | index.start |
711 | ); |
712 | } |
713 | } |
714 | } |
715 | |
716 | #[stable (feature = "cstring_asref" , since = "1.7.0" )] |
717 | impl AsRef<CStr> for CStr { |
718 | #[inline ] |
719 | fn as_ref(&self) -> &CStr { |
720 | self |
721 | } |
722 | } |
723 | |
724 | /// Calculate the length of a nul-terminated string. Defers to C's `strlen` when possible. |
725 | /// |
726 | /// # Safety |
727 | /// |
728 | /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be |
729 | /// located within `isize::MAX` from `ptr`. |
730 | #[inline ] |
731 | const unsafe fn const_strlen(ptr: *const c_char) -> usize { |
732 | const fn strlen_ct(s: *const c_char) -> usize { |
733 | let mut len = 0; |
734 | |
735 | // SAFETY: Outer caller has provided a pointer to a valid C string. |
736 | while unsafe { *s.add(len) } != 0 { |
737 | len += 1; |
738 | } |
739 | |
740 | len |
741 | } |
742 | |
743 | #[inline ] |
744 | fn strlen_rt(s: *const c_char) -> usize { |
745 | extern "C" { |
746 | /// Provided by libc or compiler_builtins. |
747 | fn strlen(s: *const c_char) -> usize; |
748 | } |
749 | |
750 | // SAFETY: Outer caller has provided a pointer to a valid C string. |
751 | unsafe { strlen(s) } |
752 | } |
753 | |
754 | intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) |
755 | } |
756 | |
757 | /// An iterator over the bytes of a [`CStr`], without the nul terminator. |
758 | /// |
759 | /// This struct is created by the [`bytes`] method on [`CStr`]. |
760 | /// See its documentation for more. |
761 | /// |
762 | /// [`bytes`]: CStr::bytes |
763 | #[must_use = "iterators are lazy and do nothing unless consumed" ] |
764 | #[unstable (feature = "cstr_bytes" , issue = "112115" )] |
765 | #[derive (Clone, Debug)] |
766 | pub struct Bytes<'a> { |
767 | // since we know the string is nul-terminated, we only need one pointer |
768 | ptr: NonNull<u8>, |
769 | phantom: PhantomData<&'a u8>, |
770 | } |
771 | impl<'a> Bytes<'a> { |
772 | #[inline ] |
773 | fn new(s: &'a CStr) -> Self { |
774 | Self { ptr: s.as_non_null_ptr().cast(), phantom: PhantomData } |
775 | } |
776 | |
777 | #[inline ] |
778 | fn is_empty(&self) -> bool { |
779 | // SAFETY: We uphold that the pointer is always valid to dereference |
780 | // by starting with a valid C string and then never incrementing beyond |
781 | // the nul terminator. |
782 | unsafe { self.ptr.read() == 0 } |
783 | } |
784 | } |
785 | |
786 | #[unstable (feature = "cstr_bytes" , issue = "112115" )] |
787 | impl Iterator for Bytes<'_> { |
788 | type Item = u8; |
789 | |
790 | #[inline ] |
791 | fn next(&mut self) -> Option<u8> { |
792 | // SAFETY: We only choose a pointer from a valid C string, which must |
793 | // be non-null and contain at least one value. Since we always stop at |
794 | // the nul terminator, which is guaranteed to exist, we can assume that |
795 | // the pointer is non-null and valid. This lets us safely dereference |
796 | // it and assume that adding 1 will create a new, non-null, valid |
797 | // pointer. |
798 | unsafe { |
799 | let ret = self.ptr.read(); |
800 | if ret == 0 { |
801 | None |
802 | } else { |
803 | self.ptr = self.ptr.offset(1); |
804 | Some(ret) |
805 | } |
806 | } |
807 | } |
808 | |
809 | #[inline ] |
810 | fn size_hint(&self) -> (usize, Option<usize>) { |
811 | if self.is_empty() { (0, Some(0)) } else { (1, None) } |
812 | } |
813 | } |
814 | |
815 | #[unstable (feature = "cstr_bytes" , issue = "112115" )] |
816 | impl FusedIterator for Bytes<'_> {} |
817 | |