open_dis_rust/warfare/
detonation_pdu.rs

1//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
2//                     Simulation (DIS) application protocol
3//     Copyright (C) 2023 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7use bytes::{Buf, BufMut, BytesMut};
8use std::any::Any;
9
10use crate::common::{
11    dis_error::DISError,
12    entity_id::EntityId,
13    event_id::EventId,
14    pdu::Pdu,
15    pdu_header::{PduHeader, PduType, ProtocolFamily},
16    vector3_double::Vector3Double,
17    vector3_float::Vector3Float,
18};
19
20use super::data_types::{
21    munition_descriptor::MunitionDescriptor, variable_parameter::VariableParameter,
22};
23
24#[derive(Clone, Debug)]
25/// Implemented according to IEEE 1278.1-2012 ยง7.3.3
26pub struct DetonationPdu {
27    pub pdu_header: PduHeader,
28    pub firing_entity_id: EntityId,
29    pub target_entity_id: EntityId,
30    pub exploding_entity_id: EntityId,
31    pub event_id: EventId,
32    pub velocity: Vector3Float,
33    pub location_in_world_coordinates: Vector3Double,
34    pub descriptor: MunitionDescriptor,
35    pub location_in_entitys_coordinates: Vector3Float,
36    pub detonation_result: u8,
37    pub number_of_variable_parameters: u8,
38    pub padding: u16,
39    pub variable_parameters: Vec<VariableParameter>,
40}
41
42impl Default for DetonationPdu {
43    /// Creates a default Detonation PDU with arbitrary firing entity ID and target entity ID
44    ///
45    /// # Examples
46    ///
47    /// Initializing a Detonation PDU:
48    /// ```
49    /// use open_dis_rust::warfare::detonation_pdu::DetonationPdu;
50    /// let detonation_pdu = DetonationPdu::default();
51    /// ```
52    ///
53    fn default() -> Self {
54        DetonationPdu {
55            pdu_header: PduHeader::default(PduType::Detonation, ProtocolFamily::Warfare, 56),
56            firing_entity_id: EntityId::default(1),
57            target_entity_id: EntityId::default(2),
58            exploding_entity_id: EntityId::default(3),
59            event_id: EventId::default(1),
60            velocity: Vector3Float::default(),
61            location_in_world_coordinates: Vector3Double::default(),
62            descriptor: MunitionDescriptor::default(),
63            location_in_entitys_coordinates: Vector3Float::default(),
64            detonation_result: 0,
65            number_of_variable_parameters: 0,
66            padding: 0,
67            variable_parameters: vec![],
68        }
69    }
70}
71
72impl Pdu for DetonationPdu {
73    fn serialize(&mut self, buf: &mut BytesMut) {
74        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
75            .expect("The length of the PDU should fit in a u16.");
76        self.pdu_header.serialize(buf);
77        self.firing_entity_id.serialize(buf);
78        self.target_entity_id.serialize(buf);
79        self.exploding_entity_id.serialize(buf);
80        self.event_id.serialize(buf);
81        self.velocity.serialize(buf);
82        self.location_in_world_coordinates.serialize(buf);
83        self.descriptor.serialize(buf);
84        self.location_in_entitys_coordinates.serialize(buf);
85        buf.put_u8(self.detonation_result);
86        buf.put_u8(self.number_of_variable_parameters);
87        buf.put_u16(self.padding);
88        for i in 0..self.variable_parameters.len() {
89            self.variable_parameters[i].serialize(buf);
90        }
91    }
92
93    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
94    where
95        Self: Sized,
96    {
97        let pdu_header = PduHeader::deserialize(&mut buffer);
98        if pdu_header.pdu_type == PduType::Detonation {
99            let firing_entity_id = EntityId::deserialize(&mut buffer);
100            let target_entity_id = EntityId::deserialize(&mut buffer);
101            let exploding_entity_id = EntityId::deserialize(&mut buffer);
102            let event_id = EventId::deserialize(&mut buffer);
103            let velocity = Vector3Float::deserialize(&mut buffer);
104            let location_in_world_coordinates = Vector3Double::deserialize(&mut buffer);
105            let descriptor = MunitionDescriptor::deserialize(&mut buffer);
106            let location_in_entitys_coordinates = Vector3Float::deserialize(&mut buffer);
107            let detonation_result = buffer.get_u8();
108            let number_of_variable_parameters = buffer.get_u8();
109            let padding = buffer.get_u16();
110            let mut variable_parameters: Vec<VariableParameter> = vec![];
111            for _i in 0..number_of_variable_parameters {
112                variable_parameters.push(VariableParameter::deserialize(&mut buffer));
113            }
114            Ok(DetonationPdu {
115                pdu_header,
116                firing_entity_id,
117                target_entity_id,
118                exploding_entity_id,
119                event_id,
120                velocity,
121                location_in_world_coordinates,
122                descriptor,
123                location_in_entitys_coordinates,
124                detonation_result,
125                number_of_variable_parameters,
126                padding,
127                variable_parameters,
128            })
129        } else {
130            Err(DISError::invalid_header(
131                format!(
132                    "Expected PDU type Detonation, got {:?}",
133                    pdu_header.pdu_type
134                ),
135                None,
136            ))
137        }
138    }
139
140    fn as_any(&self) -> &dyn Any {
141        self
142    }
143
144    fn deserialize_without_header(
145        mut buffer: BytesMut,
146        pdu_header: PduHeader,
147    ) -> Result<Self, DISError>
148    where
149        Self: Sized,
150    {
151        let firing_entity_id = EntityId::deserialize(&mut buffer);
152        let target_entity_id = EntityId::deserialize(&mut buffer);
153        let exploding_entity_id = EntityId::deserialize(&mut buffer);
154        let event_id = EventId::deserialize(&mut buffer);
155        let velocity = Vector3Float::deserialize(&mut buffer);
156        let location_in_world_coordinates = Vector3Double::deserialize(&mut buffer);
157        let descriptor = MunitionDescriptor::deserialize(&mut buffer);
158        let location_in_entitys_coordinates = Vector3Float::deserialize(&mut buffer);
159        let detonation_result = buffer.get_u8();
160        let number_of_variable_parameters = buffer.get_u8();
161        let padding = buffer.get_u16();
162        let mut variable_parameters: Vec<VariableParameter> = vec![];
163        for _i in 0..number_of_variable_parameters {
164            variable_parameters.push(VariableParameter::deserialize(&mut buffer));
165        }
166        Ok(DetonationPdu {
167            pdu_header,
168            firing_entity_id,
169            target_entity_id,
170            exploding_entity_id,
171            event_id,
172            velocity,
173            location_in_world_coordinates,
174            descriptor,
175            location_in_entitys_coordinates,
176            detonation_result,
177            number_of_variable_parameters,
178            padding,
179            variable_parameters,
180        })
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use super::DetonationPdu;
187    use crate::common::{
188        pdu::Pdu,
189        pdu_header::{PduHeader, PduType, ProtocolFamily},
190    };
191    use bytes::BytesMut;
192
193    #[test]
194    fn create_header() {
195        let detonation_pdu = DetonationPdu::default();
196        let pdu_header = PduHeader::default(PduType::Detonation, ProtocolFamily::Warfare, 448 / 8);
197
198        assert_eq!(
199            pdu_header.protocol_version,
200            detonation_pdu.pdu_header.protocol_version
201        );
202        assert_eq!(
203            pdu_header.exercise_id,
204            detonation_pdu.pdu_header.exercise_id
205        );
206        assert_eq!(pdu_header.pdu_type, detonation_pdu.pdu_header.pdu_type);
207        assert_eq!(
208            pdu_header.protocol_family,
209            detonation_pdu.pdu_header.protocol_family
210        );
211        assert_eq!(pdu_header.length, detonation_pdu.pdu_header.length);
212        assert_eq!(
213            pdu_header.status_record,
214            detonation_pdu.pdu_header.status_record
215        );
216    }
217
218    #[test]
219    fn deserialize_header() {
220        let mut detonation_pdu = DetonationPdu::default();
221        let mut buffer = BytesMut::new();
222        detonation_pdu.serialize(&mut buffer);
223
224        let new_detonation_pdu = DetonationPdu::deserialize(buffer).unwrap();
225        assert_eq!(new_detonation_pdu.pdu_header, detonation_pdu.pdu_header);
226    }
227}