lstring/lib.rs
1//! Key String: Optimized for map keys.
2//!
3//! # Examples
4//!
5//! String creation
6//! ```rust
7//! # use lstring::{kformat, kstring, KString};
8//! // Explicit (static)
9//! let literal = <KString>::from_static("literal");
10//! // Using macro (static)
11//! let literal: KString = kstring!("literal");
12//! // Multiple literals will be concatenated
13//! const CONST_STRING: KString = kstring!("const", "ant");
14//! // Macro also accepts constants
15//! const HELLO_WORLD: &str = "Hello world!";
16//! static STATIC_STRING: KString = kstring!(HELLO_WORLD);
17//!
18//! // Explicit (inline)
19//! let inline = <KString>::try_inline("stack").unwrap();
20//! let inline = <KString>::from_ref("stack");
21//!
22//! // Formatted
23//! let formatted: KString = kformat!("Hello {literal} and {inline}");
24//! ```
25//!
26//! # Background
27//!
28//! Considerations:
29//! - Large maps
30//! - Most keys live and drop without being used in any other way
31//! - Most keys are relatively small (single to double digit bytes)
32//! - Keys are immutable
33//! - Allow zero-cost abstractions between structs and maps (e.g. no allocating
34//! when dealing with struct field names)
35//!
36//! Ramifications:
37//! - Inline small strings rather than going to the heap.
38//! - Preserve `&'static str` across strings ([`KString`]),
39//! references ([`KStringRef`]), and lifetime abstractions ([`KStringCow`]) to avoid
40//! allocating for struct field names.
41//! - Use `Box<str>` rather than `String` to use less memory.
42//!
43//! Significant changes:
44//! - Because `From<&'static str>` is unsound it changed to `From<&str>`. To instantiate
45//! from static str use [`KString::from_static`] instead of [`From::from`] (or [`kstring`](crate::kstring) macro).
46//! - Added default generic to types `KStringBase` and `KStringCowBase` which renamed
47//! to [`KString`] and [`KStringCow`]. Corresponding type aliases is removed. To instantiate
48//! types with default backend wrap it with angle brackets (`KString::from_ref("abc")` =>
49//! `<KString>::from_ref("abc")`).
50//! - Added `KStringWriter` and `kformat` macros. Also added `FromIterator` trait impls.
51//! - Added `from_utf8` and `from_utf16` functions.
52//!
53//! # Feature Flags
54//!
55#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
56#![cfg_attr(not(feature = "unsafe"), forbid(unsafe_code))]
57#![cfg_attr(docsrs, feature(doc_auto_cfg))]
58
59#[cfg(not(feature = "std"))]
60compile_error!("`std` feature is required; reserved for future `no_std` support");
61
62mod format;
63#[cfg(feature = "kstring")]
64mod interop;
65mod stack;
66mod string;
67mod string_cow;
68mod string_ref;
69
70pub mod backend;
71
72pub use format::*;
73pub use stack::StackString;
74pub use string::*;
75pub use string_cow::*;
76pub use string_ref::*;
77
78/// Creates a `KString` from a static string literal.
79///
80/// This macro is designed to create `KString` instances directly from string literals,
81/// leveraging the fact that these strings are static and can be safely managed without additional allocations.
82///
83/// # Examples
84///
85/// ```
86/// # use lstring::{KString, kstring};
87///
88/// let key1: KString = kstring!("example_key");
89/// assert_eq!(key1, "example_key");
90///
91/// let key2: KString = kstring!("example", "-", "key");
92/// assert_eq!(key2, "example-key");
93///
94/// const CONST_STR: &str = "example_key";
95/// let key3: KString = kstring!(CONST_STR);
96/// assert_eq!(key3, "example_key");
97///
98/// static STATIC_STR: &str = "example-key";
99/// let key4: KString = kstring!(STATIC_STR);
100/// assert_eq!(key4, "example-key");
101///
102/// struct Strs<'a> {
103/// a: &'a str,
104/// b: [&'a str; 2],
105/// }
106///
107/// static DATA: Strs<'static> = Strs {
108/// a: "example",
109/// b: ["hello", "world"],
110/// };
111///
112/// let key5: KString = kstring!(DATA.a);
113/// assert_eq!(key5, "example");
114/// let key6: KString = kstring!(DATA.b[0]);
115/// assert_eq!(key6, "hello");
116/// let key7: KString = kstring!(DATA.b[1]);
117/// assert_eq!(key7, "world");
118/// ```
119#[macro_export]
120macro_rules! kstring {
121 ($($str:literal),*) => {
122 $crate::KString::from_static(concat!($($str),*))
123 };
124 ($str:expr) => {
125 $crate::KString::from_static($str)
126 };
127}
128
129#[cfg(test)]
130mod test {
131 #[test]
132 fn test_size() {
133 println!("String: {}", std::mem::size_of::<String>());
134 println!(
135 "Box<str>: {}",
136 std::mem::size_of::<crate::backend::DefaultStr>()
137 );
138 println!(
139 "Box<Box<str>>: {}",
140 std::mem::size_of::<Box<crate::backend::DefaultStr>>()
141 );
142 println!("str: {}", std::mem::size_of::<&'static str>());
143 println!(
144 "Cow: {}",
145 std::mem::size_of::<std::borrow::Cow<'static, str>>()
146 );
147 }
148}