open_dis_rust/minefield/
minefield_query_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 crate::common::{
8    dis_error::DISError,
9    entity_id::EntityId,
10    entity_type::EntityType,
11    pdu::Pdu,
12    pdu_header::{PduHeader, PduType, ProtocolFamily},
13};
14use bytes::{Buf, BufMut, BytesMut};
15use std::any::Any;
16
17use super::data_types::point::Point;
18
19#[derive(Clone, Debug)]
20/// Implemented according to IEEE 1278.1-2012 ยง7.9.3
21pub struct MinefieldQueryPdu {
22    pub pdu_header: PduHeader,
23    pub minefield_id: EntityId,
24    pub requesting_entity_id: EntityId,
25    pub request_id: u8,
26    pub number_of_perimeter_points: u8,
27    pub pad2: u8,
28    pub number_of_sensor_types: u8,
29    pub data_filter: u32,
30    pub requested_mine_type: EntityType,
31    pub requested_perimeter_points: Vec<Point>,
32    pub sensor_types: Vec<u16>,
33}
34
35impl Default for MinefieldQueryPdu {
36    fn default() -> Self {
37        MinefieldQueryPdu {
38            pdu_header: PduHeader::default(PduType::MinefieldQuery, ProtocolFamily::Minefield, 56),
39            minefield_id: EntityId::default(1),
40            requesting_entity_id: EntityId::default(2),
41            request_id: 0,
42            number_of_perimeter_points: 0,
43            pad2: 0,
44            number_of_sensor_types: 0,
45            data_filter: 0,
46            requested_mine_type: EntityType::default(),
47            requested_perimeter_points: vec![Point::default()],
48            sensor_types: vec![0],
49        }
50    }
51}
52
53impl Pdu for MinefieldQueryPdu {
54    fn serialize(&mut self, buf: &mut BytesMut) {
55        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
56            .expect("The length of the PDU should fit in a u16.");
57        self.pdu_header.serialize(buf);
58        self.minefield_id.serialize(buf);
59        self.requesting_entity_id.serialize(buf);
60        buf.put_u8(self.request_id);
61        buf.put_u8(self.number_of_perimeter_points);
62        buf.put_u8(self.pad2);
63        buf.put_u8(self.number_of_sensor_types);
64        buf.put_u32(self.data_filter);
65        self.requested_mine_type.serialize(buf);
66        for i in 0..self.requested_perimeter_points.len() {
67            self.requested_perimeter_points[i].serialize(buf);
68        }
69        for i in 0..self.sensor_types.len() {
70            buf.put_u16(self.sensor_types[i]);
71        }
72    }
73
74    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
75    where
76        Self: Sized,
77    {
78        let pdu_header = PduHeader::deserialize(&mut buffer);
79        if pdu_header.pdu_type == PduType::MinefieldQuery {
80            let minefield_id = EntityId::deserialize(&mut buffer);
81            let requesting_entity_id = EntityId::deserialize(&mut buffer);
82            let request_id = buffer.get_u8();
83            let number_of_perimeter_points = buffer.get_u8();
84            let pad2 = buffer.get_u8();
85            let number_of_sensor_types = buffer.get_u8();
86            let data_filter = buffer.get_u32();
87            let requested_mine_type = EntityType::deserialize(&mut buffer);
88            let mut requested_perimeter_points: Vec<Point> = vec![];
89            for _i in 0..number_of_perimeter_points as usize {
90                requested_perimeter_points.push(Point::deserialize(&mut buffer));
91            }
92            let mut sensor_types: Vec<u16> = vec![];
93            for _i in 0..number_of_sensor_types as usize {
94                sensor_types.push(buffer.get_u16());
95            }
96
97            Ok(MinefieldQueryPdu {
98                pdu_header,
99                minefield_id,
100                requesting_entity_id,
101                request_id,
102                number_of_perimeter_points,
103                pad2,
104                number_of_sensor_types,
105                data_filter,
106                requested_mine_type,
107                requested_perimeter_points,
108                sensor_types,
109            })
110        } else {
111            Err(DISError::invalid_header(
112                format!(
113                    "Expected PDU type MinefieldQuery, got {:?}",
114                    pdu_header.pdu_type
115                ),
116                None,
117            ))
118        }
119    }
120
121    fn as_any(&self) -> &dyn Any {
122        self
123    }
124
125    fn deserialize_without_header(
126        mut buffer: BytesMut,
127        pdu_header: PduHeader,
128    ) -> Result<Self, DISError>
129    where
130        Self: Sized,
131    {
132        let minefield_id = EntityId::deserialize(&mut buffer);
133        let requesting_entity_id = EntityId::deserialize(&mut buffer);
134        let request_id = buffer.get_u8();
135        let number_of_perimeter_points = buffer.get_u8();
136        let pad2 = buffer.get_u8();
137        let number_of_sensor_types = buffer.get_u8();
138        let data_filter = buffer.get_u32();
139        let requested_mine_type = EntityType::deserialize(&mut buffer);
140        let mut requested_perimeter_points: Vec<Point> = vec![];
141        for _i in 0..number_of_perimeter_points as usize {
142            requested_perimeter_points.push(Point::deserialize(&mut buffer));
143        }
144        let mut sensor_types: Vec<u16> = vec![];
145        for _i in 0..number_of_sensor_types as usize {
146            sensor_types.push(buffer.get_u16());
147        }
148
149        Ok(MinefieldQueryPdu {
150            pdu_header,
151            minefield_id,
152            requesting_entity_id,
153            request_id,
154            number_of_perimeter_points,
155            pad2,
156            number_of_sensor_types,
157            data_filter,
158            requested_mine_type,
159            requested_perimeter_points,
160            sensor_types,
161        })
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use super::MinefieldQueryPdu;
168    use crate::common::pdu_header::{PduHeader, PduType, ProtocolFamily};
169
170    #[test]
171    fn create_header() {
172        let minefield_query_pdu = MinefieldQueryPdu::default();
173        let pdu_header =
174            PduHeader::default(PduType::MinefieldQuery, ProtocolFamily::Minefield, 448 / 8);
175
176        assert_eq!(
177            pdu_header.protocol_version,
178            minefield_query_pdu.pdu_header.protocol_version
179        );
180        assert_eq!(
181            pdu_header.exercise_id,
182            minefield_query_pdu.pdu_header.exercise_id
183        );
184        assert_eq!(pdu_header.pdu_type, minefield_query_pdu.pdu_header.pdu_type);
185        assert_eq!(
186            pdu_header.protocol_family,
187            minefield_query_pdu.pdu_header.protocol_family
188        );
189        assert_eq!(pdu_header.length, minefield_query_pdu.pdu_header.length);
190        assert_eq!(
191            pdu_header.status_record,
192            minefield_query_pdu.pdu_header.status_record
193        );
194    }
195}