Skip to content

Commit

Permalink
Fix macro use externally to isomdl.
Browse files Browse the repository at this point in the history
Add macro attribute to select path to isomdl crate, and use "crate" as
the path internally.
  • Loading branch information
cobward committed Aug 15, 2024
1 parent 9d99da6 commit 2f6836f
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 14 deletions.
24 changes: 17 additions & 7 deletions macros/src/from_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed, Ident};

pub fn derive(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
let DeriveInput {
ident, data, attrs, ..
} = parse_macro_input!(input);
let isomdl_path = Ident::new(
&attrs
.iter()
.filter_map(super::crate_path)
.next()
.unwrap_or_else(|| "isomdl".to_owned()),
Span::call_site(),
);
let struct_data = match data {
Data::Struct(s) => s,
Data::Enum(_) => {
Expand All @@ -22,16 +32,16 @@ pub fn derive(input: TokenStream) -> TokenStream {
};

match struct_data.fields {
Fields::Named(f) => named_fields(ident, f),
Fields::Unnamed(f) => unnamed_fields(ident, f),
Fields::Named(f) => named_fields(isomdl_path, ident, f),
Fields::Unnamed(f) => unnamed_fields(isomdl_path, ident, f),
Fields::Unit => quote! {
compile_error!("cannot derive FromJson for unit struct");
}
.into(),
}
}

fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
fn named_fields(isomdl_path: Ident, ident: Ident, input: FieldsNamed) -> TokenStream {
let mut conversions = quote! {};
let mut fields = quote! {};

Expand Down Expand Up @@ -83,7 +93,7 @@ fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
mod #mod_name {
use serde_json::Value;
use super::*;
use crate::definitions::traits::{FromJson, FromJsonError, FromJsonMap};
use #isomdl_path::definitions::traits::{FromJson, FromJsonError, FromJsonMap};
impl FromJson for #ident {
fn from_json(value: &Value) -> Result<#ident, FromJsonError> {
let map = match value {
Expand Down Expand Up @@ -115,7 +125,7 @@ fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
output.into()
}

fn unnamed_fields(ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
fn unnamed_fields(isomdl_path: Ident, ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
let field_type =
match input.unnamed.pop() {
Some(pair) => pair.into_value().ty,
Expand All @@ -140,7 +150,7 @@ fn unnamed_fields(ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
let output = quote! {
mod #mod_name {
use super::*;
use crate::definitions::traits::{FromJson, FromJsonError};
use #isomdl_path::definitions::traits::{FromJson, FromJsonError};
use serde_json::Value;
impl FromJson for #ident {
fn from_json(value: &Value) -> Result<#ident, FromJsonError> {
Expand Down
26 changes: 26 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,32 @@ fn is_optional(ty: &Type) -> bool {
}
}

// Attribute for setting the path to the isomdl crate, mostly for use
// internally in isomdl to refer to itself as 'crate'.
fn crate_path(attr: &Attribute) -> Option<String> {
get_isomdl_attributes(attr)?
.filter_map(|nested_meta| {
let meta = match nested_meta {
NestedMeta::Meta(meta) => meta,
_ => return None,
};
match meta {
Meta::NameValue(pair) => {
if !pair.path.is_ident("crate") {
return None;
}
if let Lit::Str(s) = pair.lit {
Some(s.value())
} else {
None
}
}
_ => None,
}
})
.next()
}

fn rename(attr: &Attribute) -> Option<String> {
get_isomdl_attributes(attr)?
.filter_map(|nested_meta| {
Expand Down
24 changes: 17 additions & 7 deletions macros/src/to_cbor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed, Ident};

pub fn derive(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
let DeriveInput {
ident, data, attrs, ..
} = parse_macro_input!(input);
let isomdl_path = Ident::new(
&attrs
.iter()
.filter_map(super::crate_path)
.next()
.unwrap_or_else(|| "isomdl".to_owned()),
Span::call_site(),
);
let struct_data = match data {
Data::Struct(s) => s,
Data::Enum(_) => {
Expand All @@ -22,16 +32,16 @@ pub fn derive(input: TokenStream) -> TokenStream {
};

match struct_data.fields {
Fields::Named(f) => named_fields(ident, f),
Fields::Unnamed(f) => unnamed_fields(ident, f),
Fields::Named(f) => named_fields(isomdl_path, ident, f),
Fields::Unnamed(f) => unnamed_fields(isomdl_path, ident, f),
Fields::Unit => quote! {
compile_error!("cannot derive ToCbor for unit struct");
}
.into(),
}
}

fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
fn named_fields(isomdl_path: Ident, ident: Ident, input: FieldsNamed) -> TokenStream {
let mut conversions = quote! {};

input.named.into_iter().for_each(
Expand Down Expand Up @@ -78,7 +88,7 @@ fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
mod #mod_name {
use serde_cbor::Value;
use super::*;
use crate::definitions::traits::{ToCbor, ToNamespaceMap};
use #isomdl_path::definitions::traits::{ToCbor, ToNamespaceMap};
impl ToNamespaceMap for #ident {
fn to_ns_map(self) -> std::collections::BTreeMap<String, Value> {
let mut map = std::collections::BTreeMap::default();
Expand All @@ -103,7 +113,7 @@ fn named_fields(ident: Ident, input: FieldsNamed) -> TokenStream {
output.into()
}

fn unnamed_fields(ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
fn unnamed_fields(isomdl_path: Ident, ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
let field_type = match input.unnamed.pop() {
Some(pair) => pair.into_value().ty,
None => {
Expand All @@ -129,7 +139,7 @@ fn unnamed_fields(ident: Ident, mut input: FieldsUnnamed) -> TokenStream {
let output = quote! {
mod #mod_name {
use super::*;
use crate::definitions::traits::{ToCbor, ToCborError};
use #isomdl_path::definitions::traits::{ToCbor, ToCborError};
use serde_cbor::Value;
impl ToCbor for #ident {
fn to_cbor(self) -> Value {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde_cbor::Value as Cbor;

/// `driving_privileges` in the org.iso.18013.5.1 namespace.
#[derive(Clone, Debug, FromJson)]
#[isomdl(crate = "crate")]
pub struct DrivingPrivileges(Vec<DrivingPrivilege>);

impl From<DrivingPrivileges> for Cbor {
Expand All @@ -16,6 +17,7 @@ impl From<DrivingPrivileges> for Cbor {
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct DrivingPrivilege {
pub vehicle_category_code: String,
pub issue_date: Option<FullDate>,
Expand All @@ -24,6 +26,7 @@ pub struct DrivingPrivilege {
}

#[derive(Clone, Debug, FromJson)]
#[isomdl(crate = "crate")]
pub struct Codes(NonEmptyVec<Code>);

impl From<Codes> for Cbor {
Expand All @@ -33,6 +36,7 @@ impl From<Codes> for Cbor {
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct Code {
pub code: String,
pub sign: Option<String>,
Expand Down
1 change: 1 addition & 0 deletions src/definitions/namespaces/org_iso_18013_5_1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::{

/// The `org.iso.18013.5.1` namespace.
#[derive(Debug, Clone, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct OrgIso1801351 {
pub family_name: Latin1,
pub given_name: Latin1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use serde_cbor::Value as Cbor;
/// `domestic_driving_privileges` in the org.iso.18013.5.1.aamva namespace, as per the AAMVA mDL Implementation
/// Guidelines (Version 1.0).
#[derive(Clone, Debug, FromJson)]
#[isomdl(crate = "crate")]
pub struct DomesticDrivingPrivileges(Vec<DomesticDrivingPrivilege>);

impl ToCbor for DomesticDrivingPrivileges {
Expand All @@ -17,13 +18,15 @@ impl ToCbor for DomesticDrivingPrivileges {
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct DomesticDrivingPrivilege {
pub domestic_vehicle_class: Option<DomesticVehicleClass>,
pub domestic_vehicle_restrictions: Option<DomesticVehicleRestrictions>,
pub domestic_vehicle_endorsements: Option<DomesticVehicleEndorsements>,
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct DomesticVehicleClass {
pub domestic_vehicle_class_code: String,
pub domestic_vehicle_class_description: String,
Expand All @@ -32,6 +35,7 @@ pub struct DomesticVehicleClass {
}

#[derive(Clone, Debug, FromJson)]
#[isomdl(crate = "crate")]
pub struct DomesticVehicleRestrictions(NonEmptyVec<DomesticVehicleRestriction>);

impl ToCbor for DomesticVehicleRestrictions {
Expand All @@ -47,12 +51,14 @@ impl ToCbor for DomesticVehicleRestrictions {
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct DomesticVehicleRestriction {
pub domestic_vehicle_restriction_code: Option<String>,
pub domestic_vehicle_restriction_description: String,
}

#[derive(Clone, Debug, FromJson)]
#[isomdl(crate = "crate")]
pub struct DomesticVehicleEndorsements(NonEmptyVec<DomesticVehicleEndorsement>);

impl ToCbor for DomesticVehicleEndorsements {
Expand All @@ -68,6 +74,7 @@ impl ToCbor for DomesticVehicleEndorsements {
}

#[derive(Clone, Debug, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct DomesticVehicleEndorsement {
pub domestic_vehicle_endorsement_code: Option<String>,
pub domestic_vehicle_endorsement_description: String,
Expand Down
1 change: 1 addition & 0 deletions src/definitions/namespaces/org_iso_18013_5_1_aamva/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::macros::{FromJson, ToCbor};
/// `org.iso.18013.5.1.aamva` namespace, as per the AAMVA mDL Implementation
/// Guidelines (Version 1.2).
#[derive(Debug, Clone, FromJson, ToCbor)]
#[isomdl(crate = "crate")]
pub struct OrgIso1801351Aamva {
pub domestic_driving_privileges: DomesticDrivingPrivileges,
pub name_suffix: Option<NameSuffix>,
Expand Down
1 change: 1 addition & 0 deletions src/definitions/traits/from_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ mod tests {
use serde_json::{json, Value};

#[derive(FromJson)]
#[isomdl(crate = "crate")]
struct S {
a: Option<u32>,
}
Expand Down

0 comments on commit 2f6836f

Please sign in to comment.