bitwarden_uuid_macro/
lib.rs

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