1use core::fmt;
2use std::{marker::PhantomData, str::FromStr};
3
4use serde::{Deserialize, Serialize};
5use ssi_dids_core::registration::DIDTransactionCreationError;
6
7use super::{InvalidSidetreeDIDSuffix, Sidetree};
8
9pub enum SidetreeDID<S: Sidetree> {
15 Short { did_suffix: DIDSuffix },
19
20 Long {
24 did_suffix: DIDSuffix,
25 create_operation_data: String,
26 _marker: PhantomData<S>,
27 },
28}
29
30#[derive(Debug, thiserror::Error)]
31pub enum InvalidSidetreeDID {
32 #[error("invalid URI scheme")]
33 InvalidURIScheme,
34
35 #[error("DID method mismatch")]
36 DIDMethodMismatch,
37
38 #[error("Sidetree network mismatch")]
39 SidetreeNetworkMismatch,
40
41 #[error("missing sidetree DID suffix")]
42 MissingSidetreeDIDSuffix,
43
44 #[error(transparent)]
45 InvalidSidetreeDIDSuffix(#[from] InvalidSidetreeDIDSuffix),
46
47 #[error("unexpected data after Sidetree Long-Form DID")]
48 UnexpectedData,
49}
50
51impl<S: Sidetree> FromStr for SidetreeDID<S> {
52 type Err = InvalidSidetreeDID;
53
54 fn from_str(did: &str) -> Result<Self, Self::Err> {
55 let mut parts = did.split(':');
56
57 if parts.next() != Some("did") {
58 return Err(InvalidSidetreeDID::InvalidURIScheme);
59 }
60
61 if parts.next() != Some(S::METHOD) {
62 return Err(InvalidSidetreeDID::DIDMethodMismatch);
63 }
64
65 if let Some(network) = S::NETWORK {
66 if parts.next() != Some(network) {
67 return Err(InvalidSidetreeDID::SidetreeNetworkMismatch);
68 }
69 }
70
71 let did_suffix_str = parts
72 .next()
73 .ok_or(InvalidSidetreeDID::MissingSidetreeDIDSuffix)?;
74 let did_suffix = DIDSuffix(did_suffix_str.to_string());
75 S::validate_did_suffix(&did_suffix)?;
76 let create_operation_data_opt = parts.next();
77 if parts.next().is_some() {
78 return Err(InvalidSidetreeDID::UnexpectedData);
79 }
80 Ok(match create_operation_data_opt {
81 None => Self::Short { did_suffix },
82 Some(data) => Self::Long {
83 did_suffix,
84 create_operation_data: data.to_string(),
85 _marker: PhantomData,
86 },
87 })
88 }
89}
90
91impl<S: Sidetree> fmt::Display for SidetreeDID<S> {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 write!(f, "did:{}:", S::METHOD)?;
94 if let Some(network) = S::NETWORK {
95 write!(f, "{}:", network)?;
96 }
97 match self {
98 Self::Short { did_suffix } => f.write_str(&did_suffix.0),
99 Self::Long {
100 did_suffix,
101 create_operation_data,
102 _marker,
103 } => write!(f, "{}:{}", did_suffix.0, create_operation_data),
104 }
105 }
106}
107
108impl From<InvalidSidetreeDID> for DIDTransactionCreationError {
109 fn from(_value: InvalidSidetreeDID) -> Self {
110 DIDTransactionCreationError::InvalidDID
111 }
112}
113
114#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
118pub struct DIDSuffix(pub String);
119
120impl fmt::Display for DIDSuffix {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 write!(f, "{}", self.0)?;
123 Ok(())
124 }
125}
126
127impl<S: Sidetree> From<SidetreeDID<S>> for DIDSuffix {
128 fn from(did: SidetreeDID<S>) -> DIDSuffix {
129 match did {
130 SidetreeDID::Short { did_suffix } => did_suffix,
131 SidetreeDID::Long { did_suffix, .. } => did_suffix,
132 }
133 }
134}