datex_core/global/protocol_structures/
block_header.rs

1use super::serializable::Serializable;
2use crate::values::core_values::endpoint::Endpoint;
3use binrw::{BinRead, BinWrite};
4use modular_bitfield::{Specifier, bitfield, prelude::B43};
5use strum_macros::Display;
6
7// 4 bit
8#[derive(Debug, Display, PartialEq, Clone, Copy, Default, Specifier)]
9#[cfg_attr(feature = "debug", derive(serde::Serialize, serde::Deserialize))]
10#[bits = 4]
11pub enum BlockType {
12    #[default]
13    Request = 0,
14    Response = 1,
15    Hello = 2,
16    Trace = 3,
17    TraceBack = 4,
18}
19
20impl BlockType {
21    pub fn is_response(&self) -> bool {
22        matches!(self, BlockType::Response | BlockType::TraceBack)
23    }
24}
25
26// 21 bit + 43 bit = 64 bit
27/// has_side_effects: If set, the block can have side effects that change external state. Default is true
28/// has_only_data: If set, the block does only contain data and no executable instructions. Default is false
29#[bitfield]
30#[derive(BinWrite, BinRead, Clone, Copy, Debug, PartialEq)]
31#[bw(map = |&x| Self::into_bytes(x))]
32#[br(map = Self::from_bytes)]
33#[brw(little)]
34pub struct FlagsAndTimestamp {
35    pub block_type: BlockType,
36    pub has_side_effects: bool,
37    pub has_only_data: bool,
38    pub is_end_of_section: bool,
39    pub is_end_of_context: bool,
40    pub has_lifetime: bool,
41    pub has_represented_by: bool,
42    pub has_iv: bool,
43    pub is_compressed: bool,
44    pub is_signature_in_last_subblock: bool,
45
46    #[allow(unused)]
47    unused_0: bool,
48    #[allow(unused)]
49    unused_1: bool,
50    #[allow(unused)]
51    unused_2: bool,
52    #[allow(unused)]
53    unused_3: bool,
54    #[allow(unused)]
55    unused_4: bool,
56    #[allow(unused)]
57    unused_5: bool,
58    #[allow(unused)]
59    unused_6: bool,
60    #[allow(unused)]
61    unused_7: bool,
62
63    pub creation_timestamp: B43,
64}
65
66#[cfg(feature = "debug")]
67mod flags_and_timestamp_serde {
68    use super::*;
69    use serde::{Deserialize, Deserializer, Serialize, Serializer};
70
71    #[derive(Serialize, Deserialize)]
72    struct FlagsHelper {
73        block_type: BlockType,
74        has_side_effects: bool,
75        has_only_data: bool,
76        is_end_of_section: bool,
77        is_end_of_context: bool,
78        has_lifetime: bool,
79        has_represented_by: bool,
80        has_iv: bool,
81        is_compressed: bool,
82        is_signature_in_last_subblock: bool,
83        creation_timestamp: u64,
84    }
85
86    impl Serialize for FlagsAndTimestamp {
87        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
88        where
89            S: Serializer,
90        {
91            let helper = FlagsHelper {
92                block_type: self.block_type(),
93                has_side_effects: self.has_side_effects(),
94                has_only_data: self.has_only_data(),
95                is_end_of_section: self.is_end_of_section(),
96                is_end_of_context: self.is_end_of_context(),
97                has_lifetime: self.has_lifetime(),
98                has_represented_by: self.has_represented_by(),
99                has_iv: self.has_iv(),
100                is_compressed: self.is_compressed(),
101                is_signature_in_last_subblock: self
102                    .is_signature_in_last_subblock(),
103                creation_timestamp: self.creation_timestamp(),
104            };
105            helper.serialize(serializer)
106        }
107    }
108
109    impl<'de> Deserialize<'de> for FlagsAndTimestamp {
110        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111        where
112            D: Deserializer<'de>,
113        {
114            let helper = FlagsHelper::deserialize(deserializer)?;
115            Ok(FlagsAndTimestamp::new()
116                .with_block_type(helper.block_type)
117                .with_has_side_effects(helper.has_side_effects)
118                .with_has_only_data(helper.has_only_data)
119                .with_is_end_of_section(helper.is_end_of_section)
120                .with_is_end_of_context(helper.is_end_of_context)
121                .with_has_lifetime(helper.has_lifetime)
122                .with_has_represented_by(helper.has_represented_by)
123                .with_has_iv(helper.has_iv)
124                .with_is_compressed(helper.is_compressed)
125                .with_is_signature_in_last_subblock(
126                    helper.is_signature_in_last_subblock,
127                )
128                .with_creation_timestamp(helper.creation_timestamp))
129        }
130    }
131}
132
133impl Default for FlagsAndTimestamp {
134    fn default() -> Self {
135        FlagsAndTimestamp::new()
136            .with_block_type(BlockType::Request)
137            .with_has_side_effects(true)
138            .with_has_only_data(false)
139            .with_is_end_of_section(true)
140            .with_is_end_of_context(true)
141            .with_has_lifetime(false)
142            .with_has_represented_by(false)
143            .with_has_iv(false)
144            .with_is_compressed(false)
145            .with_is_signature_in_last_subblock(false)
146    }
147}
148
149// min: 16 byte
150// max 8 + 8 byte + 4 byte + 21 byte + 16 byte = 57 byte
151#[cfg_attr(feature = "debug", derive(serde::Serialize, serde::Deserialize))]
152#[derive(Debug, Clone, Default, BinWrite, BinRead, PartialEq)]
153#[brw(little)]
154pub struct BlockHeader {
155    /// A unique id that defines the context in which this block lives
156    /// A context has a persistent state that can e.g. contain DATEX variables
157    pub context_id: u32,
158    /// A section is a collection of multiple sequential blocks inside the same context
159    /// (each with an incrementing block number)
160    /// When a new section starts, the block number is not reset but continues to increment
161    pub section_index: u16,
162    /// A unique number that identifies a block inside a block context
163    /// The context_id combined with the block_number define a unique block from a specific endpoint
164    /// the block id (endpoint, context_id, block_number) defines a globally unique block
165    /// Note: blocks ids are not completely unique, when the block_number or section_index overflows,
166    /// it starts from 0 again, leading to duplicate block ids after a while
167    pub block_number: u16,
168
169    pub flags_and_timestamp: FlagsAndTimestamp,
170
171    #[brw(if(flags_and_timestamp.has_lifetime()))]
172    pub lifetime: Option<u32>,
173
174    #[brw(if(flags_and_timestamp.has_represented_by()))]
175    pub represented_by: Option<Endpoint>,
176
177    #[brw(if(flags_and_timestamp.has_iv()))]
178    pub iv: Option<[u8; 16]>,
179}
180
181impl Serializable for BlockHeader {}