use std::{error::Error, fmt};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Event {
id_nodes: Vec<String>,
event_type: EventType,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum EventType {
Platform, Internal, External, }
#[derive(Debug, PartialEq)]
pub enum EventError {
IdContainsDuplicates(String),
IdNodeIsEmpty(String, usize),
}
impl Event {
pub fn from(source_str: &str) -> Result<Self, EventError> {
let source_nodes: Vec<&str> = source_str.split('.').collect();
for (idx, node) in source_nodes.iter().enumerate() {
if node.is_empty() {
return Err(EventError::IdNodeIsEmpty(String::from(source_str), idx));
}
}
let mut deduped_nodes = source_nodes.clone();
deduped_nodes.sort_unstable();
deduped_nodes.dedup();
if source_nodes.len() != deduped_nodes.len() {
return Err(EventError::IdContainsDuplicates(String::from(source_str)));
}
let mut composed_nodes = Vec::new();
for node in source_nodes.iter() {
composed_nodes.push(String::from(*node));
}
Ok(Self {
id_nodes: composed_nodes,
event_type: EventType::Platform,
})
}
pub fn id(&self) -> String {
let mut composed_id = String::new();
for node in &self.id_nodes {
composed_id.push_str(node);
composed_id.push('.');
}
composed_id.pop();
composed_id
}
}
impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut id_node_iter = self.id_nodes.iter().peekable();
while let Some(id_node) = id_node_iter.next() {
write!(f, "{}", id_node)?;
if id_node_iter.peek().is_some() {
write!(f, ".")?;
}
}
Ok(())
}
}
impl Error for EventError {}
impl fmt::Display for EventError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::IdContainsDuplicates(source) => {
write!(f, "source string '{}' contains duplicate ID nodes", source)
}
Self::IdNodeIsEmpty(source, node_idx) => {
write!(
f,
"source string '{}' node index {} is empty",
source, node_idx
)
}
}
}
}
#[cfg(test)]
mod tests {
use std::error::Error;
use crate::event::{Event, EventError};
type TestResult = Result<(), Box<dyn Error>>;
#[test]
fn id_contains_duplicates() -> TestResult {
let valid_string = "error.send.failed";
let invalid_string = "error.send.error";
assert_eq!(
Event::from(valid_string).is_ok(),
true,
"Failed to parse a valid event descriptor"
);
assert_eq!(
Event::from(invalid_string),
Err(EventError::IdContainsDuplicates(String::from(
invalid_string
))),
"Failed to reject invalid event descriptor"
);
Ok(())
}
#[test]
fn empty_node() -> TestResult {
let empty_node = "this.has.an..empty.node";
assert_eq!(
Event::from(empty_node),
Err(EventError::IdNodeIsEmpty(String::from(empty_node), 3)),
"Failed to catch empty node"
);
Ok(())
}
#[test]
fn output() -> TestResult {
let source = "error.send.failed";
let event = Event::from(source)?;
println!("Event ID: '{}'", event);
assert_eq!(
source,
format!("{}", event),
"Formatted Event does not match source string"
);
Ok(())
}
}