Skip to content

Commit 575f6c5

Browse files
authored
Rollup merge of #93686 - dbrgn:trim-on-byte-slices, r=joshtriplett
core: Implement ASCII trim functions on byte slices Hi ````````@rust-lang/libs!```````` This is a feature that I wished for when implementing serial protocols with microcontrollers. Often these protocols may contain leading or trailing whitespace, which needs to be removed. Because oftentimes drivers will operate on the byte level, decoding to unicode and checking for unicode whitespace is unnecessary overhead. This PR adds three new methods to byte slices: - `trim_ascii_start` - `trim_ascii_end` - `trim_ascii` I did not find any pre-existing discussions about this, which surprises me a bit. Maybe I'm missing something, and this functionality is already possible through other means? There's rust-lang/rfcs#2547 ("Trim methods on slices"), but that has a different purpose. As per the [std dev guide](https://std-dev-guide.rust-lang.org/feature-lifecycle/new-unstable-features.html), this is a proposed implementation without any issue / RFC. If this is the wrong process, please let me know. However, I thought discussing code is easier than discussing a mere idea, and hacking on the stdlib was fun. Tracking issue: #94035
2 parents 4f533de + f7448a7 commit 575f6c5

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

library/core/src/slice/ascii.rs

+78
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,84 @@ impl [u8] {
7979
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
8080
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
8181
}
82+
83+
/// Returns a byte slice with leading ASCII whitespace bytes removed.
84+
///
85+
/// 'Whitespace' refers to the definition used by
86+
/// `u8::is_ascii_whitespace`.
87+
///
88+
/// # Examples
89+
///
90+
/// ```
91+
/// #![feature(byte_slice_trim_ascii)]
92+
///
93+
/// assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
94+
/// assert_eq!(b" ".trim_ascii_start(), b"");
95+
/// assert_eq!(b"".trim_ascii_start(), b"");
96+
/// ```
97+
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
98+
pub const fn trim_ascii_start(&self) -> &[u8] {
99+
let mut bytes = self;
100+
// Note: A pattern matching based approach (instead of indexing) allows
101+
// making the function const.
102+
while let [first, rest @ ..] = bytes {
103+
if first.is_ascii_whitespace() {
104+
bytes = rest;
105+
} else {
106+
break;
107+
}
108+
}
109+
bytes
110+
}
111+
112+
/// Returns a byte slice with trailing ASCII whitespace bytes removed.
113+
///
114+
/// 'Whitespace' refers to the definition used by
115+
/// `u8::is_ascii_whitespace`.
116+
///
117+
/// # Examples
118+
///
119+
/// ```
120+
/// #![feature(byte_slice_trim_ascii)]
121+
///
122+
/// assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
123+
/// assert_eq!(b" ".trim_ascii_end(), b"");
124+
/// assert_eq!(b"".trim_ascii_end(), b"");
125+
/// ```
126+
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
127+
pub const fn trim_ascii_end(&self) -> &[u8] {
128+
let mut bytes = self;
129+
// Note: A pattern matching based approach (instead of indexing) allows
130+
// making the function const.
131+
while let [rest @ .., last] = bytes {
132+
if last.is_ascii_whitespace() {
133+
bytes = rest;
134+
} else {
135+
break;
136+
}
137+
}
138+
bytes
139+
}
140+
141+
/// Returns a byte slice with leading and trailing ASCII whitespace bytes
142+
/// removed.
143+
///
144+
/// 'Whitespace' refers to the definition used by
145+
/// `u8::is_ascii_whitespace`.
146+
///
147+
/// # Examples
148+
///
149+
/// ```
150+
/// #![feature(byte_slice_trim_ascii)]
151+
///
152+
/// assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
153+
/// assert_eq!(b" ".trim_ascii(), b"");
154+
/// assert_eq!(b"".trim_ascii(), b"");
155+
/// ```
156+
#[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
157+
pub const fn trim_ascii(&self) -> &[u8] {
158+
self.trim_ascii_start().trim_ascii_end()
159+
}
82160
}
83161

84162
impl_fn_for_zst! {

0 commit comments

Comments
 (0)