open_dis_rust/
entity_management.rs

1//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
2//                     Simulation (DIS) application protocol
3//     Copyright (C) 2025 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7//! The Entity Management protocol family
8
9use crate::{
10    common::{
11        GenericHeader, SerializedLength,
12        data_types::{
13            EntityId, EntityType, EulerAngles, LinearVelocity, SimulationIdentifier, Vector3Float,
14            WorldCoordinate, datum_records::VariableDatumRecord, named_location::NamedLocation,
15            record_specification::RecordSpecification, relationship::Relationship,
16        },
17        enums::{
18            AggregateStateAggregateState, AggregateStateFormation, ForceId,
19            IsGroupOfGroupedEntityCategory, PduType, ProtocolFamily, RequiredReliabilityService,
20            TransferControlTransferType,
21        },
22        pdu::Pdu,
23        pdu_header::PduHeader,
24    },
25    define_pdu,
26};
27
28use crate::common::data_types::{aggregate_id::AggregateId, aggregate_marking::AggregateMarking};
29
30define_pdu! {
31    #[derive(Debug)]
32    /// Implemented according to IEEE 1278.1-2012 §7.8.2
33    pub struct AggregateStatePdu {
34        header: PduHeader,
35        pdu_type: PduType::AggregateState,
36        protocol_family: ProtocolFamily::EntityManagement,
37        fields: {
38            pub aggregate_id: AggregateId,
39            pub force_id: ForceId,
40            pub aggregate_state: AggregateStateAggregateState,
41            pub aggregate_type: EntityType,
42            pub formation: AggregateStateFormation,
43            pub aggregate_marking: AggregateMarking,
44            pub dimensions: Vector3Float,
45            pub orientation: EulerAngles,
46            pub center_of_mass: WorldCoordinate,
47            pub velocity: LinearVelocity,
48            pub number_of_dis_aggregates: u16,
49            pub number_of_dis_entities: u16,
50            pub number_of_silent_aggregate_types: u16,
51            pub number_of_silent_entity_types: u16,
52            pub aggregate_id_list: Vec<AggregateId>,
53            pub entity_id_list: Vec<EntityId>,
54            padding: Vec<u8>,
55            pub silent_aggregate_system_list: Vec<EntityType>,
56            pub silent_entity_system_list: Vec<EntityType>,
57            pub number_of_variable_datum_records: u32,
58            pub variable_datum_list: Vec<VariableDatumRecord>,
59        }
60    }
61}
62
63define_pdu! {
64    #[derive(Debug)]
65    /// Implemented according to IEEE 1278.1-2012 §7.8.3
66    pub struct IsGroupOfPdu {
67        header: PduHeader,
68        pdu_type: PduType::IsGroupOf,
69        protocol_family: ProtocolFamily::EntityManagement,
70        fields: {
71            pub group_entity_id: EntityId,
72            pub grouped_entity_category: IsGroupOfGroupedEntityCategory,
73            pub number_of_grouped_entities: u8,
74            padding: u32,
75            pub latitude: f64,
76            pub longitude: f64,
77            pub grouped_entity_descriptions: Vec<u64>,
78        }
79    }
80}
81
82define_pdu! {
83    #[derive(Debug)]
84    /// Implemented according to IEEE 1278.1-2012 §7.8.4
85    pub struct TransferOwnershipPdu {
86        header: PduHeader,
87        pdu_type: PduType::TransferOwnership,
88        protocol_family: ProtocolFamily::EntityManagement,
89        fields: {
90            pub originating_id: SimulationIdentifier,
91            pub receiving_id: SimulationIdentifier,
92            pub request_id: u32,
93            pub required_reliability_service: RequiredReliabilityService,
94            pub transfer_type: TransferControlTransferType,
95            pub transfer_entity_id: EntityId,
96            pub record_information: RecordSpecification,
97        }
98    }
99}
100
101define_pdu! {
102    #[derive(Debug)]
103    /// Implemented according to IEEE 1278.1-2012 §7.8.5
104    pub struct IsPartOfPdu {
105        header: PduHeader,
106        pdu_type: PduType::IsPartOf,
107        protocol_family: ProtocolFamily::EntityManagement,
108        fields: {
109            pub originating_entity_id: EntityId,
110            pub receiving_entity_id: EntityId,
111            pub relationship: Relationship,
112            pub part_location: Vector3Float,
113            pub named_location_id: NamedLocation,
114            pub part_entity_type: EntityType,
115        }
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    use crate::common::{constants::BITS_PER_BYTE, pdu::Pdu};
123    use bytes::BytesMut;
124
125    mod aggregate_state_pdu_tests {
126        use super::*;
127
128        #[test]
129        fn cast_to_any() {
130            let pdu = AggregateStatePdu::new();
131            let any_pdu = pdu.as_any();
132
133            assert!(any_pdu.is::<AggregateStatePdu>());
134        }
135
136        #[test]
137        fn serialize_then_deserialize() {
138            let mut pdu = AggregateStatePdu::new();
139            let mut serialize_buf = BytesMut::new();
140            let _ = pdu.serialize(&mut serialize_buf);
141
142            let mut deserialize_buf = serialize_buf.freeze();
143            let new_pdu = AggregateStatePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
144            assert_eq!(new_pdu.header, pdu.header);
145        }
146
147        #[test]
148        fn check_default_pdu_length() {
149            const DEFAULT_LENGTH: u16 = 1088 / BITS_PER_BYTE;
150            let pdu = AggregateStatePdu::new();
151            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
152        }
153    }
154
155    mod transfer_ownership_pdu_tests {
156        use super::*;
157
158        #[test]
159        fn cast_to_any() {
160            let pdu = TransferOwnershipPdu::new();
161            let any_pdu = pdu.as_any();
162
163            assert!(any_pdu.is::<TransferOwnershipPdu>());
164        }
165
166        #[test]
167        fn serialize_then_deserialize() {
168            let mut pdu = TransferOwnershipPdu::new();
169            let mut serialize_buf = BytesMut::new();
170            let _ = pdu.serialize(&mut serialize_buf);
171
172            let mut deserialize_buf = serialize_buf.freeze();
173            let new_pdu =
174                TransferOwnershipPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
175            assert_eq!(new_pdu.header, pdu.header);
176        }
177
178        #[test]
179        fn check_default_pdu_length() {
180            const DEFAULT_LENGTH: u16 = 320 / BITS_PER_BYTE;
181            let pdu = TransferOwnershipPdu::new();
182            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
183        }
184    }
185
186    mod is_group_of_pdu_tests {
187        use super::*;
188
189        #[test]
190        fn cast_to_any() {
191            let pdu = IsGroupOfPdu::new();
192            let any_pdu = pdu.as_any();
193
194            assert!(any_pdu.is::<IsGroupOfPdu>());
195        }
196
197        #[test]
198        fn serialize_then_deserialize() {
199            let mut pdu = IsGroupOfPdu::new();
200            let mut serialize_buf = BytesMut::new();
201            let _ = pdu.serialize(&mut serialize_buf);
202
203            let mut deserialize_buf = serialize_buf.freeze();
204            let new_pdu = IsGroupOfPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
205            assert_eq!(new_pdu.header, pdu.header);
206        }
207
208        #[test]
209        fn check_default_pdu_length() {
210            const DEFAULT_LENGTH: u16 = 320 / BITS_PER_BYTE;
211            let pdu = IsGroupOfPdu::new();
212            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
213        }
214    }
215
216    mod is_part_of_pdu_tests {
217        use super::*;
218
219        #[test]
220        fn cast_to_any() {
221            let pdu = IsPartOfPdu::new();
222            let any_pdu = pdu.as_any();
223
224            assert!(any_pdu.is::<IsPartOfPdu>());
225        }
226
227        #[test]
228        fn serialize_then_deserialize() {
229            let mut pdu = IsPartOfPdu::new();
230            let mut serialize_buf = BytesMut::new();
231            let _ = pdu.serialize(&mut serialize_buf);
232
233            let mut deserialize_buf = serialize_buf.freeze();
234            let new_pdu = IsPartOfPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
235            assert_eq!(new_pdu.header, pdu.header);
236        }
237
238        #[test]
239        fn check_default_pdu_length() {
240            const DEFAULT_LENGTH: u16 = 416 / BITS_PER_BYTE;
241            let pdu = IsPartOfPdu::new();
242            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
243        }
244    }
245}