datex_core/global/protocol_structures/
block_header.rs

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