1/// Replaces all the instances of `$pattern` in `$input`
2/// (a `&'static str` constant) with `$replace_with` (a `&'static str` constant).
3///
4/// # Signature
5///
6/// This macro acts like a function of this signature:
7/// ```rust
8/// # trait Pattern {}
9/// fn str_replace(
10/// input: &'static str,
11/// pattern: impl Pattern,
12/// replace_with: &'static str,
13/// ) -> &'static str
14/// # {""}
15/// ```
16/// and is evaluated at compile-time.
17///
18/// Where `pattern` can be any of these types:
19///
20/// - `&'static str`
21///
22/// - `char`
23///
24/// - `u8`: required to be ascii (`0` up to `127` inclusive).
25///
26/// # Example
27///
28///
29/// ```rust
30/// use const_format::str_replace;
31///
32/// // Passing a string pattern
33/// assert_eq!(
34/// str_replace!("The incredible shrinking man.", "i", "eee"),
35/// "The eeencredeeeble shreeenkeeeng man.",
36/// );
37///
38/// // Passing a char pattern
39/// assert_eq!(
40/// str_replace!("The incredible shrinking man.", ' ', "---"),
41/// "The---incredible---shrinking---man.",
42/// );
43///
44/// // Passing an ascii u8 pattern.
45/// assert_eq!(
46/// str_replace!("The incredible shrinking man.", b'i', "eee"),
47/// "The eeencredeeeble shreeenkeeeng man.",
48/// );
49///
50/// // Removing all instances of the pattern
51/// assert_eq!(
52/// str_replace!("remove haire", "re", ""),
53/// "move hai",
54/// );
55///
56/// // This shows that all the arguments can be `const`s, they don't have to be literals.
57/// {
58/// const IN: &str = "Foo Boo Patoo";
59/// const REPLACING: &str = "oo";
60/// const REPLACE_WITH: &str = "uh";
61/// assert_eq!(str_replace!(IN, REPLACING, REPLACE_WITH), "Fuh Buh Patuh");
62/// }
63/// ```
64///
65/// [`str::replace`]: https://doc.rust-lang.org/std/primitive.str.html#method.replace
66#[macro_export]
67macro_rules! str_replace {
68 ($input:expr, $pattern:expr, $replace_with:expr $(,)*) => {{
69 const ARGS_OSRCTFL4A: $crate::__str_methods::ReplaceInput =
70 $crate::__str_methods::ReplaceInputConv($input, $pattern, $replace_with).conv();
71
72 {
73 const OB: &[$crate::pmr::u8; ARGS_OSRCTFL4A.replace_length()] =
74 &ARGS_OSRCTFL4A.replace();
75
76 const OS: &$crate::pmr::str = unsafe { $crate::__priv_transmute_bytes_to_str!(OB) };
77
78 OS
79 }
80 }};
81}
82
83/// Creates a `&'static str` by repeating a `&'static str` constant `times` times
84///
85/// This is evaluated at compile-time.
86///
87/// # Example
88///
89/// ```rust
90/// use const_format::str_repeat;
91///
92/// {
93/// const OUT: &str = str_repeat!("hi ", 4);
94/// assert_eq!(OUT, "hi hi hi hi ")
95/// }
96/// {
97/// const IN: &str = "bye ";
98/// const REPEAT: usize = 5;
99/// const OUT: &str = str_repeat!(IN, REPEAT);
100/// assert_eq!(OUT, "bye bye bye bye bye ")
101/// }
102///
103/// ```
104///
105/// ### Failing
106///
107/// If this macro would produce too large a string,
108/// it causes a compile-time error.
109///
110/// ```compile_fail
111/// const_format::str_repeat!("hello", usize::MAX / 4);
112/// ```
113///
114#[cfg_attr(
115 feature = "__test",
116 doc = r##"
117```rust
118const_format::str_repeat!("hello", usize::MAX.wrapping_add(4));
119```
120"##
121)]
122#[macro_export]
123macro_rules! str_repeat {
124 ($string:expr, $times:expr $(,)*) => {{
125 const P_OSRCTFL4A: &$crate::__str_methods::StrRepeatArgs =
126 &$crate::__str_methods::StrRepeatArgs($string, $times);
127
128 {
129 use $crate::__hidden_utils::PtrToRef;
130 use $crate::pmr::{str, transmute, u8};
131
132 const P: &$crate::__str_methods::StrRepeatArgs = P_OSRCTFL4A;
133
134 $crate::pmr::respan_to! {
135 ($string)
136 const _ASSERT_VALID_LEN: () = P.assert_valid();
137 }
138
139 const OUT_B: &[u8; P.out_len] = &unsafe {
140 let ptr = P.str.as_ptr() as *const [u8; P.str_len];
141 transmute::<[[u8; P.str_len]; P.repeat], [u8; P.out_len]>(
142 [*PtrToRef { ptr }.reff; P.repeat],
143 )
144 };
145 const OUT_S: &str = unsafe { $crate::__priv_transmute_bytes_to_str!(OUT_B) };
146 OUT_S
147 }
148 }};
149}
150
151/// Replaces a substring in a `&'static str` constant.
152/// Returns both the new resulting `&'static str`, and the replaced substring.
153///
154/// # Signature
155///
156/// This macro acts like a function of this signature:
157/// ```rust
158/// # trait SomeIndex {}
159/// fn str_splice(
160/// input: &'static str,
161/// range: impl SomeIndex,
162/// replace_with: &'static str,
163/// ) -> const_format::SplicedStr
164/// # {unimplemented!()}
165/// ```
166/// and is evaluated at compile-time.
167///
168/// ### `range` argument
169///
170/// The `range` parameter determines what part of `input` is replaced,
171/// and can be any of these types:
172///
173/// - `usize`: the starting index of a char, only includes that char.
174/// - `Range<usize>`
175/// - `RangeTo<usize>`
176/// - `RangeFrom<usize>`
177/// - `RangeInclusive<usize>`
178/// - `RangeToInclusive<usize>`
179/// - `RangeFull`
180///
181/// [`SplicedStr`] contains:
182/// - `output`: a `&'static str` with the substring at `range` in `input` replaced with
183/// `replace_with`.
184/// - `removed`: the substring at `range` in `input`.
185///
186/// # Example
187///
188/// ```rust
189/// use const_format::{str_splice, SplicedStr};
190///
191/// const OUT: SplicedStr = str_splice!("foo bar baz", 4..=6, "is");
192/// assert_eq!(OUT , SplicedStr{output: "foo is baz", removed: "bar"});
193///
194/// // You can pass `const`ants to this macro, not just literals
195/// {
196/// const IN: &str = "this is bad";
197/// const INDEX: std::ops::RangeFrom<usize> = 8..;
198/// const REPLACE_WITH: &str = "... fine";
199/// const OUT: SplicedStr = str_splice!(IN, INDEX, REPLACE_WITH);
200/// assert_eq!(OUT , SplicedStr{output: "this is ... fine", removed: "bad"});
201/// }
202/// {
203/// const OUT: SplicedStr = str_splice!("ABC豆-", 3, "DEFGH");
204/// assert_eq!(OUT , SplicedStr{output: "ABCDEFGH-", removed: "豆"});
205/// }
206/// ```
207///
208/// ### Invalid index
209///
210/// Invalid indices cause compilation errors.
211///
212/// ```compile_fail
213/// const_format::str_splice!("foo", 0..10, "");
214/// ```
215#[cfg_attr(
216 feature = "__test",
217 doc = r#"
218```rust
219const_format::str_splice!("foo", 0..3, "");
220```
221
222```compile_fail
223const_format::str_splice!("foo", 0..usize::MAX, "");
224```
225
226```rust
227assert_eq!(
228 const_format::str_splice!("効率的", 3..6, "A"),
229 const_format::SplicedStr{output: "効A的", removed: "率"} ,
230);
231```
232
233```compile_fail
234assert_eq!(
235 const_format::str_splice!("効率的", 1..6, "A"),
236 const_format::SplicedStr{output: "効A的", removed: "率"} ,
237);
238```
239
240```compile_fail
241assert_eq!(
242 const_format::str_splice!("効率的", 3..5, "A"),
243 const_format::SplicedStr{output: "効A的", removed: "率"} ,
244);
245```
246
247"#
248)]
249///
250///
251/// [`SplicedStr`]: ./struct.SplicedStr.html
252#[macro_export]
253macro_rules! str_splice {
254 ($string:expr, $index:expr, $insert:expr $(,)*) => {{
255 const P_OSRCTFL4A: $crate::__str_methods::StrSpliceArgs =
256 $crate::__str_methods::StrSplceArgsConv($string, $index, $insert).conv();
257 {
258 use $crate::__hidden_utils::PtrToRef;
259 use $crate::__str_methods::{DecomposedString, SplicedStr, StrSpliceArgs};
260 use $crate::pmr::{str, u8};
261
262 const P: &StrSpliceArgs = &P_OSRCTFL4A;
263
264 type DecompIn =
265 DecomposedString<[u8; P.used_rstart], [u8; P.used_rlen], [u8; P.suffix_len]>;
266
267 type DecompOut =
268 DecomposedString<[u8; P.used_rstart], [u8; P.insert_len], [u8; P.suffix_len]>;
269
270 $crate::pmr::respan_to! {
271 ($string)
272 const _ASSERT_VALID_INDEX: () = P.index_validity.assert_valid();
273 }
274
275 const OUT_A: (&DecompOut, &str) = unsafe {
276 let input = PtrToRef {
277 ptr: P.str.as_ptr() as *const DecompIn,
278 }
279 .reff;
280 let insert = PtrToRef {
281 ptr: P.insert.as_ptr() as *const [u8; P.insert_len],
282 }
283 .reff;
284
285 (
286 &DecomposedString {
287 prefix: input.prefix,
288 middle: *insert,
289 suffix: input.suffix,
290 },
291 $crate::__priv_transmute_bytes_to_str!(&input.middle),
292 )
293 };
294
295 const OUT: SplicedStr = unsafe {
296 let output = OUT_A.0 as *const DecompOut as *const [u8; P.out_len];
297 SplicedStr {
298 output: $crate::__priv_transmute_raw_bytes_to_str!(output),
299 removed: OUT_A.1,
300 }
301 };
302
303 OUT
304 }
305 }};
306}
307
308/// Indexes a `&'static str` constant.
309///
310///
311/// # Signature
312///
313/// This macro acts like a function of this signature:
314/// ```rust
315/// # trait SomeIndex {}
316/// fn str_index(input: &'static str, range: impl SomeIndex) -> &'static str
317/// # {unimplemented!()}
318/// ```
319/// and is evaluated at compile-time.
320///
321/// This accepts
322/// [the same `range` arguments as `str_splice`](macro.str_splice.html#range-argument)
323///
324/// # Example
325///
326/// ```
327/// use const_format::str_index;
328///
329/// use std::ops::RangeFrom;
330///
331/// assert_eq!(str_index!("foo bar baz", ..7), "foo bar");
332/// assert_eq!(str_index!("foo bar baz", 4..7), "bar");
333/// assert_eq!(str_index!("foo bar baz", 4..), "bar baz");
334///
335/// {
336/// const IN: &str = "hello world";
337/// const INDEX: RangeFrom<usize> = 6..;
338/// // You can pass `const`ants to this macro, not just literals
339/// const OUT_0: &str = str_index!(IN, INDEX);
340/// assert_eq!(OUT_0, "world");
341/// }
342/// {
343/// const OUT: &str = str_index!("hello world", 4);
344/// assert_eq!(OUT, "o");
345/// }
346///
347/// ```
348///
349/// ### Invalid index
350///
351/// Invalid indices cause compilation errors.
352///
353/// ```compile_fail
354/// const_format::str_index!("foo", 0..10);
355/// ```
356#[cfg_attr(
357 feature = "__test",
358 doc = r#"
359```rust
360assert_eq!(const_format::str_index!("効率的", 3..6), "率");
361```
362
363```compile_fail
364assert_eq!(const_format::str_index!("効率的", 3..5), "率");
365```
366```compile_fail
367assert_eq!(const_format::str_index!("効率的", 4..6), "率");
368```
369"#
370)]
371///
372///
373#[macro_export]
374macro_rules! str_index {
375 ($string:expr, $index:expr $(,)*) => {{
376 const P_OSRCTFL4A: $crate::__str_methods::StrIndexArgs =
377 $crate::__str_methods::StrIndexArgsConv($string, $index).conv();
378
379 {
380 $crate::pmr::respan_to! {
381 ($string)
382 const _ASSERT_VALID_INDEX: () =
383 P_OSRCTFL4A.index_validity.assert_valid();
384 }
385
386 use $crate::__hidden_utils::PtrToRef;
387 use $crate::__str_methods::DecomposedString;
388 type DecompIn = DecomposedString<
389 [u8; P_OSRCTFL4A.used_rstart],
390 [u8; P_OSRCTFL4A.used_rlen],
391 [u8; 0],
392 >;
393
394 const OUT: &'static str = unsafe {
395 let input = PtrToRef {
396 ptr: P_OSRCTFL4A.str.as_ptr() as *const DecompIn,
397 }
398 .reff;
399 $crate::__priv_transmute_raw_bytes_to_str!(&input.middle)
400 };
401
402 OUT
403 }
404 }};
405}
406
407/// Indexes a `&'static str` constant,
408/// returning `None` when the index is not on a character boundary.
409///
410///
411/// # Signature
412///
413/// This macro acts like a function of this signature:
414/// ```rust
415/// # trait SomeIndex {}
416/// fn str_get(input: &'static str, range: impl SomeIndex) -> Option<&'static str>
417/// # {unimplemented!()}
418/// ```
419/// and is evaluated at compile-time.
420///
421/// This accepts
422/// [the same `range` arguments as `str_splice`](macro.str_splice.html#range-argument)
423///
424/// # Example
425///
426/// ```
427/// use const_format::str_get;
428///
429/// use std::ops::RangeFrom;
430///
431/// assert_eq!(str_get!("foo 鉄 baz", ..7), Some("foo 鉄"));
432/// assert_eq!(str_get!("foo 鉄 baz", 4..7), Some("鉄"));
433/// assert_eq!(str_get!("foo 鉄 baz", 4..100), None);
434///
435///
436/// {
437/// const IN: &str = "hello 鉄";
438/// const INDEX: RangeFrom<usize> = 6..;
439/// // You can pass `const`ants to this macro, not just literals
440/// const OUT: Option<&str> = str_get!(IN, INDEX);
441/// assert_eq!(OUT, Some("鉄"));
442/// }
443/// {
444/// const OUT: Option<&str> = str_get!("hello 鉄", 4);
445/// assert_eq!(OUT, Some("o"));
446/// }
447/// {
448/// // End index not on a character boundary
449/// const OUT: Option<&str> = str_get!("hello 鉄", 0..7);
450/// assert_eq!(OUT, None);
451/// }
452/// {
453/// // Out of bounds indexing
454/// const OUT: Option<&str> = str_get!("hello 鉄", 0..1000 );
455/// assert_eq!(OUT, None);
456/// }
457///
458/// ```
459#[cfg_attr(
460 feature = "__test",
461 doc = r#"
462```rust
463assert_eq!(const_format::str_get!("効率的", 3..6), Some("率"));
464assert_eq!(const_format::str_get!("効率的", 3..5), None);
465assert_eq!(const_format::str_get!("効率的", 4..6), None);
466```
467"#
468)]
469///
470#[macro_export]
471macro_rules! str_get {
472 ($string:expr, $index:expr $(,)*) => {{
473 const P_OSRCTFL4A: $crate::__str_methods::StrIndexArgs =
474 $crate::__str_methods::StrIndexArgsConv($string, $index).conv();
475
476 {
477 use $crate::__hidden_utils::PtrToRef;
478 use $crate::__str_methods::DecomposedString;
479 type DecompIn = DecomposedString<
480 [u8; P_OSRCTFL4A.used_rstart],
481 [u8; P_OSRCTFL4A.used_rlen],
482 [u8; 0],
483 >;
484
485 const OUT: $crate::pmr::Option<&'static $crate::pmr::str> = unsafe {
486 if P_OSRCTFL4A.index_validity.is_valid() {
487 let input = PtrToRef {
488 ptr: P_OSRCTFL4A.str.as_ptr() as *const DecompIn,
489 }
490 .reff;
491
492 $crate::pmr::Some($crate::__priv_transmute_raw_bytes_to_str!(&input.middle))
493 } else {
494 $crate::pmr::None
495 }
496 };
497
498 OUT
499 }
500 }};
501}
502
503/// Splits `$string` (a `&'static str` constant) with `$splitter`,
504/// returning an array of `&'static str`s.
505///
506/// # Signature
507///
508/// This macro acts like a function of this signature:
509/// ```rust
510/// # const LEN: usize = 0;
511/// # trait Splitter {}
512/// fn str_split(string: &'static str, splitter: impl Splitter) -> [&'static str; LEN]
513/// # { [] }
514/// ```
515/// and is evaluated at compile-time.
516///
517/// `impl Splitter` is any of these types:
518///
519/// - `&'static str`
520///
521/// - `char`
522///
523/// - `u8`: only ascii values (0 up to 127 inclusive) are allowed
524///
525/// The value of `LEN` depends on the `string` and `splitter` arguments.
526///
527///
528/// # Example
529///
530/// ```rust
531/// use const_format::str_split;
532///
533/// assert_eq!(str_split!("this is nice", ' '), ["this", "is", "nice"]);
534///
535/// assert_eq!(str_split!("Hello, world!", ", "), ["Hello", "world!"]);
536///
537/// // A `""` splitter outputs all chars individually (`str::split` does the same)
538/// assert_eq!(str_split!("🧡BAR🧠", ""), ["", "🧡", "B", "A", "R", "🧠", ""]);
539///
540/// // Splitting the string with an ascii byte
541/// assert_eq!(str_split!("dash-separated-string", b'-'), ["dash", "separated", "string"]);
542///
543/// {
544/// const STR: &str = "foo bar baz";
545/// const SPLITTER: &str = " ";
546///
547/// // both arguments to the `str_aplit` macro can be non-literal constants
548/// const SPLIT: [&str; 3] = str_split!(STR, SPLITTER);
549///
550/// assert_eq!(SPLIT, ["foo", "bar", "baz"]);
551/// }
552///
553/// ```
554#[macro_export]
555#[cfg(feature = "rust_1_64")]
556#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "rust_1_64")))]
557macro_rules! str_split {
558 ($string:expr, $splitter:expr $(,)?) => {{
559 const ARGS_OSRCTFL4A: $crate::__str_methods::SplitInput =
560 $crate::__str_methods::SplitInputConv($string, $splitter).conv();
561
562 {
563 const OB: [&$crate::pmr::str; ARGS_OSRCTFL4A.length()] = ARGS_OSRCTFL4A.split_it();
564 OB
565 }
566 }};
567}
568