1use crate::error::ParseError;
2use crate::prelude::*;
3use std::borrow::Cow;
4use std::fmt;
5use std::iter::FusedIterator;
6
7#[derive(Clone, Debug)]
16pub struct Read {
17 pub pid: u32,
19
20 pub tid: u32,
22
23 pub values: ReadValue,
25}
26
27#[derive(Clone)]
29pub struct ReadValue {
30 read_format: ReadFormat,
31 value: u64,
32 time_enabled: u64,
33 time_running: u64,
34 id: u64,
35 lost: u64,
36}
37
38impl ReadValue {
39 pub fn from_group_and_entry(group: &ReadGroup<'_>, entry: &GroupEntry) -> Self {
41 Self {
42 read_format: group.read_format - ReadFormat::GROUP,
43 value: entry.value,
44 time_enabled: group.time_enabled,
45 time_running: group.time_running,
46 id: entry.id,
47 lost: entry.lost,
48 }
49 }
50
51 pub fn value(&self) -> u64 {
53 self.value
54 }
55
56 pub fn time_enabled(&self) -> Option<u64> {
58 self.read_format
59 .contains(ReadFormat::TOTAL_TIME_ENABLED)
60 .then_some(self.time_enabled)
61 }
62
63 pub fn time_running(&self) -> Option<u64> {
68 self.read_format
69 .contains(ReadFormat::TOTAL_TIME_RUNNING)
70 .then_some(self.time_running)
71 }
72
73 pub fn id(&self) -> Option<u64> {
75 self.read_format.contains(ReadFormat::ID).then_some(self.id)
76 }
77
78 pub fn lost(&self) -> Option<u64> {
80 self.read_format
81 .contains(ReadFormat::LOST)
82 .then_some(self.lost)
83 }
84}
85
86impl TryFrom<ReadGroup<'_>> for ReadValue {
87 type Error = TryFromGroupError;
88
89 fn try_from(value: ReadGroup<'_>) -> Result<Self, Self::Error> {
90 let mut entries = value.entries();
91 let entry = entries.next().ok_or(TryFromGroupError(()))?;
92
93 if entries.next().is_some() {
94 return Err(TryFromGroupError(()));
95 }
96
97 Ok(Self {
98 read_format: value.read_format - ReadFormat::GROUP,
99 value: entry.value(),
100 time_enabled: value.time_enabled,
101 time_running: value.time_running,
102 id: entry.id,
103 lost: entry.lost,
104 })
105 }
106}
107
108impl fmt::Debug for ReadValue {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 let read_format = self.read_format;
111 let mut dbg = debug_if! {
112 f.debug_struct("SingleRead") => {
113 value => self.value,
114 time_enabled if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) => self.time_enabled,
115 time_running if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) => self.time_running,
116 id if read_format.contains(ReadFormat::ID) => self.id,
117 lost if read_format.contains(ReadFormat::LOST) => self.lost,
118
119 }
120 };
121
122 dbg.finish_non_exhaustive()
123 }
124}
125
126#[derive(Clone)]
128pub struct ReadGroup<'a> {
129 read_format: ReadFormat,
130 time_enabled: u64,
131 time_running: u64,
132 data: Cow<'a, [u64]>,
133}
134
135impl<'a> ReadGroup<'a> {
136 pub fn len(&self) -> usize {
138 self.entries().count()
139 }
140
141 pub fn is_empty(&self) -> bool {
143 self.len() == 0
144 }
145
146 pub fn into_owned(self) -> ReadGroup<'static> {
148 ReadGroup {
149 data: self.data.into_owned().into(),
150 ..self
151 }
152 }
153
154 pub fn time_enabled(&self) -> Option<u64> {
156 self.read_format
157 .contains(ReadFormat::TOTAL_TIME_ENABLED)
158 .then_some(self.time_enabled)
159 }
160
161 pub fn time_running(&self) -> Option<u64> {
166 self.read_format
167 .contains(ReadFormat::TOTAL_TIME_RUNNING)
168 .then_some(self.time_running)
169 }
170
171 pub fn get(&self, index: usize) -> Option<GroupEntry> {
173 self.entries().nth(index)
174 }
175
176 pub fn get_by_id(&self, id: u64) -> Option<GroupEntry> {
178 if !self.read_format.contains(ReadFormat::ID) {
179 return None;
180 }
181
182 self.entries().find(|entry| entry.id() == Some(id))
183 }
184
185 pub fn entries(&self) -> GroupIter {
187 GroupIter::new(self)
188 }
189}
190
191impl<'a> From<ReadValue> for ReadGroup<'a> {
192 fn from(value: ReadValue) -> Self {
193 let mut data = Vec::with_capacity(3);
194 data.push(value.value());
195 data.extend(value.id());
196 data.extend(value.lost());
197
198 Self {
199 read_format: value.read_format | ReadFormat::GROUP,
200 time_enabled: value.time_enabled,
201 time_running: value.time_running,
202 data: Cow::Owned(data),
203 }
204 }
205}
206
207impl fmt::Debug for ReadGroup<'_> {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 struct Entries<'a>(GroupIter<'a>);
210
211 impl fmt::Debug for Entries<'_> {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 f.debug_list().entries(self.0.clone()).finish()
214 }
215 }
216
217 let read_format = self.read_format;
218 let mut dbg = debug_if! {
219 f.debug_struct("GroupRead") => {
220 time_enabled if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) => self.time_enabled,
221 time_running if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) => self.time_running,
222 entries => Entries(self.entries()),
223 }
224 };
225
226 dbg.finish_non_exhaustive()
227 }
228}
229
230#[derive(Copy, Clone)]
235pub struct GroupEntry {
236 read_format: ReadFormat,
237 value: u64,
238 id: u64,
239 lost: u64,
240}
241
242impl GroupEntry {
243 pub fn value(&self) -> u64 {
245 self.value
246 }
247
248 pub fn id(&self) -> Option<u64> {
250 self.read_format.contains(ReadFormat::ID).then_some(self.id)
251 }
252
253 pub fn lost(&self) -> Option<u64> {
255 self.read_format
256 .contains(ReadFormat::LOST)
257 .then_some(self.lost)
258 }
259
260 fn new(config: ReadFormat, slice: &[u64]) -> Self {
261 let mut iter = slice.iter().copied();
262 let mut read = || {
263 iter.next()
264 .expect("slice was not the correct size for the configured read_format")
265 };
266
267 Self {
268 read_format: config,
269 value: read(),
270 id: config.contains(ReadFormat::ID).then(&mut read).unwrap_or(0),
271 lost: config
272 .contains(ReadFormat::LOST)
273 .then(&mut read)
274 .unwrap_or(0),
275 }
276 }
277}
278
279impl fmt::Debug for GroupEntry {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 let read_format = self.read_format;
282
283 let mut dbg = debug_if! {
284 f.debug_struct("GroupEntry") => {
285 value => self.value(),
286 id if read_format.contains(ReadFormat::ID) => self.id,
287 lost if read_format.contains(ReadFormat::LOST) => self.lost,
288 }
289 };
290
291 dbg.finish_non_exhaustive()
292 }
293}
294
295#[derive(Clone)]
299pub struct GroupIter<'a> {
300 iter: std::slice::ChunksExact<'a, u64>,
301 read_format: ReadFormat,
302}
303
304impl<'a> GroupIter<'a> {
305 fn new(group: &'a ReadGroup) -> Self {
306 let read_format = group.read_format;
307
308 Self {
309 iter: group.data.chunks_exact(read_format.element_len()),
310 read_format,
311 }
312 }
313}
314
315impl<'a> Iterator for GroupIter<'a> {
316 type Item = GroupEntry;
317
318 fn next(&mut self) -> Option<Self::Item> {
319 Some(GroupEntry::new(self.read_format, self.iter.next()?))
320 }
321
322 fn size_hint(&self) -> (usize, Option<usize>) {
323 self.iter.size_hint()
324 }
325
326 fn count(self) -> usize {
327 self.iter.count()
328 }
329
330 fn nth(&mut self, n: usize) -> Option<Self::Item> {
331 Some(GroupEntry::new(self.read_format, self.iter.nth(n)?))
332 }
333
334 fn last(self) -> Option<Self::Item> {
335 Some(GroupEntry::new(self.read_format, self.iter.last()?))
336 }
337}
338
339impl<'a> DoubleEndedIterator for GroupIter<'a> {
340 fn next_back(&mut self) -> Option<Self::Item> {
341 Some(GroupEntry::new(self.read_format, self.iter.next_back()?))
342 }
343
344 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
345 Some(GroupEntry::new(self.read_format, self.iter.nth_back(n)?))
346 }
347}
348
349impl<'a> ExactSizeIterator for GroupIter<'a> {
350 #[inline]
351 fn len(&self) -> usize {
352 self.iter.len()
353 }
354}
355
356impl<'a> FusedIterator for GroupIter<'a> {}
357
358impl<'p> Parse<'p> for ReadValue {
359 fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
360 where
361 E: Endian,
362 B: ParseBuf<'p>,
363 {
364 let read_format = p.config().read_format();
365
366 if read_format.contains(ReadFormat::GROUP) {
367 return Err(ParseError::custom(
368 ErrorKind::UnsupportedConfig,
369 "attempted to parse a SingleRead with a config that has GROUP set in read_format",
370 ));
371 }
372
373 if !(read_format - ReadFormat::all()).is_empty() {
374 return Err(ParseError::custom(
375 ErrorKind::UnsupportedConfig,
376 "read_format contains unsupported flags",
377 ));
378 }
379
380 Ok(Self {
381 read_format,
382 value: p.parse()?,
383 time_enabled: p
384 .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_ENABLED))?
385 .unwrap_or(0),
386 time_running: p
387 .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_RUNNING))?
388 .unwrap_or(0),
389 id: p
390 .parse_if(read_format.contains(ReadFormat::ID))?
391 .unwrap_or(0),
392 lost: p
393 .parse_if(read_format.contains(ReadFormat::LOST))?
394 .unwrap_or(0),
395 })
396 }
397}
398
399impl<'p> Parse<'p> for ReadGroup<'p> {
400 fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
401 where
402 E: Endian,
403 B: ParseBuf<'p>,
404 {
405 let read_format = p.config().read_format();
406
407 if !read_format.contains(ReadFormat::GROUP) {
408 return Err(ParseError::custom(
409 ErrorKind::UnsupportedConfig,
410 "attempted to parse a GroupRead with a config that does not have GROUP set in read_format"
411 ));
412 }
413
414 if !(read_format - ReadFormat::all()).is_empty() {
415 return Err(ParseError::custom(
416 ErrorKind::UnsupportedConfig,
417 "read_format contains unsupported flags",
418 ));
419 }
420
421 let nr = p.parse_u64()? as usize;
422 let time_enabled = p
423 .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_ENABLED))?
424 .unwrap_or(0);
425 let time_running = p
426 .parse_if(read_format.contains(ReadFormat::TOTAL_TIME_RUNNING))?
427 .unwrap_or(0);
428
429 let element_len = read_format.element_len();
430 let data_len = nr .checked_mul(element_len)
432 .ok_or_else(|| {
433 ParseError::custom(
434 ErrorKind::InvalidRecord,
435 "number of elements in group read was too large for data type",
436 )
437 })?;
438 let data = unsafe { p.parse_slice(data_len)? };
439
440 Ok(Self {
441 read_format,
442 time_enabled,
443 time_running,
444 data,
445 })
446 }
447}
448
449impl<'p> Parse<'p> for Read {
450 fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
451 where
452 E: Endian,
453 B: ParseBuf<'p>,
454 {
455 Ok(Self {
456 pid: p.parse()?,
457 tid: p.parse()?,
458 values: p.parse()?,
459 })
460 }
461}
462
463#[derive(Clone, Debug)]
465pub struct TryFromGroupError(());
466
467impl fmt::Display for TryFromGroupError {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 f.write_str("can only convert groups with a single element to ReadValues")
470 }
471}
472
473impl std::error::Error for TryFromGroupError {}