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

Fix macro use externally to isomdl. #91

Merged
merged 3 commits into from
Aug 19, 2024
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
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(),
);
cobward marked this conversation as resolved.
Show resolved Hide resolved
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()
}

cobward marked this conversation as resolved.
Show resolved Hide resolved
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(),
);
cobward marked this conversation as resolved.
Show resolved Hide resolved
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")]
cobward marked this conversation as resolved.
Show resolved Hide resolved
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")]
cobward marked this conversation as resolved.
Show resolved Hide resolved
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
1 change: 1 addition & 0 deletions tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use anyhow::{anyhow, Context, Result};
use signature::Signer;
use uuid::Uuid;
Expand Down
18 changes: 18 additions & 0 deletions tests/namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use isomdl::{
definitions::traits::FromJson,
macros::{FromJson, ToCbor},
};

#[derive(FromJson, ToCbor)]
pub struct NewNamespace {
field: String,
}

#[test]
fn new_namespace() {
let json = serde_json::json!({
"field": "value"
});

NewNamespace::from_json(&json).unwrap();
}