11#[ cfg( all( not( feature = "std" ) , feature = "alloc" ) ) ]
22use alloc:: { borrow:: Cow , string:: String } ;
3+ use core:: cmp;
34use core:: fmt;
45use 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) ]
2931pub 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-
8986impl 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+
95100impl 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) ]
119209mod 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