1use crate::{Asn1Type, Tag, TagMode, TagNumber};
4use proc_macro2::{Span, TokenStream};
5use quote::quote;
6use std::{fmt::Debug, str::FromStr};
7use syn::punctuated::Punctuated;
8use syn::{parse::Parse, parse::ParseStream, Attribute, Ident, LitStr, Path, Token};
9
10pub(crate) const ATTR_NAME: &str = "asn1";
12
13#[derive(Clone, Debug, Default)]
15pub(crate) struct TypeAttrs {
16 pub tag_mode: TagMode,
21}
22
23impl TypeAttrs {
24 pub fn parse(attrs: &[Attribute]) -> syn::Result<Self> {
26 let mut tag_mode = None;
27
28 let mut parsed_attrs = Vec::new();
29 AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?;
30
31 for attr in parsed_attrs {
32 let mode = attr.parse_value("tag_mode")?.ok_or_else(|| {
34 syn::Error::new_spanned(
35 &attr.name,
36 "invalid `asn1` attribute (valid options are `tag_mode`)",
37 )
38 })?;
39
40 if tag_mode.is_some() {
41 return Err(syn::Error::new_spanned(
42 &attr.name,
43 "duplicate ASN.1 `tag_mode` attribute",
44 ));
45 }
46
47 tag_mode = Some(mode);
48 }
49
50 Ok(Self {
51 tag_mode: tag_mode.unwrap_or_default(),
52 })
53 }
54}
55
56#[derive(Clone, Debug, Default)]
58pub(crate) struct FieldAttrs {
59 pub asn1_type: Option<Asn1Type>,
61
62 pub context_specific: Option<TagNumber>,
64
65 pub default: Option<Path>,
68
69 pub extensible: bool,
71
72 pub optional: bool,
74
75 pub tag_mode: TagMode,
81
82 pub constructed: bool,
84}
85
86impl FieldAttrs {
87 fn is_optional(&self) -> bool {
91 self.optional || self.default.is_some()
92 }
93
94 pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> syn::Result<Self> {
96 let mut asn1_type = None;
97 let mut context_specific = None;
98 let mut default = None;
99 let mut extensible = None;
100 let mut optional = None;
101 let mut tag_mode = None;
102 let mut constructed = None;
103
104 let mut parsed_attrs = Vec::new();
105 AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?;
106
107 for attr in parsed_attrs {
108 if let Some(tag_number) = attr.parse_value("context_specific")? {
110 if context_specific.is_some() {
111 abort!(attr.name, "duplicate ASN.1 `context_specific` attribute");
112 }
113
114 context_specific = Some(tag_number);
115 } else if attr.parse_value::<String>("default")?.is_some() {
117 if default.is_some() {
118 abort!(attr.name, "duplicate ASN.1 `default` attribute");
119 }
120
121 default = Some(attr.value.parse().map_err(|e| {
122 syn::Error::new_spanned(
123 attr.value,
124 format_args!("error parsing ASN.1 `default` attribute: {e}"),
125 )
126 })?);
127 } else if let Some(ext) = attr.parse_value("extensible")? {
129 if extensible.is_some() {
130 abort!(attr.name, "duplicate ASN.1 `extensible` attribute");
131 }
132
133 extensible = Some(ext);
134 } else if let Some(opt) = attr.parse_value("optional")? {
136 if optional.is_some() {
137 abort!(attr.name, "duplicate ASN.1 `optional` attribute");
138 }
139
140 optional = Some(opt);
141 } else if let Some(mode) = attr.parse_value("tag_mode")? {
143 if tag_mode.is_some() {
144 abort!(attr.name, "duplicate ASN.1 `tag_mode` attribute");
145 }
146
147 tag_mode = Some(mode);
148 } else if let Some(ty) = attr.parse_value("type")? {
150 if asn1_type.is_some() {
151 abort!(attr.name, "duplicate ASN.1 `type` attribute");
152 }
153
154 asn1_type = Some(ty);
155 } else if let Some(ty) = attr.parse_value("constructed")? {
157 if constructed.is_some() {
158 abort!(attr.name, "duplicate ASN.1 `constructed` attribute");
159 }
160
161 constructed = Some(ty);
162 } else {
163 abort!(
164 attr.name,
165 "unknown field-level `asn1` attribute \
166 (valid options are `context_specific`, `type`)",
167 );
168 }
169 }
170
171 Ok(Self {
172 asn1_type,
173 context_specific,
174 default,
175 extensible: extensible.unwrap_or_default(),
176 optional: optional.unwrap_or_default(),
177 tag_mode: tag_mode.unwrap_or(type_attrs.tag_mode),
178 constructed: constructed.unwrap_or_default(),
179 })
180 }
181
182 pub fn tag(&self) -> syn::Result<Option<Tag>> {
184 match self.context_specific {
185 Some(tag_number) => Ok(Some(Tag::ContextSpecific {
186 constructed: self.constructed,
187 number: tag_number,
188 })),
189
190 None => match self.tag_mode {
191 TagMode::Explicit => Ok(self.asn1_type.map(Tag::Universal)),
192 TagMode::Implicit => Err(syn::Error::new(
193 Span::call_site(),
194 "implicit tagging requires a `tag_number`",
195 )),
196 },
197 }
198 }
199
200 pub fn decoder(&self) -> TokenStream {
202 if let Some(tag_number) = self.context_specific {
203 let type_params = self.asn1_type.map(|ty| ty.type_path()).unwrap_or_default();
204 let tag_number = tag_number.to_tokens();
205
206 let context_specific = match self.tag_mode {
207 TagMode::Explicit => {
208 if self.extensible || self.is_optional() {
209 quote! {
210 ::der::asn1::ContextSpecific::<#type_params>::decode_explicit(
211 reader,
212 #tag_number
213 )?
214 }
215 } else {
216 quote! {
217 match ::der::asn1::ContextSpecific::<#type_params>::decode(reader)? {
218 field if field.tag_number == #tag_number => Some(field),
219 _ => None
220 }
221 }
222 }
223 }
224 TagMode::Implicit => {
225 quote! {
226 ::der::asn1::ContextSpecific::<#type_params>::decode_implicit(
227 reader,
228 #tag_number
229 )?
230 }
231 }
232 };
233
234 if self.is_optional() {
235 if let Some(default) = &self.default {
236 quote!(#context_specific.map(|cs| cs.value).unwrap_or_else(#default))
237 } else {
238 quote!(#context_specific.map(|cs| cs.value))
239 }
240 } else {
241 let constructed = self.constructed;
243 quote! {
244 #context_specific.ok_or_else(|| {
245 der::Tag::ContextSpecific {
246 number: #tag_number,
247 constructed: #constructed
248 }.value_error()
249 })?.value
250 }
251 }
252 } else if let Some(default) = &self.default {
253 let type_params = self.asn1_type.map(|ty| ty.type_path()).unwrap_or_default();
254 self.asn1_type.map(|ty| ty.decoder()).unwrap_or_else(|| {
255 quote! {
256 Option::<#type_params>::decode(reader)?.unwrap_or_else(#default),
257 }
258 })
259 } else {
260 self.asn1_type
261 .map(|ty| ty.decoder())
262 .unwrap_or_else(|| quote!(reader.decode()?))
263 }
264 }
265
266 pub fn value_encode(&self, binding: &TokenStream) -> TokenStream {
268 match self.context_specific {
269 Some(tag_number) => {
270 let tag_number = tag_number.to_tokens();
271 let tag_mode = self.tag_mode.to_tokens();
272 quote! {
273 ::der::asn1::ContextSpecificRef {
274 tag_number: #tag_number,
275 tag_mode: #tag_mode,
276 value: #binding,
277 }.encode_value(encoder)
278 }
279 }
280
281 None => self
282 .asn1_type
283 .map(|ty| {
284 let encoder_obj = ty.encoder(binding);
285 quote!(#encoder_obj.encode_value(encoder))
286 })
287 .unwrap_or_else(|| quote!(#binding.encode_value(encoder))),
288 }
289 }
290}
291
292pub(crate) struct AttrNameValue {
294 pub name: Path,
296
297 pub value: LitStr,
299}
300
301impl Parse for AttrNameValue {
302 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
303 let name = match input.parse() {
304 Ok(name) => name,
305 Err(e) => {
309 if let Ok(tok) = input.parse::<Token![type]>() {
310 Path::from(Ident::new("type", tok.span))
311 } else {
312 return Err(e);
315 }
316 }
317 };
318 input.parse::<Token![=]>()?;
319 let value = input.parse()?;
320 Ok(Self { name, value })
321 }
322}
323
324impl AttrNameValue {
325 pub fn parse_attribute(attr: &Attribute) -> syn::Result<impl IntoIterator<Item = Self>> {
326 attr.parse_args_with(Punctuated::<Self, Token![,]>::parse_terminated)
327 }
328
329 pub fn from_attributes(attrs: &[Attribute], out: &mut Vec<Self>) -> syn::Result<()> {
331 for attr in attrs {
332 if !attr.path().is_ident(ATTR_NAME) {
333 continue;
334 }
335
336 match Self::parse_attribute(attr) {
337 Ok(parsed) => out.extend(parsed),
338 Err(e) => abort!(attr, e),
339 }
340 }
341
342 Ok(())
343 }
344
345 pub fn parse_value<T>(&self, name: &str) -> syn::Result<Option<T>>
347 where
348 T: FromStr + Debug,
349 T::Err: Debug,
350 {
351 Ok(if self.name.is_ident(name) {
352 Some(
353 self.value
354 .value()
355 .parse()
356 .map_err(|_| syn::Error::new_spanned(&self.name, "error parsing attribute"))?,
357 )
358 } else {
359 None
360 })
361 }
362}