1use 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)]
25pub 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 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}