derive_stable_id/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(StableId)]
6/**
7Derives all traits introduced by the `stable-id-traits` crate.
8The struct should be a tuple which contains an unsigned numeric primitive type.
9*/
10pub fn derive_stable_id(input: TokenStream) -> TokenStream {
11    let input = parse_macro_input!(input as DeriveInput);
12
13    let name = &input.ident;
14
15    let id_data_type = match input.data {
16        syn::Data::Struct(ref data) => {
17            let len = data.fields.len();
18            assert_eq!(len, 1, "derive struct should have 1 field");
19            let field = data.fields.iter().next().unwrap();
20
21            if let syn::Type::Path(ref tp) = field.ty {
22                let segments = &tp.path.segments;
23                assert_eq!(len, 1, "should have 1 segment");
24                &segments[0].ident
25            } else {
26                unreachable!("expecting a Path")
27            }
28        }
29        _ => unreachable!("expecting a Struct"),
30    }
31    .clone();
32
33    quote! {
34        impl Default for #name {
35            fn default() -> Self {
36                Self(Default::default())
37            }
38        }
39
40        impl stable_id_traits::Successor for #name {
41            fn next_value(self) -> Self {
42                assert!(self != stable_id_traits::Maximum::max_value());
43                let Self(value) = self;
44                Self(value.next_value())
45            }
46        }
47
48        impl stable_id_traits::Predecessor for #name {
49            fn prev_value(self) -> Self {
50                assert!(self != Default::default());
51                let Self(value) = self;
52                Self(value.prev_value())
53            }
54        }
55
56
57        impl stable_id_traits::Maximum for #name {
58            fn max_value() -> Self {
59                Self(#id_data_type::max_value())
60            }
61        }
62
63        impl stable_id_traits::CastUsize for #name {
64            fn cast_from(val: usize) -> Self {
65                let val = #id_data_type::cast_from(val);
66                Self(val as #id_data_type)
67            }
68
69            fn cast_to(self) -> usize {
70                self.0 as usize
71            }
72        }
73
74        impl stable_id_traits::Inner<#id_data_type> for #name {
75            fn project(self) -> #id_data_type {
76                self.0
77            }
78        }
79
80        impl PartialEq for #name {
81            fn eq(&self, other: &Self) -> bool {
82                use stable_id_traits::Inner;
83                self.project().eq(&other.project())
84            }
85        }
86
87        impl std::cmp::Eq for #name {
88            fn assert_receiver_is_total_eq(&self) {
89                use stable_id_traits::Inner;
90                self.project().assert_receiver_is_total_eq();
91            }
92        }
93
94        impl PartialOrd for #name {
95            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
96                use stable_id_traits::Inner;
97                self.project().partial_cmp(&other.project())
98            }
99        }
100
101        impl Ord for #name {
102            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
103                use stable_id_traits::Inner;
104                self.project().cmp(&other.project())
105            }
106        }
107
108        impl Clone for #name {
109            fn clone(&self) -> Self {
110                use stable_id_traits::Inner;
111                Self(self.project())
112            }
113        }
114
115        impl Copy for #name {}
116
117        impl std::hash::Hash for #name {
118            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
119                use stable_id_traits::Inner;
120                self.project().hash(state);
121            }
122        }
123    }
124    .into()
125}