1use super::{
2 AttributesIntoIteratorV03, AttributesIntoIteratorV10, AttributesV03, AttributesV10,
3 ExtensionValue, SpecVersion, UriReference,
4};
5use base64::prelude::*;
6use chrono::{DateTime, Utc};
7use serde::Serializer;
8use std::fmt;
9use url::Url;
10
11#[derive(Debug, PartialEq, Eq)]
14pub enum AttributeValue<'a> {
15 Boolean(&'a bool),
16 Integer(&'a i64),
17 String(&'a str),
18 Binary(&'a [u8]),
19 URI(&'a Url),
20 URIRef(&'a UriReference),
21 Time(&'a DateTime<Utc>),
22 SpecVersion(SpecVersion),
23}
24
25impl<'a> From<&'a ExtensionValue> for AttributeValue<'a> {
26 fn from(ev: &'a ExtensionValue) -> Self {
27 match ev {
28 ExtensionValue::String(s) => AttributeValue::String(s),
29 ExtensionValue::Boolean(b) => AttributeValue::Boolean(b),
30 ExtensionValue::Integer(i) => AttributeValue::Integer(i),
31 }
32 }
33}
34
35impl fmt::Display for AttributeValue<'_> {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 AttributeValue::Boolean(b) => f.serialize_bool(**b),
39 AttributeValue::Integer(i) => f.serialize_i64(**i),
40 AttributeValue::String(s) => f.write_str(s),
41 AttributeValue::Binary(b) => f.write_str(&BASE64_STANDARD.encode(b)),
42 AttributeValue::URI(s) => f.write_str(s.as_str()),
43 AttributeValue::URIRef(s) => f.write_str(s.as_str()),
44 AttributeValue::Time(s) => f.write_str(&s.to_rfc3339()),
45 AttributeValue::SpecVersion(s) => s.fmt(f),
46 }
47 }
48}
49
50pub trait AttributesReader {
52 fn id(&self) -> &str;
54 fn source(&self) -> &UriReference;
56 fn specversion(&self) -> SpecVersion;
58 fn ty(&self) -> &str;
60 fn datacontenttype(&self) -> Option<&str>;
62 fn dataschema(&self) -> Option<&Url>;
64 fn subject(&self) -> Option<&str>;
66 fn time(&self) -> Option<&DateTime<Utc>>;
68}
69
70pub trait AttributesWriter {
72 fn set_id(&mut self, id: impl Into<String>) -> String;
75 fn set_source(&mut self, source: impl Into<UriReference>) -> UriReference;
78 fn set_type(&mut self, ty: impl Into<String>) -> String;
81 fn set_subject(&mut self, subject: Option<impl Into<String>>) -> Option<String>;
84 fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>) -> Option<DateTime<Utc>>;
87 fn set_datacontenttype(&mut self, datacontenttype: Option<impl Into<String>>)
90 -> Option<String>;
91 fn set_dataschema(&mut self, dataschema: Option<impl Into<Url>>) -> Option<Url>;
94}
95
96pub(crate) trait AttributesConverter {
97 fn into_v03(self) -> AttributesV03;
98 fn into_v10(self) -> AttributesV10;
99}
100
101#[derive(PartialEq, Debug, Clone, Copy)]
102pub(crate) enum AttributesIter<'a> {
103 IterV03(AttributesIntoIteratorV03<'a>),
104 IterV10(AttributesIntoIteratorV10<'a>),
105}
106
107impl<'a> Iterator for AttributesIter<'a> {
108 type Item = (&'a str, AttributeValue<'a>);
109 fn next(&mut self) -> Option<Self::Item> {
110 match self {
111 AttributesIter::IterV03(a) => a.next(),
112 AttributesIter::IterV10(a) => a.next(),
113 }
114 }
115}
116
117#[derive(PartialEq, Eq, Debug, Clone)]
119pub enum Attributes {
120 V03(AttributesV03),
121 V10(AttributesV10),
122}
123
124impl AttributesReader for Attributes {
125 fn id(&self) -> &str {
126 match self {
127 Attributes::V03(a) => a.id(),
128 Attributes::V10(a) => a.id(),
129 }
130 }
131
132 fn source(&self) -> &UriReference {
133 match self {
134 Attributes::V03(a) => a.source(),
135 Attributes::V10(a) => a.source(),
136 }
137 }
138
139 fn specversion(&self) -> SpecVersion {
140 match self {
141 Attributes::V03(a) => a.specversion(),
142 Attributes::V10(a) => a.specversion(),
143 }
144 }
145
146 fn ty(&self) -> &str {
147 match self {
148 Attributes::V03(a) => a.ty(),
149 Attributes::V10(a) => a.ty(),
150 }
151 }
152
153 fn datacontenttype(&self) -> Option<&str> {
154 match self {
155 Attributes::V03(a) => a.datacontenttype(),
156 Attributes::V10(a) => a.datacontenttype(),
157 }
158 }
159
160 fn dataschema(&self) -> Option<&Url> {
161 match self {
162 Attributes::V03(a) => a.dataschema(),
163 Attributes::V10(a) => a.dataschema(),
164 }
165 }
166
167 fn subject(&self) -> Option<&str> {
168 match self {
169 Attributes::V03(a) => a.subject(),
170 Attributes::V10(a) => a.subject(),
171 }
172 }
173
174 fn time(&self) -> Option<&DateTime<Utc>> {
175 match self {
176 Attributes::V03(a) => a.time(),
177 Attributes::V10(a) => a.time(),
178 }
179 }
180}
181
182impl AttributesWriter for Attributes {
183 fn set_id(&mut self, id: impl Into<String>) -> String {
184 match self {
185 Attributes::V03(a) => a.set_id(id),
186 Attributes::V10(a) => a.set_id(id),
187 }
188 }
189
190 fn set_source(&mut self, source: impl Into<UriReference>) -> UriReference {
191 match self {
192 Attributes::V03(a) => a.set_source(source),
193 Attributes::V10(a) => a.set_source(source),
194 }
195 }
196
197 fn set_type(&mut self, ty: impl Into<String>) -> String {
198 match self {
199 Attributes::V03(a) => a.set_type(ty),
200 Attributes::V10(a) => a.set_type(ty),
201 }
202 }
203
204 fn set_subject(&mut self, subject: Option<impl Into<String>>) -> Option<String> {
205 match self {
206 Attributes::V03(a) => a.set_subject(subject),
207 Attributes::V10(a) => a.set_subject(subject),
208 }
209 }
210
211 fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>) -> Option<DateTime<Utc>> {
212 match self {
213 Attributes::V03(a) => a.set_time(time),
214 Attributes::V10(a) => a.set_time(time),
215 }
216 }
217
218 fn set_datacontenttype(
219 &mut self,
220 datacontenttype: Option<impl Into<String>>,
221 ) -> Option<String> {
222 match self {
223 Attributes::V03(a) => a.set_datacontenttype(datacontenttype),
224 Attributes::V10(a) => a.set_datacontenttype(datacontenttype),
225 }
226 }
227
228 fn set_dataschema(&mut self, dataschema: Option<impl Into<Url>>) -> Option<Url> {
229 match self {
230 Attributes::V03(a) => a.set_dataschema(dataschema),
231 Attributes::V10(a) => a.set_dataschema(dataschema),
232 }
233 }
234}
235
236impl Attributes {
237 pub(crate) fn into_v10(self) -> Self {
238 match self {
239 Attributes::V03(v03) => Attributes::V10(v03.into_v10()),
240 _ => self,
241 }
242 }
243 pub(crate) fn into_v03(self) -> Self {
244 match self {
245 Attributes::V10(v10) => Attributes::V03(v10.into_v03()),
246 _ => self,
247 }
248 }
249
250 pub(crate) fn iter(&self) -> impl Iterator<Item = (&str, AttributeValue)> {
251 match self {
252 Attributes::V03(a) => AttributesIter::IterV03(a.into_iter()),
253 Attributes::V10(a) => AttributesIter::IterV10(a.into_iter()),
254 }
255 }
256}
257
258#[cfg(not(target_arch = "wasm32"))]
259pub(crate) fn default_hostname() -> Url {
260 Url::parse(
261 format!(
262 "http://{}",
263 hostname::get()
264 .ok()
265 .and_then(|s| s.into_string().ok())
266 .unwrap_or_else(|| "localhost".to_string())
267 )
268 .as_ref(),
269 )
270 .unwrap()
271}
272
273#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
274pub(crate) fn default_hostname() -> Url {
275 use std::str::FromStr;
276
277 Url::from_str(
278 web_sys::window()
279 .map(|w| w.location().host().ok())
280 .flatten()
281 .unwrap_or(String::from("http://localhost"))
282 .as_str(),
283 )
284 .unwrap()
285}
286
287#[cfg(all(target_arch = "wasm32", target_os = "wasi"))]
288pub(crate) fn default_hostname() -> Url {
289 use std::str::FromStr;
290
291 Url::from_str("http://localhost").unwrap()
292}