dpp_digital_link/linktype/
vocabulary.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub enum Gs1LinkType {
12 ProductInformationPage,
14 ElectronicLeaflet,
16 SustainabilityInfo,
18 RecyclingInfo,
20 MasterData,
22 CertificationInfo,
24 Instructions,
26 SafetyInfo,
28 Traceability,
30 DigitalProductPassport,
33 Custom(String),
35}
36
37impl Gs1LinkType {
38 pub fn parse(s: &str) -> Self {
40 match s {
41 "gs1:pip" | "https://ref.gs1.org/voc/pip" => Self::ProductInformationPage,
42 "gs1:epil" | "https://ref.gs1.org/voc/epil" => Self::ElectronicLeaflet,
43 "gs1:sustainabilityInfo" | "https://ref.gs1.org/voc/sustainabilityInfo" => {
44 Self::SustainabilityInfo
45 }
46 "gs1:recyclingInfo" | "https://ref.gs1.org/voc/recyclingInfo" => Self::RecyclingInfo,
47 "gs1:masterData" | "https://ref.gs1.org/voc/masterData" => Self::MasterData,
48 "gs1:certificationInfo" | "https://ref.gs1.org/voc/certificationInfo" => {
49 Self::CertificationInfo
50 }
51 "gs1:instructions" | "https://ref.gs1.org/voc/instructions" => Self::Instructions,
52 "gs1:safetyInfo" | "https://ref.gs1.org/voc/safetyInfo" => Self::SafetyInfo,
53 "gs1:traceability" | "https://ref.gs1.org/voc/traceability" => Self::Traceability,
54 "gs1:dpp" | "https://ref.gs1.org/voc/dpp" => Self::DigitalProductPassport,
55 other => Self::Custom(other.to_owned()),
56 }
57 }
58
59 pub fn as_gs1_uri(&self) -> &str {
61 match self {
62 Self::ProductInformationPage => "https://ref.gs1.org/voc/pip",
63 Self::ElectronicLeaflet => "https://ref.gs1.org/voc/epil",
64 Self::SustainabilityInfo => "https://ref.gs1.org/voc/sustainabilityInfo",
65 Self::RecyclingInfo => "https://ref.gs1.org/voc/recyclingInfo",
66 Self::MasterData => "https://ref.gs1.org/voc/masterData",
67 Self::CertificationInfo => "https://ref.gs1.org/voc/certificationInfo",
68 Self::Instructions => "https://ref.gs1.org/voc/instructions",
69 Self::SafetyInfo => "https://ref.gs1.org/voc/safetyInfo",
70 Self::Traceability => "https://ref.gs1.org/voc/traceability",
71 Self::DigitalProductPassport => "https://ref.gs1.org/voc/dpp",
72 Self::Custom(uri) => uri.as_str(),
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn every_known_link_type_round_trips_via_canonical_uri() {
83 let all = [
84 Gs1LinkType::ProductInformationPage,
85 Gs1LinkType::ElectronicLeaflet,
86 Gs1LinkType::SustainabilityInfo,
87 Gs1LinkType::RecyclingInfo,
88 Gs1LinkType::MasterData,
89 Gs1LinkType::CertificationInfo,
90 Gs1LinkType::Instructions,
91 Gs1LinkType::SafetyInfo,
92 Gs1LinkType::Traceability,
93 Gs1LinkType::DigitalProductPassport,
94 ];
95 for lt in all {
96 let uri = lt.as_gs1_uri();
97 assert_eq!(Gs1LinkType::parse(uri), lt, "canonical URI must round-trip");
98 }
99 }
100
101 #[test]
102 fn shorthand_and_full_uris_parse_equivalently() {
103 assert_eq!(
104 Gs1LinkType::parse("gs1:dpp"),
105 Gs1LinkType::DigitalProductPassport
106 );
107 assert_eq!(
108 Gs1LinkType::parse("gs1:pip"),
109 Gs1LinkType::ProductInformationPage
110 );
111 assert_eq!(
112 Gs1LinkType::parse("gs1:safetyInfo"),
113 Gs1LinkType::SafetyInfo
114 );
115 }
116
117 #[test]
118 fn unknown_link_type_becomes_custom() {
119 let custom = Gs1LinkType::parse("https://example.com/voc/warranty");
120 assert_eq!(
121 custom,
122 Gs1LinkType::Custom("https://example.com/voc/warranty".to_owned())
123 );
124 assert_eq!(custom.as_gs1_uri(), "https://example.com/voc/warranty");
125 }
126}