mod attributes;
mod builder;
mod data;
mod extensions;
#[macro_use]
mod format;
mod message;
mod spec_version;
mod types;
pub use attributes::Attributes;
pub use attributes::{AttributeValue, AttributesReader, AttributesWriter};
pub use builder::Error as EventBuilderError;
pub use builder::EventBuilder;
pub use data::Data;
pub use extensions::ExtensionValue;
pub(crate) use message::EventBinarySerializer;
pub(crate) use message::EventStructuredSerializer;
pub use spec_version::SpecVersion;
pub use spec_version::UnknownSpecVersion;
pub use types::{TryIntoTime, TryIntoUrl, UriReference};
mod v03;
pub use v03::Attributes as AttributesV03;
pub(crate) use v03::AttributesIntoIterator as AttributesIntoIteratorV03;
pub use v03::EventBuilder as EventBuilderV03;
pub(crate) use v03::EventFormatDeserializer as EventFormatDeserializerV03;
pub(crate) use v03::EventFormatSerializer as EventFormatSerializerV03;
mod v10;
pub use v10::Attributes as AttributesV10;
pub(crate) use v10::AttributesIntoIterator as AttributesIntoIteratorV10;
pub use v10::EventBuilder as EventBuilderV10;
pub(crate) use v10::EventFormatDeserializer as EventFormatDeserializerV10;
pub(crate) use v10::EventFormatSerializer as EventFormatSerializerV10;
use chrono::{DateTime, Utc};
use delegate_attr::delegate;
use std::collections::HashMap;
use std::fmt;
use url::Url;
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Event {
pub(crate) attributes: Attributes,
pub(crate) data: Option<Data>,
pub(crate) extensions: HashMap<String, ExtensionValue>,
}
#[delegate(self.attributes)]
impl AttributesReader for Event {
fn id(&self) -> &str;
fn source(&self) -> &UriReference;
fn specversion(&self) -> SpecVersion;
fn ty(&self) -> &str;
fn datacontenttype(&self) -> Option<&str>;
fn dataschema(&self) -> Option<&Url>;
fn subject(&self) -> Option<&str>;
fn time(&self) -> Option<&DateTime<Utc>>;
}
#[delegate(self.attributes)]
impl AttributesWriter for Event {
fn set_id(&mut self, id: impl Into<String>) -> String;
fn set_source(&mut self, source: impl Into<UriReference>) -> UriReference;
fn set_type(&mut self, ty: impl Into<String>) -> String;
fn set_subject(&mut self, subject: Option<impl Into<String>>) -> Option<String>;
fn set_time(&mut self, time: Option<impl Into<DateTime<Utc>>>) -> Option<DateTime<Utc>>;
fn set_datacontenttype(&mut self, datacontenttype: Option<impl Into<String>>)
-> Option<String>;
fn set_dataschema(&mut self, dataschema: Option<impl Into<Url>>) -> Option<Url>;
}
impl Default for Event {
fn default() -> Self {
Event {
attributes: Attributes::V10(AttributesV10::default()),
data: None,
extensions: HashMap::default(),
}
}
}
impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "CloudEvent:")?;
self.iter()
.try_for_each(|(name, val)| writeln!(f, " {}: '{}'", name, val))?;
match self.data() {
Some(data) => write!(f, " {}", data)?,
None => write!(f, " No data")?,
}
writeln!(f)
}
}
impl Event {
pub fn iter(&self) -> impl Iterator<Item = (&str, AttributeValue)> {
self.iter_attributes()
.chain(self.extensions.iter().map(|(k, v)| (k.as_str(), v.into())))
}
pub fn iter_attributes(&self) -> impl Iterator<Item = (&str, AttributeValue)> {
self.attributes.iter()
}
pub fn iter_extensions(&self) -> impl Iterator<Item = (&str, &ExtensionValue)> {
self.extensions.iter().map(|(k, v)| (k.as_str(), v))
}
pub fn data(&self) -> Option<&Data> {
self.data.as_ref()
}
pub fn take_data(&mut self) -> (Option<String>, Option<Url>, Option<Data>) {
(
self.attributes.set_datacontenttype(None as Option<String>),
self.attributes.set_dataschema(None as Option<Url>),
self.data.take(),
)
}
pub fn set_data(
&mut self,
datacontenttype: impl Into<String>,
data: impl Into<Data>,
) -> (Option<String>, Option<Data>) {
(
self.attributes.set_datacontenttype(Some(datacontenttype)),
std::mem::replace(&mut self.data, Some(data.into())),
)
}
pub fn set_data_unchecked(&mut self, data: impl Into<Data>) -> Option<Data> {
std::mem::replace(&mut self.data, Some(data.into()))
}
pub fn extension(&self, extension_name: &str) -> Option<&ExtensionValue> {
self.extensions.get(extension_name)
}
pub fn set_extension<'name, 'event: 'name>(
&'event mut self,
extension_name: &'name str,
extension_value: impl Into<ExtensionValue>,
) {
self.extensions
.insert(extension_name.to_owned(), extension_value.into());
}
pub fn remove_extension<'name, 'event: 'name>(
&'event mut self,
extension_name: &'name str,
) -> Option<ExtensionValue> {
self.extensions.remove(extension_name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn take_data() {
let mut e = Event::default();
e.set_data(
"application/json",
serde_json::json!({
"hello": "world"
}),
);
let (datacontenttype, dataschema, data) = e.take_data();
assert!(datacontenttype.is_some());
assert!(dataschema.is_none());
assert!(data.is_some());
assert!(e.data().is_none());
assert!(e.dataschema().is_none());
assert!(e.datacontenttype().is_none());
}
#[test]
fn set_id() {
let mut e = Event::default();
e.set_id("001");
assert_eq!(e.set_id("002"), String::from("001"));
assert_eq!(e.id(), "002")
}
#[test]
fn iter() {
let mut e = Event::default();
e.set_extension("aaa", "bbb");
e.set_data(
"application/json",
serde_json::json!({
"hello": "world"
}),
);
let mut v: HashMap<&str, AttributeValue> = e.iter().collect();
assert_eq!(
v.remove("specversion"),
Some(AttributeValue::SpecVersion(SpecVersion::V10))
);
assert_eq!(v.remove("aaa"), Some(AttributeValue::String("bbb")))
}
}