open_dis_rust/
logistics.rs

1//     open-dis-rust - Rust implementation of the IEEE-1278.1 Distributed Interactive Simulation
2//     Copyright (C) 2025 Cameron Howell
3//
4//     Licensed under the BSD-2-Clause License
5
6//! The Logistics protocol family
7
8use crate::{
9    common::{
10        GenericHeader, SerializedLength,
11        data_types::{entity_id::EntityId, supply_quantity::SupplyQuantity},
12        enums::{
13            PduType, ProtocolFamily, RepairCompleteRepair, RepairResponseRepairResult,
14            ServiceRequestServiceTypeRequested,
15        },
16        pdu::Pdu,
17        pdu_header::PduHeader,
18    },
19    define_pdu,
20};
21
22define_pdu! {
23    #[derive(Debug)]
24    /// Implemented according to IEEE 1278.1-2012 §7.4.2
25    pub struct ServiceRequestPdu {
26        header: PduHeader,
27        pdu_type: PduType::ServiceRequest,
28        protocol_family: ProtocolFamily::Logistics,
29        fields: {
30            pub receiving_entity_id: EntityId,
31            pub servicing_entity_id: EntityId,
32            pub service_type_requested: ServiceRequestServiceTypeRequested,
33            pub number_of_supply_types: u8,
34            padding: u16,
35            pub supplies: Vec<SupplyQuantity>,
36        }
37    }
38}
39
40define_pdu! {
41    #[derive(Debug)]
42    /// Implemented according to IEEE 1278.1-2012 §7.4.3
43    pub struct ResupplyOfferPdu {
44        header: PduHeader,
45        pdu_type: PduType::ResupplyOffer,
46        protocol_family: ProtocolFamily::Logistics,
47        fields: {
48            pub receiving_entity_id: EntityId,
49            pub supplying_entity_id: EntityId,
50            pub number_of_supply_types: u8,
51            padding: u8,
52            padding2: u16,
53            pub supplies: Vec<SupplyQuantity>,
54        }
55    }
56}
57
58define_pdu! {
59    #[derive(Debug)]
60    /// Implemented according to IEEE 1278.1-2012 §7.4.4
61    pub struct ResupplyReceivedPdu {
62        header: PduHeader,
63        pdu_type: PduType::ResupplyReceived,
64        protocol_family: ProtocolFamily::Logistics,
65        fields: {
66            pub receiving_entity_id: EntityId,
67            pub supplying_entity_id: EntityId,
68            pub number_of_supply_types: u8,
69            padding: u8,
70            padding2: u16,
71            pub supplies: Vec<SupplyQuantity>,
72        }
73    }
74}
75
76define_pdu! {
77    #[derive(Debug)]
78    /// Implemented according to IEEE 1278.1-2012 §7.4.5
79    pub struct ResupplyCancelPdu {
80        header: PduHeader,
81        pdu_type: PduType::ResupplyCancel,
82        protocol_family: ProtocolFamily::Logistics,
83        fields: {
84            pub receiving_entity_id: EntityId,
85            pub supplying_entity_id: EntityId,
86        }
87    }
88}
89
90define_pdu! {
91    #[derive(Debug)]
92    /// Implemented according to IEEE 1278.1-2012 §7.4.6
93    pub struct RepairCompletePdu {
94        header: PduHeader,
95        pdu_type: PduType::RepairComplete,
96        protocol_family: ProtocolFamily::Logistics,
97        fields: {
98            pub receiving_entity_id: EntityId,
99            pub repairing_entity_id: EntityId,
100            pub repair: RepairCompleteRepair,
101            padding: u16,
102        }
103    }
104}
105
106define_pdu! {
107    #[derive(Debug)]
108    /// Implemented according to IEEE 1278.1-2012 §7.4.7
109    pub struct RepairResponsePdu {
110        header: PduHeader,
111        pdu_type: PduType::RepairResponse,
112        protocol_family: ProtocolFamily::Logistics,
113        fields: {
114            pub receiving_entity_id: EntityId,
115            pub repairing_entity_id: EntityId,
116            pub repair_result: RepairResponseRepairResult,
117            padding: u8,
118            padding2: u16,
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use crate::common::{constants::BITS_PER_BYTE, pdu::Pdu};
127    use bytes::BytesMut;
128
129    mod service_request_pdu_tests {
130        use super::*;
131
132        #[test]
133        fn cast_to_any() {
134            let pdu = ServiceRequestPdu::new();
135            let any_pdu = pdu.as_any();
136
137            assert!(any_pdu.is::<ServiceRequestPdu>());
138        }
139
140        #[test]
141        fn serialize_then_deserialize() {
142            let mut pdu = ServiceRequestPdu::new();
143            let mut serialize_buf = BytesMut::new();
144            let _ = pdu.serialize(&mut serialize_buf);
145
146            let mut deserialize_buf = serialize_buf.freeze();
147            let new_pdu = ServiceRequestPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
148            assert_eq!(new_pdu.header, pdu.header);
149        }
150
151        #[test]
152        fn check_default_pdu_length() {
153            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
154            let pdu = ServiceRequestPdu::new();
155            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
156        }
157    }
158
159    mod resupply_offer_pdu_tests {
160        use super::*;
161
162        #[test]
163        fn cast_to_any() {
164            let pdu = ResupplyOfferPdu::new();
165            let any_pdu = pdu.as_any();
166
167            assert!(any_pdu.is::<ResupplyOfferPdu>());
168        }
169
170        #[test]
171        fn serialize_then_deserialize() {
172            let mut pdu = ResupplyOfferPdu::new();
173            let mut serialize_buf = BytesMut::new();
174            let _ = pdu.serialize(&mut serialize_buf);
175
176            let mut deserialize_buf = serialize_buf.freeze();
177            let new_pdu = ResupplyOfferPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
178            assert_eq!(new_pdu.header, pdu.header);
179        }
180
181        #[test]
182        fn check_default_pdu_length() {
183            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
184            let pdu = ResupplyOfferPdu::new();
185            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
186        }
187    }
188
189    mod resupply_received_pdu_tests {
190        use super::*;
191
192        #[test]
193        fn cast_to_any() {
194            let pdu = ResupplyReceivedPdu::new();
195            let any_pdu = pdu.as_any();
196
197            assert!(any_pdu.is::<ResupplyReceivedPdu>());
198        }
199
200        #[test]
201        fn serialize_then_deserialize() {
202            let mut pdu = ResupplyReceivedPdu::new();
203            let mut serialize_buf = BytesMut::new();
204            let _ = pdu.serialize(&mut serialize_buf);
205
206            let mut deserialize_buf = serialize_buf.freeze();
207            let new_pdu =
208                ResupplyReceivedPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
209            assert_eq!(new_pdu.header, pdu.header);
210        }
211
212        #[test]
213        fn check_default_pdu_length() {
214            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
215            let pdu = ResupplyReceivedPdu::new();
216            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
217        }
218    }
219
220    mod resupply_cancel_pdu_tests {
221        use super::*;
222
223        #[test]
224        fn cast_to_any() {
225            let pdu = ResupplyCancelPdu::new();
226            let any_pdu = pdu.as_any();
227
228            assert!(any_pdu.is::<ResupplyCancelPdu>());
229        }
230
231        #[test]
232        fn serialize_then_deserialize() {
233            let mut pdu = ResupplyCancelPdu::new();
234            let mut serialize_buf = BytesMut::new();
235            let _ = pdu.serialize(&mut serialize_buf);
236
237            let mut deserialize_buf = serialize_buf.freeze();
238            let new_pdu = ResupplyCancelPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
239            assert_eq!(new_pdu.header, pdu.header);
240        }
241
242        #[test]
243        fn check_default_pdu_length() {
244            const DEFAULT_LENGTH: u16 = 192 / BITS_PER_BYTE;
245            let pdu = ResupplyCancelPdu::new();
246            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
247        }
248    }
249
250    mod repair_complete_pdu_tests {
251        use super::*;
252
253        #[test]
254        fn cast_to_any() {
255            let pdu = RepairCompletePdu::new();
256            let any_pdu = pdu.as_any();
257
258            assert!(any_pdu.is::<RepairCompletePdu>());
259        }
260
261        #[test]
262        fn serialize_then_deserialize() {
263            let mut pdu = RepairCompletePdu::new();
264            let mut serialize_buf = BytesMut::new();
265            let _ = pdu.serialize(&mut serialize_buf);
266
267            let mut deserialize_buf = serialize_buf.freeze();
268            let new_pdu = RepairCompletePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
269            assert_eq!(new_pdu.header, pdu.header);
270        }
271
272        #[test]
273        fn check_default_pdu_length() {
274            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
275            let pdu = RepairCompletePdu::new();
276            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
277        }
278    }
279
280    mod repair_response_pdu_tests {
281        use super::*;
282
283        #[test]
284        fn cast_to_any() {
285            let pdu = RepairResponsePdu::new();
286            let any_pdu = pdu.as_any();
287
288            assert!(any_pdu.is::<RepairResponsePdu>());
289        }
290
291        #[test]
292        fn serialize_then_deserialize() {
293            let mut pdu = RepairResponsePdu::new();
294            let mut serialize_buf = BytesMut::new();
295            let _ = pdu.serialize(&mut serialize_buf);
296
297            let mut deserialize_buf = serialize_buf.freeze();
298            let new_pdu = RepairResponsePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
299            assert_eq!(new_pdu.header, pdu.header);
300        }
301
302        #[test]
303        fn check_default_pdu_length() {
304            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
305            let pdu = RepairResponsePdu::new();
306            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
307        }
308    }
309}