ngx/core/string.rs
1use core::slice;
2use core::str::{self, Utf8Error};
3
4#[cfg(all(not(feature = "std"), feature = "alloc"))]
5use alloc::{borrow::Cow, string::String};
6#[cfg(feature = "std")]
7use std::{borrow::Cow, string::String};
8
9use crate::ffi::{ngx_str_t, u_char};
10
11/// Static string initializer for [`ngx_str_t`].
12///
13/// The resulting byte string is always nul-terminated (just like a C string).
14///
15/// [`ngx_str_t`]: https://nginx.org/en/docs/dev/development_guide.html#string_overview
16#[macro_export]
17macro_rules! ngx_string {
18 ($s:expr) => {{
19 $crate::ffi::ngx_str_t {
20 len: $s.len() as _,
21 data: concat!($s, "\0").as_ptr() as *mut u8,
22 }
23 }};
24}
25
26/// Representation of a borrowed [Nginx string].
27///
28/// [Nginx string]: https://nginx.org/en/docs/dev/development_guide.html#string_overview
29pub struct NgxStr([u_char]);
30
31impl NgxStr {
32 /// Create an [`NgxStr`] from an [`ngx_str_t`].
33 ///
34 /// [`ngx_str_t`]: https://nginx.org/en/docs/dev/development_guide.html#string_overview
35 ///
36 /// # Safety
37 ///
38 /// The caller has provided a valid `ngx_str_t` with a `data` pointer that points
39 /// to range of bytes of at least `len` bytes, whose content remains valid and doesn't
40 /// change for the lifetime of the returned `NgxStr`.
41 pub unsafe fn from_ngx_str<'a>(str: ngx_str_t) -> &'a NgxStr {
42 slice::from_raw_parts(str.data, str.len).into()
43 }
44
45 /// Access the [`NgxStr`] as a byte slice.
46 pub fn as_bytes(&self) -> &[u8] {
47 &self.0
48 }
49
50 /// Yields a `&str` slice if the [`NgxStr`] contains valid UTF-8.
51 pub fn to_str(&self) -> Result<&str, Utf8Error> {
52 str::from_utf8(self.as_bytes())
53 }
54
55 /// Converts an [`NgxStr`] into a [`Cow<str>`], replacing invalid UTF-8 sequences.
56 ///
57 /// See [`String::from_utf8_lossy`].
58 #[cfg(feature = "alloc")]
59 pub fn to_string_lossy(&self) -> Cow<str> {
60 String::from_utf8_lossy(self.as_bytes())
61 }
62
63 /// Returns `true` if the [`NgxStr`] is empty, otherwise `false`.
64 pub fn is_empty(&self) -> bool {
65 self.0.is_empty()
66 }
67}
68
69impl From<&[u8]> for &NgxStr {
70 fn from(bytes: &[u8]) -> Self {
71 // SAFETY: An `NgxStr` is identical to a `[u8]` slice, given `u_char` is an alias for `u8`.
72 unsafe { &*(bytes as *const [u8] as *const NgxStr) }
73 }
74}
75
76impl From<&str> for &NgxStr {
77 fn from(s: &str) -> Self {
78 s.as_bytes().into()
79 }
80}
81
82impl AsRef<[u8]> for NgxStr {
83 fn as_ref(&self) -> &[u8] {
84 self.as_bytes()
85 }
86}
87
88impl Default for &NgxStr {
89 fn default() -> Self {
90 // SAFETY: The empty `ngx_str_t` is always a valid Nginx string.
91 unsafe { NgxStr::from_ngx_str(ngx_str_t::default()) }
92 }
93}