ssi_dids_core/document/
representation.rs1use core::fmt;
17use std::{ops::Deref, str::FromStr};
18
19use serde::{Deserialize, Serialize};
20pub mod json;
21pub mod json_ld;
22
23pub use self::json_ld::JsonLd;
24pub use json::Json;
25
26use crate::Document;
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(untagged)]
31pub enum Represented<D = Document> {
32 Json(Json<D>),
33 JsonLd(JsonLd<D>),
34}
35
36impl<D> Represented<D> {
37 pub fn new(document: D, options: Options) -> Self {
38 match options {
39 Options::Json => Self::Json(Json::new(document)),
40 Options::JsonLd(o) => Self::JsonLd(JsonLd::new(document, o)),
41 }
42 }
43
44 pub fn media_type(&self) -> MediaType {
45 match self {
46 Self::Json(_) => MediaType::Json,
47 Self::JsonLd(_) => MediaType::JsonLd,
48 }
49 }
50
51 pub fn document(&self) -> &D {
52 match self {
53 Self::Json(d) => d.document(),
54 Self::JsonLd(d) => d.document(),
55 }
56 }
57
58 pub fn into_document(self) -> D {
59 match self {
60 Self::Json(d) => d.into_document(),
61 Self::JsonLd(d) => d.into_document(),
62 }
63 }
64}
65
66impl<D: Serialize> Represented<D> {
67 pub fn to_bytes(&self) -> Vec<u8> {
68 match self {
69 Self::Json(d) => d.to_bytes(),
70 Self::JsonLd(d) => d.to_bytes(),
71 }
72 }
73}
74
75impl<D> Deref for Represented<D> {
76 type Target = D;
77
78 fn deref(&self) -> &Self::Target {
79 self.document()
80 }
81}
82
83#[derive(Debug, thiserror::Error)]
84#[error("unknown DID document representation `{0}`")]
85pub struct Unknown(pub String);
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
89pub enum MediaType {
90 #[serde(rename = "application/did+json")]
92 Json,
93
94 #[serde(rename = "application/did+ld+json")]
96 JsonLd,
97}
98
99impl MediaType {
100 pub fn name(&self) -> &'static str {
102 match self {
103 Self::Json => "application/did+json",
104 Self::JsonLd => "application/did+ld+json",
105 }
106 }
107
108 pub fn into_name(self) -> &'static str {
109 self.name()
110 }
111
112 pub fn from_bytes(s: &[u8]) -> Result<Self, Unknown> {
113 match s {
114 b"application/did+json" => Ok(Self::Json),
115 b"application/did+ld+json" => Ok(Self::JsonLd),
116 unknown => Err(Unknown(String::from_utf8_lossy(unknown).into_owned())),
117 }
118 }
119}
120
121impl From<MediaType> for String {
122 fn from(value: MediaType) -> Self {
123 value.name().to_owned()
124 }
125}
126
127impl fmt::Display for MediaType {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 self.name().fmt(f)
130 }
131}
132
133impl FromStr for MediaType {
134 type Err = Unknown;
135
136 fn from_str(s: &str) -> Result<Self, Self::Err> {
137 match s {
138 "application/did+json" => Ok(Self::Json),
139 "application/did+ld+json" => Ok(Self::JsonLd),
140 unknown => Err(Unknown(unknown.to_string())),
141 }
142 }
143}
144
145#[derive(Debug, thiserror::Error)]
146pub enum InvalidMediaType {
147 #[error(transparent)]
148 Unknown(Unknown),
149
150 #[error("invalid DID document media type")]
151 NotAString,
152}
153
154impl<'a> TryFrom<&'a [u8]> for MediaType {
155 type Error = InvalidMediaType;
156
157 fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
158 match s {
159 b"application/did+json" => Ok(Self::Json),
160 b"application/did+ld+json" => Ok(Self::JsonLd),
161 unknown => match String::from_utf8(unknown.to_vec()) {
162 Ok(s) => Err(InvalidMediaType::Unknown(Unknown(s))),
163 Err(_) => Err(InvalidMediaType::NotAString),
164 },
165 }
166 }
167}
168
169pub enum Options {
171 Json,
172 JsonLd(json_ld::Options),
173}
174
175impl Options {
176 pub fn from_media_type(
177 type_: MediaType,
178 json_ld_options: impl FnOnce() -> json_ld::Options,
179 ) -> Self {
180 match type_ {
181 MediaType::Json => Self::Json,
182 MediaType::JsonLd => Self::JsonLd(json_ld_options()),
183 }
184 }
185}