From 6702a363ac7af34c7fca186f3e2f64bcf9d3da39 Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Tue, 13 Oct 2020 16:38:49 +0530 Subject: [PATCH 01/10] no_std #1 Signed-off-by: adpranavb2000@gmail.com --- .history/src/lib_20201107132414.rs | 60 +++++++ .history/src/lib_20201107132439.rs | 57 +++++++ Cargo.toml | 1 + src/event/attributes.rs | 1 + src/event/data.rs | 1 + src/event/event.rs | 257 +++++++++++++++++++++++++++++ src/event/extensions.rs | 1 + src/event/format.rs | 1 + src/event/message.rs | 1 + src/event/spec_version.rs | 1 + src/event/types.rs | 1 + src/event/v03/attributes.rs | 1 + src/event/v03/builder.rs | 1 + src/event/v03/format.rs | 1 + src/event/v10/attributes.rs | 1 + src/event/v10/builder.rs | 1 + src/event/v10/format.rs | 1 + src/lib.rs | 8 + src/message/error.rs | 1 + src/message/serializer.rs | 1 + src/message/types.rs | 1 + 21 files changed, 399 insertions(+) create mode 100644 .history/src/lib_20201107132414.rs create mode 100644 .history/src/lib_20201107132439.rs create mode 100644 src/event/event.rs diff --git a/.history/src/lib_20201107132414.rs b/.history/src/lib_20201107132414.rs new file mode 100644 index 00000000..e5314baf --- /dev/null +++ b/.history/src/lib_20201107132414.rs @@ -0,0 +1,60 @@ +//! This crate implements the [CloudEvents](https://cloudevents.io/) Spec for Rust. +//! +//! ``` +//! # use std::error::Error; +//! # fn main() -> Result<(), Box> { +//! use cloudevents::{EventBuilder, AttributesReader, EventBuilderV10}; +//! use chrono::{Utc, DateTime}; +//! use url::Url; +//! +//! let event = EventBuilderV10::new() +//! .id("my_event.my_application") +//! .source("http://localhost:8080") +//! .ty("example.demo") +//! .time(Utc::now()) +//! .build()?; +//! +//! println!("CloudEvent Id: {}", event.id()); +//! match event.time() { +//! Some(t) => println!("CloudEvent Time: {}", t), +//! None => println!("CloudEvent Time: None") +//! } +//! # Ok(()) +//! # } +//! ``` +//! +//! This crate includes: +//! +//! * The [`Event`] data structure, to represent CloudEvent (version 1.0 and 0.3) +//! * The [`EventBuilder`] trait and implementations, to create [`Event`] instances +//! * The implementation of [`serde::Serialize`] and [`serde::Deserialize`] for [`Event`] to serialize/deserialize CloudEvents to/from JSON +//! * Traits and utilities in [`message`] to implement Protocol Bindings +//! +//! If you're looking for Protocol Binding implementations, look at crates: +//! +//! * [cloudevents-sdk-actix-web](https://docs.rs/cloudevents-sdk-actix-web): Integration with [Actix Web](https://github.com/actix/actix-web) +//! * [cloudevents-sdk-reqwest](https://docs.rs/cloudevents-sdk-reqwest): Integration with [reqwest](https://github.com/seanmonstar/reqwest) +//! * [cloudevents-sdk-rdkafka](https://docs.rs/cloudevents-sdk-rdkafka): Integration with [rdkafka](https://fede1024.github.io/rust-rdkafka) +//! + +<<<<<<< master +#![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.3.0")] +#![deny(broken_intra_doc_links)] +======= +#![no_std] + +extern crate no_std_compat as std; + +extern crate serde; +extern crate serde_json; +extern crate serde_value; +extern crate snafu; +>>>>>>> no_std #1 + +pub mod event; +pub mod message; + +pub use event::Data; +pub use event::Event; +pub use event::{AttributesReader, AttributesWriter}; +pub use event::{EventBuilder, EventBuilderV03, EventBuilderV10}; diff --git a/.history/src/lib_20201107132439.rs b/.history/src/lib_20201107132439.rs new file mode 100644 index 00000000..7bc164b4 --- /dev/null +++ b/.history/src/lib_20201107132439.rs @@ -0,0 +1,57 @@ +//! This crate implements the [CloudEvents](https://cloudevents.io/) Spec for Rust. +//! +//! ``` +//! # use std::error::Error; +//! # fn main() -> Result<(), Box> { +//! use cloudevents::{EventBuilder, AttributesReader, EventBuilderV10}; +//! use chrono::{Utc, DateTime}; +//! use url::Url; +//! +//! let event = EventBuilderV10::new() +//! .id("my_event.my_application") +//! .source("http://localhost:8080") +//! .ty("example.demo") +//! .time(Utc::now()) +//! .build()?; +//! +//! println!("CloudEvent Id: {}", event.id()); +//! match event.time() { +//! Some(t) => println!("CloudEvent Time: {}", t), +//! None => println!("CloudEvent Time: None") +//! } +//! # Ok(()) +//! # } +//! ``` +//! +//! This crate includes: +//! +//! * The [`Event`] data structure, to represent CloudEvent (version 1.0 and 0.3) +//! * The [`EventBuilder`] trait and implementations, to create [`Event`] instances +//! * The implementation of [`serde::Serialize`] and [`serde::Deserialize`] for [`Event`] to serialize/deserialize CloudEvents to/from JSON +//! * Traits and utilities in [`message`] to implement Protocol Bindings +//! +//! If you're looking for Protocol Binding implementations, look at crates: +//! +//! * [cloudevents-sdk-actix-web](https://docs.rs/cloudevents-sdk-actix-web): Integration with [Actix Web](https://github.com/actix/actix-web) +//! * [cloudevents-sdk-reqwest](https://docs.rs/cloudevents-sdk-reqwest): Integration with [reqwest](https://github.com/seanmonstar/reqwest) +//! * [cloudevents-sdk-rdkafka](https://docs.rs/cloudevents-sdk-rdkafka): Integration with [rdkafka](https://fede1024.github.io/rust-rdkafka) +//! + +#![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.3.0")] +#![deny(broken_intra_doc_links)] +#![no_std] + +extern crate no_std_compat as std; + +extern crate serde; +extern crate serde_json; +extern crate serde_value; +extern crate snafu; + +pub mod event; +pub mod message; + +pub use event::Data; +pub use event::Event; +pub use event::{AttributesReader, AttributesWriter}; +pub use event::{EventBuilder, EventBuilderV03, EventBuilderV10}; diff --git a/Cargo.toml b/Cargo.toml index 3c0badb4..172db1ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ base64 = "^0.12" url = { version = "^2.1", features = ["serde"] } snafu = "^0.6" bitflags = "^1.2" +no-std-compat = { version = "^0.4.1", features = ["alloc"] } [target."cfg(not(target_arch = \"wasm32\"))".dependencies] hostname = "^0.3" diff --git a/src/event/attributes.rs b/src/event/attributes.rs index 120bb9c6..a508e33a 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -5,6 +5,7 @@ use super::{ use chrono::{DateTime, Utc}; use serde::Serializer; use std::fmt; +use std::prelude::v1::*; use url::Url; /// Enum representing a borrowed value of a CloudEvent attribute. diff --git a/src/event/data.rs b/src/event/data.rs index c039ce02..42a100a4 100644 --- a/src/event/data.rs +++ b/src/event/data.rs @@ -2,6 +2,7 @@ use serde_json::Value; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; +use std::prelude::v1::*; /// Event [data attribute](https://github.com/cloudevents/spec/blob/master/spec.md#event-data) representation #[derive(PartialEq, Eq, Debug, Clone)] diff --git a/src/event/event.rs b/src/event/event.rs new file mode 100644 index 00000000..0e17a3d9 --- /dev/null +++ b/src/event/event.rs @@ -0,0 +1,257 @@ +use super::{ + AttributeValue, Attributes, AttributesReader, AttributesV10, AttributesWriter, Data, + ExtensionValue, SpecVersion, +}; +use chrono::{DateTime, Utc}; +use delegate_attr::delegate; +use std::collections::HashMap; +use std::fmt; +use std::convert::TryFrom; +use std::prelude::v1::*; +use url::Url; + +/// Data structure that represents a [CloudEvent](https://github.com/cloudevents/spec/blob/master/spec.md). +/// It provides methods to get the attributes through [`AttributesReader`] +/// and write them through [`AttributesWriter`]. +/// It also provides methods to read and write the [event data](https://github.com/cloudevents/spec/blob/master/spec.md#event-data). +/// +/// You can build events using [`super::EventBuilder`] +/// ``` +/// use cloudevents::*; +/// use std::convert::TryInto; +/// +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// // Create an event using the Default trait +/// let mut e = Event::default(); +/// e.set_data( +/// "application/json", +/// serde_json::json!({"hello": "world"}) +/// ); +/// +/// // Print the event id +/// println!("Event id: {}", e.id()); +/// +/// // Get the event data +/// let data: Option = e.data().cloned(); +/// match data { +/// Some(d) => println!("{}", d), +/// None => println!("No event data") +/// } +/// # Ok(()) +/// # } +/// ``` +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Event { + pub(crate) attributes: Attributes, + pub(crate) data: Option, + pub(crate) extensions: HashMap, +} + +#[delegate(self.attributes)] +impl AttributesReader for Event { + fn id(&self) -> &str; + fn source(&self) -> &Url; + 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>; +} + +#[delegate(self.attributes)] +impl AttributesWriter for Event { + fn set_id(&mut self, id: impl Into) -> String; + fn set_source(&mut self, source: impl Into) -> Url; + fn set_type(&mut self, ty: impl Into) -> String; + fn set_subject(&mut self, subject: Option>) -> Option; + fn set_time(&mut self, time: Option>>) -> Option>; + fn set_datacontenttype(&mut self, datacontenttype: Option>) + -> Option; + fn set_dataschema(&mut self, dataschema: Option>) -> Option; +} + +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 { + write!(f, "CloudEvent:\n")?; + self.iter() + .map(|(name, val)| write!(f, " {}: '{}'\n", name, val)) + .collect::()?; + match self.data() { + Some(data) => write!(f, " {}", data)?, + None => write!(f, " No data")?, + } + write!(f, "\n") + } +} + +impl Event { + /// Returns an [`Iterator`] for all the available [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes) and extensions. + /// Same as chaining [`Event::iter_attributes()`] and [`Event::iter_extensions()`] + pub fn iter(&self) -> impl Iterator { + self.iter_attributes() + .chain(self.extensions.iter().map(|(k, v)| (k.as_str(), v.into()))) + } + + /// Returns an [`Iterator`] for all the available [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes), excluding extensions. + /// This iterator does not contain the `data` field. + pub fn iter_attributes(&self) -> impl Iterator { + self.attributes.iter() + } + + /// Get all the [extensions](https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes) + pub fn iter_extensions(&self) -> impl Iterator { + self.extensions.iter().map(|(k, v)| (k.as_str(), v)) + } + + /// Get `data` from this `Event` + pub fn data(&self) -> Option<&Data> { + self.data.as_ref() + } + + /// Take (`datacontenttype`, `dataschema`, `data`) from this event, leaving these fields empty + /// + /// ``` + /// use cloudevents::Event; + /// use serde_json::json; + /// use std::convert::Into; + /// + /// let mut e = Event::default(); + /// e.set_data("application/json", json!({})); + /// + /// let (datacontenttype, dataschema, data) = e.take_data(); + /// ``` + pub fn take_data(&mut self) -> (Option, Option, Option) { + ( + self.attributes.set_datacontenttype(None as Option), + self.attributes.set_dataschema(None as Option), + self.data.take(), + ) + } + + /// Set `data` into this `Event` with the specified `datacontenttype`. + /// Returns the previous value of `datacontenttype` and `data`. + /// + /// ``` + /// use cloudevents::Event; + /// use serde_json::json; + /// use std::convert::Into; + /// + /// let mut e = Event::default(); + /// let (old_datacontenttype, old_data) = e.set_data("application/json", json!({})); + /// ``` + pub fn set_data( + &mut self, + datacontenttype: impl Into, + data: impl Into, + ) -> (Option, Option) { + ( + self.attributes.set_datacontenttype(Some(datacontenttype)), + std::mem::replace(&mut self.data, Some(data.into())), + ) + } + + /// Set `data` into this `Event`, without checking if there is a `datacontenttype`. + /// Returns the previous value of `data`. + /// + /// ``` + /// use cloudevents::Event; + /// use serde_json::json; + /// use std::convert::Into; + /// + /// let mut e = Event::default(); + /// let old_data = e.set_data_unchecked(json!({})); + /// ``` + pub fn set_data_unchecked(&mut self, data: impl Into) -> Option { + std::mem::replace(&mut self.data, Some(data.into())) + } + + /// Get the [extension](https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes) named `extension_name` + pub fn extension(&self, extension_name: &str) -> Option<&ExtensionValue> { + self.extensions.get(extension_name) + } + + /// Set the [extension](https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes) named `extension_name` with `extension_value` + pub fn set_extension<'name, 'event: 'name>( + &'event mut self, + extension_name: &'name str, + extension_value: impl Into, + ) { + self.extensions + .insert(extension_name.to_owned(), extension_value.into()); + } + + /// Remove the [extension](https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes) named `extension_name` + pub fn remove_extension<'name, 'event: 'name>( + &'event mut self, + extension_name: &'name str, + ) -> Option { + 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"))) + } +} diff --git a/src/event/extensions.rs b/src/event/extensions.rs index d2670e8a..f3e4ec1e 100644 --- a/src/event/extensions.rs +++ b/src/event/extensions.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize, Serializer}; use std::convert::From; use std::fmt; +use std::prelude::v1::*; #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] diff --git a/src/event/format.rs b/src/event/format.rs index 5eed6f82..30188840 100644 --- a/src/event/format.rs +++ b/src/event/format.rs @@ -7,6 +7,7 @@ use serde::de::{Error, IntoDeserializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; +use std::prelude::v1::*; macro_rules! parse_field { ($value:expr, $target_type:ty, $error:ty) => { diff --git a/src/event/message.rs b/src/event/message.rs index a65351db..f47da92e 100644 --- a/src/event/message.rs +++ b/src/event/message.rs @@ -7,6 +7,7 @@ use crate::message::{ StructuredSerializer, }; use crate::{EventBuilder, EventBuilderV03, EventBuilderV10}; +use std::prelude::v1::*; impl StructuredDeserializer for Event { fn deserialize_structured>(self, visitor: V) -> Result { diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 9cdab6db..23a0a6f4 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -2,6 +2,7 @@ use super::{v03, v10}; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; +use std::prelude::v1::*; pub(crate) const SPEC_VERSIONS: [&str; 2] = ["0.3", "1.0"]; diff --git a/src/event/types.rs b/src/event/types.rs index 2ae2f649..2d4dd77a 100644 --- a/src/event/types.rs +++ b/src/event/types.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use std::prelude::v1::*; use url::Url; /// Trait to define conversion to [`Url`] diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index cbdb7a23..576050f9 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -3,6 +3,7 @@ use crate::event::AttributesV10; use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; use crate::message::{BinarySerializer, MessageAttributeValue}; use chrono::{DateTime, Utc}; +use std::prelude::v1::*; use url::Url; use uuid::Uuid; diff --git a/src/event/v03/builder.rs b/src/event/v03/builder.rs index d40b4368..9a0e5f7b 100644 --- a/src/event/v03/builder.rs +++ b/src/event/v03/builder.rs @@ -6,6 +6,7 @@ use crate::message::MessageAttributeValue; use chrono::{DateTime, Utc}; use std::collections::HashMap; use std::convert::TryInto; +use std::prelude::v1::*; use url::Url; /// Builder to create a CloudEvent V0.3 diff --git a/src/event/v03/format.rs b/src/event/v03/format.rs index e735e10c..6691c92d 100644 --- a/src/event/v03/format.rs +++ b/src/event/v03/format.rs @@ -7,6 +7,7 @@ use serde::ser::SerializeMap; use serde::{Deserialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; +use std::prelude::v1::*; use url::Url; pub(crate) struct EventFormatDeserializer {} diff --git a/src/event/v10/attributes.rs b/src/event/v10/attributes.rs index 4e604424..2e877245 100644 --- a/src/event/v10/attributes.rs +++ b/src/event/v10/attributes.rs @@ -3,6 +3,7 @@ use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersio use crate::message::{BinarySerializer, MessageAttributeValue}; use chrono::{DateTime, Utc}; use core::fmt::Debug; +use std::prelude::v1::*; use url::Url; use uuid::Uuid; diff --git a/src/event/v10/builder.rs b/src/event/v10/builder.rs index 1fceeeeb..85771d2f 100644 --- a/src/event/v10/builder.rs +++ b/src/event/v10/builder.rs @@ -6,6 +6,7 @@ use crate::message::MessageAttributeValue; use chrono::{DateTime, Utc}; use std::collections::HashMap; use std::convert::TryInto; +use std::prelude::v1::*; use url::Url; /// Builder to create a CloudEvent V1.0 diff --git a/src/event/v10/format.rs b/src/event/v10/format.rs index df624639..c1b7c2e9 100644 --- a/src/event/v10/format.rs +++ b/src/event/v10/format.rs @@ -7,6 +7,7 @@ use serde::ser::SerializeMap; use serde::{Deserialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; +use std::prelude::v1::*; use url::Url; pub(crate) struct EventFormatDeserializer {} diff --git a/src/lib.rs b/src/lib.rs index 89c6ca41..a1db48fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,14 @@ #![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.3.1")] #![deny(broken_intra_doc_links)] +#![no_std] + +extern crate no_std_compat as std; + +extern crate serde; +extern crate serde_json; +extern crate serde_value; +extern crate snafu; pub mod event; pub mod message; diff --git a/src/message/error.rs b/src/message/error.rs index 900ae584..ac1892f6 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -1,4 +1,5 @@ use snafu::Snafu; +use std::prelude::v1::*; /// Represents an error during serialization/deserialization process #[derive(Debug, Snafu)] diff --git a/src/message/serializer.rs b/src/message/serializer.rs index c7c0cb5b..5bf476df 100644 --- a/src/message/serializer.rs +++ b/src/message/serializer.rs @@ -1,5 +1,6 @@ use super::{MessageAttributeValue, Result}; use crate::event::SpecVersion; +use std::prelude::v1::*; /// Serializer for structured mode messages. pub trait StructuredSerializer { diff --git a/src/message/types.rs b/src/message/types.rs index 7abf2632..8cfe08ea 100644 --- a/src/message/types.rs +++ b/src/message/types.rs @@ -2,6 +2,7 @@ use crate::event::ExtensionValue; use chrono::{DateTime, Utc}; use std::convert::TryInto; use std::fmt; +use std::prelude::v1::*; use url::Url; /// Union type representing a [CloudEvent context attribute type](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system). From 337e9ab7bf36e5f8a837d785c29672e5cf91fb55 Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Wed, 28 Oct 2020 15:51:00 +0530 Subject: [PATCH 02/10] marker#1 Signed-off-by: adpranavb2000@gmail.com --- src/event/spec_version.rs | 4 ++-- src/lib.rs | 2 ++ src/message/error.rs | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 23a0a6f4..d418ee4a 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -60,12 +60,12 @@ impl fmt::Display for UnknownSpecVersion { } } -impl std::error::Error for UnknownSpecVersion {} +impl no_error::Error for InvalidSpecVersion {} impl TryFrom<&str> for SpecVersion { type Error = UnknownSpecVersion; - fn try_from(value: &str) -> Result { + fn try_from(value: &str) -> core::result::Result { match value { "0.3" => Ok(SpecVersion::V03), "1.0" => Ok(SpecVersion::V10), diff --git a/src/lib.rs b/src/lib.rs index a1db48fb..c7f2fa38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ #![no_std] extern crate no_std_compat as std; +extern crate no_error; +extern crate core_io; extern crate serde; extern crate serde_json; diff --git a/src/message/error.rs b/src/message/error.rs index ac1892f6..fce77a0f 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -1,3 +1,5 @@ +use no_error::*; +use core_io::Error; use snafu::Snafu; use std::prelude::v1::*; @@ -32,11 +34,9 @@ pub enum Error { SerdeJsonError { source: serde_json::Error }, #[snafu(display("IO Error: {}", source))] #[snafu(context(false))] - IOError { source: std::io::Error }, - #[snafu(display("Other error: {}", source))] - Other { - source: Box, - }, + IOError { source: core_io::Error }, + #[snafu(display("Other error: {:#?}", source))] + Other { source: Box }, } /// Result type alias for return values during serialization/deserialization process From 016f79fb103a9ab2a9f04f1b2b65f53b8ae37876 Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Wed, 28 Oct 2020 18:33:32 +0530 Subject: [PATCH 03/10] replaced std::io::Error Signed-off-by: adpranavb2000@gmail.com --- src/event/event.rs | 1 - src/event/spec_version.rs | 4 +- src/lib.rs | 2 - src/message/error.rs | 6 +- src/message/mod.rs | 2 + src/message/no_std_io.rs | 208 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 214 insertions(+), 9 deletions(-) create mode 100644 src/message/no_std_io.rs diff --git a/src/event/event.rs b/src/event/event.rs index 0e17a3d9..8193959b 100644 --- a/src/event/event.rs +++ b/src/event/event.rs @@ -6,7 +6,6 @@ use chrono::{DateTime, Utc}; use delegate_attr::delegate; use std::collections::HashMap; use std::fmt; -use std::convert::TryFrom; use std::prelude::v1::*; use url::Url; diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index d418ee4a..38764094 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -60,12 +60,12 @@ impl fmt::Display for UnknownSpecVersion { } } -impl no_error::Error for InvalidSpecVersion {} +impl std::error::Error for UnknownSpecVersion {} impl TryFrom<&str> for SpecVersion { type Error = UnknownSpecVersion; - fn try_from(value: &str) -> core::result::Result { + fn try_from(value: &str) -> core::result::Result { match value { "0.3" => Ok(SpecVersion::V03), "1.0" => Ok(SpecVersion::V10), diff --git a/src/lib.rs b/src/lib.rs index c7f2fa38..a1db48fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,8 +42,6 @@ #![no_std] extern crate no_std_compat as std; -extern crate no_error; -extern crate core_io; extern crate serde; extern crate serde_json; diff --git a/src/message/error.rs b/src/message/error.rs index fce77a0f..65141343 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -1,5 +1,3 @@ -use no_error::*; -use core_io::Error; use snafu::Snafu; use std::prelude::v1::*; @@ -34,8 +32,8 @@ pub enum Error { SerdeJsonError { source: serde_json::Error }, #[snafu(display("IO Error: {}", source))] #[snafu(context(false))] - IOError { source: core_io::Error }, - #[snafu(display("Other error: {:#?}", source))] + IOError { source: super::no_std_io::Error }, + #[snafu(display("Other error: {:?}", source))] Other { source: Box }, } diff --git a/src/message/mod.rs b/src/message/mod.rs index 14660574..83e84438 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -5,9 +5,11 @@ mod deserializer; mod encoding; mod error; +mod no_std_io; mod serializer; mod types; +pub use no_std_io::{Error,Read,Write}; pub use deserializer::*; pub use encoding::*; pub use error::*; diff --git a/src/message/no_std_io.rs b/src/message/no_std_io.rs new file mode 100644 index 00000000..6f4c74dc --- /dev/null +++ b/src/message/no_std_io.rs @@ -0,0 +1,208 @@ +//! https://docs.rs/not-io/0.1.0-alpha/not_io/ +//! Provides `Read` and `Write` alternatives on `no_std` while being compatible with the full +//! traits from `std` when allowed. +//! +//! ## Motivation +//! +//! The file parser ecosystem of Rust is more or less split across crates that use `no_std` and +//! crates that do not, as well as between crates using `alloc` and no-alloc (and the largely +//! overlapping zero-copy) crates. This has several reasons: +//! +//! * The `std::io::Read` and `std::io::Write` traits require an allocator due to their internal +//! implementation and were not written to be OS independent. +//! * Before `1.36` it was not possible to depend on `alloc` without `std`. +//! * The lack of specialization makes it hard to be both generic over implementors of the standard +//! traits while still allowing use when those traits are not available. This is in particular +//! also since several types (e.g. `&[u8]`) implement those traits but would obviously be useful +//! as byte sources and sinks even when they are unavailable. +//! +//! ## Usage guide +//! +//! This crate assumes you have a structure declared roughly as follows: +//! +//! ```rust +//! # struct SomeItem; +//! # use std::io::Read; +//! +//! struct Decoder { +//! reader: T, +//! } +//! +//! impl Decoder { +//! fn next(&mut self) -> Result { +//! let mut buffer = vec![]; +//! self.reader.read_to_end(&mut buffer)?; +//! # unimplemented!() +//! } +//! } +//! ``` +//! +//! There is only one necessary change, be sure to keep the `std` feature enabled for now. This +//! should not break any code except if you relied on the precise type `T` in which case you will +//! need to use a few derefs and/or `into_inner`. +//! +//! ``` +//! use not_io::AllowStd; +//! # use std::io::Read; +//! +//! struct Decoder { +//! reader: AllowStd, +//! } +//! +//! # struct SomeItem; +//! # impl Decoder { +//! # fn next(&mut self) -> Result { +//! # let mut buffer = vec![]; +//! # self.reader.0.read_to_end(&mut buffer)?; +//! # unimplemented!() +//! # } +//! # } +//! ``` +//! +//! And finally you can add to your crate a new default feature which enables the `std`/`alloc` +//! feature of this crate, and conditionally active your existing interfaces only when that feature +//! is active. Then add a few new impls that can be used even when the feature is inactive. +//! +//! ``` +//! use not_io::AllowStd; +//! # struct SomeItem; +//! +//! struct Decoder { +//! reader: AllowStd, +//! } +//! +//! /// The interface which lets the caller select which feature to turn on. +//! impl Decoder +//! where +//! AllowStd: not_io::Read +//! { +//! fn no_std_next(&mut self) -> Result { +//! # unimplemented!() +//! } +//! } +//! +//! /// An interface for pure no_std use with caller provide no_std reader. +//! impl Decoder +//! where +//! T: not_io::Read +//! { +//! fn not_io_next(&mut self) -> Result { +//! let reader = &mut self.reader.0; +//! # unimplemented!() +//! } +//! } +//! ``` +//! +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; + +#[derive(Debug)] +pub struct Error { + _private: (), +} + +pub type Result = core::result::Result; + +pub trait Read { + fn read(&mut self, buf: &mut [u8]) -> Result; +} + +pub trait Write { + fn write(&mut self, buf: &[u8]) -> Result; +} + +/// A simple new type wrapper holding a potential reader or writer. +/// +/// This type allows the library to satisfy the compatibility across different features without +/// having to resort to specialization. Simply put, this struct implements `Read` and `Write`: +/// +/// * for all types that implement the respective trait from `std` if the `std` feature is active. +/// * on a concrete subset of those types if the `alloc` feature but not the `std` feature has been +/// turned on. +/// * only for types from `core` when neither feature is turned on. +/// +/// Note that without this type we couldn't safely introduce a conditionally active, generic impl +/// of our own traits. The reason is that features must only activate SemVer compatible changes. +/// These two sets of impls are not SemVer compatible due to the uncovered generic `T`. In +/// particular in the first case you'd be allowed to implement the trait for your own type that +/// also implements `std::io::Read` while in the second this is an impl conflict. +/// +/// * `impl Read for &'_ [u8]` +/// * `impl Read for T where std::io::Read` +/// +/// By adding our own private struct as a layer of indirection, you are no longer allowed to make +/// such changes: +/// +/// * `impl Read for AllowStd<&'_ [u8]>` +/// * `impl Read for AllowStd where T: std::io::Read` +/// +/// This still means there is one impl which will never be added. Instead, the impls for +/// core/standard types are provided separately and individually. +/// +/// * `impl Read for AllowStd where T: crate::Read` +pub struct AllowStd(pub T); + +#[cfg(not(feature = "alloc"))] +mod impls_on_neither {} + +#[cfg(feature = "alloc")] +mod impls_on_alloc {} + +#[cfg(feature = "std")] +mod impls_on_std { + use super::{AllowStd, Error, Result}; + use std::io::{self, IoSlice, IoSliceMut}; + + impl super::Read for AllowStd { + fn read(&mut self, buf: &mut [u8]) -> Result { + io::Read::read(&mut self.0, buf).map_err(Error::from) + } + } + + impl io::Read for AllowStd { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result { + self.0.read_vectored(bufs) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + self.0.read_to_string(buf) + } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + self.0.read_exact(buf) + } + } + + impl super::Write for AllowStd { + fn write(&mut self, buf: &[u8]) -> Result { + io::Write::write(&mut self.0, buf).map_err(Error::from) + } + } + + impl io::Write for AllowStd { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result { + self.0.write_vectored(bufs) + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0.write_all(buf) + } + } + + impl From for Error { + fn from(_: io::Error) -> Error { + Error { _private: () } + } + } +} \ No newline at end of file From 6858566e660115adda28607d9dcb0bce5cd56afd Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Sat, 7 Nov 2020 03:19:00 +0530 Subject: [PATCH 04/10] major fixes Signed-off-by: adpranavb2000@gmail.com --- src/event/builder.rs | 8 ++++-- src/event/displayerr.rs | 25 +++++++++++++++++ src/event/mod.rs | 4 +++ src/event/spec_version.rs | 4 ++- src/event/types.rs | 1 + src/event/v03/attributes.rs | 2 +- src/event/v03/builder.rs | 9 +++--- src/event/v10/builder.rs | 9 +++--- src/lib.rs | 1 + src/message/deserializer.rs | 4 +-- src/message/error.rs | 55 ++++++++++++++++++++++++++++++++----- src/message/mod.rs | 2 +- src/message/no_std_io.rs | 12 ++++++-- 13 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 src/event/displayerr.rs diff --git a/src/event/builder.rs b/src/event/builder.rs index 2e5790d6..d018fbb7 100644 --- a/src/event/builder.rs +++ b/src/event/builder.rs @@ -1,4 +1,4 @@ -use super::Event; +use super::{DisplayError, Event}; use snafu::Snafu; /// Trait to implement a builder for [`Event`]: @@ -41,7 +41,8 @@ pub enum Error { ))] ParseTimeError { attribute_name: &'static str, - source: chrono::ParseError, + #[snafu(source(from(chrono::ParseError, DisplayError)))] + source: DisplayError, }, #[snafu(display( "Error while setting attribute '{}' with uri/uriref type: {}", @@ -50,6 +51,7 @@ pub enum Error { ))] ParseUrlError { attribute_name: &'static str, - source: url::ParseError, + #[snafu(source(from(url::ParseError, DisplayError)))] + source: DisplayError, }, } diff --git a/src/event/displayerr.rs b/src/event/displayerr.rs new file mode 100644 index 00000000..b5b42bc6 --- /dev/null +++ b/src/event/displayerr.rs @@ -0,0 +1,25 @@ +use core::fmt::{self, Debug, Display}; +use snafu::Snafu; + +#[derive(Clone)] +pub struct DisplayError(pub T); + +impl Debug for DisplayError +where + T: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Display for DisplayError +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl snafu::Error for DisplayError where T: Display + Debug {} diff --git a/src/event/mod.rs b/src/event/mod.rs index 2d88b7ce..f31363b1 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -3,6 +3,8 @@ mod attributes; mod builder; mod data; +mod displayerr; +mod event; mod extensions; #[macro_use] mod format; @@ -15,6 +17,8 @@ pub use attributes::{AttributeValue, AttributesReader, AttributesWriter}; pub use builder::Error as EventBuilderError; pub use builder::EventBuilder; pub use data::Data; +pub use displayerr::DisplayError; +pub use event::Event; pub use extensions::ExtensionValue; pub(crate) use message::EventBinarySerializer; pub(crate) use message::EventStructuredSerializer; diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 38764094..7db62f6f 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -1,4 +1,6 @@ use super::{v03, v10}; +use serde::export::Formatter; // double check +use snafu::Snafu; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; @@ -60,7 +62,7 @@ impl fmt::Display for UnknownSpecVersion { } } -impl std::error::Error for UnknownSpecVersion {} +impl snafu::Error for UnknownSpecVersion {} impl TryFrom<&str> for SpecVersion { type Error = UnknownSpecVersion; diff --git a/src/event/types.rs b/src/event/types.rs index 2d4dd77a..2b02ac6c 100644 --- a/src/event/types.rs +++ b/src/event/types.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use snafu; use std::prelude::v1::*; use url::Url; diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index 576050f9..51723cd3 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -162,7 +162,7 @@ impl Default for Attributes { datacontenttype: None, schemaurl: None, subject: None, - time: Some(Utc::now()), + time: Some(chrono::offset::Utc::now()), } } } diff --git a/src/event/v03/builder.rs b/src/event/v03/builder.rs index 9a0e5f7b..1997aa8e 100644 --- a/src/event/v03/builder.rs +++ b/src/event/v03/builder.rs @@ -1,6 +1,7 @@ use super::Attributes as AttributesV03; use crate::event::{ - Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl, + Attributes, Data, DisplayError, Event, EventBuilderError, ExtensionValue, TryIntoTime, + TryIntoUrl, }; use crate::message::MessageAttributeValue; use chrono::{DateTime, Utc}; @@ -36,7 +37,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseUrlError { attribute_name: "source", - source: e, + source: DisplayError(e), }) } }; @@ -59,7 +60,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseTimeError { attribute_name: "time", - source: e, + source: DisplayError(e), }) } }; @@ -99,7 +100,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseUrlError { attribute_name: "schemaurl", - source: e, + source: DisplayError(e), }) } }; diff --git a/src/event/v10/builder.rs b/src/event/v10/builder.rs index 85771d2f..c1afed67 100644 --- a/src/event/v10/builder.rs +++ b/src/event/v10/builder.rs @@ -1,6 +1,7 @@ use super::Attributes as AttributesV10; use crate::event::{ - Attributes, Data, Event, EventBuilderError, ExtensionValue, TryIntoTime, TryIntoUrl, + Attributes, Data, DisplayError, Event, EventBuilderError, ExtensionValue, TryIntoTime, + TryIntoUrl, }; use crate::message::MessageAttributeValue; use chrono::{DateTime, Utc}; @@ -36,7 +37,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseUrlError { attribute_name: "source", - source: e, + source: DisplayError(e), }) } }; @@ -59,7 +60,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseTimeError { attribute_name: "time", - source: e, + source: DisplayError(e), }) } }; @@ -99,7 +100,7 @@ impl EventBuilder { Err(e) => { self.error = Some(EventBuilderError::ParseUrlError { attribute_name: "dataschema", - source: e, + source: DisplayError(e), }) } }; diff --git a/src/lib.rs b/src/lib.rs index a1db48fb..00a8be23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ #![deny(broken_intra_doc_links)] #![no_std] +extern crate core_error; extern crate no_std_compat as std; extern crate serde; diff --git a/src/message/deserializer.rs b/src/message/deserializer.rs index a1fe19e6..03928853 100644 --- a/src/message/deserializer.rs +++ b/src/message/deserializer.rs @@ -1,4 +1,4 @@ -use super::{BinarySerializer, Encoding, Error, Result, StructuredSerializer}; +use super::{BinarySerializer, Encoding, Result, StructuredSerializer}; use crate::event::{EventBinarySerializer, EventStructuredSerializer}; use crate::Event; @@ -46,7 +46,7 @@ where match self.encoding() { Encoding::BINARY => BinaryDeserializer::into_event(self), Encoding::STRUCTURED => StructuredDeserializer::into_event(self), - _ => Err(Error::WrongEncoding {}), + _ => Err(super::error::Error::WrongEncoding {}), } } diff --git a/src/message/error.rs b/src/message/error.rs index 65141343..d2431645 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -1,6 +1,29 @@ +use core::fmt::{self, Debug, Display}; use snafu::Snafu; use std::prelude::v1::*; +struct DisplayError(pub T); + +impl Debug for DisplayError +where + T: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Display for DisplayError +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl snafu::Error for DisplayError where T: Display + Debug {} + /// Represents an error during serialization/deserialization process #[derive(Debug, Snafu)] pub enum Error { @@ -20,21 +43,39 @@ pub enum Error { }, #[snafu(display("Error while parsing a time string: {}", source))] #[snafu(context(false))] - ParseTimeError { source: chrono::ParseError }, + ParseTimeError { + #[snafu(source(from(chrono::ParseError, DisplayError)))] + source: DisplayError, + }, #[snafu(display("Error while parsing a url: {}", source))] #[snafu(context(false))] - ParseUrlError { source: url::ParseError }, + ParseUrlError { + #[snafu(source(from(url::ParseError, DisplayError)))] + source: DisplayError, + }, #[snafu(display("Error while decoding base64: {}", source))] #[snafu(context(false))] - Base64DecodingError { source: base64::DecodeError }, + Base64DecodingError { + #[snafu(source(from(base64::DecodeError, DisplayError)))] + source: DisplayError, + }, #[snafu(display("Error while serializing/deserializing to json: {}", source))] #[snafu(context(false))] - SerdeJsonError { source: serde_json::Error }, + SerdeJsonError { + #[snafu(source(from(serde_json::Error, DisplayError)))] + source: DisplayError, + }, #[snafu(display("IO Error: {}", source))] #[snafu(context(false))] - IOError { source: super::no_std_io::Error }, - #[snafu(display("Other error: {:?}", source))] - Other { source: Box }, + IOError { + #[snafu(source(from(super::no_std_io::IoError, DisplayError)))] + source: DisplayError, + }, + #[snafu(display("Other error: {}", source))] + Other { + #[snafu(source(from(Box, DisplayError)))] + source: DisplayError>, + }, } /// Result type alias for return values during serialization/deserialization process diff --git a/src/message/mod.rs b/src/message/mod.rs index 83e84438..62782b78 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -9,9 +9,9 @@ mod no_std_io; mod serializer; mod types; -pub use no_std_io::{Error,Read,Write}; pub use deserializer::*; pub use encoding::*; pub use error::*; +pub use no_std_io::{IoError, Read, Write}; pub use serializer::*; pub use types::MessageAttributeValue; diff --git a/src/message/no_std_io.rs b/src/message/no_std_io.rs index 6f4c74dc..baf4f492 100644 --- a/src/message/no_std_io.rs +++ b/src/message/no_std_io.rs @@ -98,12 +98,18 @@ #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; +pub type Result = core::result::Result; + #[derive(Debug)] -pub struct Error { +pub struct IoError { _private: (), } -pub type Result = core::result::Result; +impl core::fmt::Display for IoError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "()") + } +} pub trait Read { fn read(&mut self, buf: &mut [u8]) -> Result; @@ -205,4 +211,4 @@ mod impls_on_std { Error { _private: () } } } -} \ No newline at end of file +} From 3caf4a32163b08512a766fd7fc6e7bcd61f3ccbc Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Sat, 7 Nov 2020 13:18:10 +0530 Subject: [PATCH 05/10] no_std compat lib(sorta) Signed-off-by: adpranavb2000@gmail.com --- Cargo.toml | 10 +++++----- src/event/displayerr.rs | 1 - src/event/spec_version.rs | 2 +- src/event/types.rs | 1 - src/message/error.rs | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 172db1ff..f4214dcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,11 +17,11 @@ categories = ["web-programming", "encoding", "data-structures"] name = "cloudevents" [dependencies] -serde = { version = "^1.0", features = ["derive"] } -serde_json = "^1.0" -chrono = { version = "^0.4", features = ["serde"] } +serde = { version = "^1.0", default-features=false,features = ["derive","alloc"] } +serde_json = { version = "^1.0", default-features = false, features = ["alloc"] } +chrono = { version = "^0.4", default-features=false ,features = ["serde","alloc","clock"] } delegate-attr = "^0.2" -base64 = "^0.12" +base64 = { version = "^0.12", default-features = false, features = ["alloc"] } url = { version = "^2.1", features = ["serde"] } snafu = "^0.6" bitflags = "^1.2" @@ -32,7 +32,7 @@ hostname = "^0.3" uuid = { version = "^0.8", features = ["v4"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -web-sys = { version = "^0.3", features = ["Window", "Location"] } +web-sys = { version = "^0.3", default-features = false,features = ["Window", "Location"] } uuid = { version = "^0.8", features = ["v4", "wasm-bindgen"] } [dev-dependencies] diff --git a/src/event/displayerr.rs b/src/event/displayerr.rs index b5b42bc6..3cb7068c 100644 --- a/src/event/displayerr.rs +++ b/src/event/displayerr.rs @@ -1,5 +1,4 @@ use core::fmt::{self, Debug, Display}; -use snafu::Snafu; #[derive(Clone)] pub struct DisplayError(pub T); diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 7db62f6f..4579ea28 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -1,5 +1,5 @@ use super::{v03, v10}; -use serde::export::Formatter; // double check +use serde::export::Formatter; use snafu::Snafu; use std::convert::TryFrom; use std::fmt; diff --git a/src/event/types.rs b/src/event/types.rs index 2b02ac6c..2d4dd77a 100644 --- a/src/event/types.rs +++ b/src/event/types.rs @@ -1,5 +1,4 @@ use chrono::{DateTime, Utc}; -use snafu; use std::prelude::v1::*; use url::Url; diff --git a/src/message/error.rs b/src/message/error.rs index d2431645..f21df0e5 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -2,7 +2,7 @@ use core::fmt::{self, Debug, Display}; use snafu::Snafu; use std::prelude::v1::*; -struct DisplayError(pub T); +pub struct DisplayError(pub T); impl Debug for DisplayError where From 6a99cd177bf6e2451b5089bfc924a2210c405ca3 Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Sat, 7 Nov 2020 13:42:23 +0530 Subject: [PATCH 06/10] rebased Signed-off-by: adpranavb2000@gmail.com --- src/event/displayerr.rs | 24 ------------------------ src/event/mod.rs | 34 +++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 29 deletions(-) delete mode 100644 src/event/displayerr.rs diff --git a/src/event/displayerr.rs b/src/event/displayerr.rs deleted file mode 100644 index 3cb7068c..00000000 --- a/src/event/displayerr.rs +++ /dev/null @@ -1,24 +0,0 @@ -use core::fmt::{self, Debug, Display}; - -#[derive(Clone)] -pub struct DisplayError(pub T); - -impl Debug for DisplayError -where - T: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Display for DisplayError -where - T: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl snafu::Error for DisplayError where T: Display + Debug {} diff --git a/src/event/mod.rs b/src/event/mod.rs index f31363b1..afef3ea2 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -3,8 +3,6 @@ mod attributes; mod builder; mod data; -mod displayerr; -mod event; mod extensions; #[macro_use] mod format; @@ -17,8 +15,6 @@ pub use attributes::{AttributeValue, AttributesReader, AttributesWriter}; pub use builder::Error as EventBuilderError; pub use builder::EventBuilder; pub use data::Data; -pub use displayerr::DisplayError; -pub use event::Event; pub use extensions::ExtensionValue; pub(crate) use message::EventBinarySerializer; pub(crate) use message::EventStructuredSerializer; @@ -45,9 +41,11 @@ pub(crate) use v10::EventFormatSerializer as EventFormatSerializerV10; use chrono::{DateTime, Utc}; use delegate_attr::delegate; use std::collections::HashMap; -use std::fmt; +//use std::fmt; +use std::prelude::v1::*; use url::Url; +use core::fmt::{self,Debug, Display}; /// Data structure that represents a [CloudEvent](https://github.com/cloudevents/spec/blob/master/spec.md). /// It provides methods to get the attributes through [`AttributesReader`] /// and write them through [`AttributesWriter`]. @@ -239,6 +237,32 @@ impl Event { } } +// Facilitates compatibility with snafu::Error for external objects + +#[derive(PartialEq, Eq, Clone)] +pub struct DisplayError(pub T); + +impl Debug for DisplayError +where + T: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Display for DisplayError +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl snafu::Error for DisplayError where T: Display + Debug {} + + #[cfg(test)] mod tests { use super::*; From 0b830c90e3c0f601ebc4a89003543d13ff4869d4 Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Mon, 4 Jan 2021 01:16:50 +0530 Subject: [PATCH 07/10] Cleaned up cargo.toml+fixes Signed-off-by: adpranavb2000@gmail.com --- Cargo.toml | 27 +++++++++++++++++++-------- src/event/attributes.rs | 11 +++++++++++ src/event/mod.rs | 5 ++--- src/event/spec_version.rs | 1 + src/event/v10/attributes.rs | 20 +++++++++++++++++++- src/lib.rs | 4 +++- src/message/error.rs | 13 +++++++------ src/message/mod.rs | 2 -- src/message/types.rs | 13 +++++++++++++ 9 files changed, 75 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f4214dcc..1986acb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,16 +16,27 @@ categories = ["web-programming", "encoding", "data-structures"] [lib] name = "cloudevents" +[features] +default = ["std"] +chrono_no_std = ["chrono/serde", "chrono/alloc", "chrono/clock"] +no_std = ["no-std-compat", "serde_no_std", "chrono_no_std", "base64/alloc"] +serde_no_std = ["serde/derive", "serde/alloc", "serde_json/alloc"] +std = ["snafu/std", "snafu/guide", "serde/std", "serde_json/std", "chrono/std", "base64/std", "url"] + [dependencies] -serde = { version = "^1.0", default-features=false,features = ["derive","alloc"] } -serde_json = { version = "^1.0", default-features = false, features = ["alloc"] } -chrono = { version = "^0.4", default-features=false ,features = ["serde","alloc","clock"] } +base64 = { version = "^0.12", default-features = false } +chrono = { version = "^0.4", default-features = false } delegate-attr = "^0.2" -base64 = { version = "^0.12", default-features = false, features = ["alloc"] } -url = { version = "^2.1", features = ["serde"] } -snafu = "^0.6" -bitflags = "^1.2" -no-std-compat = { version = "^0.4.1", features = ["alloc"] } +serde = { version = "^1.0", default-features=false } +serde_json = { version = "^1.0", default-features = false, features = ["alloc"] } +serde-value = "^0.7" +snafu = { version = "^0.6",default-features = false } +url = { version = "^2.1", features = ["serde"], optional=true } + +[dependencies.no-std-compat] +version = "^0.4.1" +features = ["alloc", "compat_hash", "compat_sync", "compat_macros"] +optional=true [target."cfg(not(target_arch = \"wasm32\"))".dependencies] hostname = "^0.3" diff --git a/src/event/attributes.rs b/src/event/attributes.rs index a508e33a..4c43549e 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -6,7 +6,11 @@ use chrono::{DateTime, Utc}; use serde::Serializer; use std::fmt; use std::prelude::v1::*; + +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; /// Enum representing a borrowed value of a CloudEvent attribute. /// This represents the types defined in the [CloudEvent spec type system](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system) @@ -253,6 +257,7 @@ impl Attributes { } } +#[cfg(feature = "std")] #[cfg(not(target_arch = "wasm32"))] pub(crate) fn default_hostname() -> Url { Url::parse( @@ -269,6 +274,7 @@ pub(crate) fn default_hostname() -> Url { .unwrap() } +#[cfg(feature = "std")] #[cfg(target_arch = "wasm32")] pub(crate) fn default_hostname() -> Url { use std::str::FromStr; @@ -282,3 +288,8 @@ pub(crate) fn default_hostname() -> Url { ) .unwrap() } + +#[cfg(not(feature = "std"))] +pub(crate) fn default_hostname() -> Url { + String::from("http://localhost") +} diff --git a/src/event/mod.rs b/src/event/mod.rs index afef3ea2..defbe239 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -45,7 +45,7 @@ use std::collections::HashMap; use std::prelude::v1::*; use url::Url; -use core::fmt::{self,Debug, Display}; +use core::fmt::{self, Debug, Display}; /// Data structure that represents a [CloudEvent](https://github.com/cloudevents/spec/blob/master/spec.md). /// It provides methods to get the attributes through [`AttributesReader`] /// and write them through [`AttributesWriter`]. @@ -237,7 +237,7 @@ impl Event { } } -// Facilitates compatibility with snafu::Error for external objects +// Facilitates compatibility with snafu::Error for external objects #[derive(PartialEq, Eq, Clone)] pub struct DisplayError(pub T); @@ -262,7 +262,6 @@ where impl snafu::Error for DisplayError where T: Display + Debug {} - #[cfg(test)] mod tests { use super::*; diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 4579ea28..19ffab96 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -5,6 +5,7 @@ use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; use std::prelude::v1::*; +use std::vec; pub(crate) const SPEC_VERSIONS: [&str; 2] = ["0.3", "1.0"]; diff --git a/src/event/v10/attributes.rs b/src/event/v10/attributes.rs index 2e877245..9b109370 100644 --- a/src/event/v10/attributes.rs +++ b/src/event/v10/attributes.rs @@ -4,9 +4,13 @@ use crate::message::{BinarySerializer, MessageAttributeValue}; use chrono::{DateTime, Utc}; use core::fmt::Debug; use std::prelude::v1::*; -use url::Url; use uuid::Uuid; +#[cfg(feature = "std")] +use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; + pub(crate) const ATTRIBUTE_NAMES: [&str; 8] = [ "specversion", "id", @@ -206,6 +210,20 @@ impl AttributesConverter for Attributes { self } + #[cfg(feature = "std")] + fn into_v03(self) -> AttributesV03 { + AttributesV03 { + id: self.id, + ty: self.ty, + source: self.source, + datacontenttype: self.datacontenttype, + schemaurl: self.dataschema, + subject: self.subject, + time: self.time, + } + } + + #[cfg(not(feature = "std"))] fn into_v03(self) -> AttributesV03 { AttributesV03 { id: self.id, diff --git a/src/lib.rs b/src/lib.rs index 00a8be23..69ab6616 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,8 +41,10 @@ #![deny(broken_intra_doc_links)] #![no_std] -extern crate core_error; +#[cfg(not(feature = "std"))] extern crate no_std_compat as std; +#[cfg(feature = "std")] +extern crate std; extern crate serde; extern crate serde_json; diff --git a/src/message/error.rs b/src/message/error.rs index f21df0e5..642c2320 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -65,16 +65,17 @@ pub enum Error { #[snafu(source(from(serde_json::Error, DisplayError)))] source: DisplayError, }, + + #[cfg(feature = "std")] #[snafu(display("IO Error: {}", source))] #[snafu(context(false))] - IOError { - #[snafu(source(from(super::no_std_io::IoError, DisplayError)))] - source: DisplayError, - }, + IOError { source: std::io::Error }, + + #[cfg(feature = "std")] #[snafu(display("Other error: {}", source))] Other { - #[snafu(source(from(Box, DisplayError)))] - source: DisplayError>, + //#[snafu(source(from(Box, DisplayError)))] + source: Box, }, } diff --git a/src/message/mod.rs b/src/message/mod.rs index 62782b78..14660574 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -5,13 +5,11 @@ mod deserializer; mod encoding; mod error; -mod no_std_io; mod serializer; mod types; pub use deserializer::*; pub use encoding::*; pub use error::*; -pub use no_std_io::{IoError, Read, Write}; pub use serializer::*; pub use types::MessageAttributeValue; diff --git a/src/message/types.rs b/src/message/types.rs index 8cfe08ea..5ab664eb 100644 --- a/src/message/types.rs +++ b/src/message/types.rs @@ -3,7 +3,11 @@ use chrono::{DateTime, Utc}; use std::convert::TryInto; use std::fmt; use std::prelude::v1::*; + +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; /// Union type representing a [CloudEvent context attribute type](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system). #[derive(PartialEq, Eq, Debug, Clone)] @@ -33,6 +37,7 @@ impl TryInto> for MessageAttributeValue { impl TryInto for MessageAttributeValue { type Error = super::Error; + #[cfg(feature = "std")] fn try_into(self) -> Result { match self { MessageAttributeValue::Uri(u) => Ok(u), @@ -40,6 +45,14 @@ impl TryInto for MessageAttributeValue { v => Ok(Url::parse(v.to_string().as_ref())?), } } + #[cfg(not(feature = "std"))] + fn try_into(self) -> Result { + match self { + MessageAttributeValue::Uri(u) => Ok(u), + MessageAttributeValue::UriRef(u) => Ok(u), + v => Ok(v.to_string()), + } + } } impl fmt::Display for MessageAttributeValue { From 0fd3024a2717a6c7a457fc4250f3668922fecc4e Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Mon, 4 Jan 2021 04:56:19 +0530 Subject: [PATCH 08/10] fixes#2 Signed-off-by: adpranavb2000@gmail.com --- Cargo.toml | 19 ++++---- src/event/attributes.rs | 4 +- src/event/builder.rs | 2 +- src/event/mod.rs | 32 ++++++++++++- src/event/spec_version.rs | 1 - src/event/types.rs | 16 ++++++- src/event/v03/attributes.rs | 45 ++++++++++++++++++- src/event/v03/builder.rs | 4 ++ src/event/v03/format.rs | 4 ++ src/event/v10/attributes.rs | 43 +++++++++++++++++- src/event/v10/builder.rs | 4 ++ src/event/v10/format.rs | 4 ++ src/message/error.rs | 12 +++++ .../{no_std_io.rs => hello_no_std_io.rs} | 0 tests/attributes_iter.rs | 2 + tests/builder_v03.rs | 6 +++ tests/builder_v10.rs | 6 +++ tests/message.rs | 4 ++ tests/serde_json.rs | 2 + tests/test_data/v03.rs | 9 ++++ tests/test_data/v10.rs | 10 +++++ tests/version_conversion.rs | 2 + 22 files changed, 212 insertions(+), 19 deletions(-) rename src/message/{no_std_io.rs => hello_no_std_io.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index 1986acb7..d95fd8ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,26 +17,25 @@ categories = ["web-programming", "encoding", "data-structures"] name = "cloudevents" [features] -default = ["std"] +default = ["no_std"] +std = ["no_std_compat_bypass","snafu/std", "snafu/guide", "serde/std", "serde_json/std", "chrono/std", "base64/std", "url"] +no_std = ["no_std_compat_bypass", "serde_no_std", "chrono_no_std", "base64/alloc"] + +no_std_compat_bypass=["no-std-compat/std"] +no_std_compat_layer=["no-std-compat/alloc", "no-std-compat/compat_hash", "no-std-compat/compat_sync"] chrono_no_std = ["chrono/serde", "chrono/alloc", "chrono/clock"] -no_std = ["no-std-compat", "serde_no_std", "chrono_no_std", "base64/alloc"] serde_no_std = ["serde/derive", "serde/alloc", "serde_json/alloc"] -std = ["snafu/std", "snafu/guide", "serde/std", "serde_json/std", "chrono/std", "base64/std", "url"] [dependencies] base64 = { version = "^0.12", default-features = false } -chrono = { version = "^0.4", default-features = false } +chrono = { version = "^0.4", default-features = false , features = ["serde", "clock"]} delegate-attr = "^0.2" serde = { version = "^1.0", default-features=false } serde_json = { version = "^1.0", default-features = false, features = ["alloc"] } -serde-value = "^0.7" -snafu = { version = "^0.6",default-features = false } +snafu = { version = "^0.6", default-features = false } url = { version = "^2.1", features = ["serde"], optional=true } -[dependencies.no-std-compat] -version = "^0.4.1" -features = ["alloc", "compat_hash", "compat_sync", "compat_macros"] -optional=true +no-std-compat = { version = "^0.4.1", features = ["alloc", "compat_hash", "compat_sync"], optional=true } [target."cfg(not(target_arch = \"wasm32\"))".dependencies] hostname = "^0.3" diff --git a/src/event/attributes.rs b/src/event/attributes.rs index 4c43549e..beffab1d 100644 --- a/src/event/attributes.rs +++ b/src/event/attributes.rs @@ -7,10 +7,10 @@ use serde::Serializer; use std::fmt; use std::prelude::v1::*; +#[cfg(not(feature = "std"))] +use std::string::String as Url; #[cfg(feature = "std")] use url::Url; -#[cfg(not(feature = "std"))] -use String as Url; /// Enum representing a borrowed value of a CloudEvent attribute. /// This represents the types defined in the [CloudEvent spec type system](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system) diff --git a/src/event/builder.rs b/src/event/builder.rs index d018fbb7..5d95bed2 100644 --- a/src/event/builder.rs +++ b/src/event/builder.rs @@ -1,4 +1,4 @@ -use super::{DisplayError, Event}; +use super::{url, DisplayError, Event}; use snafu::Snafu; /// Trait to implement a builder for [`Event`]: diff --git a/src/event/mod.rs b/src/event/mod.rs index defbe239..e8a8b24a 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -41,9 +41,39 @@ pub(crate) use v10::EventFormatSerializer as EventFormatSerializerV10; use chrono::{DateTime, Utc}; use delegate_attr::delegate; use std::collections::HashMap; -//use std::fmt; use std::prelude::v1::*; + +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; + +pub trait UrlExtend { + fn parse(&self) -> Result; +} + +impl UrlExtend for Url { + fn parse(&self) -> Result { + Ok(self.to_string()) + } +} + +pub mod url { + use super::{fmt, String}; + + #[derive(Debug, Clone)] + pub enum ParseError { + Error(String), + } + + impl snafu::Error for ParseError {} + + impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt(f) + } + } +} use core::fmt::{self, Debug, Display}; /// Data structure that represents a [CloudEvent](https://github.com/cloudevents/spec/blob/master/spec.md). diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 19ffab96..4579ea28 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -5,7 +5,6 @@ use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; use std::prelude::v1::*; -use std::vec; pub(crate) const SPEC_VERSIONS: [&str; 2] = ["0.3", "1.0"]; diff --git a/src/event/types.rs b/src/event/types.rs index 2d4dd77a..b9db6839 100644 --- a/src/event/types.rs +++ b/src/event/types.rs @@ -1,6 +1,11 @@ use chrono::{DateTime, Utc}; use std::prelude::v1::*; -use url::Url; + +use super::url; +#[cfg(not(feature = "std"))] +use super::{Url, UrlExtend}; +#[cfg(feature = "std")] +use url::{self, ParseError, Url}; /// Trait to define conversion to [`Url`] pub trait TryIntoUrl { @@ -13,12 +18,21 @@ impl TryIntoUrl for Url { } } +#[cfg(not(feature = "std"))] +impl TryIntoUrl for &str { + fn into_url(self) -> Result { + Url::parse(&self.to_string()) + } +} + +#[cfg(feature = "std")] impl TryIntoUrl for &str { fn into_url(self) -> Result { Url::parse(self) } } +#[cfg(feature = "std")] impl TryIntoUrl for String { fn into_url(self) -> Result { self.as_str().into_url() diff --git a/src/event/v03/attributes.rs b/src/event/v03/attributes.rs index 51723cd3..37b189ae 100644 --- a/src/event/v03/attributes.rs +++ b/src/event/v03/attributes.rs @@ -4,9 +4,13 @@ use crate::event::{AttributesReader, AttributesWriter, SpecVersion}; use crate::message::{BinarySerializer, MessageAttributeValue}; use chrono::{DateTime, Utc}; use std::prelude::v1::*; -use url::Url; use uuid::Uuid; +#[cfg(not(feature = "std"))] +use super::super::Url; +#[cfg(feature = "std")] +use url::Url; + pub(crate) const ATTRIBUTE_NAMES: [&str; 8] = [ "specversion", "id", @@ -222,8 +226,10 @@ impl crate::event::message::AttributesDeserializer for super::Attributes { #[cfg(test)] mod tests { use super::*; + use crate::event::UrlExtend; use chrono::NaiveDateTime; + #[cfg(feature = "std")] #[test] fn iterator_test_v03() { let a = Attributes { @@ -259,4 +265,41 @@ mod tests { ); assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap()); } + + #[cfg(not(feature = "std"))] + #[test] + fn iterator_test_v03() { + let a = Attributes { + id: String::from("1"), + ty: String::from("someType"), + source: Url::parse(&"https://example.net".to_string()).unwrap(), + datacontenttype: None, + schemaurl: None, + subject: None, + time: Some(DateTime::::from_utc( + NaiveDateTime::from_timestamp(61, 0), + Utc, + )), + }; + let b = &mut a.into_iter(); + let time = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); + + assert_eq!( + ("specversion", AttributeValue::SpecVersion(SpecVersion::V03)), + b.next().unwrap() + ); + assert_eq!(("id", AttributeValue::String("1")), b.next().unwrap()); + assert_eq!( + ("type", AttributeValue::String("someType")), + b.next().unwrap() + ); + assert_eq!( + ( + "source", + AttributeValue::URIRef(&Url::parse(&"https://example.net".to_string()).unwrap()) + ), + b.next().unwrap() + ); + assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap()); + } } diff --git a/src/event/v03/builder.rs b/src/event/v03/builder.rs index 1997aa8e..2dfbc052 100644 --- a/src/event/v03/builder.rs +++ b/src/event/v03/builder.rs @@ -8,6 +8,10 @@ use chrono::{DateTime, Utc}; use std::collections::HashMap; use std::convert::TryInto; use std::prelude::v1::*; + +#[cfg(not(feature = "std"))] +use super::super::Url; +#[cfg(feature = "std")] use url::Url; /// Builder to create a CloudEvent V0.3 diff --git a/src/event/v03/format.rs b/src/event/v03/format.rs index 6691c92d..5c58200b 100644 --- a/src/event/v03/format.rs +++ b/src/event/v03/format.rs @@ -8,6 +8,10 @@ use serde::{Deserialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; use std::prelude::v1::*; + +#[cfg(not(feature = "std"))] +use super::super::{Url, UrlExtend}; +#[cfg(feature = "std")] use url::Url; pub(crate) struct EventFormatDeserializer {} diff --git a/src/event/v10/attributes.rs b/src/event/v10/attributes.rs index 9b109370..a8288bc3 100644 --- a/src/event/v10/attributes.rs +++ b/src/event/v10/attributes.rs @@ -6,10 +6,10 @@ use core::fmt::Debug; use std::prelude::v1::*; use uuid::Uuid; +#[cfg(not(feature = "std"))] +use crate::event::Url; #[cfg(feature = "std")] use url::Url; -#[cfg(not(feature = "std"))] -use String as Url; pub(crate) const ATTRIBUTE_NAMES: [&str; 8] = [ "specversion", @@ -240,8 +240,10 @@ impl AttributesConverter for Attributes { #[cfg(test)] mod tests { use super::*; + use crate::event::UrlExtend; use chrono::NaiveDateTime; + #[cfg(feature = "std")] #[test] fn iterator_test_v10() { let a = Attributes { @@ -277,4 +279,41 @@ mod tests { ); assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap()); } + + #[cfg(not(feature = "std"))] + #[test] + fn iterator_test_v10() { + let a = Attributes { + id: String::from("1"), + ty: String::from("someType"), + source: Url::parse(&"https://example.net".to_string()).unwrap(), + datacontenttype: None, + dataschema: None, + subject: None, + time: Some(DateTime::::from_utc( + NaiveDateTime::from_timestamp(61, 0), + Utc, + )), + }; + let b = &mut a.into_iter(); + let time = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); + + assert_eq!( + ("specversion", AttributeValue::SpecVersion(SpecVersion::V10)), + b.next().unwrap() + ); + assert_eq!(("id", AttributeValue::String("1")), b.next().unwrap()); + assert_eq!( + ("type", AttributeValue::String("someType")), + b.next().unwrap() + ); + assert_eq!( + ( + "source", + AttributeValue::URIRef(&Url::parse(&"https://example.net".to_string()).unwrap()) + ), + b.next().unwrap() + ); + assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap()); + } } diff --git a/src/event/v10/builder.rs b/src/event/v10/builder.rs index c1afed67..5f659f52 100644 --- a/src/event/v10/builder.rs +++ b/src/event/v10/builder.rs @@ -8,6 +8,10 @@ use chrono::{DateTime, Utc}; use std::collections::HashMap; use std::convert::TryInto; use std::prelude::v1::*; + +#[cfg(not(feature = "std"))] +use super::super::Url; +#[cfg(feature = "std")] use url::Url; /// Builder to create a CloudEvent V1.0 diff --git a/src/event/v10/format.rs b/src/event/v10/format.rs index c1b7c2e9..865235b0 100644 --- a/src/event/v10/format.rs +++ b/src/event/v10/format.rs @@ -8,6 +8,10 @@ use serde::{Deserialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; use std::prelude::v1::*; + +#[cfg(not(feature = "std"))] +use super::super::{Url, UrlExtend}; +#[cfg(feature = "std")] use url::Url; pub(crate) struct EventFormatDeserializer {} diff --git a/src/message/error.rs b/src/message/error.rs index 642c2320..7267d9a4 100644 --- a/src/message/error.rs +++ b/src/message/error.rs @@ -2,6 +2,11 @@ use core::fmt::{self, Debug, Display}; use snafu::Snafu; use std::prelude::v1::*; +#[cfg(feature = "std")] +use url; +#[cfg(not(feature = "std"))] +use String as url; + pub struct DisplayError(pub T); impl Debug for DisplayError @@ -47,12 +52,19 @@ pub enum Error { #[snafu(source(from(chrono::ParseError, DisplayError)))] source: DisplayError, }, + #[snafu(display("Error while parsing a url: {}", source))] #[snafu(context(false))] ParseUrlError { + #[cfg(not(feature = "std"))] + #[snafu(source(from(String, DisplayError)))] + source: DisplayError, + + #[cfg(feature = "std")] #[snafu(source(from(url::ParseError, DisplayError)))] source: DisplayError, }, + #[snafu(display("Error while decoding base64: {}", source))] #[snafu(context(false))] Base64DecodingError { diff --git a/src/message/no_std_io.rs b/src/message/hello_no_std_io.rs similarity index 100% rename from src/message/no_std_io.rs rename to src/message/hello_no_std_io.rs diff --git a/tests/attributes_iter.rs b/tests/attributes_iter.rs index d7d8c6e4..3c8aaad8 100644 --- a/tests/attributes_iter.rs +++ b/tests/attributes_iter.rs @@ -3,6 +3,7 @@ use cloudevents::event::AttributeValue; use cloudevents::event::SpecVersion; use test_data::*; +#[cfg(feature="std")] #[test] fn iter_v10_test() { let in_event = v10::full_no_data(); @@ -14,6 +15,7 @@ fn iter_v10_test() { ); } +#[cfg(feature="std")] #[test] fn iter_v03_test() { let in_event = v03::full_json_data(); diff --git a/tests/builder_v03.rs b/tests/builder_v03.rs index 6524aa9c..838e752e 100644 --- a/tests/builder_v03.rs +++ b/tests/builder_v03.rs @@ -7,8 +7,14 @@ use cloudevents::event::{ }; use cloudevents::EventBuilderV03; use std::convert::TryInto; + +use cloudevents::event::UrlExtend; +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; +#[cfg(feature = "std")] #[test] fn build_event() { let id = "aaa"; diff --git a/tests/builder_v10.rs b/tests/builder_v10.rs index 60f8bade..a6f7020d 100644 --- a/tests/builder_v10.rs +++ b/tests/builder_v10.rs @@ -7,8 +7,14 @@ use cloudevents::event::{ }; use cloudevents::EventBuilderV10; use std::convert::TryInto; + +use cloudevents::event::UrlExtend; +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; +#[cfg(feature = "std")] #[test] fn build_event() { let id = "aaa"; diff --git a/tests/message.rs b/tests/message.rs index 4bb3763a..a655747a 100644 --- a/tests/message.rs +++ b/tests/message.rs @@ -5,6 +5,7 @@ use cloudevents::{AttributesReader, EventBuilder, EventBuilderV03, EventBuilderV use std::convert::TryInto; use test_data::*; +#[cfg(feature="std")] #[test] fn message_v03_roundtrip_structured() -> Result<()> { assert_eq!( @@ -14,6 +15,7 @@ fn message_v03_roundtrip_structured() -> Result<()> { Ok(()) } +#[cfg(feature="std")] #[test] fn message_v03_roundtrip_binary() -> Result<()> { //TODO this code smells because we're missing a proper way in the public APIs @@ -33,6 +35,7 @@ fn message_v03_roundtrip_binary() -> Result<()> { Ok(()) } +#[cfg(feature="std")] #[test] fn message_v10_roundtrip_structured() -> Result<()> { assert_eq!( @@ -42,6 +45,7 @@ fn message_v10_roundtrip_structured() -> Result<()> { Ok(()) } +#[cfg(feature="std")] #[test] fn message_v10_roundtrip_binary() -> Result<()> { //TODO this code smells because we're missing a proper way in the public APIs diff --git a/tests/serde_json.rs b/tests/serde_json.rs index 14f01619..e126a018 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -7,6 +7,7 @@ mod test_data; use test_data::*; /// This test is a parametrized test that uses data from tests/test_data +#[cfg(feature="std")] #[rstest( in_event, out_json, @@ -53,6 +54,7 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { } /// This test is a parametrized test that uses data from tests/test_data +#[cfg(feature="std")] #[rstest( in_json, out_event, diff --git a/tests/test_data/v03.rs b/tests/test_data/v03.rs index 2ff1c665..121904ac 100644 --- a/tests/test_data/v03.rs +++ b/tests/test_data/v03.rs @@ -2,8 +2,13 @@ use super::*; use cloudevents::{Event, EventBuilder, EventBuilderV03}; use serde_json::{json, Value}; +use cloudevents::event::UrlExtend; +#[cfg(feature = "std")] use url::Url; +#[cfg(not(feature = "std"))] +use String as Url; +#[cfg(feature = "std")] pub fn minimal() -> Event { EventBuilderV03::new() .id(id()) @@ -22,6 +27,7 @@ pub fn minimal_json() -> Value { }) } +#[cfg(feature = "std")] pub fn full_no_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -58,6 +64,7 @@ pub fn full_no_data_json() -> Value { }) } +#[cfg(feature = "std")] pub fn full_json_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -124,6 +131,7 @@ pub fn full_json_base64_data_json() -> Value { }) } +#[cfg(feature = "std")] pub fn full_xml_string_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -143,6 +151,7 @@ pub fn full_xml_string_data() -> Event { .unwrap() } +#[cfg(feature = "std")] pub fn full_xml_binary_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); diff --git a/tests/test_data/v10.rs b/tests/test_data/v10.rs index a4faa9af..b59b0ff7 100644 --- a/tests/test_data/v10.rs +++ b/tests/test_data/v10.rs @@ -1,8 +1,14 @@ use super::*; use cloudevents::{Event, EventBuilder, EventBuilderV10}; use serde_json::{json, Value}; + +#[cfg(feature="std")] use url::Url; +#[cfg(not(feature="std"))] +use String as Url; +use cloudevents::event::UrlExtend; +#[cfg(feature="std")] pub fn minimal() -> Event { EventBuilderV10::new() .id(id()) @@ -21,6 +27,7 @@ pub fn minimal_json() -> Value { }) } +#[cfg(feature="std")] pub fn full_no_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -57,6 +64,7 @@ pub fn full_no_data_json() -> Value { }) } +#[cfg(feature="std")] pub fn full_json_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -122,6 +130,7 @@ pub fn full_json_base64_data_json() -> Value { }) } +#[cfg(feature="std")] pub fn full_xml_string_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -141,6 +150,7 @@ pub fn full_xml_string_data() -> Event { .unwrap() } +#[cfg(feature="std")] pub fn full_xml_binary_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); diff --git a/tests/version_conversion.rs b/tests/version_conversion.rs index bbbb29bb..e6782d09 100644 --- a/tests/version_conversion.rs +++ b/tests/version_conversion.rs @@ -3,6 +3,7 @@ use cloudevents::event::{EventBuilderV03, EventBuilderV10}; use cloudevents::EventBuilder; use test_data::*; +#[cfg(feature = "std")] #[test] fn v10_to_v03() { let in_event = v10::full_json_data(); @@ -10,6 +11,7 @@ fn v10_to_v03() { assert_eq!(v03::full_json_data(), out_event) } +#[cfg(feature = "std")] #[test] fn v03_to_v10() { let in_event = v03::full_json_data(); From aa7cfb12b06cbe83fddfa355bc39349fd9c1bf0a Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Mon, 4 Jan 2021 05:40:38 +0530 Subject: [PATCH 09/10] fixes#3 Signed-off-by: adpranavb2000@gmail.com --- src/event/mod.rs | 7 ++++++- src/lib.rs | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/event/mod.rs b/src/event/mod.rs index e8a8b24a..a39cd698 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -70,7 +70,12 @@ pub mod url { impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt(f) + if let ParseError::Error(v) = self { + Ok(()) + } + else{ + Err(fmt::Error{}) + } } } } diff --git a/src/lib.rs b/src/lib.rs index 69ab6616..555d014d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,6 @@ extern crate std; extern crate serde; extern crate serde_json; -extern crate serde_value; extern crate snafu; pub mod event; From 40d8f4fb7856553fbafaa717a6b6a9c2018d2cfe Mon Sep 17 00:00:00 2001 From: "adpranavb2000@gmail.com" Date: Tue, 26 Jan 2021 15:24:33 +0530 Subject: [PATCH 10/10] rebase + minor cleanup#1 Signed-off-by: adpranavb2000@gmail.com --- src/event/mod.rs | 5 ++--- src/event/spec_version.rs | 2 -- tests/attributes_iter.rs | 4 ++-- tests/message.rs | 8 ++++---- tests/serde_json.rs | 4 ++-- tests/test_data/v10.rs | 16 ++++++++-------- 6 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/event/mod.rs b/src/event/mod.rs index a39cd698..84522169 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -72,9 +72,8 @@ pub mod url { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let ParseError::Error(v) = self { Ok(()) - } - else{ - Err(fmt::Error{}) + } else { + Err(fmt::Error {}) } } } diff --git a/src/event/spec_version.rs b/src/event/spec_version.rs index 4579ea28..255ed2f6 100644 --- a/src/event/spec_version.rs +++ b/src/event/spec_version.rs @@ -1,6 +1,4 @@ use super::{v03, v10}; -use serde::export::Formatter; -use snafu::Snafu; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; diff --git a/tests/attributes_iter.rs b/tests/attributes_iter.rs index 3c8aaad8..5dee89c2 100644 --- a/tests/attributes_iter.rs +++ b/tests/attributes_iter.rs @@ -3,7 +3,7 @@ use cloudevents::event::AttributeValue; use cloudevents::event::SpecVersion; use test_data::*; -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn iter_v10_test() { let in_event = v10::full_no_data(); @@ -15,7 +15,7 @@ fn iter_v10_test() { ); } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn iter_v03_test() { let in_event = v03::full_json_data(); diff --git a/tests/message.rs b/tests/message.rs index a655747a..b278df39 100644 --- a/tests/message.rs +++ b/tests/message.rs @@ -5,7 +5,7 @@ use cloudevents::{AttributesReader, EventBuilder, EventBuilderV03, EventBuilderV use std::convert::TryInto; use test_data::*; -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn message_v03_roundtrip_structured() -> Result<()> { assert_eq!( @@ -15,7 +15,7 @@ fn message_v03_roundtrip_structured() -> Result<()> { Ok(()) } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn message_v03_roundtrip_binary() -> Result<()> { //TODO this code smells because we're missing a proper way in the public APIs @@ -35,7 +35,7 @@ fn message_v03_roundtrip_binary() -> Result<()> { Ok(()) } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn message_v10_roundtrip_structured() -> Result<()> { assert_eq!( @@ -45,7 +45,7 @@ fn message_v10_roundtrip_structured() -> Result<()> { Ok(()) } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn message_v10_roundtrip_binary() -> Result<()> { //TODO this code smells because we're missing a proper way in the public APIs diff --git a/tests/serde_json.rs b/tests/serde_json.rs index e126a018..d1877865 100644 --- a/tests/serde_json.rs +++ b/tests/serde_json.rs @@ -7,7 +7,7 @@ mod test_data; use test_data::*; /// This test is a parametrized test that uses data from tests/test_data -#[cfg(feature="std")] +#[cfg(feature = "std")] #[rstest( in_event, out_json, @@ -54,7 +54,7 @@ fn serialize_should_succeed(in_event: Event, out_json: Value) { } /// This test is a parametrized test that uses data from tests/test_data -#[cfg(feature="std")] +#[cfg(feature = "std")] #[rstest( in_json, out_event, diff --git a/tests/test_data/v10.rs b/tests/test_data/v10.rs index b59b0ff7..7a3693eb 100644 --- a/tests/test_data/v10.rs +++ b/tests/test_data/v10.rs @@ -2,13 +2,13 @@ use super::*; use cloudevents::{Event, EventBuilder, EventBuilderV10}; use serde_json::{json, Value}; -#[cfg(feature="std")] +use cloudevents::event::UrlExtend; +#[cfg(feature = "std")] use url::Url; -#[cfg(not(feature="std"))] +#[cfg(not(feature = "std"))] use String as Url; -use cloudevents::event::UrlExtend; -#[cfg(feature="std")] +#[cfg(feature = "std")] pub fn minimal() -> Event { EventBuilderV10::new() .id(id()) @@ -27,7 +27,7 @@ pub fn minimal_json() -> Value { }) } -#[cfg(feature="std")] +#[cfg(feature = "std")] pub fn full_no_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -64,7 +64,7 @@ pub fn full_no_data_json() -> Value { }) } -#[cfg(feature="std")] +#[cfg(feature = "std")] pub fn full_json_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -130,7 +130,7 @@ pub fn full_json_base64_data_json() -> Value { }) } -#[cfg(feature="std")] +#[cfg(feature = "std")] pub fn full_xml_string_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension(); @@ -150,7 +150,7 @@ pub fn full_xml_string_data() -> Event { .unwrap() } -#[cfg(feature="std")] +#[cfg(feature = "std")] pub fn full_xml_binary_data() -> Event { let (string_ext_name, string_ext_value) = string_extension(); let (bool_ext_name, bool_ext_value) = bool_extension();