use std::collections::HashMap;
use ciborium::Value;
use serde::{Deserialize, Serialize};
use super::{
data_retrieval::common::{DataElementIdentifier, DataElementValue},
Bytes, DateTime, FullDate,
};
pub(crate) const MDL_DOCUMENT_TYPE: &str = "org.iso.18013.5.1.mDL";
pub(crate) const MDL_NAMESPACE: &str = "org.iso.18013.5.1";
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DateTimeOrFull {
FullDate(FullDate),
DateTime(DateTime),
}
impl From<DateTime> for DateTimeOrFull {
fn from(date_time: DateTime) -> Self {
Self::DateTime(date_time)
}
}
impl From<FullDate> for DateTimeOrFull {
fn from(full_date: FullDate) -> Self {
Self::FullDate(full_date)
}
}
impl From<DateTimeOrFull> for Value {
fn from(date: DateTimeOrFull) -> Self {
match date {
DateTimeOrFull::DateTime(date_time) => date_time.into(),
DateTimeOrFull::FullDate(full_date) => full_date.into(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MDL {
#[serde(flatten)]
pub mandatory: MDLMandatory,
#[serde(flatten)]
pub optional: MDLOptional,
}
impl MDL {
pub fn new(mandatory: MDLMandatory) -> Self {
Self {
mandatory,
optional: MDLOptional::default(),
}
}
}
impl From<MDL> for HashMap<DataElementIdentifier, DataElementValue> {
fn from(value: MDL) -> Self {
let mut mandatory_map = Self::from(value.mandatory);
let optional_map = Self::from(value.optional);
mandatory_map.extend(optional_map);
mandatory_map
}
}
macro_rules! with_into_map {
(
$(#[$attr:meta])*
$vis:vis struct $name:ident {
$($(#[$fattr:meta])* $field_vis:vis $field_name:ident: Option<$field_type:ty>,)*
}
) => {
$(#[$attr])*
$vis struct $name {
$($(#[$fattr])* $field_vis $field_name: Option<$field_type>,)*
}
impl From<$name> for HashMap<DataElementIdentifier, DataElementValue> {
fn from(value: $name) -> Self {
let mut map = HashMap::new();
$(
if let Some(v) = value.$field_name {
map.insert(stringify!($field_name).into(), v.into());
}
)*
map
}
}
};
(
$(#[$attr:meta])*
$vis:vis struct $name:ident {
$($(#[$fattr:meta])* $field_vis:vis $field_name:ident: $field_type:ty,)*
}
) => {
$(#[$attr])*
$vis struct $name {
$($(#[$fattr])* $field_vis $field_name: $field_type,)*
}
impl From<$name> for HashMap<DataElementIdentifier, DataElementValue> {
fn from(value: $name) -> Self {
let mut map = HashMap::new();
$(
map.insert(stringify!($field_name).into(), value.$field_name.into());
)*
map
}
}
};
}
with_into_map! {
#[derive(Debug, Serialize, Deserialize)]
pub struct MDLMandatory {
pub family_name: String,
pub given_name: String,
pub birth_date: FullDate,
pub issue_date: DateTimeOrFull,
pub expiry_date: DateTimeOrFull,
pub issuing_country: String,
pub issuing_authority: String,
pub document_number: String,
pub portrait: Bytes,
pub driving_privileges: u8,
pub un_distinguishing_sign: String,
}
}
with_into_map! {
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct MDLOptional {
pub administrative_number: Option<String>,
pub sex: Option<u64>,
pub height: Option<u64>,
pub weight: Option<u64>,
pub eye_colour: Option<String>,
pub hair_colour: Option<String>,
pub birth_place: Option<String>,
pub resident_address: Option<String>,
pub portrait_capture_date: Option<DateTime>,
pub age_in_years: Option<u64>,
pub age_birth_year: Option<u64>,
pub issuing_jurisdiction: Option<String>,
pub nationality: Option<String>,
pub resident_city: Option<String>,
pub resident_state: Option<String>,
pub resident_postal_code: Option<String>,
pub resident_country: Option<String>,
pub family_name_national_character: Option<String>,
pub given_name_national_character: Option<String>,
pub signature_usual_mark: Option<Bytes>,
}
}