Skip to content

Commit 3a04f2e

Browse files
committed
feat(sys): add ngx_str_t::strip_prefix/suffix methods
The former is particularly useful when parsing the configuration to avoid creation of an intermediate reference. The latter added for sake of completeness.
1 parent 2d01596 commit 3a04f2e

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

nginx-sys/src/string.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,66 @@ impl ngx_str_t {
9393
len: data.len(),
9494
}
9595
}
96+
97+
/// Divides one `ngx_str_t` into two at an index.
98+
///
99+
/// # Safety
100+
///
101+
/// The results will reference the original string; be wary of the ownership and lifetime.
102+
pub fn split_at(&self, mid: usize) -> Option<(ngx_str_t, ngx_str_t)> {
103+
if mid > self.len {
104+
return None;
105+
}
106+
107+
Some((
108+
ngx_str_t {
109+
data: self.data,
110+
len: mid,
111+
},
112+
ngx_str_t {
113+
data: unsafe { self.data.add(mid) },
114+
len: self.len - mid,
115+
},
116+
))
117+
}
118+
119+
/// Returns an `ngx_str_t` with the prefix removed.
120+
///
121+
/// If the string starts with the byte sequence `prefix`, returns the substring after the
122+
/// prefix, wrapped in `Some`. The resulting substring can be empty.
123+
///
124+
/// # Safety
125+
///
126+
/// The result will reference the original string; be wary of the ownership and lifetime.
127+
///
128+
/// The method is not marked as `unsafe` as everything it does is possible via safe interfaces.
129+
pub fn strip_prefix(&self, prefix: impl AsRef<[u8]>) -> Option<ngx_str_t> {
130+
let prefix = prefix.as_ref();
131+
if self.as_bytes().starts_with(prefix) {
132+
self.split_at(prefix.len()).map(|x| x.1)
133+
} else {
134+
None
135+
}
136+
}
137+
138+
/// Returns an `ngx_str_t` with the suffix removed.
139+
///
140+
/// If the string ends with the byte sequence `suffix`, returns the substring before the
141+
/// suffix, wrapped in `Some`. The resulting substring can be empty.
142+
///
143+
/// # Safety
144+
///
145+
/// The result will reference the original string; be wary of the ownership and lifetime.
146+
///
147+
/// The method is not marked as `unsafe` as everything it does is possible via safe interfaces.
148+
pub fn strip_suffix(&self, suffix: impl AsRef<[u8]>) -> Option<ngx_str_t> {
149+
let suffix = suffix.as_ref();
150+
if self.as_bytes().ends_with(suffix) {
151+
self.split_at(self.len - suffix.len()).map(|x| x.0)
152+
} else {
153+
None
154+
}
155+
}
96156
}
97157

98158
impl AsRef<[u8]> for ngx_str_t {
@@ -162,3 +222,31 @@ impl TryFrom<ngx_str_t> for &str {
162222
str::from_utf8(s.into())
163223
}
164224
}
225+
226+
#[cfg(test)]
227+
mod tests {
228+
use super::*;
229+
230+
#[test]
231+
fn ngx_str_prefix() {
232+
let s = "key=value";
233+
let s = ngx_str_t {
234+
data: s.as_ptr().cast_mut(),
235+
len: s.len(),
236+
};
237+
238+
assert_eq!(
239+
s.strip_prefix("key=").as_ref().map(ngx_str_t::as_bytes),
240+
Some("value".as_bytes())
241+
);
242+
243+
assert_eq!(s.strip_prefix("test"), None);
244+
245+
assert_eq!(
246+
s.strip_suffix("value").as_ref().map(ngx_str_t::as_bytes),
247+
Some("key=".as_bytes())
248+
);
249+
250+
assert_eq!(s.strip_suffix("test"), None);
251+
}
252+
}

0 commit comments

Comments
 (0)