open_dis_rust/warfare/
entity_damage_status_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.5
21pub struct EntityDamageStatusPdu {
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 EntityDamageStatusPdu {
33    /// Creates a default Entity Damage Status PDU with arbitrary firing entity ID and target entity ID
34    ///
35    /// # Examples
36    ///
37    /// Initializing an Entity Damage Status PDU:
38    /// ```
39    /// use open_dis_rust::warfare::entity_damage_status_pdu::EntityDamageStatusPdu;
40    /// let entity_damage_status_pdu = EntityDamageStatusPdu::default();
41    /// ```
42    ///
43    fn default() -> Self {
44        EntityDamageStatusPdu {
45            pdu_header: PduHeader::default(
46                PduType::EntityDamageStatus,
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 EntityDamageStatusPdu {
62    fn serialize(&mut self, buf: &mut BytesMut) {
63        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
64            .expect("The length of the PDU should fit in a u16.");
65        self.pdu_header.serialize(buf);
66        self.firing_entity_id.serialize(buf);
67        self.target_entity_id.serialize(buf);
68        self.damaged_entity_id.serialize(buf);
69        buf.put_u16(self.padding1);
70        buf.put_u16(self.padding2);
71        buf.put_u16(self.number_of_damage_descriptions);
72        for i in 0..self.damage_descriptions.len() {
73            self.damage_descriptions[i].serialize(buf);
74        }
75    }
76
77    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
78    where
79        Self: Sized,
80    {
81        let pdu_header = PduHeader::deserialize(&mut buffer);
82        if pdu_header.pdu_type == PduType::EntityDamageStatus {
83            let firing_entity_id = EntityId::deserialize(&mut buffer);
84            let target_entity_id = EntityId::deserialize(&mut buffer);
85            let damaged_entity_id = EntityId::deserialize(&mut buffer);
86            let padding1 = buffer.get_u16();
87            let padding2 = buffer.get_u16();
88            let number_of_damage_descriptions = buffer.get_u16();
89            let damage_descriptions: Vec<DirectedEnergyDamage> = vec![];
90            Ok(EntityDamageStatusPdu {
91                pdu_header,
92                firing_entity_id,
93                target_entity_id,
94                damaged_entity_id,
95                padding1,
96                padding2,
97                number_of_damage_descriptions,
98                damage_descriptions,
99            })
100        } else {
101            Err(DISError::invalid_header(
102                format!(
103                    "Expected PDU type EntityDamageStatus, got {:?}",
104                    pdu_header.pdu_type
105                ),
106                None,
107            ))
108        }
109    }
110
111    fn as_any(&self) -> &dyn Any {
112        self
113    }
114
115    fn deserialize_without_header(
116        mut buffer: BytesMut,
117        pdu_header: PduHeader,
118    ) -> Result<Self, DISError>
119    where
120        Self: Sized,
121    {
122        let firing_entity_id = EntityId::deserialize(&mut buffer);
123        let target_entity_id = EntityId::deserialize(&mut buffer);
124        let damaged_entity_id = EntityId::deserialize(&mut buffer);
125        let padding1 = buffer.get_u16();
126        let padding2 = buffer.get_u16();
127        let number_of_damage_descriptions = buffer.get_u16();
128        let damage_descriptions: Vec<DirectedEnergyDamage> = vec![];
129        Ok(EntityDamageStatusPdu {
130            pdu_header,
131            firing_entity_id,
132            target_entity_id,
133            damaged_entity_id,
134            padding1,
135            padding2,
136            number_of_damage_descriptions,
137            damage_descriptions,
138        })
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::EntityDamageStatusPdu;
145    use crate::common::{
146        pdu::Pdu,
147        pdu_header::{PduHeader, PduType, ProtocolFamily},
148    };
149    use bytes::BytesMut;
150
151    #[test]
152    fn create_header() {
153        let entity_damage_status_pdu = EntityDamageStatusPdu::default();
154        let pdu_header = PduHeader::default(
155            PduType::EntityDamageStatus,
156            ProtocolFamily::Warfare,
157            448 / 8,
158        );
159
160        assert_eq!(
161            pdu_header.protocol_version,
162            entity_damage_status_pdu.pdu_header.protocol_version
163        );
164        assert_eq!(
165            pdu_header.exercise_id,
166            entity_damage_status_pdu.pdu_header.exercise_id
167        );
168        assert_eq!(
169            pdu_header.pdu_type,
170            entity_damage_status_pdu.pdu_header.pdu_type
171        );
172        assert_eq!(
173            pdu_header.protocol_family,
174            entity_damage_status_pdu.pdu_header.protocol_family
175        );
176        assert_eq!(
177            pdu_header.length,
178            entity_damage_status_pdu.pdu_header.length
179        );
180        assert_eq!(
181            pdu_header.status_record,
182            entity_damage_status_pdu.pdu_header.status_record
183        );
184    }
185
186    #[test]
187    fn deserialize_header() {
188        let mut entity_damage_status_pdu = EntityDamageStatusPdu::default();
189        let mut buffer = BytesMut::new();
190        entity_damage_status_pdu.serialize(&mut buffer);
191
192        let new_entity_damage_status_pdu = EntityDamageStatusPdu::deserialize(buffer).unwrap();
193        assert_eq!(
194            new_entity_damage_status_pdu.pdu_header,
195            entity_damage_status_pdu.pdu_header
196        );
197    }
198}