open_dis_rust/entity_management/
is_part_of_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::BytesMut;
8use std::any::Any;
9
10use crate::common::{
11    dis_error::DISError,
12    entity_id::EntityId,
13    entity_type::EntityType,
14    pdu::Pdu,
15    pdu_header::{PduHeader, PduType, ProtocolFamily},
16    vector3_float::Vector3Float,
17};
18
19use super::data_types::{named_location::NamedLocation, relationship::Relationship};
20
21#[derive(Clone, Debug)]
22/// Implemented according to IEEE 1278.1-2012 ยง7.8.5
23pub struct IsPartOfPdu {
24    pub pdu_header: PduHeader,
25    pub originating_entity_id: EntityId,
26    pub receiving_entity_id: EntityId,
27    pub relationship: Relationship,
28    pub part_location: Vector3Float,
29    pub named_location_id: NamedLocation,
30    pub part_entity_type: EntityType,
31}
32
33impl Default for IsPartOfPdu {
34    /// Creates a default Is Part Of PDU with arbitrary aggregate ID
35    ///
36    /// # Examples
37    ///
38    /// Initializing an Is Part Of PDU:
39    /// ```
40    /// use open_dis_rust::entity_management::is_part_of_pdu::IsPartOfPdu;
41    /// let is_part_of_pdu = IsPartOfPdu::default();
42    /// ```
43    ///
44    fn default() -> Self {
45        IsPartOfPdu {
46            pdu_header: PduHeader::default(PduType::IsPartOf, ProtocolFamily::EntityManagement, 56),
47            originating_entity_id: EntityId::default(1),
48            receiving_entity_id: EntityId::default(2),
49            relationship: Relationship::default(),
50            part_location: Vector3Float::default(),
51            named_location_id: NamedLocation::default(),
52            part_entity_type: EntityType::default(),
53        }
54    }
55}
56
57impl Pdu for IsPartOfPdu {
58    fn serialize(&mut self, buf: &mut BytesMut) {
59        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
60            .expect("The length of the PDU should fit in a u16.");
61        self.pdu_header.serialize(buf);
62        self.originating_entity_id.serialize(buf);
63        self.receiving_entity_id.serialize(buf);
64        self.relationship.serialize(buf);
65        self.part_location.serialize(buf);
66        self.named_location_id.serialize(buf);
67        self.part_entity_type.serialize(buf);
68    }
69
70    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
71    where
72        Self: Sized,
73    {
74        let pdu_header = PduHeader::deserialize(&mut buffer);
75        if pdu_header.pdu_type == PduType::IsPartOf {
76            let originating_entity_id = EntityId::deserialize(&mut buffer);
77            let receiving_entity_id = EntityId::deserialize(&mut buffer);
78            let relationship = Relationship::deserialize(&mut buffer);
79            let part_location = Vector3Float::deserialize(&mut buffer);
80            let named_location_id = NamedLocation::deserialize(&mut buffer);
81            let part_entity_type = EntityType::deserialize(&mut buffer);
82            Ok(IsPartOfPdu {
83                pdu_header,
84                originating_entity_id,
85                receiving_entity_id,
86                relationship,
87                part_location,
88                named_location_id,
89                part_entity_type,
90            })
91        } else {
92            Err(DISError::invalid_header(
93                format!("Expected PDU type IsPartOf, got {:?}", pdu_header.pdu_type),
94                None,
95            ))
96        }
97    }
98
99    fn as_any(&self) -> &dyn Any {
100        self
101    }
102
103    fn deserialize_without_header(
104        mut buffer: BytesMut,
105        pdu_header: PduHeader,
106    ) -> Result<Self, DISError>
107    where
108        Self: Sized,
109    {
110        let originating_entity_id = EntityId::deserialize(&mut buffer);
111        let receiving_entity_id = EntityId::deserialize(&mut buffer);
112        let relationship = Relationship::deserialize(&mut buffer);
113        let part_location = Vector3Float::deserialize(&mut buffer);
114        let named_location_id = NamedLocation::deserialize(&mut buffer);
115        let part_entity_type = EntityType::deserialize(&mut buffer);
116        Ok(IsPartOfPdu {
117            pdu_header,
118            originating_entity_id,
119            receiving_entity_id,
120            relationship,
121            part_location,
122            named_location_id,
123            part_entity_type,
124        })
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::IsPartOfPdu;
131    use crate::common::{
132        pdu::Pdu,
133        pdu_header::{PduHeader, PduType, ProtocolFamily},
134    };
135    use bytes::BytesMut;
136
137    #[test]
138    fn create_header() {
139        let is_part_of_pdu = IsPartOfPdu::default();
140        let pdu_header =
141            PduHeader::default(PduType::IsPartOf, ProtocolFamily::EntityManagement, 448 / 8);
142
143        assert_eq!(
144            pdu_header.protocol_version,
145            is_part_of_pdu.pdu_header.protocol_version
146        );
147        assert_eq!(
148            pdu_header.exercise_id,
149            is_part_of_pdu.pdu_header.exercise_id
150        );
151        assert_eq!(pdu_header.pdu_type, is_part_of_pdu.pdu_header.pdu_type);
152        assert_eq!(
153            pdu_header.protocol_family,
154            is_part_of_pdu.pdu_header.protocol_family
155        );
156        assert_eq!(pdu_header.length, is_part_of_pdu.pdu_header.length);
157        assert_eq!(
158            pdu_header.status_record,
159            is_part_of_pdu.pdu_header.status_record
160        );
161    }
162
163    #[test]
164    fn deserialize_header() {
165        let mut is_part_of_pdu = IsPartOfPdu::default();
166        let mut buffer = BytesMut::new();
167        is_part_of_pdu.serialize(&mut buffer);
168
169        let new_is_part_of_pdu = IsPartOfPdu::deserialize(buffer).unwrap();
170        assert_eq!(new_is_part_of_pdu.pdu_header, is_part_of_pdu.pdu_header);
171    }
172}