1 //! Support for deriving the `ValueOrd` trait on enums and structs. 2 //! 3 //! This trait is used in conjunction with ASN.1 `SET OF` types to determine 4 //! the lexicographical order of their DER encodings. 5 6 // TODO(tarcieri): enum support 7 8 use crate::{FieldAttrs, TypeAttrs}; 9 use proc_macro2::TokenStream; 10 use proc_macro_error::abort; 11 use quote::quote; 12 use syn::{DeriveInput, Field, Ident, Lifetime, Variant}; 13 14 /// Derive the `Enumerated` trait for an enum. 15 pub(crate) struct DeriveValueOrd { 16 /// Name of the enum. 17 ident: Ident, 18 19 /// Lifetime of the struct. 20 lifetime: Option<Lifetime>, 21 22 /// Fields of structs or enum variants. 23 fields: Vec<ValueField>, 24 25 /// Type of input provided (`enum` or `struct`). 26 input_type: InputType, 27 } 28 29 impl DeriveValueOrd { 30 /// Parse [`DeriveInput`]. new(input: DeriveInput) -> Self31 pub fn new(input: DeriveInput) -> Self { 32 let ident = input.ident; 33 let type_attrs = TypeAttrs::parse(&input.attrs); 34 35 // TODO(tarcieri): properly handle multiple lifetimes 36 let lifetime = input 37 .generics 38 .lifetimes() 39 .next() 40 .map(|lt| lt.lifetime.clone()); 41 42 let (fields, input_type) = match input.data { 43 syn::Data::Enum(data) => ( 44 data.variants 45 .into_iter() 46 .map(|variant| ValueField::new_enum(variant, &type_attrs)) 47 .collect(), 48 InputType::Enum, 49 ), 50 syn::Data::Struct(data) => ( 51 data.fields 52 .into_iter() 53 .map(|field| ValueField::new_struct(field, &type_attrs)) 54 .collect(), 55 InputType::Struct, 56 ), 57 _ => abort!( 58 ident, 59 "can't derive `ValueOrd` on this type: \ 60 only `enum` and `struct` types are allowed", 61 ), 62 }; 63 64 Self { 65 ident, 66 lifetime, 67 fields, 68 input_type, 69 } 70 } 71 72 /// Lower the derived output into a [`TokenStream`]. to_tokens(&self) -> TokenStream73 pub fn to_tokens(&self) -> TokenStream { 74 let ident = &self.ident; 75 76 // Lifetime parameters 77 // TODO(tarcieri): support multiple lifetimes 78 let lt_params = self 79 .lifetime 80 .as_ref() 81 .map(|lt| vec![lt.clone()]) 82 .unwrap_or_default(); 83 84 let mut body = Vec::new(); 85 86 for field in &self.fields { 87 body.push(field.to_tokens()); 88 } 89 90 let body = match self.input_type { 91 InputType::Enum => { 92 quote! { 93 #[allow(unused_imports)] 94 use ::der::ValueOrd; 95 match (self, other) { 96 #(#body)* 97 _ => unreachable!(), 98 } 99 } 100 } 101 InputType::Struct => { 102 quote! { 103 #[allow(unused_imports)] 104 use ::der::{DerOrd, ValueOrd}; 105 106 #(#body)* 107 108 Ok(::core::cmp::Ordering::Equal) 109 } 110 } 111 }; 112 113 quote! { 114 impl<#(#lt_params)*> ::der::ValueOrd for #ident<#(#lt_params)*> { 115 fn value_cmp(&self, other: &Self) -> ::der::Result<::core::cmp::Ordering> { 116 #body 117 } 118 } 119 } 120 } 121 } 122 123 /// What kind of input was provided (i.e. `enum` or `struct`). 124 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 125 enum InputType { 126 /// Input is an `enum`. 127 Enum, 128 129 /// Input is a `struct`. 130 Struct, 131 } 132 133 struct ValueField { 134 /// Name of the field 135 ident: Ident, 136 137 /// Field-level attributes. 138 attrs: FieldAttrs, 139 140 is_enum: bool, 141 } 142 143 impl ValueField { 144 /// Create from an `enum` variant. new_enum(variant: Variant, type_attrs: &TypeAttrs) -> Self145 fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> Self { 146 let ident = variant.ident; 147 148 let attrs = FieldAttrs::parse(&variant.attrs, type_attrs); 149 Self { 150 ident, 151 attrs, 152 is_enum: true, 153 } 154 } 155 156 /// Create from a `struct` field. new_struct(field: Field, type_attrs: &TypeAttrs) -> Self157 fn new_struct(field: Field, type_attrs: &TypeAttrs) -> Self { 158 let ident = field 159 .ident 160 .as_ref() 161 .cloned() 162 .unwrap_or_else(|| abort!(&field, "tuple structs are not supported")); 163 164 let attrs = FieldAttrs::parse(&field.attrs, type_attrs); 165 Self { 166 ident, 167 attrs, 168 is_enum: false, 169 } 170 } 171 172 /// Lower to [`TokenStream`]. to_tokens(&self) -> TokenStream173 fn to_tokens(&self) -> TokenStream { 174 let ident = &self.ident; 175 176 if self.is_enum { 177 let binding1 = quote!(Self::#ident(this)); 178 let binding2 = quote!(Self::#ident(other)); 179 quote! { 180 (#binding1, #binding2) => this.value_cmp(other), 181 } 182 } else { 183 let mut binding1 = quote!(self.#ident); 184 let mut binding2 = quote!(other.#ident); 185 186 if let Some(ty) = &self.attrs.asn1_type { 187 binding1 = ty.encoder(&binding1); 188 binding2 = ty.encoder(&binding2); 189 } 190 191 quote! { 192 match #binding1.der_cmp(&#binding2)? { 193 ::core::cmp::Ordering::Equal => (), 194 other => return Ok(other), 195 } 196 } 197 } 198 } 199 } 200