const_str/__ctfe/find.rs
1use crate::utf8::CharEncodeUtf8;
2
3pub struct Contains<'a, P>(pub &'a str, pub P);
4
5impl Contains<'_, &str> {
6 pub const fn const_eval(&self) -> bool {
7 crate::str::contains(self.0, self.1)
8 }
9}
10
11impl Contains<'_, char> {
12 pub const fn const_eval(&self) -> bool {
13 let haystack = self.0;
14 let ch = CharEncodeUtf8::new(self.1);
15 let needle = ch.as_str();
16 crate::str::contains(haystack, needle)
17 }
18}
19
20/// Returns [`true`] if the given pattern matches a sub-slice of this string slice.
21///
22/// Returns [`false`] if it does not.
23///
24/// The pattern type must be one of
25///
26/// + [`&str`]
27/// + [`char`]
28///
29/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
30///
31/// # Examples
32///
33/// ```
34/// const BANANAS: &str = "bananas";
35/// const A: bool = const_str::contains!(BANANAS, "nana");
36/// const B: bool = const_str::contains!(BANANAS, "apples");
37/// const C: bool = const_str::contains!(BANANAS, 'c');
38/// assert_eq!([A, B, C], [true, false, false]);
39/// ```
40///
41#[macro_export]
42macro_rules! contains {
43 ($haystack: expr, $pattern: expr) => {{
44 $crate::__ctfe::Contains($haystack, $pattern).const_eval()
45 }};
46}
47
48pub struct StartsWith<'a, P>(pub &'a str, pub P);
49
50impl StartsWith<'_, &str> {
51 pub const fn const_eval(&self) -> bool {
52 crate::str::starts_with(self.0, self.1)
53 }
54}
55
56impl StartsWith<'_, char> {
57 pub const fn const_eval(&self) -> bool {
58 let haystack = self.0.as_bytes();
59 let ch = CharEncodeUtf8::new(self.1);
60 let needle = ch.as_bytes();
61 crate::bytes::starts_with(haystack, needle)
62 }
63}
64
65/// Returns [`true`] if the given pattern matches a prefix of this string slice.
66///
67/// Returns [`false`] if it does not.
68///
69/// The pattern type must be one of
70///
71/// + [`&str`]
72/// + [`char`]
73///
74/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
75///
76/// # Examples
77///
78/// ```
79/// const BANANAS: &str = "bananas";
80/// const A: bool = const_str::starts_with!(BANANAS, "bana");
81/// const B: bool = const_str::starts_with!(BANANAS, "nana");
82/// const C: bool = const_str::starts_with!(BANANAS, 'b');
83/// assert_eq!([A, B, C], [true, false, true]);
84/// ```
85///
86#[macro_export]
87macro_rules! starts_with {
88 ($haystack: expr, $pattern: expr) => {{
89 $crate::__ctfe::StartsWith($haystack, $pattern).const_eval()
90 }};
91}
92
93pub struct EndsWith<'a, P>(pub &'a str, pub P);
94
95impl EndsWith<'_, &str> {
96 pub const fn const_eval(&self) -> bool {
97 crate::str::ends_with(self.0, self.1)
98 }
99}
100
101impl EndsWith<'_, char> {
102 pub const fn const_eval(&self) -> bool {
103 let haystack = self.0.as_bytes();
104 let ch = CharEncodeUtf8::new(self.1);
105 let needle = ch.as_bytes();
106 crate::bytes::ends_with(haystack, needle)
107 }
108}
109
110/// Returns [`true`] if the given pattern matches a suffix of this string slice.
111///
112/// Returns [`false`] if it does not.
113///
114/// The pattern type must be one of
115///
116/// + [`&str`]
117/// + [`char`]
118///
119/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
120///
121/// # Examples
122///
123/// ```
124/// const BANANAS: &str = "bananas";
125/// const A: bool = const_str::ends_with!(BANANAS, "anas");
126/// const B: bool = const_str::ends_with!(BANANAS, "nana");
127/// const C: bool = const_str::ends_with!(BANANAS, 's');
128/// assert_eq!([A, B, C], [true, false, true]);
129/// ```
130///
131#[macro_export]
132macro_rules! ends_with {
133 ($haystack: expr, $pattern: expr) => {{
134 $crate::__ctfe::EndsWith($haystack, $pattern).const_eval()
135 }};
136}
137
138pub struct StripPrefix<'a, P>(pub &'a str, pub P);
139
140impl<'a> StripPrefix<'a, &str> {
141 pub const fn const_eval(&self) -> Option<&'a str> {
142 crate::str::strip_prefix(self.0, self.1)
143 }
144}
145
146pub struct StripSuffix<'a, P>(pub &'a str, pub P);
147
148impl<'a> StripSuffix<'a, &str> {
149 pub const fn const_eval(&self) -> Option<&'a str> {
150 crate::str::strip_suffix(self.0, self.1)
151 }
152}
153
154/// Returns a string slice with the prefix removed.
155///
156/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
157///
158/// # Examples
159///
160/// ```
161/// assert_eq!(const_str::strip_prefix!("foo:bar", "foo:"), Some("bar"));
162/// assert_eq!(const_str::strip_prefix!("foo:bar", "bar"), None);
163/// assert_eq!(const_str::strip_prefix!("foofoo", "foo"), Some("foo"));
164///
165/// const FOO_BAR: &str = "foo:bar";
166/// const BAR: &str = const_str::unwrap!(const_str::strip_prefix!(FOO_BAR, "foo:"));
167/// assert_eq!(BAR, "bar");
168/// ```
169///
170#[macro_export]
171macro_rules! strip_prefix {
172 ($s: expr, $prefix: expr) => {{
173 $crate::__ctfe::StripPrefix($s, $prefix).const_eval()
174 }};
175}
176
177/// Returns a string slice with the suffix removed.
178///
179/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
180///
181/// # Examples
182///
183/// ```
184/// assert_eq!(const_str::strip_suffix!("bar:foo", ":foo"), Some("bar"));
185/// assert_eq!(const_str::strip_suffix!("bar:foo", "bar"), None);
186/// assert_eq!(const_str::strip_suffix!("foofoo", "foo"), Some("foo"));
187///
188/// const FOO_BAR: &str = "foo:bar";
189/// const FOO: &str = const_str::unwrap!(const_str::strip_suffix!(FOO_BAR, ":bar"));
190/// assert_eq!(FOO, "foo");
191/// ```
192///
193#[macro_export]
194macro_rules! strip_suffix {
195 ($s: expr, $suffix: expr) => {{
196 $crate::__ctfe::StripSuffix($s, $suffix).const_eval()
197 }};
198}