Skip to content

Commit da4f883

Browse files
committed
feat: some useful trait impls and conversions for NgxStr
1 parent 1fd19d3 commit da4f883

File tree

2 files changed

+160
-12
lines changed

2 files changed

+160
-12
lines changed

nginx-sys/src/string.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ impl ngx_str_t {
9292
}
9393
}
9494

95+
impl AsRef<[u8]> for ngx_str_t {
96+
fn as_ref(&self) -> &[u8] {
97+
self.as_bytes()
98+
}
99+
}
100+
101+
impl AsMut<[u8]> for ngx_str_t {
102+
fn as_mut(&mut self) -> &mut [u8] {
103+
self.as_bytes_mut()
104+
}
105+
}
106+
95107
impl Default for ngx_str_t {
96108
fn default() -> Self {
97109
Self::empty()
@@ -114,6 +126,26 @@ impl fmt::Display for ngx_str_t {
114126
}
115127
}
116128

129+
impl PartialEq for ngx_str_t {
130+
fn eq(&self, other: &Self) -> bool {
131+
PartialEq::eq(self.as_bytes(), other.as_bytes())
132+
}
133+
}
134+
135+
impl Eq for ngx_str_t {}
136+
137+
impl PartialOrd<Self> for ngx_str_t {
138+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
139+
Some(self.cmp(other))
140+
}
141+
}
142+
143+
impl Ord for ngx_str_t {
144+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
145+
Ord::cmp(self.as_bytes(), other.as_bytes())
146+
}
147+
}
148+
117149
impl TryFrom<ngx_str_t> for &str {
118150
type Error = core::str::Utf8Error;
119151

src/core/string.rs

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#[cfg(all(not(feature = "std"), feature = "alloc"))]
22
use alloc::{borrow::Cow, string::String};
3+
use core::cmp;
34
use core::fmt;
45
use core::str::{self, Utf8Error};
56
#[cfg(feature = "std")]
@@ -25,6 +26,7 @@ macro_rules! ngx_string {
2526
/// Representation of a borrowed [Nginx string].
2627
///
2728
/// [Nginx string]: https://nginx.org/en/docs/dev/development_guide.html#string_overview
29+
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
2830
#[repr(transparent)]
2931
pub struct NgxStr([u_char]);
3032

@@ -50,6 +52,13 @@ impl NgxStr {
5052
unsafe { &*(bytes as *const [u8] as *const NgxStr) }
5153
}
5254

55+
/// Create a mutable [NgxStr] from a borrowed byte slice.
56+
#[inline]
57+
pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self {
58+
// SAFETY: An `NgxStr` is identical to a `[u8]` slice, given `u_char` is an alias for `u8`
59+
unsafe { &mut *(bytes as *mut [u8] as *mut NgxStr) }
60+
}
61+
5362
/// Access the [`NgxStr`] as a byte slice.
5463
pub fn as_bytes(&self) -> &[u8] {
5564
&self.0
@@ -74,24 +83,20 @@ impl NgxStr {
7483
}
7584
}
7685

77-
impl<'a> From<&'a [u8]> for &'a NgxStr {
78-
fn from(bytes: &'a [u8]) -> Self {
79-
NgxStr::from_bytes(bytes)
80-
}
81-
}
82-
83-
impl<'a> From<&'a str> for &'a NgxStr {
84-
fn from(s: &'a str) -> Self {
85-
NgxStr::from_bytes(s.as_bytes())
86-
}
87-
}
88-
8986
impl AsRef<[u8]> for NgxStr {
87+
#[inline]
9088
fn as_ref(&self) -> &[u8] {
9189
self.as_bytes()
9290
}
9391
}
9492

93+
impl AsMut<[u8]> for NgxStr {
94+
#[inline]
95+
fn as_mut(&mut self) -> &mut [u8] {
96+
&mut self.0
97+
}
98+
}
99+
95100
impl fmt::Debug for NgxStr {
96101
#[inline]
97102
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -115,6 +120,91 @@ impl fmt::Display for NgxStr {
115120
}
116121
}
117122

