open_dis_rust/common/
dis_error.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 thiserror::Error;
8
9/// Protocol version and header related states
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum PduState {
12    Uninitialized,
13    HeaderValid,
14    BodyValid,
15    Complete,
16}
17
18/// Protocol version and family related states
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ProtocolVersion {
21    IEEE1278_1_1995,
22    IEEE1278_1_1998,
23    IEEE1278_1_2012,
24}
25
26#[derive(Error, Debug)]
27/// Enhanced error types for DIS protocol operations
28pub enum DISError {
29    #[error("Invalid PDU header: {reason}")]
30    InvalidHeader {
31        reason: String,
32        #[source]
33        source: Option<Box<dyn std::error::Error + Send + Sync>>,
34    },
35
36    #[error("PDU deserialization error: {msg}")]
37    DeserializationError {
38        msg: String,
39        #[source]
40        source: Option<Box<dyn std::error::Error + Send + Sync>>,
41    },
42
43    #[error("PDU serialization error: {msg}")]
44    SerializationError {
45        msg: String,
46        #[source]
47        source: Option<Box<dyn std::error::Error + Send + Sync>>,
48    },
49
50    #[error("Invalid PDU state transition: {current_state:?} -> {target_state:?}")]
51    InvalidStateTransition {
52        current_state: PduState,
53        target_state: PduState,
54    },
55
56    #[error("Protocol version mismatch: expected {expected:?}, got {got:?}")]
57    ProtocolVersionMismatch {
58        expected: ProtocolVersion,
59        got: ProtocolVersion,
60    },
61
62    #[error("Invalid field value: {field} = {value}, {reason}")]
63    InvalidFieldValue {
64        field: String,
65        value: String,
66        reason: String,
67    },
68
69    #[error("Buffer underflow: tried to read {attempted} bytes, but only {available} bytes remain")]
70    BufferUnderflow { attempted: usize, available: usize },
71
72    #[error("Network error: {0}")]
73    NetworkError(#[from] std::io::Error),
74
75    #[error("PDU size exceeds maximum allowed: {size} > {max_size}")]
76    PduSizeExceeded { size: usize, max_size: usize },
77}
78
79impl DISError {
80    /// Create a new `InvalidHeader` error with optional source error
81    pub fn invalid_header<S: Into<String>>(
82        reason: S,
83        source: Option<Box<dyn std::error::Error + Send + Sync>>,
84    ) -> Self {
85        DISError::InvalidHeader {
86            reason: reason.into(),
87            source,
88        }
89    }
90
91    /// Create a new `DeserializationError` with optional source error
92    pub fn deserialization_error<S: Into<String>>(
93        msg: S,
94        source: Option<Box<dyn std::error::Error + Send + Sync>>,
95    ) -> Self {
96        DISError::DeserializationError {
97            msg: msg.into(),
98            source,
99        }
100    }
101
102    /// Create a new `SerializationError` with optional source error
103    pub fn serialization_error<S: Into<String>>(
104        msg: S,
105        source: Option<Box<dyn std::error::Error + Send + Sync>>,
106    ) -> Self {
107        DISError::SerializationError {
108            msg: msg.into(),
109            source,
110        }
111    }
112
113    /// Create a new `InvalidFieldValue` error
114    pub fn invalid_field<S: Into<String>>(field: S, value: S, reason: S) -> Self {
115        DISError::InvalidFieldValue {
116            field: field.into(),
117            value: value.into(),
118            reason: reason.into(),
119        }
120    }
121
122    #[must_use]
123    /// Create a new `BufferUnderflow` error
124    pub fn buffer_underflow(attempted: usize, available: usize) -> Self {
125        DISError::BufferUnderflow {
126            attempted,
127            available,
128        }
129    }
130
131    #[must_use]
132    /// Create a new `PduSizeExceeded` error
133    pub const fn pdu_size_exceeded(size: usize, max_size: usize) -> Self {
134        DISError::PduSizeExceeded { size, max_size }
135    }
136}
137
138/// Result type for DIS operations
139pub type DISResult<T> = Result<T, DISError>;