1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3extern crate alloc;
4use alloc::vec::Vec;
5use proc_macro::TokenStream;
6
7mod expand;
8mod parse;
9
10#[proc_macro_attribute]
24pub fn newtype(attr: TokenStream, item: TokenStream) -> TokenStream {
25 let kind = match parse::parse_newtype_kind(attr.into()) {
26 Ok(kind) => kind,
27 Err(err) => return err.to_compile_error().into(),
28 };
29 let input = item.clone();
30 let newtype = match parse::parse_newtype(input) {
31 Ok(newtype) => newtype,
32 Err(err) => return err.to_compile_error().into(),
33 };
34 expand::expand_newtype(newtype, kind, item)
35}
36
37#[proc_macro_derive(Newtype, attributes(newtype))]
45pub fn newtype_derive(input: TokenStream) -> TokenStream {
46 let newtype_derives = match parse::parse_newtype_derives(input.into()) {
47 Ok(newtype_derives) => newtype_derives,
48 Err(err) => return err.to_compile_error().into(),
49 };
50 expand::expand_newtype_derives(newtype_derives)
51}
52
53struct Newtype {
60 newtype: syn::Ident,
62 inner_ty: syn::Type,
64 generics: syn::Generics,
66}
67
68impl Newtype {
69 fn new(newtype: syn::Ident, inner_ty: syn::Type, generics: syn::Generics) -> Self {
71 Self {
72 newtype,
73 inner_ty,
74 generics,
75 }
76 }
77}
78
79#[derive(Default)]
87struct NewtypeDerives {
88 from: Vec<(syn::Type, syn::Expr)>,
90 try_from: Vec<(syn::Type, syn::Type, syn::Expr)>,
92 into: Vec<(syn::Type, syn::Expr)>,
94 try_into: Vec<(syn::Type, syn::Type, syn::Expr)>,
96 add: Vec<(syn::Type, syn::Type, syn::Expr)>,
98 add_assign: Vec<(syn::Type, syn::Expr)>,
100 bitand: Vec<(syn::Type, syn::Type, syn::Expr)>,
102 bitand_assign: Vec<(syn::Type, syn::Expr)>,
104 bitor: Vec<(syn::Type, syn::Type, syn::Expr)>,
106 bitor_assign: Vec<(syn::Type, syn::Expr)>,
108 bitxor: Vec<(syn::Type, syn::Type, syn::Expr)>,
110 bitxor_assign: Vec<(syn::Type, syn::Expr)>,
112 div: Vec<(syn::Type, syn::Type, syn::Expr)>,
114 div_assign: Vec<(syn::Type, syn::Expr)>,
116 mul: Vec<(syn::Type, syn::Type, syn::Expr)>,
118 mul_assign: Vec<(syn::Type, syn::Expr)>,
120 rem: Vec<(syn::Type, syn::Type, syn::Expr)>,
122 rem_assign: Vec<(syn::Type, syn::Expr)>,
124 shl: Vec<(syn::Type, syn::Type, syn::Expr)>,
126 shl_assign: Vec<(syn::Type, syn::Expr)>,
128 shr: Vec<(syn::Type, syn::Type, syn::Expr)>,
130 shr_assign: Vec<(syn::Type, syn::Expr)>,
132 partial_eq: Vec<(syn::Type, syn::Expr)>,
134 sub: Vec<(syn::Type, syn::Type, syn::Expr)>,
136 sub_assign: Vec<(syn::Type, syn::Expr)>,
138}
139
140#[derive(Debug, PartialEq)]
147enum NewtypeKind {
148 Amount,
149 Id,
150}
151
152impl core::fmt::Display for NewtypeKind {
153 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154 match self {
155 Self::Amount => f.write_str("Amount"),
156 Self::Id => f.write_str("Id"),
157 }
158 }
159}
160
161impl TryFrom<&syn::Ident> for NewtypeKind {
162 type Error = syn::Error;
163
164 fn try_from(value: &syn::Ident) -> Result<Self, Self::Error> {
165 match value {
166 ident if ident == "Amount" => Ok(Self::Amount),
167 ident if ident == "Id" => Ok(Self::Id),
168 _ => Err(syn::Error::new_spanned(value, "expected 'Amount' or 'Id'")),
169 }
170 }
171}
172
173#[derive(Debug, PartialEq)]
181enum DeriveType {
182 From,
183 TryFrom,
184 Into,
185 TryInto,
186 Add,
187 AddAssign,
188 BitAnd,
189 BitAndAssign,
190 BitOr,
191 BitOrAssign,
192 BitXor,
193 BitXorAssign,
194 Div,
195 DivAssign,
196 Mul,
197 MulAssign,
198 Rem,
199 RemAssign,
200 Shl,
201 ShlAssign,
202 Shr,
203 ShrAssign,
204 PartialEq,
205 Sub,
206 SubAssign,
207}
208
209impl core::fmt::Display for DeriveType {
210 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211 match self {
212 Self::From => f.write_str("from"),
213 Self::TryFrom => f.write_str("try_from"),
214 Self::Into => f.write_str("into"),
215 Self::TryInto => f.write_str("try_into"),
216 Self::Add => f.write_str("add"),
217 Self::AddAssign => f.write_str("add_assign"),
218 Self::BitAnd => f.write_str("bitand"),
219 Self::BitAndAssign => f.write_str("bitand_assign"),
220 Self::BitOr => f.write_str("bitor"),
221 Self::BitOrAssign => f.write_str("bitor_assign"),
222 Self::BitXor => f.write_str("bitxor"),
223 Self::BitXorAssign => f.write_str("bitxor_assign"),
224 Self::Div => f.write_str("div"),
225 Self::DivAssign => f.write_str("div_assign"),
226 Self::Mul => f.write_str("mul"),
227 Self::MulAssign => f.write_str("mul_assign"),
228 Self::Rem => f.write_str("rem"),
229 Self::RemAssign => f.write_str("rem_assign"),
230 Self::Shl => f.write_str("shl"),
231 Self::ShlAssign => f.write_str("shl_assign"),
232 Self::Shr => f.write_str("shr"),
233 Self::ShrAssign => f.write_str("shr_assign"),
234 Self::PartialEq => f.write_str("partial_eq"),
235 Self::Sub => f.write_str("sub"),
236 Self::SubAssign => f.write_str("sub_assign"),
237 }
238 }
239}
240
241impl TryFrom<Option<&syn::Ident>> for DeriveType {
242 type Error = syn::Error;
243
244 fn try_from(value: Option<&syn::Ident>) -> Result<Self, Self::Error> {
245 match value {
246 Some(ident) if ident == "from" => Ok(Self::From),
247 Some(ident) if ident == "try_from" => Ok(Self::TryFrom),
248 Some(ident) if ident == "into" => Ok(Self::Into),
249 Some(ident) if ident == "try_into" => Ok(Self::TryInto),
250 Some(ident) if ident == "add" => Ok(Self::Add),
251 Some(ident) if ident == "add_assign" => Ok(Self::AddAssign),
252 Some(ident) if ident == "bitand" => Ok(Self::BitAnd),
253 Some(ident) if ident == "bitand_assign" => Ok(Self::BitAndAssign),
254 Some(ident) if ident == "bitor" => Ok(Self::BitOr),
255 Some(ident) if ident == "bitor_assign" => Ok(Self::BitOrAssign),
256 Some(ident) if ident == "bitxor" => Ok(Self::BitXor),
257 Some(ident) if ident == "bitxor_assign" => Ok(Self::BitXorAssign),
258 Some(ident) if ident == "div" => Ok(Self::Div),
259 Some(ident) if ident == "div_assign" => Ok(Self::DivAssign),
260 Some(ident) if ident == "mul" => Ok(Self::Mul),
261 Some(ident) if ident == "mul_assign" => Ok(Self::MulAssign),
262 Some(ident) if ident == "rem" => Ok(Self::Rem),
263 Some(ident) if ident == "rem_assign" => Ok(Self::RemAssign),
264 Some(ident) if ident == "shl" => Ok(Self::Shl),
265 Some(ident) if ident == "shl_assign" => Ok(Self::ShlAssign),
266 Some(ident) if ident == "shr" => Ok(Self::Shr),
267 Some(ident) if ident == "shr_assign" => Ok(Self::ShrAssign),
268 Some(ident) if ident == "partial_eq" => Ok(Self::PartialEq),
269 Some(ident) if ident == "sub" => Ok(Self::Sub),
270 Some(ident) if ident == "sub_assign" => Ok(Self::SubAssign),
271 _ => Err(syn::Error::new_spanned(
272 value,
273 "expected `(try_)from`, `(try_)into`, `add(_assign)`, `bitand(_assign)`, \
274 `bitor(_assign)`, `bitxor(_assign)`, `div(_assign)`, `mul(_assign)`, \
275 `rem(_assign)`, `shl(_assign)`, `shr(_assign)`, `partial_eq`, or `sub(_assign)`",
276 )),
277 }
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 #[test]
284 fn newtype_kind_display_roundtrip() {
285 use super::NewtypeKind;
286 assert_eq!(format!("{}", NewtypeKind::Amount), "Amount");
287 assert_eq!(format!("{}", NewtypeKind::Id), "Id");
288 }
289
290 #[test]
291 fn derive_type_display_roundtrip() {
292 use super::DeriveType;
293 assert_eq!(format!("{}", DeriveType::From), "from");
294 assert_eq!(format!("{}", DeriveType::TryFrom), "try_from");
295 assert_eq!(format!("{}", DeriveType::Into), "into");
296 assert_eq!(format!("{}", DeriveType::TryInto), "try_into");
297 assert_eq!(format!("{}", DeriveType::Add), "add");
298 assert_eq!(format!("{}", DeriveType::AddAssign), "add_assign");
299 assert_eq!(format!("{}", DeriveType::BitAnd), "bitand");
300 assert_eq!(format!("{}", DeriveType::BitAndAssign), "bitand_assign");
301 assert_eq!(format!("{}", DeriveType::BitOr), "bitor");
302 assert_eq!(format!("{}", DeriveType::BitOrAssign), "bitor_assign");
303 assert_eq!(format!("{}", DeriveType::BitXor), "bitxor");
304 assert_eq!(format!("{}", DeriveType::BitXorAssign), "bitxor_assign");
305 assert_eq!(format!("{}", DeriveType::Div), "div");
306 assert_eq!(format!("{}", DeriveType::DivAssign), "div_assign");
307 assert_eq!(format!("{}", DeriveType::Mul), "mul");
308 assert_eq!(format!("{}", DeriveType::MulAssign), "mul_assign");
309 assert_eq!(format!("{}", DeriveType::Rem), "rem");
310 assert_eq!(format!("{}", DeriveType::RemAssign), "rem_assign");
311 assert_eq!(format!("{}", DeriveType::Shl), "shl");
312 assert_eq!(format!("{}", DeriveType::ShlAssign), "shl_assign");
313 assert_eq!(format!("{}", DeriveType::Shr), "shr");
314 assert_eq!(format!("{}", DeriveType::ShrAssign), "shr_assign");
315 assert_eq!(format!("{}", DeriveType::PartialEq), "partial_eq");
316 assert_eq!(format!("{}", DeriveType::Sub), "sub");
317 assert_eq!(format!("{}", DeriveType::SubAssign), "sub_assign");
318 }
319}