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#![doc = concat!("[This version of `mut-str` on crates.io](https://crates.io/crates/mut-str/", env!("CARGO_PKG_VERSION"), ")  ")]
49//! [`mut-str` on GitHub](https://github.com/tomBoddaert/mut-str)
50//!
51//! # Features
52#![doc = concat!("[Features on docs.rs](https://docs.rs/crate/mut-str/", env!("CARGO_PKG_VERSION"), "/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}