staticstr/lib.rs
1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 */
6
7//! [`StaticStr`] - a string type that can handle both static and owned strings.
8//!
9//! # Overview
10//!
11//! The [`StaticStr`] type is designed to optimize string handling in scenarios where most strings are static
12//! (known at compile time) but some need to be dynamically generated. It internally uses a [`Cow`] to avoid
13//! unnecessary allocations when working with static strings while still maintaining the flexibility to handle
14//! owned strings when needed.
15//!
16//! # Use Cases
17//!
18//! - Configuration values that are usually hardcoded but sometimes need to be generated
19//! - Message templates with occasional dynamic content
20//! - Any situation where you frequently use `&'static str` but occasionally need `String`
21//!
22//! # Example
23//!
24//! ```rust
25//! use staticstr::StaticStr;
26//!
27//! // Use with static strings - no allocation
28//! let static_message: StaticStr = "Hello, World!".into();
29//!
30//! // Use with owned strings - allocates only when needed
31//! let dynamic_message: StaticStr = format!("Hello, {}!", "User").into();
32//!
33//! // Both types can be used the same way
34//! println!("{}", static_message); // Hello, World!
35//! println!("{}", dynamic_message); // Hello, User!
36//! ```
37//!
38//! [`Cow`]: std::borrow::Cow
39
40use std::{borrow::Cow, fmt::Display, ops::Deref};
41
42/// A string that always has a 'static lifetime.
43///
44/// This makes it possible to use [`&'static str`]'s directly without allocating
45/// while also allowing the use of plain regular-old [`String`]s.
46/// This is most useful in places where in 99% of times a [`&'static str`] is used but sometimes a [`format!()`]'ed string may be required.
47/// Technically, this could be used everywhere instead of [`String`]s but this introduces too much boilerplate and `.into()` transitions
48/// that just pollute the code for little benefit.
49#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct StaticStr(Cow<'static, str>);
51
52impl StaticStr {
53 #[must_use]
54 pub const fn from_static_str(s: &'static str) -> Self {
55 Self(Cow::Borrowed(s))
56 }
57
58 #[must_use]
59 pub fn as_str(&self) -> &str {
60 &self.0
61 }
62}
63
64impl Deref for StaticStr {
65 type Target = str;
66
67 fn deref(&self) -> &Self::Target {
68 self.0.deref()
69 }
70}
71
72impl From<String> for StaticStr {
73 fn from(value: String) -> Self {
74 Self(Cow::Owned(value))
75 }
76}
77
78impl From<&'static str> for StaticStr {
79 fn from(value: &'static str) -> Self {
80 Self(Cow::Borrowed(value))
81 }
82}
83
84impl Display for StaticStr {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 f.write_str(self)
87 }
88}
89
90impl AsRef<str> for StaticStr {
91 fn as_ref(&self) -> &str {
92 self.0.as_ref()
93 }
94}
95
96impl From<StaticStr> for String {
97 fn from(value: StaticStr) -> Self {
98 value.0.into_owned()
99 }
100}
101
102impl From<&StaticStr> for String {
103 fn from(value: &StaticStr) -> Self {
104 value.as_str().to_owned()
105 }
106}
107
108impl Default for StaticStr {
109 fn default() -> Self {
110 Self(Cow::Borrowed(""))
111 }
112}
113
114pub fn add(left: u64, right: u64) -> u64 {
115 left + right
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn it_works() {
124 let result = add(2, 2);
125 assert_eq!(result, 4);
126 }
127}