modality_trace_recorder_plugin/
deviant_event_parser.rs

1use 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    // Event ID offsets from the base
21    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    /// Returns true if the event was a deviant custom event
45    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, // UUID
132            _ => 16 + 16 + 4,                        // UUID, UUID, u32
133        }
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}