Skip to main content

str_utils/
trim_line.rs

1#[cfg(feature = "alloc")]
2use alloc::borrow::Cow;
3
4#[cfg(feature = "alloc")]
5use crate::to_substring_in_place;
6
7/// To extend `str` and `Cow<str>` with methods that trim empty lines.
8///
9/// Lines are separated only by LF (`\n`), and a line is empty when all of its characters are Unicode whitespace.
10pub trait TrimLine: Sized {
11    /// Trims empty lines from both ends of the string.
12    fn trim_line(self) -> Self;
13
14    /// Trims empty lines from the start of the string.
15    fn trim_line_start(self) -> Self;
16
17    /// Trims empty lines from the end of the string.
18    fn trim_line_end(self) -> Self;
19}
20
21impl TrimLine for &str {
22    #[inline]
23    fn trim_line(self) -> Self {
24        self.trim_line_start().trim_line_end()
25    }
26
27    fn trim_line_start(self) -> Self {
28        let mut start = 0;
29
30        for (p, c) in self.char_indices() {
31            if c == '\n' {
32                start = p + 1;
33            } else if !c.is_whitespace() {
34                return &self[start..];
35            }
36        }
37
38        &self[self.len()..]
39    }
40
41    fn trim_line_end(self) -> Self {
42        let mut end = self.len();
43
44        for (p, c) in self.char_indices().rev() {
45            if c == '\n' {
46                end = p;
47            } else if !c.is_whitespace() {
48                return &self[..end];
49            }
50        }
51
52        &self[..0]
53    }
54}
55
56#[cfg(feature = "alloc")]
57impl<'a> TrimLine for Cow<'a, str> {
58    #[inline]
59    fn trim_line(self) -> Self {
60        match self {
61            Cow::Borrowed(s) => Cow::Borrowed(s.trim_line()),
62            Cow::Owned(s) => {
63                let ss = s.trim_line();
64
65                Cow::Owned(unsafe { to_substring_in_place!(s, ss) })
66            },
67        }
68    }
69
70    #[inline]
71    fn trim_line_start(self) -> Self {
72        match self {
73            Cow::Borrowed(s) => Cow::Borrowed(s.trim_line_start()),
74            Cow::Owned(s) => {
75                let ss = s.trim_line_start();
76
77                Cow::Owned(unsafe { to_substring_in_place!(s, ss) })
78            },
79        }
80    }
81
82    #[inline]
83    fn trim_line_end(self) -> Self {
84        match self {
85            Cow::Borrowed(s) => Cow::Borrowed(s.trim_line_end()),
86            Cow::Owned(s) => {
87                let ss = s.trim_line_end();
88
89                Cow::Owned(unsafe { to_substring_in_place!(s, ss) })
90            },
91        }
92    }
93}