Skip to main content

wasm4pm_compat/
event_log.rs

1//! Serde-facing event-log import shapes (the `event_log` spelling).
2//!
3//! ## What this module IS
4//!
5//! - Concrete, serializable event/log structs used when *importing* external
6//!   logs (timestamps as `chrono` types, attributes as plain fields).
7//!
8//! ## What this module is **NOT**
9//!
10//! - **Not** the typed canon surface. The builder-ergonomic, engine-graduating
11//!   shapes live in [`crate::eventlog`]; this module is the wire/import shape.
12//! - **Not** an engine. It parses structure; it mines nothing.
13//!
14//! Structure only. Graduate to `wasm4pm` for any analysis over these logs.
15
16use chrono::{DateTime, FixedOffset};
17use serde::{Deserialize, Serialize};
18use uuid::Uuid;
19
20/// Possible attribute values according to the XES Standard
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22#[serde(tag = "type", content = "content")]
23pub enum AttributeValue {
24    String(String),
25    Date(DateTime<FixedOffset>),
26    Int(i64),
27    Float(f64),
28    Boolean(bool),
29    ID(Uuid),
30    List(Vec<Attribute>),
31    Container(Vec<Attribute>),
32    None(),
33}
34
35impl AttributeValue {
36    pub fn as_string(&self) -> Option<&str> {
37        match self {
38            AttributeValue::String(s) => Some(s.as_str()),
39            _ => None,
40        }
41    }
42
43    pub fn as_i64(&self) -> Option<i64> {
44        match self {
45            AttributeValue::Int(i) => Some(*i),
46            _ => None,
47        }
48    }
49
50    pub fn as_f64(&self) -> Option<f64> {
51        match self {
52            AttributeValue::Float(f) => Some(*f),
53            _ => None,
54        }
55    }
56
57    pub fn as_bool(&self) -> Option<bool> {
58        match self {
59            AttributeValue::Boolean(b) => Some(*b),
60            _ => None,
61        }
62    }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66pub struct Attribute {
67    pub key: String,
68    pub value: AttributeValue,
69    pub own_attributes: Option<Vec<Attribute>>,
70}
71
72impl Attribute {
73    pub fn new(key: String, value: AttributeValue) -> Self {
74        Attribute {
75            key,
76            value,
77            own_attributes: None,
78        }
79    }
80}
81
82pub type Attributes = Vec<Attribute>;
83
84pub trait XESEditableAttribute {
85    fn add_to_attributes(&mut self, key: String, value: AttributeValue);
86    fn add_attribute(&mut self, attr: Attribute);
87    fn get_by_key(&self, key: &str) -> Option<&Attribute>;
88    fn get_by_key_mut(&mut self, key: &str) -> Option<&mut Attribute>;
89}
90
91impl XESEditableAttribute for Attributes {
92    fn add_to_attributes(&mut self, key: String, value: AttributeValue) {
93        self.push(Attribute::new(key, value));
94    }
95
96    fn add_attribute(&mut self, attr: Attribute) {
97        self.push(attr);
98    }
99
100    fn get_by_key(&self, key: &str) -> Option<&Attribute> {
101        self.iter().find(|a| a.key == key)
102    }
103
104    fn get_by_key_mut(&mut self, key: &str) -> Option<&mut Attribute> {
105        self.iter_mut().find(|a| a.key == key)
106    }
107}
108
109/// A single event in a trace
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
111pub struct Event {
112    pub attributes: Attributes,
113}
114
115impl Event {
116    pub fn new(attributes: Attributes) -> Self {
117        Event { attributes }
118    }
119
120    pub fn with_activity(activity: &str) -> Self {
121        let mut attributes = Vec::new();
122        attributes.add_to_attributes(
123            "concept:name".to_string(),
124            AttributeValue::String(activity.to_string()),
125        );
126        Event { attributes }
127    }
128
129    pub fn get_activity(&self, key: &str) -> Option<String> {
130        self.attributes
131            .get_by_key(key)
132            .and_then(|a| a.value.as_string().map(|s| s.to_string()))
133    }
134}
135
136/// A trace (sequence of events for one case)
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
138pub struct Trace {
139    pub attributes: Attributes,
140    pub events: Vec<Event>,
141}
142
143impl Trace {
144    pub fn new(case_id: String, events: Vec<Event>) -> Self {
145        let mut attributes = Vec::new();
146        attributes.add_to_attributes("concept:name".to_string(), AttributeValue::String(case_id));
147        Trace { attributes, events }
148    }
149
150    pub fn len(&self) -> usize {
151        self.events.len()
152    }
153
154    pub fn is_empty(&self) -> bool {
155        self.events.is_empty()
156    }
157}
158
159/// An event log (collection of traces)
160#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
161pub struct EventLog {
162    pub attributes: Attributes,
163    pub traces: Vec<Trace>,
164    pub extensions: Option<Vec<EventLogExtension>>,
165    pub classifiers: Option<Vec<EventLogClassifier>>,
166    pub global_trace_attrs: Option<Attributes>,
167    pub global_event_attrs: Option<Attributes>,
168}
169
170impl EventLog {
171    pub fn new(traces: Vec<Trace>, attributes: Attributes) -> Self {
172        EventLog {
173            traces,
174            attributes,
175            ..Default::default()
176        }
177    }
178
179    pub fn len(&self) -> usize {
180        self.traces.len()
181    }
182
183    pub fn is_empty(&self) -> bool {
184        self.traces.is_empty()
185    }
186
187    pub fn event_count(&self) -> usize {
188        self.traces.iter().map(|t| t.len()).sum()
189    }
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
193pub struct EventLogExtension {
194    pub name: String,
195    pub prefix: String,
196    pub uri: String,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
200pub struct EventLogClassifier {
201    pub name: String,
202    pub keys: Vec<String>,
203}