Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove proc-macro-error dependency #1180

Merged
merged 1 commit into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion der/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ proc-macro = true

[dependencies]
proc-macro2 = "1"
proc-macro-error = "1"
quote = "1"
syn = { version = "2", features = ["extra-traits"] }
98 changes: 54 additions & 44 deletions der/derive/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! 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::punctuated::Punctuated;
Expand All @@ -23,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(),
}
})
}
}

Expand Down Expand Up @@ -90,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;
Expand All @@ -100,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);
Expand All @@ -163,28 +168,31 @@ impl FieldAttrs {
}
}

Self {
Ok(Self {
asn1_type,
context_specific,
default,
extensible: extensible.unwrap_or_default(),
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`",
)),
},
}
}
Expand Down Expand Up @@ -319,34 +327,36 @@ impl AttrNameValue {
}

/// 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) {
continue;
}

match Self::parse_attribute(attr) {
Ok(parsed) => out.extend(parsed),
Err(e) => abort!(attr, "{}", e),
};
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
}
})
}
}
15 changes: 7 additions & 8 deletions der/derive/src/choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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!(
Expand All @@ -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`].
Expand Down Expand Up @@ -161,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);
Expand Down Expand Up @@ -201,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);
Expand Down
29 changes: 15 additions & 14 deletions der/derive/src/choice/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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",
))
}
}

Expand All @@ -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");
Expand All @@ -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<'_>>`.
Expand Down
Loading