open_dis_rust/simulation_management/
action_request_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
17#[derive(Copy, Clone, Debug)]
18/// Implemented according to IEEE 1278.1-2012 ยง7.5.7
19pub struct ActionRequestPdu {
20    pub pdu_header: PduHeader,
21    pub originating_entity_id: EntityId,
22    pub receiving_entity_id: EntityId,
23    pub request_id: u32,
24    pub action_id: u32,
25    pub number_of_fixed_datum_records: u32,
26    pub number_of_variable_datum_records: u32,
27    pub fixed_datum_records: u64,
28    pub variable_datum_records: u64,
29}
30
31impl Default for ActionRequestPdu {
32    /// Creates a default-initialized Action Request PDU
33    ///
34    /// # Examples
35    ///
36    /// Initializing an Action Request PDU:
37    /// ```
38    /// use open_dis_rust::simulation_management::action_request_pdu::ActionRequestPdu;
39    /// let mut action_request_pdu = ActionRequestPdu::default();
40    /// ```
41    ///
42    fn default() -> Self {
43        ActionRequestPdu {
44            pdu_header: PduHeader::default(
45                PduType::ActionRequest,
46                ProtocolFamily::SimulationManagement,
47                56,
48            ),
49            originating_entity_id: EntityId::default(1),
50            receiving_entity_id: EntityId::default(2),
51            request_id: 0,
52            action_id: 0,
53            number_of_fixed_datum_records: 0,
54            number_of_variable_datum_records: 0,
55            fixed_datum_records: 0,
56            variable_datum_records: 0,
57        }
58    }
59}
60
61impl Pdu for ActionRequestPdu {
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.originating_entity_id.serialize(buf);
67        self.receiving_entity_id.serialize(buf);
68        buf.put_u32(self.request_id);
69        buf.put_u32(self.action_id);
70        buf.put_u32(self.number_of_fixed_datum_records);
71        buf.put_u32(self.number_of_variable_datum_records);
72        buf.put_u64(self.fixed_datum_records);
73        buf.put_u64(self.variable_datum_records);
74    }
75
76    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
77    where
78        Self: Sized,
79    {
80        let pdu_header = PduHeader::deserialize(&mut buffer);
81        if pdu_header.pdu_type == PduType::ActionRequest {
82            let originating_entity_id = EntityId::deserialize(&mut buffer);
83            let receiving_entity_id = EntityId::deserialize(&mut buffer);
84            let request_id = buffer.get_u32();
85            let action_id = buffer.get_u32();
86            let number_of_fixed_datum_records = buffer.get_u32();
87            let number_of_variable_datum_records = buffer.get_u32();
88            let mut fixed_datum_records: u64 = 0;
89            for _record in 0..number_of_fixed_datum_records as usize {
90                fixed_datum_records += buffer.get_u64();
91            }
92            let mut variable_datum_records: u64 = 0;
93            for _record in 0..number_of_variable_datum_records as usize {
94                variable_datum_records += buffer.get_u64();
95            }
96
97            Ok(ActionRequestPdu {
98                pdu_header,
99                originating_entity_id,
100                receiving_entity_id,
101                request_id,
102                action_id,
103                number_of_fixed_datum_records,
104                number_of_variable_datum_records,
105                fixed_datum_records,
106                variable_datum_records,
107            })
108        } else {
109            Err(DISError::invalid_header(
110                format!(
111                    "Expected PDU type ActionRequest, got {:?}",
112                    pdu_header.pdu_type
113                ),
114                None,
115            ))
116        }
117    }
118
119    fn as_any(&self) -> &dyn Any {
120        self
121    }
122
123    fn deserialize_without_header(
124        mut buffer: BytesMut,
125        pdu_header: PduHeader,
126    ) -> Result<Self, DISError>
127    where
128        Self: Sized,
129    {
130        let originating_entity_id = EntityId::deserialize(&mut buffer);
131        let receiving_entity_id = EntityId::deserialize(&mut buffer);
132        let request_id = buffer.get_u32();
133        let action_id = buffer.get_u32();
134        let number_of_fixed_datum_records = buffer.get_u32();
135        let number_of_variable_datum_records = buffer.get_u32();
136        let mut fixed_datum_records: u64 = 0;
137        for _record in 0..number_of_fixed_datum_records as usize {
138            fixed_datum_records += buffer.get_u64();
139        }
140        let mut variable_datum_records: u64 = 0;
141        for _record in 0..number_of_variable_datum_records as usize {
142            variable_datum_records += buffer.get_u64();
143        }
144
145        Ok(ActionRequestPdu {
146            pdu_header,
147            originating_entity_id,
148            receiving_entity_id,
149            request_id,
150            action_id,
151            number_of_fixed_datum_records,
152            number_of_variable_datum_records,
153            fixed_datum_records,
154            variable_datum_records,
155        })
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::ActionRequestPdu;
162    use crate::common::{
163        pdu::Pdu,
164        pdu_header::{PduHeader, PduType, ProtocolFamily},
165    };
166    use bytes::BytesMut;
167
168    #[test]
169    fn create_header() {
170        let action_request_pdu = ActionRequestPdu::default();
171        let pdu_header = PduHeader::default(
172            PduType::ActionRequest,
173            ProtocolFamily::SimulationManagement,
174            448 / 8,
175        );
176
177        assert_eq!(
178            pdu_header.protocol_version,
179            action_request_pdu.pdu_header.protocol_version
180        );
181        assert_eq!(
182            pdu_header.exercise_id,
183            action_request_pdu.pdu_header.exercise_id
184        );
185        assert_eq!(pdu_header.pdu_type, action_request_pdu.pdu_header.pdu_type);
186        assert_eq!(
187            pdu_header.protocol_family,
188            action_request_pdu.pdu_header.protocol_family
189        );
190        assert_eq!(pdu_header.length, action_request_pdu.pdu_header.length);
191        assert_eq!(
192            pdu_header.status_record,
193            action_request_pdu.pdu_header.status_record
194        );
195    }
196
197    #[test]
198    fn cast_to_any() {
199        let action_request_pdu = ActionRequestPdu::default();
200        let any_pdu = action_request_pdu.as_any();
201
202        assert!(any_pdu.is::<ActionRequestPdu>());
203    }
204
205    #[test]
206    fn deserialize_header() {
207        let mut action_request_pdu = ActionRequestPdu::default();
208        let mut buffer = BytesMut::new();
209        action_request_pdu.serialize(&mut buffer);
210
211        let new_action_request_pdu = ActionRequestPdu::deserialize(buffer).unwrap();
212        assert_eq!(
213            new_action_request_pdu.pdu_header,
214            action_request_pdu.pdu_header
215        );
216    }
217}