Proper BinarySerializer & StructuredSerializer implementations for Event (#61)
* WIP Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Progress Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Seems like everything works Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * fmt'ed more stuff Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
fc3790a7bd
commit
e87605734e
|
@ -181,7 +181,7 @@ mod tests {
|
||||||
//TODO this is required now because the message deserializer implictly set default values
|
//TODO this is required now because the message deserializer implictly set default values
|
||||||
// As soon as this defaulting doesn't happen anymore, we can remove it (Issues #40/#41)
|
// As soon as this defaulting doesn't happen anymore, we can remove it (Issues #40/#41)
|
||||||
.time(time)
|
.time(time)
|
||||||
.data("application/json", j.clone())
|
.data("application/json", j.to_string().into_bytes())
|
||||||
.extension("someint", "10")
|
.extension("someint", "10")
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -195,7 +195,7 @@ mod tests {
|
||||||
// As soon as this defaulting doesn't happen anymore, we can remove it (Issues #40/#41)
|
// As soon as this defaulting doesn't happen anymore, we can remove it (Issues #40/#41)
|
||||||
.time(time)
|
.time(time)
|
||||||
.source(Url::from_str("http://localhost").unwrap())
|
.source(Url::from_str("http://localhost").unwrap())
|
||||||
.data("application/json", j.clone())
|
.data("application/json", j.to_string().into_bytes())
|
||||||
.extension("someint", "10")
|
.extension("someint", "10")
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_json_content_type(ct: &str) -> bool {
|
pub(crate) fn is_json_content_type(ct: &str) -> bool {
|
||||||
ct == "application/json" || ct == "text/json" || ct.ends_with("+json")
|
ct.starts_with("application/json") || ct.starts_with("text/json") || ct.ends_with("+json")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Data> for serde_json::Value {
|
impl Into<Data> for serde_json::Value {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::message::{
|
||||||
BinaryDeserializer, BinarySerializer, MessageAttributeValue, Result, StructuredDeserializer,
|
BinaryDeserializer, BinarySerializer, MessageAttributeValue, Result, StructuredDeserializer,
|
||||||
StructuredSerializer,
|
StructuredSerializer,
|
||||||
};
|
};
|
||||||
|
use crate::{EventBuilder, EventBuilderV03, EventBuilderV10};
|
||||||
|
|
||||||
impl StructuredDeserializer for Event {
|
impl StructuredDeserializer for Event {
|
||||||
fn deserialize_structured<R, V: StructuredSerializer<R>>(self, visitor: V) -> Result<R> {
|
fn deserialize_structured<R, V: StructuredSerializer<R>>(self, visitor: V) -> Result<R> {
|
||||||
|
@ -37,10 +38,6 @@ pub(crate) trait AttributesDeserializer {
|
||||||
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, visitor: V) -> Result<V>;
|
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, visitor: V) -> Result<V>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait AttributesSerializer {
|
|
||||||
fn serialize_attribute(&mut self, name: &str, value: MessageAttributeValue) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttributesDeserializer for Attributes {
|
impl AttributesDeserializer for Attributes {
|
||||||
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, visitor: V) -> Result<V> {
|
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, visitor: V) -> Result<V> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -50,50 +47,125 @@ impl AttributesDeserializer for Attributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttributesSerializer for Attributes {
|
pub(crate) trait AttributesSerializer {
|
||||||
fn serialize_attribute(&mut self, name: &str, value: MessageAttributeValue) -> Result<()> {
|
fn serialize_attribute(&mut self, name: &str, value: MessageAttributeValue) -> Result<()>;
|
||||||
match self {
|
}
|
||||||
Attributes::V03(v03) => v03.serialize_attribute(name, value),
|
|
||||||
Attributes::V10(v10) => v10.serialize_attribute(name, value),
|
#[derive(Debug)]
|
||||||
}
|
pub(crate) struct EventStructuredSerializer {}
|
||||||
|
|
||||||
|
impl StructuredSerializer<Event> for EventStructuredSerializer {
|
||||||
|
fn set_structured_event(self, bytes: Vec<u8>) -> Result<Event> {
|
||||||
|
Ok(serde_json::from_slice(&bytes)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructuredSerializer<Event> for Event {
|
#[derive(Debug)]
|
||||||
fn set_structured_event(mut self, bytes: Vec<u8>) -> Result<Event> {
|
pub(crate) enum EventBinarySerializer {
|
||||||
let new_event: Event = serde_json::from_slice(&bytes)?;
|
V10(EventBuilderV10),
|
||||||
self.attributes = new_event.attributes;
|
V03(EventBuilderV03),
|
||||||
self.data = new_event.data;
|
}
|
||||||
self.extensions = new_event.extensions;
|
|
||||||
Ok(self)
|
impl EventBinarySerializer {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
EventBinarySerializer::V10(EventBuilderV10::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinarySerializer<Event> for Event {
|
impl BinarySerializer<Event> for EventBinarySerializer {
|
||||||
fn set_spec_version(mut self, spec_version: SpecVersion) -> Result<Self> {
|
fn set_spec_version(self, spec_version: SpecVersion) -> Result<Self> {
|
||||||
match spec_version {
|
Ok(match spec_version {
|
||||||
SpecVersion::V03 => self.attributes = self.attributes.clone().into_v03(),
|
SpecVersion::V03 => EventBinarySerializer::V03(EventBuilderV03::new()),
|
||||||
SpecVersion::V10 => self.attributes = self.attributes.clone().into_v10(),
|
SpecVersion::V10 => EventBinarySerializer::V10(EventBuilderV10::new()),
|
||||||
}
|
})
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_attribute(mut self, name: &str, value: MessageAttributeValue) -> Result<Self> {
|
fn set_attribute(mut self, name: &str, value: MessageAttributeValue) -> Result<Self> {
|
||||||
self.attributes.serialize_attribute(name, value)?;
|
match &mut self {
|
||||||
|
EventBinarySerializer::V03(eb) => eb.serialize_attribute(name, value)?,
|
||||||
|
EventBinarySerializer::V10(eb) => eb.serialize_attribute(name, value)?,
|
||||||
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_extension(mut self, name: &str, value: MessageAttributeValue) -> Result<Self> {
|
fn set_extension(self, name: &str, value: MessageAttributeValue) -> Result<Self> {
|
||||||
self.extensions.insert(name.to_string(), value.into());
|
Ok(match self {
|
||||||
Ok(self)
|
EventBinarySerializer::V03(eb) => EventBinarySerializer::V03(eb.extension(name, value)),
|
||||||
|
EventBinarySerializer::V10(eb) => EventBinarySerializer::V10(eb.extension(name, value)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_with_data(mut self, bytes: Vec<u8>) -> Result<Event> {
|
fn end_with_data(self, bytes: Vec<u8>) -> Result<Event> {
|
||||||
self.data = Some(Data::from_binary(self.get_datacontenttype(), bytes)?);
|
Ok(match self {
|
||||||
Ok(self)
|
EventBinarySerializer::V03(eb) => {
|
||||||
|
eb.data_without_content_type(Data::Binary(bytes)).build()
|
||||||
|
}
|
||||||
|
EventBinarySerializer::V10(eb) => {
|
||||||
|
eb.data_without_content_type(Data::Binary(bytes)).build()
|
||||||
|
}
|
||||||
|
}?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Event> {
|
fn end(self) -> Result<Event> {
|
||||||
Ok(self)
|
Ok(match self {
|
||||||
|
EventBinarySerializer::V03(eb) => eb.build(),
|
||||||
|
EventBinarySerializer::V10(eb) => eb.build(),
|
||||||
|
}?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::message::Error;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binary_deserializer_unrecognized_attribute_v03() {
|
||||||
|
assert_eq!(
|
||||||
|
Error::UnrecognizedAttributeName {
|
||||||
|
name: "dataschema".to_string()
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
EventBinarySerializer::new()
|
||||||
|
.set_spec_version(SpecVersion::V03)
|
||||||
|
.unwrap()
|
||||||
|
.set_attribute("dataschema", MessageAttributeValue::Boolean(true))
|
||||||
|
.expect_err("Should return an error")
|
||||||
|
.to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binary_deserializer_missing_id() {
|
||||||
|
assert_eq!(
|
||||||
|
Error::EventBuilderError {
|
||||||
|
source: crate::event::EventBuilderError::MissingRequiredAttribute {
|
||||||
|
attribute_name: "id"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
EventBinarySerializer::new()
|
||||||
|
.set_spec_version(SpecVersion::V10)
|
||||||
|
.unwrap()
|
||||||
|
.end()
|
||||||
|
.unwrap_err()
|
||||||
|
.to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binary_deserializer_unrecognized_attribute_v10() {
|
||||||
|
assert_eq!(
|
||||||
|
Error::UnrecognizedAttributeName {
|
||||||
|
name: "schemaurl".to_string()
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
EventBinarySerializer::new()
|
||||||
|
.set_spec_version(SpecVersion::V10)
|
||||||
|
.unwrap()
|
||||||
|
.set_attribute("schemaurl", MessageAttributeValue::Boolean(true))
|
||||||
|
.expect_err("Should return an error")
|
||||||
|
.to_string()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ pub use builder::EventBuilder;
|
||||||
pub use data::Data;
|
pub use data::Data;
|
||||||
pub use event::Event;
|
pub use event::Event;
|
||||||
pub use extensions::ExtensionValue;
|
pub use extensions::ExtensionValue;
|
||||||
|
pub(crate) use message::EventBinarySerializer;
|
||||||
|
pub(crate) use message::EventStructuredSerializer;
|
||||||
pub use spec_version::InvalidSpecVersion;
|
pub use spec_version::InvalidSpecVersion;
|
||||||
pub use spec_version::SpecVersion;
|
pub use spec_version::SpecVersion;
|
||||||
pub use types::{TryIntoTime, TryIntoUrl};
|
pub use types::{TryIntoTime, TryIntoUrl};
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::event::attributes::{
|
||||||
};
|
};
|
||||||
use crate::event::AttributesV10;
|
use crate::event::AttributesV10;
|
||||||
use crate::event::{AttributesReader, AttributesWriter, SpecVersion};
|
use crate::event::{AttributesReader, AttributesWriter, SpecVersion};
|
||||||
|
use crate::message::{BinarySerializer, MessageAttributeValue};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -184,6 +185,40 @@ impl AttributesConverter for Attributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::event::message::AttributesDeserializer for super::Attributes {
|
||||||
|
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(
|
||||||
|
self,
|
||||||
|
mut visitor: V,
|
||||||
|
) -> crate::message::Result<V> {
|
||||||
|
visitor = visitor.set_attribute("id", MessageAttributeValue::String(self.id))?;
|
||||||
|
visitor = visitor.set_attribute("type", MessageAttributeValue::String(self.ty))?;
|
||||||
|
visitor = visitor.set_attribute("source", MessageAttributeValue::UriRef(self.source))?;
|
||||||
|
if self.datacontenttype.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"datacontenttype",
|
||||||
|
MessageAttributeValue::String(self.datacontenttype.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.schemaurl.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"schemaurl",
|
||||||
|
MessageAttributeValue::Uri(self.schemaurl.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.subject.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"subject",
|
||||||
|
MessageAttributeValue::String(self.subject.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.time.is_some() {
|
||||||
|
visitor = visitor
|
||||||
|
.set_attribute("time", MessageAttributeValue::DateTime(self.time.unwrap()))?;
|
||||||
|
}
|
||||||
|
Ok(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -2,12 +2,14 @@ use super::Attributes as AttributesV03;
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl,
|
Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl,
|
||||||
};
|
};
|
||||||
|
use crate::message::MessageAttributeValue;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// Builder to create a CloudEvent V0.3
|
/// Builder to create a CloudEvent V0.3
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EventBuilder {
|
pub struct EventBuilder {
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
ty: Option<String>,
|
ty: Option<String>,
|
||||||
|
@ -73,6 +75,11 @@ impl EventBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn data_without_content_type(mut self, data: impl Into<Data>) -> Self {
|
||||||
|
self.data = Some(data.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data(mut self, datacontenttype: impl Into<String>, data: impl Into<Data>) -> Self {
|
pub fn data(mut self, datacontenttype: impl Into<String>, data: impl Into<Data>) -> Self {
|
||||||
self.datacontenttype = Some(datacontenttype.into());
|
self.datacontenttype = Some(datacontenttype.into());
|
||||||
self.data = Some(data.into());
|
self.data = Some(data.into());
|
||||||
|
@ -173,3 +180,27 @@ impl crate::event::builder::EventBuilder for EventBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::event::message::AttributesSerializer for EventBuilder {
|
||||||
|
fn serialize_attribute(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
value: MessageAttributeValue,
|
||||||
|
) -> crate::message::Result<()> {
|
||||||
|
match name {
|
||||||
|
"id" => self.id = Some(value.to_string()),
|
||||||
|
"type" => self.ty = Some(value.to_string()),
|
||||||
|
"source" => self.source = Some(value.try_into()?),
|
||||||
|
"datacontenttype" => self.datacontenttype = Some(value.to_string()),
|
||||||
|
"schemaurl" => self.schemaurl = Some(value.try_into()?),
|
||||||
|
"subject" => self.subject = Some(value.to_string()),
|
||||||
|
"time" => self.time = Some(value.try_into()?),
|
||||||
|
_ => {
|
||||||
|
return Err(crate::message::Error::UnrecognizedAttributeName {
|
||||||
|
name: name.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
use crate::message::{BinarySerializer, Error, MessageAttributeValue, Result};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
impl crate::event::message::AttributesDeserializer for super::Attributes {
|
|
||||||
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, mut visitor: V) -> Result<V> {
|
|
||||||
visitor = visitor.set_attribute("id", MessageAttributeValue::String(self.id))?;
|
|
||||||
visitor = visitor.set_attribute("type", MessageAttributeValue::String(self.ty))?;
|
|
||||||
visitor = visitor.set_attribute("source", MessageAttributeValue::UriRef(self.source))?;
|
|
||||||
if self.datacontenttype.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"datacontenttype",
|
|
||||||
MessageAttributeValue::String(self.datacontenttype.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.schemaurl.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"schemaurl",
|
|
||||||
MessageAttributeValue::Uri(self.schemaurl.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.subject.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"subject",
|
|
||||||
MessageAttributeValue::String(self.subject.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.time.is_some() {
|
|
||||||
visitor = visitor
|
|
||||||
.set_attribute("time", MessageAttributeValue::DateTime(self.time.unwrap()))?;
|
|
||||||
}
|
|
||||||
Ok(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::event::message::AttributesSerializer for super::Attributes {
|
|
||||||
fn serialize_attribute(&mut self, name: &str, value: MessageAttributeValue) -> Result<()> {
|
|
||||||
match name {
|
|
||||||
"id" => self.id = value.to_string(),
|
|
||||||
"type" => self.ty = value.to_string(),
|
|
||||||
"source" => self.source = value.try_into()?,
|
|
||||||
"datacontenttype" => self.datacontenttype = Some(value.to_string()),
|
|
||||||
"schemaurl" => self.schemaurl = Some(value.try_into()?),
|
|
||||||
"subject" => self.subject = Some(value.to_string()),
|
|
||||||
"time" => self.time = Some(value.try_into()?),
|
|
||||||
_ => {
|
|
||||||
return Err(Error::UnrecognizedAttributeName {
|
|
||||||
name: name.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
mod attributes;
|
mod attributes;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod format;
|
mod format;
|
||||||
mod message;
|
|
||||||
|
|
||||||
pub use attributes::Attributes;
|
pub use attributes::Attributes;
|
||||||
pub(crate) use attributes::AttributesIntoIterator;
|
pub(crate) use attributes::AttributesIntoIterator;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::event::attributes::{
|
||||||
default_hostname, AttributeValue, AttributesConverter, DataAttributesWriter,
|
default_hostname, AttributeValue, AttributesConverter, DataAttributesWriter,
|
||||||
};
|
};
|
||||||
use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion};
|
use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion};
|
||||||
|
use crate::message::{BinarySerializer, MessageAttributeValue};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -166,6 +167,40 @@ impl Default for Attributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::event::message::AttributesDeserializer for super::Attributes {
|
||||||
|
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(
|
||||||
|
self,
|
||||||
|
mut visitor: V,
|
||||||
|
) -> crate::message::Result<V> {
|
||||||
|
visitor = visitor.set_attribute("id", MessageAttributeValue::String(self.id))?;
|
||||||
|
visitor = visitor.set_attribute("type", MessageAttributeValue::String(self.ty))?;
|
||||||
|
visitor = visitor.set_attribute("source", MessageAttributeValue::UriRef(self.source))?;
|
||||||
|
if self.datacontenttype.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"datacontenttype",
|
||||||
|
MessageAttributeValue::String(self.datacontenttype.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.dataschema.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"dataschema",
|
||||||
|
MessageAttributeValue::Uri(self.dataschema.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.subject.is_some() {
|
||||||
|
visitor = visitor.set_attribute(
|
||||||
|
"subject",
|
||||||
|
MessageAttributeValue::String(self.subject.unwrap()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if self.time.is_some() {
|
||||||
|
visitor = visitor
|
||||||
|
.set_attribute("time", MessageAttributeValue::DateTime(self.time.unwrap()))?;
|
||||||
|
}
|
||||||
|
Ok(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AttributesConverter for Attributes {
|
impl AttributesConverter for Attributes {
|
||||||
fn into_v10(self) -> Self {
|
fn into_v10(self) -> Self {
|
||||||
self
|
self
|
||||||
|
|
|
@ -2,12 +2,14 @@ use super::Attributes as AttributesV10;
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl,
|
Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl,
|
||||||
};
|
};
|
||||||
|
use crate::message::MessageAttributeValue;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// Builder to create a CloudEvent V1.0
|
/// Builder to create a CloudEvent V1.0
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EventBuilder {
|
pub struct EventBuilder {
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
ty: Option<String>,
|
ty: Option<String>,
|
||||||
|
@ -73,6 +75,11 @@ impl EventBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn data_without_content_type(mut self, data: impl Into<Data>) -> Self {
|
||||||
|
self.data = Some(data.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data(mut self, datacontenttype: impl Into<String>, data: impl Into<Data>) -> Self {
|
pub fn data(mut self, datacontenttype: impl Into<String>, data: impl Into<Data>) -> Self {
|
||||||
self.datacontenttype = Some(datacontenttype.into());
|
self.datacontenttype = Some(datacontenttype.into());
|
||||||
self.data = Some(data.into());
|
self.data = Some(data.into());
|
||||||
|
@ -173,3 +180,27 @@ impl crate::event::builder::EventBuilder for EventBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::event::message::AttributesSerializer for EventBuilder {
|
||||||
|
fn serialize_attribute(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
value: MessageAttributeValue,
|
||||||
|
) -> crate::message::Result<()> {
|
||||||
|
match name {
|
||||||
|
"id" => self.id = Some(value.to_string()),
|
||||||
|
"type" => self.ty = Some(value.to_string()),
|
||||||
|
"source" => self.source = Some(value.try_into()?),
|
||||||
|
"datacontenttype" => self.datacontenttype = Some(value.to_string()),
|
||||||
|
"dataschema" => self.dataschema = Some(value.try_into()?),
|
||||||
|
"subject" => self.subject = Some(value.to_string()),
|
||||||
|
"time" => self.time = Some(value.try_into()?),
|
||||||
|
_ => {
|
||||||
|
return Err(crate::message::Error::UnrecognizedAttributeName {
|
||||||
|
name: name.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
use crate::message::{BinarySerializer, Error, MessageAttributeValue, Result};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
impl crate::event::message::AttributesDeserializer for super::Attributes {
|
|
||||||
fn deserialize_attributes<R: Sized, V: BinarySerializer<R>>(self, mut visitor: V) -> Result<V> {
|
|
||||||
visitor = visitor.set_attribute("id", MessageAttributeValue::String(self.id))?;
|
|
||||||
visitor = visitor.set_attribute("type", MessageAttributeValue::String(self.ty))?;
|
|
||||||
visitor = visitor.set_attribute("source", MessageAttributeValue::UriRef(self.source))?;
|
|
||||||
if self.datacontenttype.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"datacontenttype",
|
|
||||||
MessageAttributeValue::String(self.datacontenttype.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.dataschema.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"dataschema",
|
|
||||||
MessageAttributeValue::Uri(self.dataschema.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.subject.is_some() {
|
|
||||||
visitor = visitor.set_attribute(
|
|
||||||
"subject",
|
|
||||||
MessageAttributeValue::String(self.subject.unwrap()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
if self.time.is_some() {
|
|
||||||
visitor = visitor
|
|
||||||
.set_attribute("time", MessageAttributeValue::DateTime(self.time.unwrap()))?;
|
|
||||||
}
|
|
||||||
Ok(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::event::message::AttributesSerializer for super::Attributes {
|
|
||||||
fn serialize_attribute(&mut self, name: &str, value: MessageAttributeValue) -> Result<()> {
|
|
||||||
match name {
|
|
||||||
"id" => self.id = value.to_string(),
|
|
||||||
"type" => self.ty = value.to_string(),
|
|
||||||
"source" => self.source = value.try_into()?,
|
|
||||||
"datacontenttype" => self.datacontenttype = Some(value.to_string()),
|
|
||||||
"dataschema" => self.dataschema = Some(value.try_into()?),
|
|
||||||
"subject" => self.subject = Some(value.to_string()),
|
|
||||||
"time" => self.time = Some(value.try_into()?),
|
|
||||||
_ => {
|
|
||||||
return Err(Error::UnrecognizedAttributeName {
|
|
||||||
name: name.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
mod attributes;
|
mod attributes;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod format;
|
mod format;
|
||||||
mod message;
|
|
||||||
|
|
||||||
pub use attributes::Attributes;
|
pub use attributes::Attributes;
|
||||||
pub(crate) use attributes::AttributesIntoIterator;
|
pub(crate) use attributes::AttributesIntoIterator;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{BinarySerializer, Encoding, Result, StructuredSerializer};
|
use super::{BinarySerializer, Encoding, Error, Result, StructuredSerializer};
|
||||||
|
use crate::event::{EventBinarySerializer, EventStructuredSerializer};
|
||||||
use crate::Event;
|
use crate::Event;
|
||||||
|
|
||||||
/// Deserializer trait for a Message that can be encoded as structured mode
|
/// Deserializer trait for a Message that can be encoded as structured mode
|
||||||
|
@ -14,7 +15,7 @@ where
|
||||||
|
|
||||||
/// Convert this Message to [`Event`]
|
/// Convert this Message to [`Event`]
|
||||||
fn into_event(self) -> Result<Event> {
|
fn into_event(self) -> Result<Event> {
|
||||||
self.deserialize_structured(Event::default())
|
self.deserialize_structured(EventStructuredSerializer {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ where
|
||||||
|
|
||||||
/// Convert this Message to [`Event`]
|
/// Convert this Message to [`Event`]
|
||||||
fn into_event(self) -> Result<Event> {
|
fn into_event(self) -> Result<Event> {
|
||||||
self.deserialize_binary(Event::default())
|
self.deserialize_binary(EventBinarySerializer::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,11 @@ where
|
||||||
|
|
||||||
/// Convert this Message to [`Event`]
|
/// Convert this Message to [`Event`]
|
||||||
fn into_event(self) -> Result<Event> {
|
fn into_event(self) -> Result<Event> {
|
||||||
self.deserialize_to(Event::default())
|
match self.encoding() {
|
||||||
|
Encoding::BINARY => BinaryDeserializer::into_event(self),
|
||||||
|
Encoding::STRUCTURED => StructuredDeserializer::into_event(self),
|
||||||
|
_ => Err(Error::WrongEncoding {}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize the message to [`BinarySerializer`]
|
/// Deserialize the message to [`BinarySerializer`]
|
||||||
|
|
|
@ -12,6 +12,11 @@ pub enum Error {
|
||||||
},
|
},
|
||||||
#[snafu(display("Unrecognized attribute name: {}", name))]
|
#[snafu(display("Unrecognized attribute name: {}", name))]
|
||||||
UnrecognizedAttributeName { name: String },
|
UnrecognizedAttributeName { name: String },
|
||||||
|
#[snafu(display("Error while building the final event: {}", source))]
|
||||||
|
#[snafu(context(false))]
|
||||||
|
EventBuilderError {
|
||||||
|
source: crate::event::EventBuilderError,
|
||||||
|
},
|
||||||
#[snafu(display("Error while parsing a time string: {}", source))]
|
#[snafu(display("Error while parsing a time string: {}", source))]
|
||||||
#[snafu(context(false))]
|
#[snafu(context(false))]
|
||||||
ParseTimeError { source: chrono::ParseError },
|
ParseTimeError { source: chrono::ParseError },
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
mod test_data;
|
mod test_data;
|
||||||
use cloudevents::message::{
|
use cloudevents::message::{BinaryDeserializer, Result, StructuredDeserializer};
|
||||||
BinaryDeserializer, BinarySerializer, Error, MessageAttributeValue, Result,
|
|
||||||
StructuredDeserializer,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use cloudevents::{AttributesReader, EventBuilder, EventBuilderV03, EventBuilderV10};
|
||||||
use test_data::*;
|
use test_data::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -17,8 +15,18 @@ fn message_v03_roundtrip_structured() -> Result<()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn message_v03_roundtrip_binary() -> Result<()> {
|
fn message_v03_roundtrip_binary() -> Result<()> {
|
||||||
|
//TODO this code smells because we're missing a proper way in the public APIs
|
||||||
|
// to destructure an event and rebuild it
|
||||||
|
let wanna_be_expected = v03::full_json_data();
|
||||||
|
let data: serde_json::Value = wanna_be_expected.try_get_data()?.unwrap();
|
||||||
|
let bytes = serde_json::to_vec(&data)?;
|
||||||
|
let expected = EventBuilderV03::from(wanna_be_expected.clone())
|
||||||
|
.data(wanna_be_expected.get_datacontenttype().unwrap(), bytes)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
v03::full_json_data(),
|
expected,
|
||||||
BinaryDeserializer::into_event(v03::full_json_data())?
|
BinaryDeserializer::into_event(v03::full_json_data())?
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -35,37 +43,19 @@ fn message_v10_roundtrip_structured() -> Result<()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn message_v10_roundtrip_binary() -> Result<()> {
|
fn message_v10_roundtrip_binary() -> Result<()> {
|
||||||
|
//TODO this code smells because we're missing a proper way in the public APIs
|
||||||
|
// to destructure an event and rebuild it
|
||||||
|
let wanna_be_expected = v10::full_json_data();
|
||||||
|
let data: serde_json::Value = wanna_be_expected.try_get_data()?.unwrap();
|
||||||
|
let bytes = serde_json::to_vec(&data)?;
|
||||||
|
let expected = EventBuilderV10::from(wanna_be_expected.clone())
|
||||||
|
.data(wanna_be_expected.get_datacontenttype().unwrap(), bytes)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
v10::full_json_data(),
|
expected,
|
||||||
BinaryDeserializer::into_event(v10::full_json_data())?
|
BinaryDeserializer::into_event(v10::full_json_data())?
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn message_v03_invalid_attribute_name() {
|
|
||||||
assert_eq!(
|
|
||||||
Error::UnrecognizedAttributeName {
|
|
||||||
name: "dataschema".to_string()
|
|
||||||
}
|
|
||||||
.to_string(),
|
|
||||||
v03::full_json_data()
|
|
||||||
.set_attribute("dataschema", MessageAttributeValue::Boolean(true))
|
|
||||||
.unwrap_err()
|
|
||||||
.to_string()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn message_v10_invalid_attribute_name() {
|
|
||||||
assert_eq!(
|
|
||||||
Error::UnrecognizedAttributeName {
|
|
||||||
name: "schemaurl".to_string()
|
|
||||||
}
|
|
||||||
.to_string(),
|
|
||||||
v10::full_json_data()
|
|
||||||
.set_attribute("schemaurl", MessageAttributeValue::Boolean(true))
|
|
||||||
.unwrap_err()
|
|
||||||
.to_string()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue