From 544ef9bc3c5f4e8aa9d059c63e4e03066f36929f Mon Sep 17 00:00:00 2001 From: Marco Napetti <7566389+nappa85@users.noreply.github.com> Date: Thu, 9 Dec 2021 19:46:08 +0100 Subject: [PATCH] Uniformity in the use of Cow instead of String (#32) * Uniformity in the use of Cow instead of String * rustfmt * Fix doctest --- src/dgc.rs | 138 ++++++++++++++++++------------------------- src/dgc_container.rs | 4 +- src/recovery.rs | 12 ++-- src/test.rs | 24 ++++---- src/vaccination.rs | 16 ++--- src/valuesets.rs | 26 +++++--- 6 files changed, 102 insertions(+), 118 deletions(-) diff --git a/src/dgc.rs b/src/dgc.rs index 0db4e81..0dfcd25 100644 --- a/src/dgc.rs +++ b/src/dgc.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use crate::{Recovery, Test, Vaccination}; use serde::{Deserialize, Deserializer, Serialize}; @@ -6,16 +8,16 @@ use serde::{Deserialize, Deserializer, Serialize}; pub struct DgcName { /// The forename(s) of the person addressed in the certificate #[serde(rename = "gn", skip_serializing_if = "Option::is_none")] - pub forename: Option, + pub forename: Option>, /// The surname or primary name(s) of the person addressed in the certificate #[serde(rename = "fn", skip_serializing_if = "Option::is_none")] - pub surname: Option, + pub surname: Option>, /// The forename(s) of the person, transliterated ICAO 9303 #[serde(rename = "gnt", skip_serializing_if = "Option::is_none")] - pub forename_standard: Option, + pub forename_standard: Option>, /// The surname(s) of the person, transliterated ICAO 9303 #[serde(rename = "fnt")] - pub surname_standard: String, + pub surname_standard: Cow<'static, str>, } fn empty_if_null<'de, D, T>(deserializer: D) -> Result, D::Error> @@ -32,13 +34,13 @@ where pub struct Dgc { /// The certificate version as per the published [schemas](https://github.com/ehn-dcc-development/ehn-dcc-schema). #[serde(rename = "ver")] - pub version: String, + pub version: Cow<'static, str>, /// The name of the person addressed in the DGC. #[serde(rename = "nam")] pub name: DgcName, /// Date of Birth of the person addressed in the DGC. ISO 8601 date format restricted to range 1900-2099 or empty #[serde(rename = "dob")] - pub date_of_birth: String, + pub date_of_birth: Cow<'static, str>, /// Test Group #[serde( rename = "t", @@ -79,31 +81,29 @@ impl Dgc { #[cfg(test)] mod tests { - use std::borrow::Cow; - use super::*; #[test] fn test_json_serialization() { let expected_json = "{\"ver\":\"1.3.0\",\"nam\":{\"gn\":\"ALSTON\",\"fn\":\"BLAKE\",\"gnt\":\"ALSTON\",\"fnt\":\"BLAKE\"},\"dob\":\"1990-01-01\",\"t\":[{\"tg\":\"840539006\",\"tt\":\"LP6464-4\",\"sc\":\"2021-10-09T12:03:12Z\",\"tr\":\"260415000\",\"tc\":\"Alhosn One Day Surgery\",\"co\":\"AE\",\"is\":\"Ministry of Health & Prevention\",\"ci\":\"URN:UVCI:V1:AE:8KST0RH057HI8XKW3M8K2NAD06\"}]}"; let cert = Dgc { - version: String::from("1.3.0"), + version: "1.3.0".into(), name: DgcName { - forename: Some(String::from("ALSTON")), - surname: Some(String::from("BLAKE")), - forename_standard: Some(String::from("ALSTON")), - surname_standard: String::from("BLAKE"), + forename: Some("ALSTON".into()), + surname: Some("BLAKE".into()), + forename_standard: Some("ALSTON".into()), + surname_standard: "BLAKE".into(), }, - date_of_birth: String::from("1990-01-01"), + date_of_birth: "1990-01-01".into(), tests: vec![Test { - targeted_disease: Cow::from("840539006"), - test_type: Cow::from("LP6464-4"), - date_of_collection: String::from("2021-10-09T12:03:12Z"), - result: Cow::from("260415000"), - testing_centre: Some(String::from("Alhosn One Day Surgery")), - country: Cow::from("AE"), - issuer: Cow::from("Ministry of Health & Prevention"), - id: String::from("URN:UVCI:V1:AE:8KST0RH057HI8XKW3M8K2NAD06"), + targeted_disease: "840539006".into(), + test_type: "LP6464-4".into(), + date_of_collection: "2021-10-09T12:03:12Z".into(), + result: "260415000".into(), + testing_centre: Some("Alhosn One Day Surgery".into()), + country: "AE".into(), + issuer: "Ministry of Health & Prevention".into(), + id: "URN:UVCI:V1:AE:8KST0RH057HI8XKW3M8K2NAD06".into(), name: None, manufacturer: None, date_of_result: None, @@ -146,41 +146,29 @@ mod tests { } "#; let cert: Dgc = serde_json::from_str(json_data).unwrap(); - assert_eq!(cert.version, String::from("1.0.0")); - assert_eq!(cert.name.surname, Some(String::from("Di Caprio"))); - assert_eq!(cert.name.surname_standard, String::from("DI, /// A unix timestamp representing the moment in time when the data in the container was issued #[serde(rename = "6")] pub issued_at: IntegerOrFloat, diff --git a/src/recovery.rs b/src/recovery.rs index 79b1821..15f079c 100644 --- a/src/recovery.rs +++ b/src/recovery.rs @@ -18,23 +18,23 @@ pub struct Recovery { pub country: Cow<'static, str>, /// Certificate Issuer #[serde(rename = "is")] - pub issuer: String, + pub issuer: Cow<'static, str>, /// ISO 8601 complete date: Certificate Valid From #[serde(rename = "df")] - pub valid_from: String, + pub valid_from: Cow<'static, str>, /// ISO 8601 complete date: Certificate Valid Until #[serde(rename = "du")] - pub valid_until: String, + pub valid_until: Cow<'static, str>, /// Unique Certificate Identifier, UVCI #[serde(rename = "ci")] - pub id: String, + pub id: Cow<'static, str>, } impl Recovery { /// Updates all the ids in the recovery entry with their descriptive counterparts using /// the official valueset. pub fn expand_values(&mut self) { - self.targeted_disease = lookup_value(&self.targeted_disease); - self.country = lookup_value(&self.country); + lookup_value(&mut self.targeted_disease); + lookup_value(&mut self.country); } } diff --git a/src/test.rs b/src/test.rs index 53c0feb..65cb540 100644 --- a/src/test.rs +++ b/src/test.rs @@ -15,23 +15,23 @@ pub struct Test { pub test_type: Cow<'static, str>, /// NAA Test Name #[serde(rename = "nm", skip_serializing_if = "Option::is_none")] - pub name: Option, + pub name: Option>, /// RAT Test name and manufacturer #[serde(rename = "ma", skip_serializing_if = "Option::is_none")] pub manufacturer: Option>, /// Date/Time of Sample Collection #[serde(rename = "sc")] - pub date_of_collection: String, + pub date_of_collection: Cow<'static, str>, /// Date/Time of Test Result /// Deprecated in v1.3.0 of the schema #[serde(rename = "dr", skip_serializing_if = "Option::is_none")] - pub date_of_result: Option, + pub date_of_result: Option>, /// Test Result #[serde(rename = "tr")] pub result: Cow<'static, str>, /// Testing Centre #[serde(rename = "tc", skip_serializing_if = "Option::is_none")] - pub testing_centre: Option, + pub testing_centre: Option>, /// Country of Test #[serde(rename = "co")] pub country: Cow<'static, str>, @@ -40,20 +40,20 @@ pub struct Test { pub issuer: Cow<'static, str>, /// Unique Certificate Identifier, UVCI #[serde(rename = "ci")] - pub id: String, + pub id: Cow<'static, str>, } impl Test { /// Updates all the ids in the test entry with their descriptive counterparts using /// the official valueset. pub fn expand_values(&mut self) { - self.targeted_disease = lookup_value(&self.targeted_disease); - self.test_type = lookup_value(&self.test_type); - self.result = lookup_value(&self.result); - if let Some(ma) = &mut self.manufacturer { - *ma = lookup_value(ma); + lookup_value(&mut self.targeted_disease); + lookup_value(&mut self.test_type); + lookup_value(&mut self.result); + if let Some(ma) = self.manufacturer.as_mut() { + lookup_value(ma); } - self.country = lookup_value(&self.country); - self.issuer = lookup_value(&self.issuer); + lookup_value(&mut self.country); + lookup_value(&mut self.issuer); } } diff --git a/src/vaccination.rs b/src/vaccination.rs index 2460cf8..10f544f 100644 --- a/src/vaccination.rs +++ b/src/vaccination.rs @@ -27,26 +27,26 @@ pub struct Vaccination { pub total_doses: usize, /// ISO8601 complete date: Date of Vaccination #[serde(rename = "dt")] - pub date: String, + pub date: Cow<'static, str>, /// Country of Vaccination #[serde(rename = "co")] pub country: Cow<'static, str>, /// Certificate Issuer #[serde(rename = "is")] - pub issuer: String, + pub issuer: Cow<'static, str>, /// Unique Certificate Identifier: UVCI #[serde(rename = "ci")] - pub id: String, + pub id: Cow<'static, str>, } impl Vaccination { /// Updates all the ids in the vaccination entry with their descriptive counterparts using /// the official valueset. pub fn expand_values(&mut self) { - self.targeted_disease = lookup_value(&self.targeted_disease); - self.vaccine_prophylaxis = lookup_value(&self.vaccine_prophylaxis); - self.medicinal_product = lookup_value(&self.medicinal_product); - self.manufacturer = lookup_value(&self.manufacturer); - self.country = lookup_value(&self.country); + lookup_value(&mut self.targeted_disease); + lookup_value(&mut self.vaccine_prophylaxis); + lookup_value(&mut self.medicinal_product); + lookup_value(&mut self.manufacturer); + lookup_value(&mut self.country); } } diff --git a/src/valuesets.rs b/src/valuesets.rs index c4629ae..2f2d611 100644 --- a/src/valuesets.rs +++ b/src/valuesets.rs @@ -13,17 +13,27 @@ use std::borrow::Cow; /// ``` /// # use dgc::lookup_value; /// # -/// assert_eq!(lookup_value("AQ"), "Antarctica"); -/// assert_eq!(lookup_value("840539006"), "COVID-19"); -/// assert_eq!(lookup_value("LP217198-3"), "Rapid immunoassay"); -/// assert_eq!(lookup_value("EU/1/20/1528"), "Comirnaty"); -/// assert_eq!(lookup_value("value not in valueset"), "value not in valueset"); +/// let mut value = "AQ".into(); +/// lookup_value(&mut value); +/// assert_eq!(value, "Antarctica"); +/// let mut value = "840539006".into(); +/// lookup_value(&mut value); +/// assert_eq!(value, "COVID-19"); +/// let mut value = "LP217198-3".into(); +/// lookup_value(&mut value); +/// assert_eq!(value, "Rapid immunoassay"); +/// let mut value = "EU/1/20/1528".into(); +/// lookup_value(&mut value); +/// assert_eq!(value, "Comirnaty"); +/// let mut value = "value not in valueset".into(); +/// lookup_value(&mut value); +/// assert_eq!(value, "value not in valueset"); /// ``` -pub fn lookup_value(value_id: &str) -> Cow<'static, str> { +pub fn lookup_value(value_id: &mut Cow<'static, str>) { // Populated from https://github.com/ehn-dcc-development/ehn-dcc-schema/tree/release/1.3.0/valuesets // List generated with the following Node.js snippet (for every valueset file): // > for (const [key, val] of Object.entries(fileData.valueSetValues)) { console.log(`"${key}" => Cow::Borrowed("${val.display}"),`) } - match value_id { + *value_id = match value_id.as_ref() { // https://github.com/ehn-dcc-development/ehn-dcc-schema/blob/release/1.3.0/valuesets/country-2-codes.json "AD" => Cow::Borrowed("Andorra"), "AE" => Cow::Borrowed("United Arab Emirates"), @@ -387,6 +397,6 @@ pub fn lookup_value(value_id: &str) -> Cow<'static, str> { "1119305005" => Cow::Borrowed("SARS-CoV-2 antigen vaccine"), "1119349007" => Cow::Borrowed("SARS-CoV-2 mRNA vaccine"), "J07BX03" => Cow::Borrowed("covid-19 vaccines"), - _ => Cow::Owned(value_id.to_owned()), + _ => return, } }