diff options
author | Andrew Walbran <qwandor@google.com> | 2023-12-19 14:25:26 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-12-19 14:25:26 +0000 |
commit | d83c21456d0e67c2c7145ada1a01981f625d61ee (patch) | |
tree | d7a51a0948b277f6fb2bdf69a6d20f7523902fb5 | |
parent | e254afc68bc0bb6a4ae5e54e5c20bc90a42db3da (diff) | |
parent | b6cbded0a149e33641dcca1879c7b01e0a1fb934 (diff) | |
download | der_derive-d83c21456d0e67c2c7145ada1a01981f625d61ee.tar.gz |
Upgrade der_derive to 0.7.2 am: b6cbded0a1
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/der_derive/+/2878114
Change-Id: Ica202a68386cf7c9d936b2245f4ce5a20b4fd3b6
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 5 | ||||
-rw-r--r-- | CHANGELOG.md | 20 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | Cargo.toml.orig | 7 | ||||
-rw-r--r-- | METADATA | 21 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | cargo2rulesmk.json | 1 | ||||
-rw-r--r-- | cargo_embargo.json | 3 | ||||
-rw-r--r-- | patches/rules.mk.diff | 12 | ||||
-rw-r--r-- | rules.mk | 5 | ||||
-rw-r--r-- | src/attributes.rs | 151 | ||||
-rw-r--r-- | src/choice.rs | 22 | ||||
-rw-r--r-- | src/choice/variant.rs | 29 | ||||
-rw-r--r-- | src/enumerated.rs | 72 | ||||
-rw-r--r-- | src/lib.rs | 39 | ||||
-rw-r--r-- | src/sequence.rs | 119 | ||||
-rw-r--r-- | src/sequence/field.rs | 36 | ||||
-rw-r--r-- | src/tag.rs | 9 | ||||
-rw-r--r-- | src/value_ord.rs | 40 |
20 files changed, 328 insertions, 282 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index b80855a..833570a 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "1dccbc1893d5bae33959e0ccb496b9ce5a7de122" + "sha1": "e9a38ae2a0eb0244e69548e611196d1cf03cc1a1" }, "path_in_vcs": "der/derive" }
\ No newline at end of file @@ -35,14 +35,13 @@ rust_proc_macro { name: "libder_derive", crate_name: "der_derive", cargo_env_compat: true, - cargo_pkg_version: "0.6.1", + cargo_pkg_version: "0.7.2", srcs: ["src/lib.rs"], edition: "2021", rustlibs: [ "libproc_macro2", - "libproc_macro_error", "libquote", - "libsyn_deprecated", + "libsyn", ], compile_multilib: "first", } diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a9502..194f7af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.7.2 (2023-08-07) +### Changed +- fix doc typo and use a valid tag number ([#1184]) +- remove proc-macro-error dependency ([#1180]) + +[#1180]: https://github.com/RustCrypto/formats/pull/1180 +[#1184]: https://github.com/RustCrypto/formats/pull/1184 + +## 0.7.1 (2023-04-19) +### Added + - Support for type generics in `Sequence` macro ([#1014]) + +[#1014]: https://github.com/RustCrypto/formats/pull/1014 + +## 0.7.0 (2023-02-26) +### Changed +- Eliminate dynamism from encoding ([#828]) + +[#828]: https://github.com/RustCrypto/formats/pull/828 + ## 0.6.1 (2022-12-05) ### Added - Support for deriving `ValueOrd` on `Choice` enums ([#723]) @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56" +rust-version = "1.65" name = "der_derive" -version = "0.6.1" +version = "0.7.2" authors = ["RustCrypto Developers"] description = "Custom derive support for the `der` crate's `Choice` and `Sequence` traits" documentation = "https://docs.rs/der" @@ -38,9 +38,6 @@ repository = "https://github.com/RustCrypto/formats/tree/master/der/derive" [lib] proc-macro = true -[dependencies.proc-macro-error] -version = "1" - [dependencies.proc-macro2] version = "1" @@ -48,5 +45,5 @@ version = "1" version = "1" [dependencies.syn] -version = "1.0.58" +version = "2" features = ["extra-traits"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 9360572..cced55d 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "der_derive" -version = "0.6.1" +version = "0.7.2" description = "Custom derive support for the `der` crate's `Choice` and `Sequence` traits" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" @@ -10,13 +10,12 @@ categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-i keywords = ["asn1", "der", "crypto", "itu", "pkcs"] readme = "README.md" edition = "2021" -rust-version = "1.56" +rust-version = "1.65" [lib] proc-macro = true [dependencies] proc-macro2 = "1" -proc-macro-error = "1" quote = "1" -syn = { version = "1.0.58", features = ["extra-traits"] } +syn = { version = "2", features = ["extra-traits"] } @@ -1,23 +1,20 @@ # This project was upgraded with external_updater. # Usage: tools/external_updater/updater.sh update rust/crates/der_derive -# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md name: "der_derive" description: "Custom derive support for the `der` crate\'s `Choice` and `Sequence` traits" third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/der_derive" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/der_derive/der_derive-0.6.1.crate" - } - version: "0.6.1" license_type: NOTICE last_upgrade_date { - year: 2022 + year: 2023 month: 12 - day: 9 + day: 15 + } + homepage: "https://crates.io/crates/der_derive" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/der_derive/der_derive-0.7.2.crate" + version: "0.7.2" } } @@ -7,13 +7,15 @@ ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -Custom derive support for the `der` crate's `Choice` and `Sequence` traits. +Custom derive support for the `der` crate's `Choice` and `Sequence` traits: + +<https://github.com/RustCrypto/formats/tree/master/der> [Documentation][docs-link] ## Minimum Supported Rust Version -This crate requires **Rust 1.56** at a minimum. +This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. @@ -42,7 +44,7 @@ dual licensed as above, without any additional terms or conditions. [build-image]: https://github.com/RustCrypto/formats/actions/workflows/der.yml/badge.svg [build-link]: https://github.com/RustCrypto/formats/actions/workflows/der.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats diff --git a/cargo2rulesmk.json b/cargo2rulesmk.json index 01f7467..2c63c08 100644 --- a/cargo2rulesmk.json +++ b/cargo2rulesmk.json @@ -1,3 +1,2 @@ { - "patch": "patches/rules.mk.diff" } diff --git a/cargo_embargo.json b/cargo_embargo.json index 5e1c824..5c68873 100644 --- a/cargo_embargo.json +++ b/cargo_embargo.json @@ -1,7 +1,4 @@ { - "module_name_overrides": { - "libsyn": "libsyn_deprecated" - }, "package": { "der_derive": { "device_supported": false, diff --git a/patches/rules.mk.diff b/patches/rules.mk.diff deleted file mode 100644 index e3bbe54..0000000 --- a/patches/rules.mk.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff --git b/rules.mk a/rules.mk -index 60a751a..7369647 100644 ---- b/rules.mk -+++ a/rules.mk -@@ -13,6 +13,6 @@ MODULE_LIBRARY_DEPS := \ - external/rust/crates/proc-macro-error \ - external/rust/crates/proc-macro2 \ - external/rust/crates/quote \ -- external/rust/crates/syn \ -+ external/rust/crates/syn/1.0.107 \ - - include make/library.mk @@ -1,4 +1,4 @@ -# This file is generated by cargo2rulesmk.py --run --config cargo2rulesmk.json --features . +# This file is generated by cargo2rulesmk.py --run --config cargo2rulesmk.json. # Do not modify this file as changes will be overridden on upgrade. LOCAL_DIR := $(GET_LOCAL_DIR) @@ -10,9 +10,8 @@ MODULE_SRCS := \ MODULE_RUST_EDITION := 2021 MODULE_LIBRARY_DEPS := \ - external/rust/crates/proc-macro-error \ external/rust/crates/proc-macro2 \ external/rust/crates/quote \ - external/rust/crates/syn/1.0.107 \ + external/rust/crates/syn \ include make/library.mk diff --git a/src/attributes.rs b/src/attributes.rs index c765e19..fa050cb 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -1,18 +1,15 @@ //! Attribute-related types used by the proc macro use crate::{Asn1Type, Tag, TagMode, TagNumber}; -use proc_macro2::TokenStream; -use proc_macro_error::{abort, abort_call_site}; +use proc_macro2::{Span, TokenStream}; use quote::quote; use std::{fmt::Debug, str::FromStr}; -use syn::{Attribute, Lit, LitStr, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::punctuated::Punctuated; +use syn::{parse::Parse, parse::ParseStream, Attribute, Ident, LitStr, Path, Token}; /// Attribute name. pub(crate) const ATTR_NAME: &str = "asn1"; -/// Parsing error message. -const PARSE_ERR_MSG: &str = "error parsing `asn1` attribute"; - /// Attributes on a `struct` or `enum` type. #[derive(Clone, Debug, Default)] pub(crate) struct TypeAttrs { @@ -25,31 +22,34 @@ pub(crate) struct TypeAttrs { impl TypeAttrs { /// Parse attributes from a struct field or enum variant. - pub fn parse(attrs: &[Attribute]) -> Self { + pub fn parse(attrs: &[Attribute]) -> syn::Result<Self> { let mut tag_mode = None; let mut parsed_attrs = Vec::new(); - AttrNameValue::from_attributes(attrs, &mut parsed_attrs); + AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?; for attr in parsed_attrs { // `tag_mode = "..."` attribute - if let Some(mode) = attr.parse_value("tag_mode") { - if tag_mode.is_some() { - abort!(attr.name, "duplicate ASN.1 `tag_mode` attribute"); - } - - tag_mode = Some(mode); - } else { - abort!( - attr.name, + let mode = attr.parse_value("tag_mode")?.ok_or_else(|| { + syn::Error::new_spanned( + &attr.name, "invalid `asn1` attribute (valid options are `tag_mode`)", - ); + ) + })?; + + if tag_mode.is_some() { + return Err(syn::Error::new_spanned( + &attr.name, + "duplicate ASN.1 `tag_mode` attribute", + )); } + + tag_mode = Some(mode); } - Self { + Ok(Self { tag_mode: tag_mode.unwrap_or_default(), - } + }) } } @@ -92,7 +92,7 @@ impl FieldAttrs { } /// Parse attributes from a struct field or enum variant. - pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> Self { + pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> syn::Result<Self> { let mut asn1_type = None; let mut context_specific = None; let mut default = None; @@ -102,57 +102,60 @@ impl FieldAttrs { let mut constructed = None; let mut parsed_attrs = Vec::new(); - AttrNameValue::from_attributes(attrs, &mut parsed_attrs); + AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?; for attr in parsed_attrs { // `context_specific = "..."` attribute - if let Some(tag_number) = attr.parse_value("context_specific") { + if let Some(tag_number) = attr.parse_value("context_specific")? { if context_specific.is_some() { abort!(attr.name, "duplicate ASN.1 `context_specific` attribute"); } context_specific = Some(tag_number); // `default` attribute - } else if attr.parse_value::<String>("default").is_some() { + } else if attr.parse_value::<String>("default")?.is_some() { if default.is_some() { abort!(attr.name, "duplicate ASN.1 `default` attribute"); } - default = Some(attr.value.parse().unwrap_or_else(|e| { - abort!(attr.value, "error parsing ASN.1 `default` attribute: {}", e) - })); + default = Some(attr.value.parse().map_err(|e| { + syn::Error::new_spanned( + attr.value, + format_args!("error parsing ASN.1 `default` attribute: {e}"), + ) + })?); // `extensible` attribute - } else if let Some(ext) = attr.parse_value("extensible") { + } else if let Some(ext) = attr.parse_value("extensible")? { if extensible.is_some() { abort!(attr.name, "duplicate ASN.1 `extensible` attribute"); } extensible = Some(ext); // `optional` attribute - } else if let Some(opt) = attr.parse_value("optional") { + } else if let Some(opt) = attr.parse_value("optional")? { if optional.is_some() { abort!(attr.name, "duplicate ASN.1 `optional` attribute"); } optional = Some(opt); // `tag_mode` attribute - } else if let Some(mode) = attr.parse_value("tag_mode") { + } else if let Some(mode) = attr.parse_value("tag_mode")? { if tag_mode.is_some() { abort!(attr.name, "duplicate ASN.1 `tag_mode` attribute"); } tag_mode = Some(mode); // `type = "..."` attribute - } else if let Some(ty) = attr.parse_value("type") { + } else if let Some(ty) = attr.parse_value("type")? { if asn1_type.is_some() { - abort!(attr.name, "duplicate ASN.1 `type` attribute: {}"); + abort!(attr.name, "duplicate ASN.1 `type` attribute"); } asn1_type = Some(ty); // `constructed = "..."` attribute - } else if let Some(ty) = attr.parse_value("constructed") { + } else if let Some(ty) = attr.parse_value("constructed")? { if constructed.is_some() { - abort!(attr.name, "duplicate ASN.1 `constructed` attribute: {}"); + abort!(attr.name, "duplicate ASN.1 `constructed` attribute"); } constructed = Some(ty); @@ -165,7 +168,7 @@ impl FieldAttrs { } } - Self { + Ok(Self { asn1_type, context_specific, default, @@ -173,20 +176,23 @@ impl FieldAttrs { optional: optional.unwrap_or_default(), tag_mode: tag_mode.unwrap_or(type_attrs.tag_mode), constructed: constructed.unwrap_or_default(), - } + }) } /// Get the expected [`Tag`] for this field. - pub fn tag(&self) -> Option<Tag> { + pub fn tag(&self) -> syn::Result<Option<Tag>> { match self.context_specific { - Some(tag_number) => Some(Tag::ContextSpecific { + Some(tag_number) => Ok(Some(Tag::ContextSpecific { constructed: self.constructed, number: tag_number, - }), + })), None => match self.tag_mode { - TagMode::Explicit => self.asn1_type.map(Tag::Universal), - TagMode::Implicit => abort_call_site!("implicit tagging requires a `tag_number`"), + TagMode::Explicit => Ok(self.asn1_type.map(Tag::Universal)), + TagMode::Implicit => Err(syn::Error::new( + Span::call_site(), + "implicit tagging requires a `tag_number`", + )), }, } } @@ -284,7 +290,7 @@ impl FieldAttrs { } /// Name/value pair attribute. -struct AttrNameValue { +pub(crate) struct AttrNameValue { /// Attribute name. pub name: Path, @@ -292,50 +298,65 @@ struct AttrNameValue { pub value: LitStr, } +impl Parse for AttrNameValue { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let name = match input.parse() { + Ok(name) => name, + // If it doesn't parse as a path, check if it's the keyword `type` + // The asn1 macro uses this even though Path cannot technically contain + // non-identifiers, so it needs to be forced in. + Err(e) => { + if let Ok(tok) = input.parse::<Token![type]>() { + Path::from(Ident::new("type", tok.span)) + } else { + // If it still doesn't parse, report the original error rather than the + // one produced by the workaround. + return Err(e); + } + } + }; + input.parse::<Token![=]>()?; + let value = input.parse()?; + Ok(Self { name, value }) + } +} + impl AttrNameValue { + pub fn parse_attribute(attr: &Attribute) -> syn::Result<impl IntoIterator<Item = Self>> { + attr.parse_args_with(Punctuated::<Self, Token![,]>::parse_terminated) + } + /// Parse a slice of attributes. - pub fn from_attributes(attrs: &[Attribute], out: &mut Vec<Self>) { + pub fn from_attributes(attrs: &[Attribute], out: &mut Vec<Self>) -> syn::Result<()> { for attr in attrs { - if !attr.path.is_ident(ATTR_NAME) { + if !attr.path().is_ident(ATTR_NAME) { continue; } - let nested = match attr.parse_meta().expect(PARSE_ERR_MSG) { - Meta::List(MetaList { nested, .. }) => nested, - other => abort!(other, "malformed `asn1` attribute"), - }; - - for meta in &nested { - match meta { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, - lit: Lit::Str(lit_str), - .. - })) => out.push(Self { - name: path.clone(), - value: lit_str.clone(), - }), - _ => abort!(nested, "malformed `asn1` attribute"), - } + match Self::parse_attribute(attr) { + Ok(parsed) => out.extend(parsed), + Err(e) => abort!(attr, e), } } + + Ok(()) } /// Parse an attribute value if the name matches the specified one. - pub fn parse_value<T>(&self, name: &str) -> Option<T> + pub fn parse_value<T>(&self, name: &str) -> syn::Result<Option<T>> where T: FromStr + Debug, T::Err: Debug, { - if self.name.is_ident(name) { + Ok(if self.name.is_ident(name) { Some( self.value .value() .parse() - .unwrap_or_else(|_| abort!(self.name, "error parsing attribute")), + .map_err(|_| syn::Error::new_spanned(&self.name, "error parsing attribute"))?, ) } else { None - } + }) } } diff --git a/src/choice.rs b/src/choice.rs index ac0dc37..22ab5ea 100644 --- a/src/choice.rs +++ b/src/choice.rs @@ -7,7 +7,6 @@ mod variant; use self::variant::ChoiceVariant; use crate::{default_lifetime, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, Ident, Lifetime}; @@ -25,7 +24,7 @@ pub(crate) struct DeriveChoice { impl DeriveChoice { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result<Self> { let data = match input.data { syn::Data::Enum(data) => data, _ => abort!( @@ -41,18 +40,18 @@ impl DeriveChoice { .next() .map(|lt| lt.lifetime.clone()); - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; let variants = data .variants .iter() .map(|variant| ChoiceVariant::new(variant, &type_attrs)) - .collect(); + .collect::<syn::Result<_>>()?; - Self { + Ok(Self { ident: input.ident, lifetime, variants, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -61,7 +60,10 @@ impl DeriveChoice { let lifetime = match self.lifetime { Some(ref lifetime) => quote!(#lifetime), - None => default_lifetime(), + None => { + let lifetime = default_lifetime(); + quote!(#lifetime) + } }; // Lifetime parameters @@ -108,7 +110,7 @@ impl DeriveChoice { } impl<#lt_params> ::der::EncodeValue for #ident<#lt_params> { - fn encode_value(&self, encoder: &mut dyn ::der::Writer) -> ::der::Result<()> { + fn encode_value(&self, encoder: &mut impl ::der::Writer) -> ::der::Result<()> { match self { #(#encode_body)* } @@ -158,7 +160,7 @@ mod tests { } }; - let ir = DeriveChoice::new(input); + let ir = DeriveChoice::new(input).unwrap(); assert_eq!(ir.ident, "Time"); assert_eq!(ir.lifetime, None); assert_eq!(ir.variants.len(), 2); @@ -198,7 +200,7 @@ mod tests { } }; - let ir = DeriveChoice::new(input); + let ir = DeriveChoice::new(input).unwrap(); assert_eq!(ir.ident, "ImplicitChoice"); assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); assert_eq!(ir.variants.len(), 3); diff --git a/src/choice/variant.rs b/src/choice/variant.rs index d74be61..c11ecbf 100644 --- a/src/choice/variant.rs +++ b/src/choice/variant.rs @@ -2,7 +2,6 @@ use crate::{FieldAttrs, Tag, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{Fields, Ident, Path, Type, Variant}; @@ -33,20 +32,22 @@ impl From<Path> for TagOrPath { } } -impl From<&Variant> for TagOrPath { - fn from(input: &Variant) -> Self { +impl TryFrom<&Variant> for TagOrPath { + type Error = syn::Error; + + fn try_from(input: &Variant) -> syn::Result<Self> { if let Fields::Unnamed(fields) = &input.fields { if fields.unnamed.len() == 1 { if let Type::Path(path) = &fields.unnamed[0].ty { - return path.path.clone().into(); + return Ok(path.path.clone().into()); } } } - abort!( + Err(syn::Error::new_spanned( &input.ident, - "no #[asn1(type=...)] specified for enum variant" - ) + "no #[asn1(type=...)] specified for enum variant", + )) } } @@ -73,9 +74,9 @@ pub(super) struct ChoiceVariant { impl ChoiceVariant { /// Create a new [`ChoiceVariant`] from the input [`Variant`]. - pub(super) fn new(input: &Variant, type_attrs: &TypeAttrs) -> Self { + pub(super) fn new(input: &Variant, type_attrs: &TypeAttrs) -> syn::Result<Self> { let ident = input.ident.clone(); - let attrs = FieldAttrs::parse(&input.attrs, type_attrs); + let attrs = FieldAttrs::parse(&input.attrs, type_attrs)?; if attrs.extensible { abort!(&ident, "`extensible` is not allowed on CHOICE"); @@ -88,12 +89,12 @@ impl ChoiceVariant { _ => abort!(&ident, "enum variant must be a 1-element tuple struct"), } - let tag = attrs - .tag() - .map(TagOrPath::from) - .unwrap_or_else(|| TagOrPath::from(input)); + let tag = match attrs.tag()? { + Some(x) => x.into(), + None => input.try_into()?, + }; - Self { ident, attrs, tag } + Ok(Self { ident, attrs, tag }) } /// Derive a match arm of the impl body for `TryFrom<der::asn1::Any<'_>>`. diff --git a/src/enumerated.rs b/src/enumerated.rs index 64db64a..6bdd5ff 100644 --- a/src/enumerated.rs +++ b/src/enumerated.rs @@ -2,11 +2,11 @@ //! the purposes of decoding/encoding ASN.1 `ENUMERATED` types as mapped to //! enum variants. +use crate::attributes::AttrNameValue; use crate::{default_lifetime, ATTR_NAME}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; -use syn::{DeriveInput, Expr, ExprLit, Ident, Lit, LitInt, Meta, MetaList, NestedMeta, Variant}; +use syn::{DeriveInput, Expr, ExprLit, Ident, Lit, LitInt, Variant}; /// Valid options for the `#[repr]` attribute on `Enumerated` types. const REPR_TYPES: &[&str] = &["u8", "u16", "u32"]; @@ -28,7 +28,7 @@ pub(crate) struct DeriveEnumerated { impl DeriveEnumerated { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result<Self> { let data = match input.data { syn::Data::Enum(data) => data, _ => abort!( @@ -42,23 +42,21 @@ impl DeriveEnumerated { let mut integer = false; for attr in &input.attrs { - if attr.path.is_ident(ATTR_NAME) { - if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() { - for meta in nested { - if let NestedMeta::Meta(Meta::NameValue(nv)) = meta { - if nv.path.is_ident("type") { - if let Lit::Str(lit) = nv.lit { - match lit.value().as_str() { - "ENUMERATED" => integer = false, - "INTEGER" => integer = true, - s => abort!(lit, "`type = \"{}\"` is unsupported", s), - } - } - } + if attr.path().is_ident(ATTR_NAME) { + let kvs = match AttrNameValue::parse_attribute(attr) { + Ok(kvs) => kvs, + Err(e) => abort!(attr, e), + }; + for anv in kvs { + if anv.name.is_ident("type") { + match anv.value.value().as_str() { + "ENUMERATED" => integer = false, + "INTEGER" => integer = true, + s => abort!(anv.value, format_args!("`type = \"{s}\"` is unsupported")), } } } - } else if attr.path.is_ident("repr") { + } else if attr.path().is_ident("repr") { if repr.is_some() { abort!( attr, @@ -66,16 +64,15 @@ impl DeriveEnumerated { ); } - let r = attr - .parse_args::<Ident>() - .unwrap_or_else(|_| abort!(attr, "error parsing `#[repr]` attribute")); + let r = attr.parse_args::<Ident>().map_err(|_| { + syn::Error::new_spanned(attr, "error parsing `#[repr]` attribute") + })?; // Validate if !REPR_TYPES.contains(&r.to_string().as_str()) { abort!( attr, - "invalid `#[repr]` type: allowed types are {:?}", - REPR_TYPES + format_args!("invalid `#[repr]` type: allowed types are {REPR_TYPES:?}"), ); } @@ -84,20 +81,23 @@ impl DeriveEnumerated { } // Parse enum variants - let variants = data.variants.iter().map(EnumeratedVariant::new).collect(); + let variants = data + .variants + .iter() + .map(EnumeratedVariant::new) + .collect::<syn::Result<_>>()?; - Self { + Ok(Self { ident: input.ident.clone(), - repr: repr.unwrap_or_else(|| { - abort!( + repr: repr.ok_or_else(|| { + syn::Error::new_spanned( &input.ident, - "no `#[repr]` attribute on enum: must be one of {:?}", - REPR_TYPES + format_args!("no `#[repr]` attribute on enum: must be one of {REPR_TYPES:?}"), ) - }), + })?, variants, integer, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -130,7 +130,7 @@ impl DeriveEnumerated { ::der::EncodeValue::value_len(&(*self as #repr)) } - fn encode_value(&self, encoder: &mut dyn ::der::Writer) -> ::der::Result<()> { + fn encode_value(&self, encoder: &mut impl ::der::Writer) -> ::der::Result<()> { ::der::EncodeValue::encode_value(&(*self as #repr), encoder) } } @@ -164,9 +164,9 @@ pub struct EnumeratedVariant { impl EnumeratedVariant { /// Create a new [`ChoiceVariant`] from the input [`Variant`]. - fn new(input: &Variant) -> Self { + fn new(input: &Variant) -> syn::Result<Self> { for attr in &input.attrs { - if attr.path.is_ident(ATTR_NAME) { + if attr.path().is_ident(ATTR_NAME) { abort!( attr, "`asn1` attribute is not allowed on fields of `Enumerated` types" @@ -181,10 +181,10 @@ impl EnumeratedVariant { lit: Lit::Int(discriminant), .. }), - )) => Self { + )) => Ok(Self { ident: input.ident.clone(), discriminant: discriminant.clone(), - }, + }), Some((_, other)) => abort!(other, "invalid discriminant for `Enumerated`"), None => abort!(input, "`Enumerated` variant has no discriminant"), } @@ -224,7 +224,7 @@ mod tests { } }; - let ir = DeriveEnumerated::new(input); + let ir = DeriveEnumerated::new(input).unwrap(); assert_eq!(ir.ident, "CrlReason"); assert_eq!(ir.repr, "u32"); assert_eq!(ir.variants.len(), 10); @@ -55,7 +55,7 @@ //! This attribute can be added to associate a particular `CONTEXT-SPECIFIC` //! tag number with a given enum variant or struct field. //! -//! The value must be quoted and contain a number, e.g. `#[asn1(context_specific = "42"]`. +//! The value must be quoted and contain a number, e.g. `#[asn1(context_specific = "29")]`. //! //! ### `#[asn1(default = "...")]` attribute: `DEFAULT` support //! @@ -121,6 +121,12 @@ unused_qualifications )] +macro_rules! abort { + ( $tokens:expr, $message:expr $(,)? ) => { + return Err(syn::Error::new_spanned($tokens, $message)) + }; +} + mod asn1_type; mod attributes; mod choice; @@ -140,14 +146,11 @@ use crate::{ }; use proc_macro::TokenStream; use proc_macro2::Span; -use proc_macro_error::proc_macro_error; -use quote::quote; use syn::{parse_macro_input, DeriveInput, Lifetime}; /// Get the default lifetime. -fn default_lifetime() -> proc_macro2::TokenStream { - let lifetime = Lifetime::new("'__der_lifetime", Span::call_site()); - quote!(#lifetime) +fn default_lifetime() -> Lifetime { + Lifetime::new("'__der_lifetime", Span::call_site()) } /// Derive the [`Choice`][1] trait on an `enum`. @@ -188,10 +191,12 @@ fn default_lifetime() -> proc_macro2::TokenStream { /// [3]: https://docs.rs/der/latest/der/trait.Encode.html /// [4]: https://docs.rs/der_derive/ #[proc_macro_derive(Choice, attributes(asn1))] -#[proc_macro_error] pub fn derive_choice(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveChoice::new(input).to_tokens().into() + match DeriveChoice::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive decoders and encoders for ASN.1 [`Enumerated`] types on a @@ -224,10 +229,12 @@ pub fn derive_choice(input: TokenStream) -> TokenStream { /// Note that the derive macro will write a `TryFrom<...>` impl for the /// provided `#[repr]`, which is used by the decoder. #[proc_macro_derive(Enumerated, attributes(asn1))] -#[proc_macro_error] pub fn derive_enumerated(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveEnumerated::new(input).to_tokens().into() + match DeriveEnumerated::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive the [`Sequence`][1] trait on a `struct`. @@ -264,10 +271,12 @@ pub fn derive_enumerated(input: TokenStream) -> TokenStream { /// [1]: https://docs.rs/der/latest/der/trait.Sequence.html /// [2]: https://docs.rs/der_derive/ #[proc_macro_derive(Sequence, attributes(asn1))] -#[proc_macro_error] pub fn derive_sequence(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveSequence::new(input).to_tokens().into() + match DeriveSequence::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive the [`ValueOrd`][1] trait on a `struct`. @@ -277,8 +286,10 @@ pub fn derive_sequence(input: TokenStream) -> TokenStream { /// /// [1]: https://docs.rs/der/latest/der/trait.ValueOrd.html #[proc_macro_derive(ValueOrd, attributes(asn1))] -#[proc_macro_error] pub fn derive_value_ord(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveValueOrd::new(input).to_tokens().into() + match DeriveValueOrd::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } diff --git a/src/sequence.rs b/src/sequence.rs index 3e47246..e4ad9dd 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -6,17 +6,16 @@ mod field; use crate::{default_lifetime, TypeAttrs}; use field::SequenceField; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; -use syn::{DeriveInput, Ident, Lifetime}; +use syn::{DeriveInput, GenericParam, Generics, Ident, LifetimeParam}; /// Derive the `Sequence` trait for a struct pub(crate) struct DeriveSequence { /// Name of the sequence struct. ident: Ident, - /// Lifetime of the struct. - lifetime: Option<Lifetime>, + /// Generics of the struct. + generics: Generics, /// Fields of the struct. fields: Vec<SequenceField>, @@ -24,7 +23,7 @@ pub(crate) struct DeriveSequence { impl DeriveSequence { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result<Self> { let data = match input.data { syn::Data::Struct(data) => data, _ => abort!( @@ -33,57 +32,60 @@ impl DeriveSequence { ), }; - // TODO(tarcieri): properly handle multiple lifetimes - let lifetime = input - .generics - .lifetimes() - .next() - .map(|lt| lt.lifetime.clone()); - - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; let fields = data .fields .iter() .map(|field| SequenceField::new(field, &type_attrs)) - .collect(); + .collect::<syn::Result<_>>()?; - Self { + Ok(Self { ident: input.ident, - lifetime, + generics: input.generics.clone(), fields, - } + }) } /// Lower the derived output into a [`TokenStream`]. pub fn to_tokens(&self) -> TokenStream { let ident = &self.ident; + let mut generics = self.generics.clone(); - let lifetime = match self.lifetime { - Some(ref lifetime) => quote!(#lifetime), - None => default_lifetime(), - }; - - // Lifetime parameters - // TODO(tarcieri): support multiple lifetimes - let lt_params = self - .lifetime - .as_ref() - .map(|_| lifetime.clone()) - .unwrap_or_default(); + // Use the first lifetime parameter as lifetime for Decode/Encode lifetime + // if none found, add one. + let lifetime = generics + .lifetimes() + .next() + .map(|lt| lt.lifetime.clone()) + .unwrap_or_else(|| { + let lt = default_lifetime(); + generics + .params + .insert(0, GenericParam::Lifetime(LifetimeParam::new(lt.clone()))); + lt + }); + + // We may or may not have inserted a lifetime. + let (_, ty_generics, where_clause) = self.generics.split_for_impl(); + let (impl_generics, _, _) = generics.split_for_impl(); let mut decode_body = Vec::new(); let mut decode_result = Vec::new(); - let mut encode_body = Vec::new(); + let mut encoded_lengths = Vec::new(); + let mut encode_fields = Vec::new(); for field in &self.fields { decode_body.push(field.to_decode_tokens()); decode_result.push(&field.ident); - encode_body.push(field.to_encode_tokens()); + + let field = field.to_encode_tokens(); + encoded_lengths.push(quote!(#field.encoded_len()?)); + encode_fields.push(quote!(#field.encode(writer)?;)); } quote! { - impl<#lifetime> ::der::DecodeValue<#lifetime> for #ident<#lt_params> { + impl #impl_generics ::der::DecodeValue<#lifetime> for #ident #ty_generics #where_clause { fn decode_value<R: ::der::Reader<#lifetime>>( reader: &mut R, header: ::der::Header, @@ -100,16 +102,25 @@ impl DeriveSequence { } } - impl<#lifetime> ::der::Sequence<#lifetime> for #ident<#lt_params> { - fn fields<F, T>(&self, f: F) -> ::der::Result<T> - where - F: FnOnce(&[&dyn der::Encode]) -> ::der::Result<T>, - { - f(&[ - #(#encode_body),* - ]) + impl #impl_generics ::der::EncodeValue for #ident #ty_generics #where_clause { + fn value_len(&self) -> ::der::Result<::der::Length> { + use ::der::Encode as _; + + [ + #(#encoded_lengths),* + ] + .into_iter() + .try_fold(::der::Length::ZERO, |acc, len| acc + len) + } + + fn encode_value(&self, writer: &mut impl ::der::Writer) -> ::der::Result<()> { + use ::der::Encode as _; + #(#encode_fields)* + Ok(()) } } + + impl #impl_generics ::der::Sequence<#lifetime> for #ident #ty_generics #where_clause {} } } } @@ -131,9 +142,12 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "AlgorithmIdentifier"); - assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); + assert_eq!( + ir.generics.lifetimes().next().unwrap().lifetime.to_string(), + "'a" + ); assert_eq!(ir.fields.len(), 2); let algorithm_field = &ir.fields[0]; @@ -162,9 +176,12 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "SubjectPublicKeyInfo"); - assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); + assert_eq!( + ir.generics.lifetimes().next().unwrap().lifetime.to_string(), + "'a" + ); assert_eq!(ir.fields.len(), 2); let algorithm_field = &ir.fields[0]; @@ -227,9 +244,12 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "OneAsymmetricKey"); - assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); + assert_eq!( + ir.generics.lifetimes().next().unwrap().lifetime.to_string(), + "'a" + ); assert_eq!(ir.fields.len(), 5); let version_field = &ir.fields[0]; @@ -299,9 +319,12 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "ImplicitSequence"); - assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); + assert_eq!( + ir.generics.lifetimes().next().unwrap().lifetime.to_string(), + "'a" + ); assert_eq!(ir.fields.len(), 3); let bit_string = &ir.fields[0]; diff --git a/src/sequence/field.rs b/src/sequence/field.rs index 4f478f0..3fb1832 100644 --- a/src/sequence/field.rs +++ b/src/sequence/field.rs @@ -2,7 +2,6 @@ use crate::{Asn1Type, FieldAttrs, TagMode, TagNumber, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{Field, Ident, Path, Type}; @@ -20,35 +19,35 @@ pub(super) struct SequenceField { impl SequenceField { /// Create a new [`SequenceField`] from the input [`Field`]. - pub(super) fn new(field: &Field, type_attrs: &TypeAttrs) -> Self { - let ident = field.ident.as_ref().cloned().unwrap_or_else(|| { - abort!( + pub(super) fn new(field: &Field, type_attrs: &TypeAttrs) -> syn::Result<Self> { + let ident = field.ident.as_ref().cloned().ok_or_else(|| { + syn::Error::new_spanned( field, - "no name on struct field i.e. tuple structs unsupported" + "no name on struct field i.e. tuple structs unsupported", ) - }); + })?; - let attrs = FieldAttrs::parse(&field.attrs, type_attrs); + let attrs = FieldAttrs::parse(&field.attrs, type_attrs)?; if attrs.asn1_type.is_some() && attrs.default.is_some() { - abort!( + return Err(syn::Error::new_spanned( ident, - "ASN.1 `type` and `default` options cannot be combined" - ); + "ASN.1 `type` and `default` options cannot be combined", + )); } if attrs.default.is_some() && attrs.optional { - abort!( + return Err(syn::Error::new_spanned( ident, - "`optional` and `default` field qualifiers are mutually exclusive" - ); + "`optional` and `default` field qualifiers are mutually exclusive", + )); } - Self { + Ok(Self { ident, attrs, field_type: field.ty.clone(), - } + }) } /// Derive code for decoding a field of a sequence. @@ -167,8 +166,7 @@ impl LowerFieldEncoder { /// the field encoder to tokens. fn into_tokens(self) -> TokenStream { - let encoder = self.encoder; - quote! { &#encoder } + self.encoder } /// Apply the ASN.1 type (if defined). @@ -295,7 +293,7 @@ mod tests { assert_eq!( field.to_encode_tokens().to_string(), quote! { - &self.example_field + self.example_field } .to_string() ); @@ -346,7 +344,7 @@ mod tests { assert_eq!( field.to_encode_tokens().to_string(), quote! { - &::der::asn1::ContextSpecificRef { + ::der::asn1::ContextSpecificRef { tag_number: ::der::TagNumber::N0, tag_mode: ::der::TagMode::Implicit, value: &self.implicit_field, @@ -53,11 +53,12 @@ impl Tag { } /// Tagging modes: `EXPLICIT` versus `IMPLICIT`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub(crate) enum TagMode { /// `EXPLICIT` tagging. /// /// Tag is added in addition to the inner tag of the type. + #[default] Explicit, /// `IMPLICIT` tagging. @@ -89,12 +90,6 @@ impl FromStr for TagMode { } } -impl Default for TagMode { - fn default() -> TagMode { - TagMode::Explicit - } -} - impl Display for TagMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/value_ord.rs b/src/value_ord.rs index 97e37ca..0ba8ddf 100644 --- a/src/value_ord.rs +++ b/src/value_ord.rs @@ -7,7 +7,6 @@ use crate::{FieldAttrs, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, Field, Ident, Lifetime, Variant}; @@ -28,9 +27,9 @@ pub(crate) struct DeriveValueOrd { impl DeriveValueOrd { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result<Self> { let ident = input.ident; - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; // TODO(tarcieri): properly handle multiple lifetimes let lifetime = input @@ -44,14 +43,14 @@ impl DeriveValueOrd { data.variants .into_iter() .map(|variant| ValueField::new_enum(variant, &type_attrs)) - .collect(), + .collect::<syn::Result<_>>()?, InputType::Enum, ), syn::Data::Struct(data) => ( data.fields .into_iter() .map(|field| ValueField::new_struct(field, &type_attrs)) - .collect(), + .collect::<syn::Result<_>>()?, InputType::Struct, ), _ => abort!( @@ -61,12 +60,12 @@ impl DeriveValueOrd { ), }; - Self { + Ok(Self { ident, lifetime, fields, input_type, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -142,31 +141,30 @@ struct ValueField { impl ValueField { /// Create from an `enum` variant. - fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> Self { + fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> syn::Result<Self> { let ident = variant.ident; - let attrs = FieldAttrs::parse(&variant.attrs, type_attrs); - Self { + let attrs = FieldAttrs::parse(&variant.attrs, type_attrs)?; + Ok(Self { ident, attrs, is_enum: true, - } + }) } /// Create from a `struct` field. - fn new_struct(field: Field, type_attrs: &TypeAttrs) -> Self { - let ident = field - .ident - .as_ref() - .cloned() - .unwrap_or_else(|| abort!(&field, "tuple structs are not supported")); - - let attrs = FieldAttrs::parse(&field.attrs, type_attrs); - Self { + fn new_struct(field: Field, type_attrs: &TypeAttrs) -> syn::Result<Self> { + let ident = + field.ident.as_ref().cloned().ok_or_else(|| { + syn::Error::new_spanned(&field, "tuple structs are not supported") + })?; + + let attrs = FieldAttrs::parse(&field.attrs, type_attrs)?; + Ok(Self { ident, attrs, is_enum: false, - } + }) } /// Lower to [`TokenStream`]. |