looprs_core/macros.rs
1/// Define a newtype wrapper around `String` with common trait impls.
2///
3/// Generates a struct with:
4/// - `new(impl Into<String>) -> Self`
5/// - `as_str() -> &str`
6/// - `Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize`
7/// - `#[serde(transparent)]`
8/// - `Display` (delegates to inner string)
9///
10/// # Example
11///
12/// ```
13/// use looprs_core::newtype_id;
14///
15/// newtype_id!(UserId);
16///
17/// let id = UserId::new("u-42");
18/// assert_eq!(id.as_str(), "u-42");
19/// assert_eq!(format!("{id}"), "u-42");
20/// ```
21#[macro_export]
22macro_rules! newtype_id {
23 ($name:ident) => {
24 #[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
25 #[serde(transparent)]
26 pub struct $name(String);
27
28 impl $name {
29 pub fn new(value: impl Into<String>) -> Self {
30 Self(value.into())
31 }
32
33 pub fn as_str(&self) -> &str {
34 &self.0
35 }
36 }
37
38 impl std::fmt::Display for $name {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.write_str(&self.0)
41 }
42 }
43 };
44}
45
46/// Define a domain event enum with auto-generated `name()` method.
47///
48/// Generates an enum with:
49/// - `#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]`
50/// - `fn name(&self) -> &'static str` returning the variant name as a string
51///
52/// # Example
53///
54/// ```
55/// use looprs_core::domain_event;
56///
57/// domain_event!(MyEvent {
58/// Started,
59/// Stopped,
60/// });
61///
62/// assert_eq!(MyEvent::Started.name(), "Started");
63/// assert_eq!(MyEvent::Stopped.name(), "Stopped");
64/// ```
65#[macro_export]
66macro_rules! domain_event {
67 ($name:ident { $($variant:ident),* $(,)? }) => {
68 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69 pub enum $name {
70 $($variant),*
71 }
72
73 impl $name {
74 pub fn name(&self) -> &'static str {
75 match self {
76 $(Self::$variant => stringify!($variant)),*
77 }
78 }
79 }
80 };
81}