Skip to main content

Module error

Module error 

Source
Expand description

Error handling for razor-stream RPC framework.

This module provides the error types and traits used for RPC error handling. It supports both internal RPC errors and user-defined custom errors.

§Default Supported Error Types

The following types have built-in RpcErrCodec implementations:

  • Numeric types: i8, u8, i16, u16, i32, u32

    • Encoded as u32 values for efficient transport
    • Useful for errno-style error codes
  • () (unit type)

    • Encoded as 0u32
    • Used when no additional error information is needed
  • String and &str

    • Encoded as UTF-8 bytes
    • Useful for descriptive error messages
  • nix::errno::Errno

    • Encoded as u32 values
    • For system-level error codes

§Custom Error Types

To use your own error type in RPC methods, implement the RpcErrCodec trait.

Keep in mind that your type should can be serialized into or deserialized from one of the variants of EncodedErr. You have to choose in-between numeric or string:

§Approach 1: Numeric Encoding (errno-style)

Use this when you want compact, efficient numeric error codes.

use num_enum::TryFromPrimitive;
use razor_stream::{Codec, error::{RpcErrCodec, RpcIntErr, EncodedErr}};

#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum MyErrorCode {
    NotFound = 1,
    PermissionDenied = 2,
    Timeout = 3,
}

impl RpcErrCodec for MyErrorCode {
    fn encode<C: Codec>(&self, _codec: &C) -> EncodedErr {
        EncodedErr::Num(*self as u32)
    }

    fn decode<C: Codec>(_codec: &C, buf: Result<u32, &[u8]>) -> Result<Self, ()> {
        if let Ok(code) = buf {
            return MyErrorCode::try_from(code).map_err(|_| ());
        }
        Err(())
    }

    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(self, f)
    }
}

§Approach 2: String Encoding (with strum)

Use this when you want human-readable error strings that can be serialized/deserialized. Uses EncodedErr::Static to avoid heap allocation during encoding.

use razor_stream::{Codec, error::{RpcErrCodec, RpcIntErr, EncodedErr}};
use std::str::FromStr;
use strum::{Display, EnumString, IntoStaticStr};

#[derive(Debug, Clone, Display, EnumString, IntoStaticStr, PartialEq)]
pub enum MyStringError {
    #[strum(serialize = "not_found")]
    NotFound,
    #[strum(serialize = "permission_denied")]
    PermissionDenied,
    #[strum(serialize = "timeout")]
    Timeout,
}

impl RpcErrCodec for MyStringError {
    fn encode<C: Codec>(&self, _codec: &C) -> EncodedErr {
        // Use EncodedErr::Static to avoid heap allocation, with the help of strum::IntoStaticStr
        EncodedErr::Static(self.into())
    }

    fn decode<C: Codec>(_codec: &C, buf: Result<u32, &[u8]>) -> Result<Self, ()> {
        // Decode with zero-copy: directly parse from &[u8] without allocating
        if let Err(bytes) = buf {
            // Safety: error strings are valid ASCII (subset of UTF-8), so unchecked is safe
            let s = unsafe { std::str::from_utf8_unchecked(bytes) };
            // Use strum's EnumString derive to parse from string
            return MyStringError::from_str(s).map_err(|_| ());
        }
        Err(())
    }

    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt(self, f)
    }
}

Enums§

EncodedErr
A container for error message parse from / send into transport
RpcError
A error type defined by client-side user logic
RpcIntErr
RpcIntErr represent internal error from the framework

Constants§

RPC_ERR_PREFIX
“rpc_” prefix is reserved for internal error, you should avoid conflict with it

Traits§

RpcErrCodec
Serialize and Deserialize trait for custom RpcError