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