Skip to main content

str_utils/
lib.rs

1/*!
2# str Utils
3
4This crate provides some traits to extend `[u8]`, `str` and `Cow<str>`.
5
6## Examples
7
8```rust
9# #[cfg(feature = "alloc")]
10# extern crate alloc;
11
12# #[cfg(feature = "alloc")]
13# use alloc::borrow::Cow;
14
15use str_utils::*;
16
17assert_eq!(true, "foobar".starts_with_ignore_ascii_case("FoO"));
18assert_eq!(Some(1), "photo.jpg".ends_with_ignore_ascii_case_multiple(&[".png", ".jpg", ".gif"]));
19assert_eq!(true, "foobar".starts_with_ignore_ascii_case("FoO"));
20
21# #[cfg(feature = "alloc")]
22assert_eq!("here is a ZERO_WIDTH_SPACE -> ​".len() - 3, "here is a ZERO_WIDTH_SPACE -> ​".remove_all_invisible_characters().len());
23
24# #[cfg(feature = "alloc")]
25assert_eq!(r"foo\% b\_r", r"foo% b_r".escape_ascii_characters(b'\\', b"%_"));
26
27assert!(!"AaBb\u{0130}Zz".is_lowercased());
28assert!(!"AaBbZz".is_ascii_lowercased());
29assert!(!"aabbßzz".is_uppercased());
30assert!(!"aabbzz".is_ascii_uppercased());
31
32# #[cfg(feature = "alloc")]
33assert_eq!("aabbi\u{0307}zz", "AaBb\u{0130}Zz".to_lowercase_cow());
34# #[cfg(feature = "alloc")]
35assert_eq!("aabb\u{0130}zz", "AaBb\u{0130}Zz".to_ascii_lowercase_cow());
36# #[cfg(feature = "alloc")]
37assert_eq!("AABBSSZZ", "aabbßzz".to_uppercase_cow());
38# #[cfg(feature = "alloc")]
39assert_eq!("AABBßZZ", "aabbßzz".to_ascii_uppercase_cow());
40
41# #[cfg(feature = "alloc")]
42assert_eq!("Line 1 Line 2 Line 2 Line 3 Line 4 Line 5", "Line 1\r\nLine 2\r\nLine 2\rLine 3\nLine 4\nLine 5".replace_newlines_with_space());
43
44# #[cfg(feature = "alloc")]
45assert_eq!("abc", Cow::from(" abc ").trim_cow()); // the `trim_cow` family of methods can be used on a `Cow<str>` to allow fluent method chaining.
46```
47
48## No Std
49
50Disable the default features to compile this crate without std.
51
52```toml
53[dependencies.str-utils]
54version = "*"
55default-features = false
56```
57*/
58
59#![cfg_attr(not(feature = "std"), no_std)]
60#![cfg_attr(docsrs, feature(doc_cfg))]
61
62// TODO eq_ignore_case_multiple
63// TODO starts_with_ignore_case_multiple
64// TODO ends_with_ignore_case_multiple
65
66#[cfg(feature = "alloc")]
67extern crate alloc;
68
69#[cfg(feature = "alloc")]
70use alloc::string::String;
71
72#[cfg(feature = "alloc")]
73#[doc(hidden)]
74pub mod __macro_private {
75    pub use alloc::borrow::Cow;
76}
77
78/// Converts a `Cow` produced from an existing owned value back into an owned value.
79///
80/// If the `Cow` is owned, this returns the owned value inside it. If the `Cow` is borrowed, this returns the original owned value.
81///
82/// This is a macro so the `Cow` expression can borrow from the original value before the macro moves that value in the borrowed branch.
83///
84/// # Examples
85///
86/// ```rust
87/// use str_utils::{cow_into_owned, ToLowercase};
88///
89/// let s = String::from("abc");
90/// let ptr = s.as_ptr();
91/// let s = cow_into_owned!(s, s.as_str().to_lowercase_cow());
92///
93/// assert_eq!("abc", s);
94/// assert_eq!(ptr, s.as_ptr());
95/// ```
96#[cfg(feature = "alloc")]
97#[macro_export]
98macro_rules! cow_into_owned {
99    ($owned:expr, $cow:expr $(,)?) => {{
100        match $cow {
101            $crate::__macro_private::Cow::Owned(s) => s,
102            $crate::__macro_private::Cow::Borrowed(_) => $owned,
103        }
104    }};
105}
106
107mod ends_with_ignore_ascii_case;
108mod ends_with_ignore_ascii_case_multiple;
109#[cfg(feature = "alloc")]
110mod ends_with_ignore_case;
111mod ends_with_multiple;
112mod eq_ignore_ascii_case;
113mod eq_ignore_ascii_case_multiple;
114#[cfg(feature = "unicase")]
115mod eq_ignore_case;
116mod eq_multiple;
117#[cfg(feature = "alloc")]
118mod escape_characters;
119mod is_ascii_lowercased;
120mod is_ascii_uppercased;
121mod is_lowercased;
122mod is_uppercased;
123#[cfg(feature = "alloc")]
124mod remove_all_invisible_characters;
125#[cfg(feature = "alloc")]
126mod replace_newlines_with_space;
127mod starts_with_ignore_ascii_case;
128mod starts_with_ignore_ascii_case_multiple;
129#[cfg(feature = "alloc")]
130mod starts_with_ignore_case;
131mod starts_with_multiple;
132#[cfg(feature = "alloc")]
133mod to_lowercase;
134#[cfg(feature = "alloc")]
135mod to_uppercase;
136#[cfg(feature = "alloc")]
137mod trim;
138
139pub use ends_with_ignore_ascii_case::*;
140pub use ends_with_ignore_ascii_case_multiple::*;
141#[cfg(feature = "alloc")]
142pub use ends_with_ignore_case::*;
143pub use ends_with_multiple::*;
144pub use eq_ignore_ascii_case::*;
145pub use eq_ignore_ascii_case_multiple::*;
146#[cfg(feature = "unicase")]
147pub use eq_ignore_case::*;
148pub use eq_multiple::*;
149#[cfg(feature = "alloc")]
150pub use escape_characters::*;
151pub use is_ascii_lowercased::*;
152pub use is_ascii_uppercased::*;
153pub use is_lowercased::*;
154pub use is_uppercased::*;
155#[cfg(feature = "alloc")]
156pub use remove_all_invisible_characters::*;
157#[cfg(feature = "alloc")]
158pub use replace_newlines_with_space::*;
159pub use starts_with_ignore_ascii_case::*;
160pub use starts_with_ignore_ascii_case_multiple::*;
161#[cfg(feature = "alloc")]
162pub use starts_with_ignore_case::*;
163pub use starts_with_multiple::*;
164#[cfg(feature = "alloc")]
165pub use to_lowercase::*;
166#[cfg(feature = "alloc")]
167pub use to_uppercase::*;
168#[cfg(feature = "alloc")]
169pub use trim::*;
170
171#[cfg(feature = "alloc")]
172pub(crate) unsafe fn find_substring_position(parent: &str, sub: &str) -> (usize, usize) {
173    let parent_start_address = parent.as_ptr() as usize;
174
175    let sub_start_address = sub.as_ptr() as usize;
176    let position_len = sub.len();
177
178    let position_start = sub_start_address - parent_start_address;
179
180    (position_start, position_len)
181}
182
183#[cfg(feature = "alloc")]
184pub(crate) unsafe fn into_substring_in_place(
185    mut s: String,
186    (start, len): (usize, usize),
187) -> String {
188    let bytes = s.as_mut_vec();
189
190    bytes.drain(..start);
191    bytes.truncate(len);
192
193    s
194}
195
196#[cfg(feature = "alloc")]
197macro_rules! to_substring_in_place {
198    ($parent:ident, $sub:ident) => {{
199        let position = $crate::find_substring_position($parent.as_str(), $sub);
200
201        $crate::into_substring_in_place($parent, position)
202    }};
203}
204
205#[cfg(feature = "alloc")]
206pub(crate) use to_substring_in_place;