open_dis_rust/warfare/
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    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::munition_descriptor::MunitionDescriptor;
21
22#[derive(Clone, Debug)]
23/// Implemented according to IEEE 1278.1-2012 ยง7.3.2
24pub struct FirePdu {
25    pub pdu_header: PduHeader,
26    pub firing_entity_id: EntityId,
27    pub target_entity_id: EntityId,
28    pub munition_expendable_id: EntityId,
29    pub event_id: EventId,
30    pub fire_mission_index: u32,
31    pub location_in_world_coordinates: Vector3Double,
32    pub descriptor: MunitionDescriptor,
33    pub velocity: Vector3Float,
34    pub range: f32,
35}
36
37impl Default for FirePdu {
38    /// Creates a default Fire PDU with arbitrary firing entity ID and target entity ID
39    ///
40    /// # Examples
41    ///
42    /// Initializing a Fire PDU:
43    /// ```
44    /// use open_dis_rust::warfare::fire_pdu::FirePdu;
45    /// let fire_pdu = FirePdu::default();
46    /// ```
47    ///
48    fn default() -> Self {
49        FirePdu {
50            pdu_header: PduHeader::default(PduType::Fire, ProtocolFamily::Warfare, 56),
51            firing_entity_id: EntityId::default(1),
52            target_entity_id: EntityId::default(2),
53            munition_expendable_id: EntityId::default(3),
54            event_id: EventId::default(1),
55            fire_mission_index: 0,
56            location_in_world_coordinates: Vector3Double::default(),
57            descriptor: MunitionDescriptor::default(),
58            velocity: Vector3Float::default(),
59            range: 0.0,
60        }
61    }
62}
63
64impl Pdu for FirePdu {
65    fn serialize(&mut self, buf: &mut BytesMut) {
66        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
67            .expect("The length of the PDU should fit in a u16.");
68        self.pdu_header.serialize(buf);
69        self.firing_entity_id.serialize(buf);
70        self.target_entity_id.serialize(buf);
71        self.munition_expendable_id.serialize(buf);
72        self.event_id.serialize(buf);
73        buf.put_u32(self.fire_mission_index);
74        self.location_in_world_coordinates.serialize(buf);
75        self.descriptor.serialize(buf);
76        self.velocity.serialize(buf);
77        buf.put_f32(self.range);
78    }
79
80    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
81    where
82        Self: Sized,
83    {
84        let pdu_header = PduHeader::deserialize(&mut buffer);
85        if pdu_header.pdu_type == PduType::Fire {
86            let firing_entity_id = EntityId::deserialize(&mut buffer);
87            let target_entity_id = EntityId::deserialize(&mut buffer);
88            let munition_expendable_id = EntityId::deserialize(&mut buffer);
89            let event_id = EventId::deserialize(&mut buffer);
90            let fire_mission_index = buffer.get_u32();
91            let location_in_world_coordinates = Vector3Double::deserialize(&mut buffer);
92            let descriptor = MunitionDescriptor::deserialize(&mut buffer);
93            let velocity = Vector3Float::deserialize(&mut buffer);
94            let range = buffer.get_f32();
95            Ok(FirePdu {
96                pdu_header,
97                firing_entity_id,
98                target_entity_id,
99                munition_expendable_id,
100                event_id,
101                fire_mission_index,
102                location_in_world_coordinates,
103                descriptor,
104                velocity,
105                range,
106            })
107        } else {
108            Err(DISError::invalid_header(
109                format!("Expected PDU type Fire, got {:?}", pdu_header.pdu_type),
110                None,
111            ))
112        }
113    }
114
115    fn as_any(&self) -> &dyn Any {
116        self
117    }
118
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 munition_expendable_id = EntityId::deserialize(&mut buffer);
129        let event_id = EventId::deserialize(&mut buffer);
130        let fire_mission_index = buffer.get_u32();
131        let location_in_world_coordinates = Vector3Double::deserialize(&mut buffer);
132        let descriptor = MunitionDescriptor::deserialize(&mut buffer);
133        let velocity = Vector3Float::deserialize(&mut buffer);
134        let range = buffer.get_f32();
135        Ok(FirePdu {
136            pdu_header,
137            firing_entity_id,
138            target_entity_id,
139            munition_expendable_id,
140            event_id,
141            fire_mission_index,
142            location_in_world_coordinates,
143            descriptor,
144            velocity,
145            range,
146        })
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::FirePdu;
153    use crate::common::{
154        pdu::Pdu,
155        pdu_header::{PduHeader, PduType, ProtocolFamily},
156    };
157    use bytes::BytesMut;
158
159    #[test]
160    fn create_header() {
161        let fire_pdu = FirePdu::default();
162        let pdu_header = PduHeader::default(PduType::Fire, ProtocolFamily::Warfare, 448 / 8);
163
164        assert_eq!(
165            pdu_header.protocol_version,
166            fire_pdu.pdu_header.protocol_version
167        );
168        assert_eq!(pdu_header.exercise_id, fire_pdu.pdu_header.exercise_id);
169        assert_eq!(pdu_header.pdu_type, fire_pdu.pdu_header.pdu_type);
170        assert_eq!(
171            pdu_header.protocol_family,
172            fire_pdu.pdu_header.protocol_family
173        );
174        assert_eq!(pdu_header.length, fire_pdu.pdu_header.length);
175        assert_eq!(pdu_header.status_record, fire_pdu.pdu_header.status_record);
176    }
177
178    #[test]
179    fn deserialize_header() {
180        let mut fire_pdu = FirePdu::default();
181        let mut buffer = BytesMut::new();
182        fire_pdu.serialize(&mut buffer);
183
184        let new_fire_pdu = FirePdu::deserialize(buffer).unwrap();
185        assert_eq!(new_fire_pdu.pdu_header, fire_pdu.pdu_header);
186    }
187}