1use crate::{trace_header, ParseError, ParseResult, THREAD_RECORD_TYPE};
6use nom::combinator::all_consuming;
7use nom::number::complete::le_u64;
8use nom::Parser;
9use std::num::NonZeroU8;
10
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
12pub struct ProcessKoid(pub u64);
13
14impl From<u64> for ProcessKoid {
15 fn from(n: u64) -> Self {
16 Self(n)
17 }
18}
19
20impl PartialEq<u64> for ProcessKoid {
21 fn eq(&self, other: &u64) -> bool {
22 self.0.eq(other)
23 }
24}
25
26impl std::fmt::Display for ProcessKoid {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(f, "{}", self.0)
29 }
30}
31
32#[derive(Clone, Debug, PartialEq)]
33pub enum ProcessRef {
34 Index(NonZeroU8),
35 Inline(ProcessKoid),
36}
37
38impl ProcessRef {
39 pub(crate) fn parse<'a>(thread_ref: u8, buf: &'a [u8]) -> ParseResult<'a, Self> {
40 Ok(if let Some(index) = NonZeroU8::new(thread_ref) {
41 (buf, Self::Index(index))
42 } else {
43 let (buf, koid) = le_u64(buf)?;
44 (buf, Self::Inline(ProcessKoid(koid)))
45 })
46 }
47}
48
49#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
50pub struct ThreadKoid(pub u64);
51
52impl From<u64> for ThreadKoid {
53 fn from(n: u64) -> Self {
54 Self(n)
55 }
56}
57
58impl PartialEq<u64> for ThreadKoid {
59 fn eq(&self, other: &u64) -> bool {
60 self.0.eq(other)
61 }
62}
63
64impl std::fmt::Display for ThreadKoid {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 write!(f, "{}", self.0)
67 }
68}
69
70#[derive(Clone, Debug, PartialEq)]
71pub enum ThreadRef {
72 Index(NonZeroU8),
73 Inline(ThreadKoid),
74}
75
76impl ThreadRef {
77 pub(crate) fn parse<'a>(thread_ref: u8, buf: &'a [u8]) -> ParseResult<'a, Self> {
78 Ok(if let Some(index) = NonZeroU8::new(thread_ref) {
79 (buf, Self::Index(index))
80 } else {
81 let (buf, koid) = le_u64(buf)?;
82 (buf, Self::Inline(ThreadKoid(koid)))
83 })
84 }
85}
86
87#[derive(Debug, PartialEq)]
88pub(crate) struct ThreadRecord {
89 pub index: NonZeroU8,
90 pub process_koid: ProcessKoid,
91 pub thread_koid: ThreadKoid,
92}
93
94impl ThreadRecord {
95 pub(super) fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
96 let (buf, header) = ThreadHeader::parse(buf)?;
97 let (rem, payload) = header.take_payload(buf)?;
98 let (payload, process_koid) = nom::combinator::map(le_u64, ProcessKoid).parse(payload)?;
99 let (empty, thread_koid) =
100 all_consuming(nom::combinator::map(le_u64, ThreadKoid)).parse(payload)?;
101 assert!(empty.is_empty(), "all_consuming must not return any remaining buffer");
102 let index =
103 NonZeroU8::new(header.thread_index()).ok_or(nom::Err::Error(ParseError::InvalidRef))?;
104 Ok((rem, Self { index, process_koid, thread_koid }))
105 }
106}
107
108trace_header! {
109 ThreadHeader (THREAD_RECORD_TYPE) {
110 u8, thread_index: 16, 23;
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::RawTraceRecord;
118
119 #[test]
120 fn process_ref_index() {
121 let (trailing, parsed) = ProcessRef::parse(11, &[1, 1, 1, 1]).unwrap();
122 assert_eq!(parsed, ProcessRef::Index(NonZeroU8::new(11).unwrap()));
123 assert_eq!(trailing, [1, 1, 1, 1],);
124 }
125
126 #[test]
127 fn process_ref_inline() {
128 let mut buf = 52u64.to_le_bytes().to_vec(); buf.extend([1, 1, 1, 1]); let (trailing, parsed) = ProcessRef::parse(0, &buf).unwrap();
132 assert_eq!(parsed, ProcessRef::Inline(ProcessKoid(52)));
133 assert_eq!(trailing, [1, 1, 1, 1]);
134 }
135
136 #[test]
137 fn thread_ref_index() {
138 let (trailing, parsed) = ThreadRef::parse(14, &[1, 1, 1, 1]).unwrap();
139 assert_eq!(parsed, ThreadRef::Index(NonZeroU8::new(14).unwrap()));
140 assert_eq!(trailing, [1, 1, 1, 1]);
141 }
142
143 #[test]
144 fn thread_ref_inline() {
145 let mut buf = 54u64.to_le_bytes().to_vec(); buf.extend([1, 1, 1, 1]); let (trailing, parsed) = ThreadRef::parse(0, &buf).unwrap();
149 assert_eq!(parsed, ThreadRef::Inline(ThreadKoid(54)));
150 assert_eq!(trailing, [1, 1, 1, 1]);
151 }
152
153 #[test]
154 fn thread_record() {
155 let mut header = ThreadHeader::empty();
156 header.set_thread_index(10);
157 header.set_size_words(3); let mut buf = header.0.to_le_bytes().to_vec(); buf.extend(52u64.to_le_bytes()); buf.extend(54u64.to_le_bytes()); buf.extend([1, 1, 1, 1]); let (trailing, parsed) = RawTraceRecord::parse(&buf).unwrap();
165 assert_eq!(
166 parsed.parsed,
167 RawTraceRecord::Thread(ThreadRecord {
168 index: NonZeroU8::new(10).unwrap(),
169 process_koid: ProcessKoid(52),
170 thread_koid: ThreadKoid(54)
171 })
172 );
173 assert_eq!(trailing, [1, 1, 1, 1]);
174 }
175}