mut_str/lib.rs
1//! # `mut-str`
2//!
3//! A toolkit for working with mutable string slices (`&mut str`), and immutable ones too!
4//!
5//! Pretty much all you can do safely in the standard library with mutable string slices is make them lower or upper case.
6//! This package allows for splitting and slicing by character index (rather than byte index), replacing strings and using references to characters.
7//!
8//! All functions on string slices are available either at the package root or as methods on the `StrExt` trait.
9//!
10//! ```
11//! use mut_str::StrExt;
12//!
13//! let mut welcome = Box::<str>::from("Hello, World!");
14//!
15//! // Split by character index
16//! let (l, r) = welcome.char_split_at_mut(7).unwrap();
17//! assert_eq!(l, "Hello, ");
18//! assert_eq!(r, "World!");
19//!
20//! // Replace string slices
21//! l.replace_with("mut-str").unwrap();
22//! assert_eq!(l, "mut-str");
23//!
24//! // Replace with padding
25//! let sub = r.replace_with_pad_left_char("👑!", ' ').unwrap();
26//! assert_eq!(sub, "👑!");
27//! assert_eq!(r, " 👑!");
28//!
29//! assert_eq!(&*welcome, "mut-str 👑!");
30//!
31//! // Get character references
32//! let crown = welcome.get_char_mut(8).unwrap();
33//! assert_eq!(crown, '👑');
34//!
35//! // Mutate characters
36//! crown.replace('🌍').unwrap();
37//! assert_eq!(crown, '🌍');
38//!
39//! // Slice by character index
40//! let l = welcome.char_slice_mut(..7).unwrap();
41//! l.replace_with_pad_left_space("👋").unwrap();
42//!
43//! assert_eq!(&*welcome, " 👋 🌍!");
44//! ```
45//!
46//! ## Links
47//! [Latest version of `mut-str` on crates.io](https://crates.io/crates/mut-str)
48#, ") ")]
49//! [`mut-str` on GitHub](https://github.com/tomBoddaert/mut-str)
50//!
51//! # Features
52#, "/features) ")]
53//! - `alloc` (enabled by default) adds implementations that require the `alloc` library.
54//! - `std` (enabled by default, requires `alloc`) adds implementations specific to the standard library.
55//!
56//! To make this package `no-std` compatible, disable the `std` feature.
57//! ```sh
58//! cargo add mut-str --no-default-features
59//! ```
60//! ```sh
61//! cargo add mut-str --no-default-features --features=alloc
62//! ```
63//!
64//! ## License
65//!
66//! [`mut-str`](https://github.com/tomBoddaert/mut-str) is dual-licensed under either the Apache License Version 2.0 or MIT license at your option.
67
68#![warn(
69 clippy::all,
70 clippy::pedantic,
71 clippy::nursery,
72 clippy::perf,
73 clippy::cargo,
74 clippy::alloc_instead_of_core,
75 clippy::std_instead_of_alloc,
76 clippy::std_instead_of_core,
77 clippy::get_unwrap,
78 clippy::panic_in_result_fn,
79 clippy::todo,
80 clippy::undocumented_unsafe_blocks
81)]
82#![allow(clippy::module_name_repetitions)]
83#![cfg_attr(not(feature = "std"), no_std)]
84
85use core::str;
86
87mod char_owned;
88mod char_ref;
89/// Errors.
90pub mod errors;
91mod get;
92/// Iterators over UTF-8 character references.
93pub mod iter;
94mod replace;
95mod slice;
96mod split;
97mod traits;
98
99pub use char_owned::*;
100pub use char_ref::*;
101pub use get::*;
102pub use replace::*;
103pub use slice::*;
104pub use split::*;
105pub use traits::*;
106
107#[inline]
108/// Copy the [`prim@str`] to a byte buffer and get the new [`prim@str`] containing the inserted character.
109/// Returns `None` if `buffer` is shorter than the string slice.
110///
111/// ```
112/// use mut_str::copy_to;
113///
114/// let s = "Hello, World!";
115/// let mut buffer = [0; 50];
116/// let new_s = copy_to(s, &mut buffer).unwrap();
117///
118/// assert_eq!(new_s, s);
119/// ```
120pub fn copy_to<'a>(s: &str, buffer: &'a mut [u8]) -> Option<&'a mut str> {
121 if s.len() > buffer.len() {
122 None
123 } else {
124 let exact_buffer = &mut buffer[..s.len()];
125 exact_buffer.copy_from_slice(s.as_bytes());
126
127 // SAFETY:
128 // This is valid as a utf8 string slice of the same length was just
129 // copied to the slice.
130 Some(unsafe { str::from_utf8_unchecked_mut(exact_buffer) })
131 }
132}
133
134#[cfg(test)]
135#[allow(clippy::module_name_repetitions)]
136mod test {
137 pub static TEST_STR: &str = "oΦ⏣🌑";
138
139 pub fn test_str_owned() -> Box<str> {
140 Box::from(TEST_STR)
141 }
142}