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