1#[macro_export]
21macro_rules! newtype {
22 ($name:ident, $type:ty $(, $derive:ty)*, $docs:literal) => {
23 #[doc = $docs]
24 #[derive(
25 Clone,
26 Debug,
27 derive_more::From,
28 PartialEq,
29 Eq,
30 derive_more::AsRef,
31 serde::Serialize,
32 serde::Deserialize,
33 $($derive),*
34 )]
35 pub struct $name($type);
36 impl $name {
37 pub fn new(value: impl Into<$type>) -> Self {
38 Self(value.into())
39 }
40 #[allow(clippy::missing_const_for_fn)]
41 #[must_use]
42 pub fn peel(self) -> $type {
43 self.0
44 }
45 }
46 impl std::ops::Deref for $name {
47 type Target = $type;
48
49 fn deref(&self) -> &Self::Target {
50 &self.0
51 }
52 }
53 impl std::ops::DerefMut for $name {
54 fn deref_mut(&mut self) -> &mut Self::Target {
55 &mut self.0
56 }
57 }
58 impl From<$name> for $type {
59 fn from(value: $name) -> $type {
60 value.peel()
61 }
62 }
63 };
64}
65
66#[cfg(test)]
67mod tests {
68
69 use derive_more::Display;
70
71 newtype!(A, String, "a type");
73
74 #[test]
75 fn newtype_reflexive() {
76 let a = A::new("bob");
77 assert_eq!(a, a);
78 }
79 #[test]
80 fn newtype_new_is_equal_from() {
81 assert_eq!(A::new("bob"), A::from("bob".to_string()));
82 }
83
84 #[test]
85 fn newtype_is_clone() {
86 let a1 = A::new("bob");
87 let a2 = a1.clone();
88 assert_eq!(a1, a2);
89 }
90
91 #[test]
92 fn newtype_is_debug() {
93 assert_eq!(format!("{:?}", A::new("bob")), r#"A("bob")"#);
94 }
95
96 #[test]
97 fn newtype_with_derive_display_is_display() {
98 newtype!(B, String, Display, "displayable");
99 assert_eq!(format!("{}", B::new("bob")), r"bob");
100 }
101
102 #[test]
103 fn newtype_is_peelable() {
104 let a = A::new("bob");
105 assert_eq!(a.peel(), "bob");
106 }
107
108 #[test]
109 fn newtype_as_ref() {
110 let a = A::new("bob");
111 let b: &str = a.as_ref();
112 assert_eq!(b, "bob");
113 }
114
115 #[test]
116 fn newtype_serialize() {
117 let a = A::new("bob");
118 let s = serde_json::to_string(&a).unwrap();
119 assert_eq!(s, "\"bob\"");
120 }
121
122 #[test]
123 fn newtype_deserialize() {
124 let a = A::new("bob");
125 let s: A = serde_json::from_str("\"bob\"").unwrap();
126 assert_eq!(s, a);
127 }
128}