open_dis_rust/warfare/
directed_energy_fire_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    pdu::Pdu,
14    pdu_header::{PduHeader, PduType, ProtocolFamily},
15};
16
17use super::data_types::directed_energy_damage::DirectedEnergyDamage;
18
19#[derive(Clone, Debug)]
20/// Implemented according to IEEE 1278.1-2012 ยง7.3.4
21pub struct DirectedEnergyFirePdu {
22    pub pdu_header: PduHeader,
23    pub firing_entity_id: EntityId,
24    pub target_entity_id: EntityId,
25    pub damaged_entity_id: EntityId,
26    pub padding1: u16,
27    pub padding2: u16,
28    pub number_of_damage_descriptions: u16,
29    pub damage_descriptions: Vec<DirectedEnergyDamage>,
30}
31
32impl Default for DirectedEnergyFirePdu {
33    /// Creates a default-initialized Directed Energy Fire PDU
34    ///
35    /// # Examples
36    ///
37    /// Initializing a Directed Energy Fire PDU:
38    /// ```
39    /// use open_dis_rust::warfare::directed_energy_fire_pdu::DirectedEnergyFirePdu;
40    /// let directed_energy_fire_pdu = DirectedEnergyFirePdu::default();
41    /// ```
42    ///
43    fn default() -> Self {
44        DirectedEnergyFirePdu {
45            pdu_header: PduHeader::default(
46                PduType::DirectedEnergyFire,
47                ProtocolFamily::Warfare,
48                56,
49            ),
50            firing_entity_id: EntityId::default(1),
51            target_entity_id: EntityId::default(2),
52            damaged_entity_id: EntityId::default(3),
53            padding1: 0,
54            padding2: 0,
55            number_of_damage_descriptions: 0,
56            damage_descriptions: vec![],
57        }
58    }
59}
60
61impl Pdu for DirectedEnergyFirePdu {
62    /// Serialize contents of `DirectedEnergyFirePdu` into `BytesMut` buffer
63    fn serialize(&mut self, buf: &mut BytesMut) {
64        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
65            .expect("The length of the PDU should fit in a u16.");
66        self.pdu_header.serialize(buf);
67        self.firing_entity_id.serialize(buf);
68        self.target_entity_id.serialize(buf);
69        self.damaged_entity_id.serialize(buf);
70        buf.put_u16(self.padding1);
71        buf.put_u16(self.padding2);
72        buf.put_u16(self.number_of_damage_descriptions);
73        for i in 0..self.damage_descriptions.len() {
74            self.damage_descriptions[i].serialize(buf);
75        }
76    }
77
78    /// Deserialize bytes from `BytesMut` buffer and interpret as `DirectedEnergyFirePdu`
79    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
80    where
81        Self: Sized,
82    {
83        let pdu_header = PduHeader::deserialize(&mut buffer);
84        if pdu_header.pdu_type == PduType::DirectedEnergyFire {
85            let firing_entity_id = EntityId::deserialize(&mut buffer);
86            let target_entity_id = EntityId::deserialize(&mut buffer);
87            let damaged_entity_id = EntityId::deserialize(&mut buffer);
88            let padding1 = buffer.get_u16();
89            let padding2 = buffer.get_u16();
90            let number_of_damage_descriptions = buffer.get_u16();
91            let damage_descriptions: Vec<DirectedEnergyDamage> = vec![];
92            Ok(DirectedEnergyFirePdu {
93                pdu_header,
94                firing_entity_id,
95                target_entity_id,
96                damaged_entity_id,
97                padding1,
98                padding2,
99                number_of_damage_descriptions,
100                damage_descriptions,
101            })
102        } else {
103            Err(DISError::invalid_header(
104                format!(
105                    "Expected PDU type DirectedEnergyFire, got {:?}",
106                    pdu_header.pdu_type
107                ),
108                None,
109            ))
110        }
111    }
112
113    /// Treat `DirectedEnergyFirePdu` as Any type
114    fn as_any(&self) -> &dyn Any {
115        self
116    }
117
118    /// Deserialize
119    fn deserialize_without_header(
120        mut buffer: BytesMut,
121        pdu_header: PduHeader,
122    ) -> Result<Self, DISError>
123    where
124        Self: Sized,
125    {
126        let firing_entity_id = EntityId::deserialize(&mut buffer);
127        let target_entity_id = EntityId::deserialize(&mut buffer);
128        let damaged_entity_id = EntityId::deserialize(&mut buffer);
129        let padding1 = buffer.get_u16();
130        let padding2 = buffer.get_u16();
131        let number_of_damage_descriptions = buffer.get_u16();
132        let damage_descriptions: Vec<DirectedEnergyDamage> = vec![];
133        Ok(DirectedEnergyFirePdu {
134            pdu_header,
135            firing_entity_id,
136            target_entity_id,
137            damaged_entity_id,
138            padding1,
139            padding2,
140            number_of_damage_descriptions,
141            damage_descriptions,
142        })
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::DirectedEnergyFirePdu;
149    use crate::common::{
150        pdu::Pdu,
151        pdu_header::{PduHeader, PduType, ProtocolFamily},
152    };
153    use bytes::BytesMut;
154
155    #[test]
156    fn create_header() {
157        let directed_energy_fire_pdu = DirectedEnergyFirePdu::default();
158        let pdu_header = PduHeader::default(
159            PduType::DirectedEnergyFire,
160            ProtocolFamily::Warfare,
161            448 / 8,
162        );
163
164        assert_eq!(
165            pdu_header.protocol_version,
166            directed_energy_fire_pdu.pdu_header.protocol_version
167        );
168        assert_eq!(
169            pdu_header.exercise_id,
170            directed_energy_fire_pdu.pdu_header.exercise_id
171        );
172        assert_eq!(
173            pdu_header.pdu_type,
174            directed_energy_fire_pdu.pdu_header.pdu_type
175        );
176        assert_eq!(
177            pdu_header.protocol_family,
178            directed_energy_fire_pdu.pdu_header.protocol_family
179        );
180        assert_eq!(
181            pdu_header.length,
182            directed_energy_fire_pdu.pdu_header.length
183        );
184        assert_eq!(
185            pdu_header.status_record,
186            directed_energy_fire_pdu.pdu_header.status_record
187        );
188    }
189
190    #[test]
191    fn cast_to_any() {
192        let directed_energy_fire_pdu = DirectedEnergyFirePdu::default();
193        let any_pdu = directed_energy_fire_pdu.as_any();
194
195        assert!(any_pdu.is::<DirectedEnergyFirePdu>());
196    }
197
198    #[test]
199    fn deserialize_header() {
200        let mut directed_energy_fire_pdu = DirectedEnergyFirePdu::default();
201        let mut buffer = BytesMut::new();
202        directed_energy_fire_pdu.serialize(&mut buffer);
203
204        let new_directed_energy_fire_pdu = DirectedEnergyFirePdu::deserialize(buffer).unwrap();
205        assert_eq!(
206            new_directed_energy_fire_pdu.pdu_header,
207            directed_energy_fire_pdu.pdu_header
208        );
209    }
210}