123+
macro_rules! impl_partial_ord_eq_from {
124+
($self:ty, $other:ty) => { impl_partial_ord_eq_from!($self, $other;); };
125+
126+
($self:ty, $other:ty; $($args:tt)*) => {
127+
impl<'a, $($args)*> From<$other> for &'a NgxStr {
128+
#[inline]
129+
fn from(other: $other) -> Self {
130+
let other: &[u8] = other.as_ref();
131+
NgxStr::from_bytes(other)
132+
}
133+
}
134+
135+
impl_partial_eq!($self, $other; $($args)*);
136+
impl_partial_ord!($self, $other; $($args)*);
137+
};
138+
}
139+
140+
macro_rules! impl_partial_eq {
141+
($self:ty, $other:ty) => { impl_partial_eq!($self, $other;); };
142+
143+
($self:ty, $other:ty; $($args:tt)*) => {
144+
impl<'a, $($args)*> PartialEq<$other> for $self {
145+
#[inline]
146+
fn eq(&self, other: &$other) -> bool {
147+
let other: &[u8] = other.as_ref();
148+
PartialEq::eq(self.as_bytes(), other)
149+
}
150+
}
151+
152+
impl<'a, $($args)*> PartialEq<$self> for $other {
153+
#[inline]
154+
fn eq(&self, other: &$self) -> bool {
155+
let this: &[u8] = self.as_ref();
156+
PartialEq::eq(this, other.as_bytes())
157+
}
158+
}
159+
};
160+
}
161+
162+
macro_rules! impl_partial_ord {
163+
($self:ty, $other:ty) => { impl_partial_ord!($self, $other;); };
164+
165+
($self:ty, $other:ty; $($args:tt)*) => {
166+
impl<'a, $($args)*> PartialOrd<$other> for $self {
167+
#[inline]
168+
fn partial_cmp(&self, other: &$other) -> Option<cmp::Ordering> {
169+
let other: &[u8] = other.as_ref();
170+
PartialOrd::partial_cmp(self.as_bytes(), other)
171+
}
172+
}
173+
174+
impl<'a, $($args)*> PartialOrd<$self> for $other {
175+
#[inline]
176+
fn partial_cmp(&self, other: &$self) -> Option<cmp::Ordering> {
177+
let this: &[u8] = self.as_ref();
178+
PartialOrd::partial_cmp(this, other.as_bytes())
179+
}
180+
}
181+
};
182+
}
183+
184+
impl_partial_eq!(NgxStr, [u8]);
185+
impl_partial_eq!(NgxStr, [u8; N]; const N: usize);
186+
impl_partial_eq!(NgxStr, str);
187+
impl_partial_eq!(NgxStr, ngx_str_t);
188+
impl_partial_eq!(&'a NgxStr, ngx_str_t);
189+
impl_partial_ord!(NgxStr, [u8]);
190+
impl_partial_ord!(NgxStr, [u8; N]; const N: usize);
191+
impl_partial_ord!(NgxStr, str);
192+
impl_partial_ord!(NgxStr, ngx_str_t);
193+
impl_partial_ord!(&'a NgxStr, ngx_str_t);
194+
impl_partial_ord_eq_from!(NgxStr, &'a [u8]);
195+
impl_partial_ord_eq_from!(NgxStr, &'a [u8; N]; const N: usize);
196+
impl_partial_ord_eq_from!(NgxStr, &'a str);
197+
198+
#[cfg(feature = "alloc")]
199+
mod _alloc_impls {
200+
use super::*;
201+
impl_partial_eq!(NgxStr, String);
202+
impl_partial_eq!(&'a NgxStr, String);
203+
impl_partial_ord!(NgxStr, String);
204+
impl_partial_ord!(&'a NgxStr, String);
205+
impl_partial_ord_eq_from!(NgxStr, &'a String);
206+
}
207+
118208
#[cfg(test)]
119209
mod tests {
120210
extern crate alloc;
@@ -123,6 +213,32 @@ mod tests {
123213

124214
use super::*;
125215

216+
#[test]
217+
fn test_comparisons() {
218+
let string = "test".to_string();
219+
let ngx_string = ngx_str_t {
220+
data: string.as_ptr().cast_mut(),
221+
len: string.len(),
222+
};
223+
let ns: &NgxStr = string.as_bytes().into();
224+
225+
#[cfg(feature = "alloc")]
226+
assert_eq!(string, ns);
227+
assert_eq!(ngx_string, ns);
228+
assert_eq!(string.as_bytes(), ns);
229+
assert_eq!(string.as_str(), ns);
230+
assert_eq!(b"test", ns);
231+
assert_eq!("test", ns);
232+
233+
#[cfg(feature = "alloc")]
234+
assert_eq!(ns, string);
235+
assert_eq!(ns, ngx_string);
236+
assert_eq!(ns, string.as_bytes());
237+
assert_eq!(ns, string.as_str());
238+
assert_eq!(ns, b"test");
239+
assert_eq!(ns, "test");
240+
}
241+
126242
#[test]
127243
fn test_lifetimes() {
128244
let a: &NgxStr = "Hello World!".into();

0 commit comments

Comments
 (0)