open-dis-rust 0.4.2

A Rust implementation of the IEEE 1278.1-2012 DIS Standard.
Documentation
//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
//                     Simulation (DIS) application protocol
//     Copyright (C) 2025 Cameron Howell
//
//     Licensed under the BSD 2-Clause License

//! The Information Operations protocol family

use crate::common::enums::{
    IOActionIOActionPhase, IOActionIOActionType, IOActionIOSimulationSource, IOActionIOWarfareType,
    IOReportIOReportType, PduType, ProtocolFamily,
};
use crate::common::generic_header::GenericHeader;
use crate::common::{
    SerializedLength,
    data_types::{
        SimulationIdentifier, entity_id::EntityId,
        standard_variable_specification::StandardVariableSpecification,
    },
    pdu::Pdu,
    pdu_header::PduHeader,
};
use crate::define_pdu;

define_pdu! {
    #[derive(Debug)]
    /// Implemented according to IEEE 1278.1-2012 §7.12.3
    pub struct InformationOperationsReportPdu {
        header: PduHeader,
        pdu_type: PduType::InformationOperationsReport,
        protocol_family: ProtocolFamily::InformationOperations,
        fields: {
            pub originating_simulation_id: SimulationIdentifier,
            pub io_simulation_source: IOActionIOSimulationSource,
            pub io_report_type: IOReportIOReportType,
            padding: u8,
            pub io_attacker_entity_id: EntityId,
            pub primary_target_entity_id: EntityId,
            padding2: u16,
            padding3: u16,
            pub io_records: StandardVariableSpecification,
        }
    }
}

define_pdu! {
    #[derive(Debug)]
    /// Implemented according to IEEE 1278.1-2012 §7.12.2
    pub struct InformationOperationsActionPdu {
        header: PduHeader,
        pdu_type: PduType::InformationOperationsAction,
        protocol_family: ProtocolFamily::InformationOperations,
        fields: {
            pub originating_simulation_id: SimulationIdentifier,
            pub receiving_simulation_id: SimulationIdentifier,
            pub request_id: u32,
            pub io_warfare_type: IOActionIOWarfareType,
            pub io_simulation_source: IOActionIOSimulationSource,
            pub io_action_type: IOActionIOActionType,
            pub io_action_phase: IOActionIOActionPhase,
            padding: u32,
            pub io_attacker_entity_id: EntityId,
            pub io_primary_target_entity_id: EntityId,
            padding2: u16,
            pub io_records: StandardVariableSpecification,
        }
    }
}

#[cfg(test)]
mod tests {
    mod information_operations_actions_pdu {
        use crate::{
            common::{constants::BITS_PER_BYTE, pdu::Pdu},
            information_operations::InformationOperationsActionPdu,
        };
        use bytes::BytesMut;
        #[test]
        fn cast_to_any() {
            let pdu = InformationOperationsActionPdu::new();
            let any_pdu = pdu.as_any();

            assert!(any_pdu.is::<InformationOperationsActionPdu>());
        }

        #[test]
        fn serialize_then_deserialize() {
            let mut pdu = InformationOperationsActionPdu::new();
            let mut serialize_buf = BytesMut::new();
            let _ = pdu.serialize(&mut serialize_buf);

            let mut deserialize_buf = serialize_buf.freeze();
            let new_pdu =
                InformationOperationsActionPdu::deserialize(&mut deserialize_buf).expect("Some");
            assert_eq!(new_pdu.header, pdu.header);
        }

        #[test]
        fn check_default_pdu_length() {
            const DEFAULT_LENGTH: u16 = 448 / BITS_PER_BYTE;
            let pdu = InformationOperationsActionPdu::new();
            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
        }
    }

    mod information_operations_report_pdu {
        use crate::{
            common::{constants::BITS_PER_BYTE, pdu::Pdu},
            information_operations::InformationOperationsReportPdu,
        };
        use bytes::BytesMut;

        #[test]
        fn cast_to_any() {
            let pdu = InformationOperationsReportPdu::new();
            let any_pdu = pdu.as_any();

            assert!(any_pdu.is::<InformationOperationsReportPdu>());
        }

        #[test]
        fn serialize_then_deserialize() {
            let mut pdu = InformationOperationsReportPdu::new();
            let mut serialize_buf = BytesMut::new();
            let _ = pdu.serialize(&mut serialize_buf);

            let mut deserialize_buf = serialize_buf.freeze();
            let new_pdu =
                InformationOperationsReportPdu::deserialize(&mut deserialize_buf).expect("Some");
            assert_eq!(new_pdu.header, pdu.header);
        }

        #[test]
        fn check_default_pdu_length() {
            const DEFAULT_LENGTH: u16 = 320 / BITS_PER_BYTE;
            let pdu = InformationOperationsReportPdu::new();
            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
        }
    }
}