use dpp_rules::common::identifier::{DidRejection, check_did, is_absolute_web_url};
use serde::{Deserialize, Serialize};
use super::super::gtin::Gtin;
use super::error::ProductIdentifierError;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "scheme", rename_all = "camelCase")]
#[serde(try_from = "Wire")]
#[non_exhaustive]
pub enum ProductIdentifier {
#[serde(rename_all = "camelCase")]
Gs1 {
gtin: Gtin,
},
#[serde(rename_all = "camelCase")]
IdentificationLink {
url: String,
},
#[serde(rename_all = "camelCase")]
Did {
did: String,
},
}
impl ProductIdentifier {
#[must_use]
pub fn gs1(gtin: Gtin) -> Self {
Self::Gs1 { gtin }
}
pub fn identification_link(url: &str) -> Result<Self, ProductIdentifierError> {
if !is_absolute_web_url(url) {
return Err(ProductIdentifierError::NotAWebUrl(url.to_owned()));
}
Ok(Self::IdentificationLink {
url: url.to_owned(),
})
}
pub fn did(did: &str) -> Result<Self, ProductIdentifierError> {
check_did(did).map_err(|rejection| match rejection {
DidRejection::UnsupportedMethod(method) => {
ProductIdentifierError::UnsupportedDidMethod(method.to_owned())
}
DidRejection::EmptyMethodId => ProductIdentifierError::EmptyDidMethodId(did.to_owned()),
DidRejection::Malformed => ProductIdentifierError::NotADid(did.to_owned()),
})?;
Ok(Self::Did {
did: did.to_owned(),
})
}
#[must_use]
pub fn gtin(&self) -> Option<&Gtin> {
match self {
Self::Gs1 { gtin } => Some(gtin),
_ => None,
}
}
#[must_use]
pub fn value_kind(&self) -> &'static str {
match self {
Self::Gs1 { .. } => "gtin",
Self::IdentificationLink { .. } => "identificationLink",
Self::Did { .. } => "did",
}
}
#[must_use]
pub const fn is_uri(&self) -> bool {
matches!(self, Self::IdentificationLink { .. } | Self::Did { .. })
}
#[must_use]
pub fn as_str(&self) -> &str {
match self {
Self::Gs1 { gtin } => gtin.as_str(),
Self::IdentificationLink { url } => url,
Self::Did { did } => did,
}
}
}
#[derive(Deserialize)]
#[serde(tag = "scheme", rename_all = "camelCase")]
enum Wire {
#[serde(rename_all = "camelCase")]
Gs1 { gtin: Gtin },
#[serde(rename_all = "camelCase")]
IdentificationLink { url: String },
#[serde(rename_all = "camelCase")]
Did { did: String },
}
impl TryFrom<Wire> for ProductIdentifier {
type Error = ProductIdentifierError;
fn try_from(wire: Wire) -> Result<Self, Self::Error> {
match wire {
Wire::Gs1 { gtin } => Ok(Self::gs1(gtin)),
Wire::IdentificationLink { url } => Self::identification_link(&url),
Wire::Did { did } => Self::did(&did),
}
}
}