1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(StableId)]
6pub 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}