1use super::Attributes;
2use crate::event::data::is_json_content_type;
3use crate::event::format::{
4 parse_data_base64, parse_data_base64_json, parse_data_json, parse_data_string,
5};
6use crate::event::{Data, ExtensionValue};
7use base64::prelude::*;
8use chrono::{DateTime, Utc};
9use serde::de::IntoDeserializer;
10use serde::ser::SerializeMap;
11use serde::{Deserialize, Serializer};
12use serde_json::{Map, Value};
13use std::collections::HashMap;
14use url::Url;
15
16pub(crate) struct EventFormatDeserializer {}
17
18impl crate::event::format::EventFormatDeserializer for EventFormatDeserializer {
19 fn deserialize_attributes<E: serde::de::Error>(
20 map: &mut Map<String, Value>,
21 ) -> Result<crate::event::Attributes, E> {
22 Ok(crate::event::Attributes::V03(Attributes {
23 id: extract_field!(map, "id", String, E)?,
24 ty: extract_field!(map, "type", String, E)?,
25 source: extract_field!(map, "source", String, E)?,
26 datacontenttype: extract_optional_field!(map, "datacontenttype", String, E)?,
27 schemaurl: extract_optional_field!(map, "schemaurl", String, E, |s: String| {
28 Url::parse(&s)
29 })?,
30 subject: extract_optional_field!(map, "subject", String, E)?,
31 time: extract_optional_field!(map, "time", String, E, |s: String| {
32 DateTime::parse_from_rfc3339(&s).map(DateTime::<Utc>::from)
33 })?,
34 }))
35 }
36
37 fn deserialize_data<E: serde::de::Error>(
38 content_type: &str,
39 map: &mut Map<String, Value>,
40 ) -> Result<Option<Data>, E> {
41 let data = map.remove("data");
42 let is_base64 = map
43 .remove("datacontentencoding")
44 .map(String::deserialize)
45 .transpose()
46 .map_err(E::custom)?
47 .map(|dce| dce.to_lowercase() == "base64")
48 .unwrap_or(false);
49 let is_json = is_json_content_type(content_type);
50
51 Ok(match (data, is_base64, is_json) {
52 (Some(d), false, true) => Some(Data::Json(parse_data_json(d)?)),
53 (Some(d), false, false) => Some(Data::String(parse_data_string(d)?)),
54 (Some(d), true, true) => Some(Data::Json(parse_data_base64_json(d)?)),
55 (Some(d), true, false) => Some(Data::Binary(parse_data_base64(d)?)),
56 (None, _, _) => None,
57 })
58 }
59}
60
61pub(crate) struct EventFormatSerializer {}
62
63impl<S: serde::Serializer> crate::event::format::EventFormatSerializer<S, Attributes>
64 for EventFormatSerializer
65{
66 fn serialize(
67 attributes: &Attributes,
68 data: &Option<Data>,
69 extensions: &HashMap<String, ExtensionValue>,
70 serializer: S,
71 ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> {
72 let num = 4
73 + [
74 attributes.datacontenttype.is_some(),
75 attributes.schemaurl.is_some(),
76 attributes.subject.is_some(),
77 attributes.time.is_some(),
78 data.is_some(),
79 ]
80 .iter()
81 .filter(|&b| *b)
82 .count()
83 + extensions.len();
84
85 let mut state = serializer.serialize_map(Some(num))?;
86 state.serialize_entry("specversion", "0.3")?;
87 state.serialize_entry("id", &attributes.id)?;
88 state.serialize_entry("type", &attributes.ty)?;
89 state.serialize_entry("source", &attributes.source)?;
90 if let Some(datacontenttype) = &attributes.datacontenttype {
91 state.serialize_entry("datacontenttype", datacontenttype)?;
92 }
93 if let Some(schemaurl) = &attributes.schemaurl {
94 state.serialize_entry("schemaurl", schemaurl)?;
95 }
96 if let Some(subject) = &attributes.subject {
97 state.serialize_entry("subject", subject)?;
98 }
99 if let Some(time) = &attributes.time {
100 state.serialize_entry("time", time)?;
101 }
102 match data {
103 Some(Data::Json(j)) => state.serialize_entry("data", j)?,
104 Some(Data::String(s)) => state.serialize_entry("data", s)?,
105 Some(Data::Binary(v)) => {
106 state.serialize_entry("data", &BASE64_STANDARD.encode(v))?;
107 state.serialize_entry("datacontentencoding", "base64")?;
108 }
109 _ => (),
110 };
111 for (k, v) in extensions {
112 state.serialize_entry(k, v)?;
113 }
114 state.end()
115 }
116}