Skip to main content

datex_core/global/protocol_structures/
block_header.rs

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