bitwarden_uuid_macro/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{
6    Ident, Visibility,
7    parse::{Parse, ParseStream},
8    parse_macro_input,
9};
10
11#[allow(missing_docs)]
12#[proc_macro]
13pub fn uuid_newtype(input: TokenStream) -> TokenStream {
14    // Parse input as: vis ident
15    let input = parse_macro_input!(input as IdTypeInput);
16    let ident = input.ident;
17    let vis = input.vis;
18    let name_str = ident.to_string();
19
20    let tsify_type = format!("Tagged<Uuid, \"{name_str}\">");
21    let doc_string = format!(" NewType wrapper for `{name_str}`");
22
23    let expanded = quote! {
24        #[doc = #doc_string]
25        #[cfg_attr(feature = "wasm", derive(::tsify::Tsify), tsify(into_wasm_abi, from_wasm_abi))]
26        #[derive(
27            ::serde::Serialize, ::serde::Deserialize,
28            ::std::cmp::PartialEq, ::std::cmp::Eq, ::std::cmp::PartialOrd, ::std::cmp::Ord,
29            ::std::hash::Hash, ::std::clone::Clone, ::std::marker::Copy, ::std::fmt::Debug
30        )]
31        #[repr(transparent)]
32        #vis struct #ident
33        (
34            #[cfg_attr(feature = "wasm", tsify(type = #tsify_type))]
35            ::uuid::Uuid
36        );
37
38        #[cfg(feature = "uniffi")]
39        uniffi::custom_newtype!(#ident, uuid::Uuid);
40
41        impl #ident {
42            #[allow(missing_docs)]
43            pub fn new(value: uuid::Uuid) -> Self {
44                Self(value)
45            }
46
47            /// Create a new UUID v4 based id.
48            pub fn new_v4() -> Self {
49                Self(uuid::Uuid::new_v4())
50            }
51        }
52
53        impl ::std::str::FromStr for #ident {
54            type Err = uuid::Error;
55
56            fn from_str(s: &str) -> Result<Self, Self::Err> {
57                uuid::Uuid::from_str(s).map(Self)
58            }
59        }
60
61        impl From<#ident> for ::uuid::Uuid {
62            fn from(value: #ident) -> Self {
63                value.0
64            }
65        }
66
67        impl ::std::fmt::Display for #ident {
68            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
69                self.0.fmt(f)
70            }
71        }
72
73        impl ::std::default::Default for #ident {
74            fn default() -> Self {
75                Self(uuid::Uuid::default())
76            }
77        }
78    };
79
80    TokenStream::from(expanded)
81}
82
83// Helper struct to parse "vis ident"
84struct IdTypeInput {
85    vis: Visibility,
86    ident: Ident,
87}
88
89impl Parse for IdTypeInput {
90    fn parse(input: ParseStream) -> syn::Result<Self> {
91        let vis: Visibility = input.parse()?;
92        let ident: Ident = input.parse()?;
93        Ok(IdTypeInput { vis, ident })
94    }
95}