djin_protocol/
hint.rs

1use std::collections::HashMap;
2
3pub type FieldIndex = usize;
4
5/// Hints given when reading parcels.
6#[derive(Clone, Debug, PartialEq)]
7pub struct Hints {
8    pub skip_hint: Option<bool>,
9    pub current_field_index: Option<FieldIndex>,
10    /// The fields for which a length prefix
11    /// was already present earlier in the layout.
12    pub known_field_lengths: HashMap<FieldIndex, FieldLength>,
13}
14
15/// Information about the length of a field.
16#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
17pub struct FieldLength {
18    pub length: usize,
19    pub kind: LengthPrefixKind,
20}
21
22/// Specifies what kind of data the length prefix captures.
23#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
24pub enum LengthPrefixKind {
25    /// The length prefix stores the total number of bytes making up another field.
26    Bytes,
27    /// The length prefix stores the total number of elements inside another field.
28    Elements,
29    /// The length prefix stores the total number of elements inside another iterable field.
30    Pointers,
31}
32
33
34impl Default for Hints {
35    fn default() -> Self {
36        Hints {
37            skip_hint: None,
38            current_field_index: None,
39            known_field_lengths: HashMap::new(),
40        }
41    }
42}
43
44impl Hints {
45    /// Gets the length of the field currently being
46    /// read, if known.
47    pub fn current_field_length(&self) -> Option<FieldLength> {
48        self.current_field_index.and_then(|index| self.known_field_lengths.get(&index)).cloned()
49    }
50}
51
52/// Helpers for the `protocol-derive` crate.
53mod protocol_derive_helpers {
54    use super::*;
55
56    impl Hints {
57        // Sets hints indicating a new set of fields are beginning.
58        #[doc(hidden)]
59        pub fn begin_fields(&mut self) {
60            self.current_field_index = Some(0);
61        }
62
63        // Updates the hints to indicate a field was just read.
64        #[doc(hidden)]
65        pub fn next_field(&mut self) {
66            *self.current_field_index.as_mut()
67                .expect("cannot increment next field when not in a struct") += 1;
68        }
69
70        // Sets the length of a variable-sized field by its 0-based index.
71        #[doc(hidden)]
72        pub fn set_field_length(&mut self,
73                                field_index: FieldIndex,
74                                length: usize,
75                                kind: LengthPrefixKind) {
76            self.known_field_lengths.insert(field_index, FieldLength { kind, length });
77        }
78
79        // A type skipped is assumed to be Option<T>, we need to set this to bypass
80        // the default Option read method
81        #[doc(hidden)]
82        pub fn set_skip(&mut self, do_skip: bool) {
83            self.skip_hint = Some(do_skip);
84        }
85    }
86}
87