use serde::{Deserialize, Serialize};
use std::fmt;
pub const MAX_NODES: u32 = 16;
pub const HEARTBEAT_TIMEOUT: u32 = 30;
pub const MAX_PACKAGES_PER_AGENT: u32 = 64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum MessageType {
Invocation = 0,
Oneway = 1,
Reply = 2,
Notification = 3,
}
impl MessageType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(MessageType::Invocation),
1 => Some(MessageType::Oneway),
2 => Some(MessageType::Reply),
3 => Some(MessageType::Notification),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl fmt::Display for MessageType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MessageType::Invocation => write!(f, "Invocation"),
MessageType::Oneway => write!(f, "Oneway"),
MessageType::Reply => write!(f, "Reply"),
MessageType::Notification => write!(f, "Notification"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MessageInfo {
pub message_type: MessageType,
pub service: u8,
pub request: u8,
pub sequence: u32,
}
impl MessageInfo {
pub fn new(message_type: MessageType, service: u8, request: u8, sequence: u32) -> Self {
Self {
message_type,
service,
request,
sequence,
}
}
}
#[derive(Debug, Clone)]
pub struct RequestContext {
pub sequence: u32,
pub is_oneway: bool,
pub service_id: Option<u32>,
pub buffer: Vec<u8>,
}
impl RequestContext {
pub fn new(sequence: u32, is_oneway: bool) -> Self {
Self {
sequence,
is_oneway,
service_id: None,
buffer: Vec::new(),
}
}
pub fn with_service(sequence: u32, service_id: Option<u32>, is_oneway: bool) -> Self {
Self {
sequence,
is_oneway,
service_id,
buffer: Vec::new(),
}
}
pub fn is_oneway(&self) -> bool {
self.is_oneway
}
pub fn sequence(&self) -> u32 {
self.sequence
}
pub fn service_id(&self) -> Option<u32> {
self.service_id
}
pub fn set_codec_data(&mut self, data: Vec<u8>) {
self.buffer = data;
}
pub fn codec_data(&self) -> &[u8] {
&self.buffer
}
pub fn take_codec_data(self) -> Vec<u8> {
self.buffer
}
}
#[derive(Debug, Clone)]
pub struct Reference<T> {
value: Option<T>,
}
impl<T> Reference<T> {
pub fn new(value: T) -> Self {
Self { value: Some(value) }
}
pub fn empty() -> Self {
Self { value: None }
}
pub fn is_some(&self) -> bool {
self.value.is_some()
}
pub fn is_none(&self) -> bool {
self.value.is_none()
}
pub fn as_ref(&self) -> Option<&T> {
self.value.as_ref()
}
pub fn as_mut(&mut self) -> Option<&mut T> {
self.value.as_mut()
}
pub fn take(&mut self) -> Option<T> {
self.value.take()
}
}
impl<T> From<Option<T>> for Reference<T> {
fn from(value: Option<T>) -> Self {
Self { value }
}
}
impl<T> From<T> for Reference<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
pub mod utils {
use crate::error::{ErpcError, ErpcResult};
pub fn check_uint8(value: u64) -> ErpcResult<()> {
if value > u8::MAX as u64 {
Err(ErpcError::InvalidValue(format!(
"Value has to be in range from 0 to 2^8, but was {value}"
)))
} else {
Ok(())
}
}
pub fn check_uint16(value: u64) -> ErpcResult<()> {
if value > u16::MAX as u64 {
Err(ErpcError::InvalidValue(format!(
"Value has to be in range from 0 to 2^16, but was {value}"
)))
} else {
Ok(())
}
}
pub fn check_uint32(value: u64) -> ErpcResult<()> {
if value > u32::MAX as u64 {
Err(ErpcError::InvalidValue(format!(
"Value has to be in range from 0 to 2^32, but was {value}"
)))
} else {
Ok(())
}
}
pub fn check_not_null<T>(value: Option<T>, message: &str) -> ErpcResult<T> {
value.ok_or_else(|| ErpcError::InvalidValue(message.to_string()))
}
pub fn uint32_to_int(value: u32) -> i32 {
value as i32
}
pub fn uint16_to_short(value: u16) -> i16 {
value as i16
}
pub fn uint8_to_byte(value: u8) -> i8 {
value as i8
}
pub fn int_to_uint32(value: i32) -> u32 {
value as u32
}
pub fn short_to_uint16(value: i16) -> u16 {
value as u16
}
pub fn byte_to_uint8(value: i8) -> u8 {
value as u8
}
pub fn uint16_to_bytes(value: u16) -> [u8; 2] {
value.to_le_bytes()
}
pub fn byte_array_to_hex(data: &[u8]) -> String {
data.iter().map(|b| format!("{b:02x}")).collect::<String>()
}
pub fn hex_to_byte_array(hex: &str) -> ErpcResult<Vec<u8>> {
if hex.len() % 2 != 0 {
return Err(ErpcError::InvalidValue(
"Hex string must have even length".to_string(),
));
}
hex.chars()
.collect::<Vec<_>>()
.chunks(2)
.map(|chunk| {
let hex_byte = chunk.iter().collect::<String>();
u8::from_str_radix(&hex_byte, 16)
.map_err(|_| ErpcError::InvalidValue(format!("Invalid hex string: {hex}")))
})
.collect()
}
pub fn uint8_to_i8(value: u8) -> i8 {
value as i8
}
pub fn i8_to_uint8(value: i8) -> u8 {
value as u8
}
pub fn uint16_to_i16(value: u16) -> i16 {
value as i16
}
pub fn i16_to_uint16(value: i16) -> u16 {
value as u16
}
pub fn uint32_to_i32(value: u32) -> i32 {
value as i32
}
pub fn i32_to_uint32(value: i32) -> u32 {
value as u32
}
}
pub mod crc16 {
const CRC16_POLY: u16 = 0x1021;
const CRC_START: u16 = 0xEF4A;
static CRC_TABLE: [u16; 256] = compute_crc_table();
const fn compute_crc_table() -> [u16; 256] {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = 0u16;
let mut y = (i as u16) << 8;
let mut b = 0;
while b < 8 {
let temp = crc ^ y;
crc <<= 1;
if temp & 0x8000 != 0 {
crc ^= CRC16_POLY;
}
y <<= 1;
b += 1;
}
table[i] = crc;
i += 1;
}
table
}
pub fn calculate(data: &[u8]) -> u16 {
let mut crc = CRC_START;
for &byte in data {
let index = ((crc >> 8) ^ (byte as u16)) & 0xFF;
crc = ((crc << 8) ^ CRC_TABLE[index as usize]);
}
crc
}
pub fn verify(data: &[u8], expected_crc: u16) -> bool {
calculate(data) == expected_crc
}
}