Skip to content

Commit 304a2e7

Browse files
authored
Implementing an Iterator for the Attributes struct (cloudevents#26)
Signed-off-by: Pranav Bhatt <[email protected]>
1 parent a07d9a7 commit 304a2e7

File tree

3 files changed

+198
-4
lines changed

3 files changed

+198
-4
lines changed

src/event/attributes.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
use super::{AttributesV03, AttributesV10, SpecVersion};
22
use chrono::{DateTime, Utc};
3+
use std::fmt;
34
use url::Url;
45

6+
#[derive(Debug, PartialEq)]
7+
pub enum AttributeValue<'a> {
8+
SpecVersion(SpecVersion),
9+
String(&'a str),
10+
URI(&'a Url),
11+
URIRef(&'a Url),
12+
Time(&'a DateTime<Utc>),
13+
}
14+
15+
impl fmt::Display for AttributeValue<'_> {
16+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17+
match self {
18+
AttributeValue::SpecVersion(s) => s.fmt(f),
19+
AttributeValue::String(s) => f.write_str(s),
20+
AttributeValue::URI(s) => f.write_str(&s.as_str()),
21+
AttributeValue::URIRef(s) => f.write_str(&s.as_str()),
22+
AttributeValue::Time(s) => f.write_str(&s.to_rfc3339()),
23+
}
24+
}
25+
}
26+
527
/// Trait to get [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes).
628
pub trait AttributesReader {
729
/// Get the [id](https://github.com/cloudevents/spec/blob/master/spec.md#id).

src/event/v03/attributes.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use crate::event::attributes::{AttributesConverter, DataAttributesWriter};
1+
use crate::event::attributes::{AttributeValue, AttributesConverter, DataAttributesWriter};
22
use crate::event::AttributesV10;
33
use crate::event::{AttributesReader, AttributesWriter, SpecVersion};
4-
use chrono::{DateTime, Utc};
4+
use chrono::{DateTime, NaiveDateTime, Utc};
55
use hostname::get_hostname;
66
use url::Url;
77
use uuid::Uuid;
@@ -17,6 +17,60 @@ pub struct Attributes {
1717
pub(crate) time: Option<DateTime<Utc>>,
1818
}
1919

20+
impl<'a> IntoIterator for &'a Attributes {
21+
type Item = (&'a str, AttributeValue<'a>);
22+
type IntoIter = AttributesIntoIterator<'a>;
23+
24+
fn into_iter(self) -> Self::IntoIter {
25+
AttributesIntoIterator {
26+
attributes: self,
27+
index: 0,
28+
}
29+
}
30+
}
31+
32+
pub struct AttributesIntoIterator<'a> {
33+
attributes: &'a Attributes,
34+
index: usize,
35+
}
36+
37+
impl<'a> Iterator for AttributesIntoIterator<'a> {
38+
type Item = (&'a str, AttributeValue<'a>);
39+
fn next(&mut self) -> Option<Self::Item> {
40+
let result = match self.index {
41+
0 => Some(("id", AttributeValue::String(&self.attributes.id))),
42+
1 => Some(("type", AttributeValue::String(&self.attributes.ty))),
43+
2 => Some(("source", AttributeValue::URIRef(&self.attributes.source))),
44+
3 => self
45+
.attributes
46+
.datacontenttype
47+
.as_ref()
48+
.map(|v| ("datacontenttype", AttributeValue::String(v))),
49+
4 => self
50+
.attributes
51+
.schemaurl
52+
.as_ref()
53+
.map(|v| ("schemaurl", AttributeValue::URIRef(v))),
54+
5 => self
55+
.attributes
56+
.subject
57+
.as_ref()
58+
.map(|v| ("subject", AttributeValue::String(v))),
59+
6 => self
60+
.attributes
61+
.time
62+
.as_ref()
63+
.map(|v| ("time", AttributeValue::Time(v))),
64+
_ => return None,
65+
};
66+
self.index += 1;
67+
if result.is_none() {
68+
return self.next();
69+
}
70+
result
71+
}
72+
}
73+
2074
impl AttributesReader for Attributes {
2175
fn get_id(&self) -> &str {
2276
&self.id
@@ -121,3 +175,35 @@ impl AttributesConverter for Attributes {
121175
}
122176
}
123177
}
178+
179+
#[test]
180+
fn iterator_test_V03() {
181+
let a = Attributes {
182+
id: String::from("1"),
183+
ty: String::from("someType"),
184+
source: Url::parse("https://example.net").unwrap(),
185+
datacontenttype: None,
186+
schemaurl: None,
187+
subject: None,
188+
time: Some(DateTime::<Utc>::from_utc(
189+
NaiveDateTime::from_timestamp(61, 0),
190+
Utc,
191+
)),
192+
};
193+
let b = &mut a.into_iter();
194+
let time = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
195+
196+
assert_eq!(("id", AttributeValue::String("1")), b.next().unwrap());
197+
assert_eq!(
198+
("type", AttributeValue::String("someType")),
199+
b.next().unwrap()
200+
);
201+
assert_eq!(
202+
(
203+
"source",
204+
AttributeValue::URIRef(&Url::parse("https://example.net").unwrap())
205+
),
206+
b.next().unwrap()
207+
);
208+
assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap());
209+
}

src/event/v10/attributes.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::event::attributes::{AttributesConverter, DataAttributesWriter};
1+
use crate::event::attributes::{AttributeValue, AttributesConverter, DataAttributesWriter};
22
use crate::event::{AttributesReader, AttributesV03, AttributesWriter, SpecVersion};
3-
use chrono::{DateTime, Utc};
3+
use chrono::{DateTime, NaiveDateTime, Utc};
44
use hostname::get_hostname;
55
use url::Url;
66
use uuid::Uuid;
@@ -16,6 +16,60 @@ pub struct Attributes {
1616
pub(crate) time: Option<DateTime<Utc>>,
1717
}
1818

19+
impl<'a> IntoIterator for &'a Attributes {
20+
type Item = (&'a str, AttributeValue<'a>);
21+
type IntoIter = AttributesIntoIterator<'a>;
22+
23+
fn into_iter(self) -> Self::IntoIter {
24+
AttributesIntoIterator {
25+
attributes: self,
26+
index: 0,
27+
}
28+
}
29+
}
30+
31+
pub struct AttributesIntoIterator<'a> {
32+
attributes: &'a Attributes,
33+
index: usize,
34+
}
35+
36+
impl<'a> Iterator for AttributesIntoIterator<'a> {
37+
type Item = (&'a str, AttributeValue<'a>);
38+
fn next(&mut self) -> Option<Self::Item> {
39+
let result = match self.index {
40+
0 => Some(("id", AttributeValue::String(&self.attributes.id))),
41+
1 => Some(("type", AttributeValue::String(&self.attributes.ty))),
42+
2 => Some(("source", AttributeValue::URIRef(&self.attributes.source))),
43+
3 => self
44+
.attributes
45+
.datacontenttype
46+
.as_ref()
47+
.map(|v| ("datacontenttype", AttributeValue::String(v))),
48+
4 => self
49+
.attributes
50+
.dataschema
51+
.as_ref()
52+
.map(|v| ("dataschema", AttributeValue::URI(v))),
53+
5 => self
54+
.attributes
55+
.subject
56+
.as_ref()
57+
.map(|v| ("subject", AttributeValue::String(v))),
58+
6 => self
59+
.attributes
60+
.time
61+
.as_ref()
62+
.map(|v| ("time", AttributeValue::Time(v))),
63+
_ => return None,
64+
};
65+
self.index += 1;
66+
if result.is_none() {
67+
return self.next();
68+
}
69+
result
70+
}
71+
}
72+
1973
impl AttributesReader for Attributes {
2074
fn get_id(&self) -> &str {
2175
&self.id
@@ -120,3 +174,35 @@ impl AttributesConverter for Attributes {
120174
}
121175
}
122176
}
177+
178+
#[test]
179+
fn iterator_test_V10() {
180+
let a = Attributes {
181+
id: String::from("1"),
182+
ty: String::from("someType"),
183+
source: Url::parse("https://example.net").unwrap(),
184+
datacontenttype: None,
185+
dataschema: None,
186+
subject: None,
187+
time: Some(DateTime::<Utc>::from_utc(
188+
NaiveDateTime::from_timestamp(61, 0),
189+
Utc,
190+
)),
191+
};
192+
let b = &mut a.into_iter();
193+
let time = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
194+
195+
assert_eq!(("id", AttributeValue::String("1")), b.next().unwrap());
196+
assert_eq!(
197+
("type", AttributeValue::String("someType")),
198+
b.next().unwrap()
199+
);
200+
assert_eq!(
201+
(
202+
"source",
203+
AttributeValue::URIRef(&Url::parse("https://example.net").unwrap())
204+
),
205+
b.next().unwrap()
206+
);
207+
assert_eq!(("time", AttributeValue::Time(&time)), b.next().unwrap());
208+
}

0 commit comments

Comments
 (0)