modality_trace_recorder_plugin/
deviant_event_parser.rs1use crate::trace_recorder::Error;
2use byteordered::ByteOrdered;
3use modality_api::AttrVal;
4use std::io::Read;
5use trace_recorder_parser::{
6 streaming::event::{BaseEvent, EventId},
7 types::Endianness,
8};
9use uuid::Uuid;
10
11#[derive(Debug)]
12pub struct DeviantEventParser {
13 endianness: Endianness,
14 base_event_id: EventId,
15 uuid_bytes: [u8; 16],
16 scratch: Vec<u8>,
17}
18
19impl DeviantEventParser {
20 const MUTATOR_ANNOUNCED_OFFSET: u16 = 0;
22 const MUTATOR_RETIRED_OFFSET: u16 = 1;
23 const MUTATION_CMD_COMM_OFFSET: u16 = 2;
24 const MUTATION_CLR_COMM_OFFSET: u16 = 3;
25 const MUTATION_TRIGGERED_OFFSET: u16 = 4;
26 const MUTATION_INJECTED_OFFSET: u16 = 5;
27
28 pub fn new(endianness: Endianness, base_event_id: EventId) -> Result<Self, Error> {
29 if base_event_id.0 > 0x0F_FF {
30 Err(Error::DeviantEvent(format!(
31 "The deviant custom event base ID {} exceeds the max",
32 base_event_id
33 )))
34 } else {
35 Ok(Self {
36 endianness,
37 base_event_id,
38 uuid_bytes: [0; 16],
39 scratch: Vec::with_capacity(64),
40 })
41 }
42 }
43
44 pub fn parse(&mut self, event: &BaseEvent) -> Result<Option<DeviantEvent>, Error> {
46 let kind = match DeviantEventKind::from_base_event(self.base_event_id, event) {
47 Some(k) => k,
48 None => return Ok(None),
49 };
50 let params = event.parameters();
51 self.scratch.clear();
52 for p in params {
53 self.scratch.extend_from_slice(&p.to_le_bytes());
54 }
55
56 if self.scratch.len() != kind.expected_parameter_byte_count() {
57 return Err(Error::DeviantEvent(format!(
58 "The event {} ({}) has an incorrect number of parameter bytes ({}), expected {}",
59 event.code,
60 kind.to_modality_name(),
61 self.scratch.len(),
62 kind.expected_parameter_byte_count(),
63 )));
64 }
65
66 let mut r = ByteOrdered::new(
67 self.scratch.as_slice(),
68 byteordered::Endianness::from(self.endianness),
69 );
70
71 r.read_exact(&mut self.uuid_bytes)?;
72 let mutator_uuid = Uuid::from_bytes(self.uuid_bytes);
73
74 let mut deviant_event = DeviantEvent {
75 kind,
76 mutator_id: (mutator_uuid, uuid_to_integer_attr_val(&mutator_uuid)),
77 mutation_id: None,
78 mutation_success: None,
79 };
80
81 match kind {
82 DeviantEventKind::MutatorAnnounced | DeviantEventKind::MutatorRetired => (),
83 _ => {
84 r.read_exact(&mut self.uuid_bytes)?;
85 let mutation_uuid = Uuid::from_bytes(self.uuid_bytes);
86 let mutation_success = r.read_u32()?;
87 deviant_event.mutation_id =
88 Some((mutation_uuid, uuid_to_integer_attr_val(&mutation_uuid)));
89 deviant_event.mutation_success = Some((mutation_success != 0).into());
90 }
91 }
92
93 Ok(Some(deviant_event))
94 }
95}
96
97#[derive(Clone, Debug)]
98pub struct DeviantEvent {
99 pub kind: DeviantEventKind,
100 pub mutator_id: (Uuid, AttrVal),
101 pub mutation_id: Option<(Uuid, AttrVal)>,
102 pub mutation_success: Option<AttrVal>,
103}
104
105#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
106pub enum DeviantEventKind {
107 MutatorAnnounced,
108 MutatorRetired,
109 MutationCmdCommunicated,
110 MutationClearCommunicated,
111 MutationTriggered,
112 MutationInjected,
113}
114
115impl DeviantEventKind {
116 pub const fn to_modality_name(self) -> &'static str {
117 use DeviantEventKind::*;
118 match self {
119 MutatorAnnounced => "modality.mutator.announced",
120 MutatorRetired => "modality.mutator.retired",
121 MutationCmdCommunicated => "modality.mutation.command_communicated",
122 MutationClearCommunicated => "modality.mutation.clear_communicated",
123 MutationTriggered => "modality.mutation.triggered",
124 MutationInjected => "modality.mutation.injected",
125 }
126 }
127
128 const fn expected_parameter_byte_count(self) -> usize {
129 use DeviantEventKind::*;
130 match self {
131 MutatorAnnounced | MutatorRetired => 16, _ => 16 + 16 + 4, }
134 }
135
136 fn from_base_event(base_event_id: EventId, event: &BaseEvent) -> Option<Self> {
137 use DeviantEventKind::*;
138
139 if event.code.event_id().0 >= base_event_id.0 {
140 let offset = event.code.event_id().0 - base_event_id.0;
141 Some(match offset {
142 DeviantEventParser::MUTATOR_ANNOUNCED_OFFSET => MutatorAnnounced,
143 DeviantEventParser::MUTATOR_RETIRED_OFFSET => MutatorRetired,
144 DeviantEventParser::MUTATION_CMD_COMM_OFFSET => MutationCmdCommunicated,
145 DeviantEventParser::MUTATION_CLR_COMM_OFFSET => MutationClearCommunicated,
146 DeviantEventParser::MUTATION_TRIGGERED_OFFSET => MutationTriggered,
147 DeviantEventParser::MUTATION_INJECTED_OFFSET => MutationInjected,
148 _ => return None,
149 })
150 } else {
151 None
152 }
153 }
154}
155
156fn uuid_to_integer_attr_val(u: &Uuid) -> AttrVal {
157 i128::from_le_bytes(*u.as_bytes()).into()
158}