Skip to main content

zerodds_rpc/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Error types for the DDS-RPC crate (C6.1.A).
5//!
6//! Shared by [`crate::common_types`], [`crate::topic_naming`],
7//! [`crate::annotations`] and [`crate::service_mapping`].
8
9extern crate alloc;
10
11use alloc::string::{String, ToString};
12use core::fmt;
13
14/// Collective error for the foundation stage of the DDS-RPC implementation.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum RpcError {
17    /// XCDR2 encoding/decoding violated the wire format.
18    Codec(String),
19    /// DoS cap for the wire payload exceeded.
20    PayloadTooLarge {
21        /// Observed bytes.
22        got: usize,
23        /// Allowed maximum.
24        max: usize,
25    },
26    /// The service name is empty or contains invalid characters.
27    InvalidServiceName(String),
28    /// The method name is empty or invalid.
29    InvalidMethodName(String),
30    /// The method is `oneway` but has a non-`void` return.
31    OnewayWithReturn(String),
32    /// The method is `oneway` but has `out`/`inout` parameters.
33    OnewayWithOutParam {
34        /// Method name.
35        method: String,
36        /// Parameter name.
37        param: String,
38    },
39    /// Duplicate method names in an `interface`.
40    DuplicateMethod(String),
41    /// Duplicate parameter names in a method.
42    DuplicateParam {
43        /// Method name.
44        method: String,
45        /// Parameter name.
46        param: String,
47    },
48    /// Unknown `RemoteExceptionCode_t` discriminator on decode.
49    UnknownExceptionCode(u32),
50    /// Service without methods — no endpoint can be built.
51    EmptyService(String),
52    /// Request-reply wait time exceeded (foundation stage C6.1.C).
53    Timeout,
54    /// The server side returned a `RemoteExceptionCode` other than `Ok`.
55    /// The value is the raw discriminator — the caller can use
56    /// [`crate::common_types::RemoteExceptionCode::from_u32`] to map it into
57    /// the enum.
58    RemoteException(u32),
59    /// A `service_instance_name` assigned twice on the same participant.
60    DuplicateInstanceName(String),
61    /// Generic DCPS call error (topic creation, writer create, etc.).
62    Dcps(String),
63    /// QoS profile not found in the `DdsXml` library.
64    QosProfileNotFound(String),
65}
66
67impl fmt::Display for RpcError {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        match self {
70            Self::Codec(s) => write!(f, "rpc codec error: {s}"),
71            Self::PayloadTooLarge { got, max } => {
72                write!(f, "rpc payload too large: {got} > {max}")
73            }
74            Self::InvalidServiceName(s) => write!(f, "invalid service name: {s:?}"),
75            Self::InvalidMethodName(s) => write!(f, "invalid method name: {s:?}"),
76            Self::OnewayWithReturn(m) => {
77                write!(f, "oneway method {m:?} must return void")
78            }
79            Self::OnewayWithOutParam { method, param } => write!(
80                f,
81                "oneway method {method:?} must not have out/inout param {param:?}"
82            ),
83            Self::DuplicateMethod(m) => write!(f, "duplicate method {m:?}"),
84            Self::DuplicateParam { method, param } => {
85                write!(f, "duplicate parameter {param:?} in method {method:?}")
86            }
87            Self::UnknownExceptionCode(v) => {
88                write!(f, "unknown RemoteExceptionCode_t discriminator {v}")
89            }
90            Self::EmptyService(n) => write!(f, "service {n:?} has no methods"),
91            Self::Timeout => write!(f, "rpc request timed out"),
92            Self::RemoteException(code) => {
93                write!(f, "remote exception code {code}")
94            }
95            Self::DuplicateInstanceName(n) => {
96                write!(f, "duplicate service instance name {n:?}")
97            }
98            Self::Dcps(s) => write!(f, "dcps error: {s}"),
99            Self::QosProfileNotFound(n) => {
100                write!(f, "qos profile {n:?} not found")
101            }
102        }
103    }
104}
105
106#[cfg(feature = "std")]
107impl std::error::Error for RpcError {}
108
109impl RpcError {
110    /// Convenience: constructor for a codec error from a static message.
111    #[must_use]
112    pub fn codec(msg: &str) -> Self {
113        Self::Codec(msg.to_string())
114    }
115}
116
117/// Result-Alias.
118pub type RpcResult<T> = core::result::Result<T, RpcError>;