1use core::fmt;
5use core::str::FromStr;
6
7use indexmap::IndexMap;
8use serde::de::Error as _;
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use serde_json::Value;
11
12use super::{Did, DidDocument, DidError};
13
14pub const APPLICATION_DID_JSON: &str = "application/did+json";
16pub const APPLICATION_DID_LD_JSON: &str = "application/did+ld+json";
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
24#[non_exhaustive]
25pub enum ResolutionError {
26 #[error("invalid DID")]
28 InvalidDid,
29 #[error("DID not found")]
31 NotFound,
32 #[error("DID method not supported")]
34 MethodNotSupported,
35 #[error("representation not supported")]
37 RepresentationNotSupported,
38 #[error("invalid DID document")]
41 InvalidDidDocument,
42 #[error("internal resolver error")]
44 InternalError,
45 #[error("resolution error `{0}`")]
47 Other(String),
48}
49
50impl ResolutionError {
51 pub fn as_str(&self) -> &str {
53 match self {
54 Self::InvalidDid => "invalidDid",
55 Self::NotFound => "notFound",
56 Self::MethodNotSupported => "methodNotSupported",
57 Self::RepresentationNotSupported => "representationNotSupported",
58 Self::InvalidDidDocument => "invalidDidDocument",
59 Self::InternalError => "internalError",
60 Self::Other(keyword) => keyword,
61 }
62 }
63}
64
65impl FromStr for ResolutionError {
66 type Err = core::convert::Infallible;
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
70 Ok(match s {
71 "invalidDid" => Self::InvalidDid,
72 "notFound" => Self::NotFound,
73 "methodNotSupported" => Self::MethodNotSupported,
74 "representationNotSupported" => Self::RepresentationNotSupported,
75 "invalidDidDocument" => Self::InvalidDidDocument,
76 "internalError" => Self::InternalError,
77 other => Self::Other(other.to_owned()),
78 })
79 }
80}
81
82impl From<DidError> for ResolutionError {
83 fn from(_: DidError) -> Self {
84 Self::InvalidDid
85 }
86}
87
88impl Serialize for ResolutionError {
89 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
90 serializer.serialize_str(self.as_str())
91 }
92}
93
94impl<'de> Deserialize<'de> for ResolutionError {
95 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
96 let keyword = String::deserialize(deserializer)?;
97 if keyword.is_empty() || !keyword.is_ascii() {
98 return Err(D::Error::custom("error must be an ASCII keyword"));
99 }
100 keyword.parse().map_err(|never| match never {})
101 }
102}
103
104#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
106#[non_exhaustive]
107pub struct ResolutionOptions {
108 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub accept: Option<String>,
111 #[serde(flatten)]
113 pub properties: IndexMap<String, Value>,
114}
115
116impl ResolutionOptions {
117 pub fn accept(media_type: impl Into<String>) -> Self {
119 Self {
120 accept: Some(media_type.into()),
121 properties: IndexMap::new(),
122 }
123 }
124}
125
126#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
128#[non_exhaustive]
129pub struct ResolutionMetadata {
130 #[serde(
132 rename = "contentType",
133 default,
134 skip_serializing_if = "Option::is_none"
135 )]
136 pub content_type: Option<String>,
137 #[serde(default, skip_serializing_if = "Option::is_none")]
139 pub error: Option<ResolutionError>,
140 #[serde(flatten)]
142 pub properties: IndexMap<String, Value>,
143}
144
145impl ResolutionMetadata {
146 pub fn error(error: ResolutionError) -> Self {
148 Self {
149 content_type: None,
150 error: Some(error),
151 properties: IndexMap::new(),
152 }
153 }
154
155 pub fn content_type(media_type: impl Into<String>) -> Self {
157 Self {
158 content_type: Some(media_type.into()),
159 error: None,
160 properties: IndexMap::new(),
161 }
162 }
163}
164
165#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
170#[non_exhaustive]
171pub struct DocumentMetadata {
172 #[serde(default, skip_serializing_if = "Option::is_none")]
174 pub created: Option<String>,
175 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub updated: Option<String>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
180 pub deactivated: Option<bool>,
181 #[serde(
183 rename = "nextUpdate",
184 default,
185 skip_serializing_if = "Option::is_none"
186 )]
187 pub next_update: Option<String>,
188 #[serde(rename = "versionId", default, skip_serializing_if = "Option::is_none")]
190 pub version_id: Option<String>,
191 #[serde(
193 rename = "nextVersionId",
194 default,
195 skip_serializing_if = "Option::is_none"
196 )]
197 pub next_version_id: Option<String>,
198 #[serde(
200 rename = "equivalentId",
201 default,
202 skip_serializing_if = "Vec::is_empty"
203 )]
204 pub equivalent_id: Vec<Did>,
205 #[serde(
207 rename = "canonicalId",
208 default,
209 skip_serializing_if = "Option::is_none"
210 )]
211 pub canonical_id: Option<Did>,
212 #[serde(flatten)]
214 pub properties: IndexMap<String, Value>,
215}
216
217impl DocumentMetadata {
218 pub fn is_deactivated(&self) -> bool {
220 self.deactivated == Some(true)
221 }
222}
223
224#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
241#[non_exhaustive]
242pub struct ResolutionResult {
243 #[serde(
245 rename = "didDocument",
246 default,
247 skip_serializing_if = "Option::is_none"
248 )]
249 pub document: Option<DidDocument>,
250 #[serde(rename = "didResolutionMetadata", default)]
252 pub resolution_metadata: ResolutionMetadata,
253 #[serde(rename = "didDocumentMetadata", default)]
255 pub document_metadata: DocumentMetadata,
256}
257
258impl ResolutionResult {
259 pub fn new(document: DidDocument) -> Self {
261 Self {
262 document: Some(document),
263 resolution_metadata: ResolutionMetadata::default(),
264 document_metadata: DocumentMetadata::default(),
265 }
266 }
267
268 pub fn error(error: ResolutionError) -> Self {
270 Self {
271 document: None,
272 resolution_metadata: ResolutionMetadata::error(error),
273 document_metadata: DocumentMetadata::default(),
274 }
275 }
276
277 #[must_use]
279 pub fn with_document_metadata(mut self, metadata: DocumentMetadata) -> Self {
280 self.document_metadata = metadata;
281 self
282 }
283
284 #[must_use]
286 pub fn with_resolution_metadata(mut self, metadata: ResolutionMetadata) -> Self {
287 self.resolution_metadata = metadata;
288 self
289 }
290
291 pub fn error_kind(&self) -> Option<&ResolutionError> {
293 self.resolution_metadata.error.as_ref()
294 }
295
296 pub fn into_document(self) -> Result<DidDocument, ResolutionError> {
303 match (self.document, self.resolution_metadata.error) {
304 (_, Some(error)) => Err(error),
305 (Some(document), None) => Ok(document),
306 (None, None) => Err(ResolutionError::NotFound),
307 }
308 }
309}
310
311impl fmt::Display for ResolutionResult {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315 match serde_json::to_string(self) {
316 Ok(json) => f.write_str(&json),
317 Err(e) => write!(f, "<unserializable resolution result: {e}>"),
318 }
319 }
320}