1use crate::{FieldAttrs, TypeAttrs};
9use proc_macro2::TokenStream;
10use quote::quote;
11use syn::{DeriveInput, Field, Ident, Lifetime, Variant};
12
13pub(crate) struct DeriveValueOrd {
15 ident: Ident,
17
18 lifetime: Option<Lifetime>,
20
21 fields: Vec<ValueField>,
23
24 input_type: InputType,
26}
27
28impl DeriveValueOrd {
29 pub fn new(input: DeriveInput) -> syn::Result<Self> {
31 let ident = input.ident;
32 let type_attrs = TypeAttrs::parse(&input.attrs)?;
33
34 let lifetime = input
36 .generics
37 .lifetimes()
38 .next()
39 .map(|lt| lt.lifetime.clone());
40
41 let (fields, input_type) = match input.data {
42 syn::Data::Enum(data) => (
43 data.variants
44 .into_iter()
45 .map(|variant| ValueField::new_enum(variant, &type_attrs))
46 .collect::<syn::Result<_>>()?,
47 InputType::Enum,
48 ),
49 syn::Data::Struct(data) => (
50 data.fields
51 .into_iter()
52 .map(|field| ValueField::new_struct(field, &type_attrs))
53 .collect::<syn::Result<_>>()?,
54 InputType::Struct,
55 ),
56 _ => abort!(
57 ident,
58 "can't derive `ValueOrd` on this type: \
59 only `enum` and `struct` types are allowed",
60 ),
61 };
62
63 Ok(Self {
64 ident,
65 lifetime,
66 fields,
67 input_type,
68 })
69 }
70
71 pub fn to_tokens(&self) -> TokenStream {
73 let ident = &self.ident;
74
75 let lt_params = self
78 .lifetime
79 .as_ref()
80 .map(|lt| vec![lt.clone()])
81 .unwrap_or_default();
82
83 let mut body = Vec::new();
84
85 for field in &self.fields {
86 body.push(field.to_tokens());
87 }
88
89 let body = match self.input_type {
90 InputType::Enum => {
91 quote! {
92 #[allow(unused_imports)]
93 use ::der::ValueOrd;
94 match (self, other) {
95 #(#body)*
96 _ => unreachable!(),
97 }
98 }
99 }
100 InputType::Struct => {
101 quote! {
102 #[allow(unused_imports)]
103 use ::der::{DerOrd, ValueOrd};
104
105 #(#body)*
106
107 Ok(::core::cmp::Ordering::Equal)
108 }
109 }
110 };
111
112 quote! {
113 impl<#(#lt_params)*> ::der::ValueOrd for #ident<#(#lt_params)*> {
114 fn value_cmp(&self, other: &Self) -> ::der::Result<::core::cmp::Ordering> {
115 #body
116 }
117 }
118 }
119 }
120}
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124enum InputType {
125 Enum,
127
128 Struct,
130}
131
132struct ValueField {
133 ident: Ident,
135
136 attrs: FieldAttrs,
138
139 is_enum: bool,
140}
141
142impl ValueField {
143 fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> syn::Result<Self> {
145 let ident = variant.ident;
146
147 let attrs = FieldAttrs::parse(&variant.attrs, type_attrs)?;
148 Ok(Self {
149 ident,
150 attrs,
151 is_enum: true,
152 })
153 }
154
155 fn new_struct(field: Field, type_attrs: &TypeAttrs) -> syn::Result<Self> {
157 let ident =
158 field.ident.as_ref().cloned().ok_or_else(|| {
159 syn::Error::new_spanned(&field, "tuple structs are not supported")
160 })?;
161
162 let attrs = FieldAttrs::parse(&field.attrs, type_attrs)?;
163 Ok(Self {
164 ident,
165 attrs,
166 is_enum: false,
167 })
168 }
169
170 fn to_tokens(&self) -> TokenStream {
172 let ident = &self.ident;
173
174 if self.is_enum {
175 let binding1 = quote!(Self::#ident(this));
176 let binding2 = quote!(Self::#ident(other));
177 quote! {
178 (#binding1, #binding2) => this.value_cmp(other),
179 }
180 } else {
181 let mut binding1 = quote!(self.#ident);
182 let mut binding2 = quote!(other.#ident);
183
184 if let Some(ty) = &self.attrs.asn1_type {
185 binding1 = ty.encoder(&binding1);
186 binding2 = ty.encoder(&binding2);
187 }
188
189 quote! {
190 match #binding1.der_cmp(&#binding2)? {
191 ::core::cmp::Ordering::Equal => (),
192 other => return Ok(other),
193 }
194 }
195 }
196 }
197}