Skip to content

Commit 114e33c

Browse files
authored
Merge pull request #20 from MidasLamb/patskov-compile-time-macro
Compile time macro
2 parents e890aa2 + 1f88a25 commit 114e33c

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.2.6](https://github.com/MidasLamb/non-empty-string/compare/v0.2.5...v0.2.6) - 2025-04-09
11+
12+
### Added
13+
14+
- `non_empty_string!()` macro to create a `NonEmptyString` at compile time , thanks @patskovn in #19 (requires `macros` feature flag)
15+
1016
## [0.2.5](https://github.com/MidasLamb/non-empty-string/compare/v0.2.4...v0.2.5) - 2024-10-15
1117

1218
### Added

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ serde = { version = "1", features = ["derive"] }
2525

2626
[features]
2727
default = []
28+
macros = []
2829
serde = ["dep:serde"]
2930

3031

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ use delegate::delegate;
1717
#[cfg(feature = "serde")]
1818
mod serde_support;
1919

20+
#[cfg(feature = "macros")]
21+
mod macros;
22+
2023
mod trait_impls;
2124

2225
/// A simple String wrapper type, similar to NonZeroUsize and friends.

src/macros.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#[macro_export]
2+
/// Creates a `NonEmptyString` from a string literal at compile time.
3+
///
4+
/// This macro ensures that the provided string is **not empty** at compile time,
5+
/// preventing runtime errors due to empty strings.
6+
///
7+
/// # Examples
8+
///
9+
/// ```
10+
/// use non_empty_string::{non_empty_string, NonEmptyString};
11+
///
12+
/// let s: NonEmptyString = non_empty_string!("Hello, Rust!");
13+
/// assert_eq!(s, NonEmptyString::new("Hello, Rust!".to_string()).unwrap());
14+
/// ```
15+
///
16+
/// # Compile-time Failure
17+
///
18+
/// If an empty string is provided, this macro will cause a **compile-time error**.
19+
///
20+
/// ```compile_fail
21+
/// use non_empty_string::non_empty_string;
22+
///
23+
/// let s = non_empty_string!("");
24+
/// ```
25+
macro_rules! non_empty_string {
26+
($s:expr) => {{
27+
// Compile-time assertion to ensure the string is non-empty
28+
const _: () = assert!(!$s.is_empty(), "String cannot be empty");
29+
30+
// Create a NonEmptyString, unsafely wrapping since we've checked it's valid
31+
unsafe { $crate::NonEmptyString::new_unchecked($s.to_string()) }
32+
}};
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
// We explicitely DO NOT do `use crate::NonEmptyString` or anything of the sorts to ensure the macro has proper hygiene.
38+
// Otherwise tests might pass, but if a user does `non_empty_string::non_empty_string!("A")`, they might get compilation
39+
// errors that `NonEmptyString` is not in scope.
40+
41+
const NON_EMPTY_STRING: &'static str = "non-empty-string";
42+
43+
#[test]
44+
fn test_const_non_empty_string_macro_valid() {
45+
let s = non_empty_string!(NON_EMPTY_STRING);
46+
assert_eq!(
47+
s,
48+
crate::NonEmptyString::try_from(NON_EMPTY_STRING).unwrap()
49+
);
50+
}
51+
52+
#[test]
53+
fn test_inline_non_empty_string_macro_valid() {
54+
let s = non_empty_string!("Test String");
55+
assert_eq!(s, crate::NonEmptyString::try_from("Test String").unwrap());
56+
}
57+
}

0 commit comments

Comments
 (0)