use crate::Error;
use crate::error::private::InnerError;
use crate::transport::Endian;
pub const HEADER_LEN: u32 = 12;
pub const MAX_PAYLOAD_LEN: u32 = u32::MAX - HEADER_LEN;
pub trait Body: Send + Sync + Sized + 'static {
fn empty() -> Self;
fn from_error(message: &str) -> Self;
fn as_error(&self) -> Result<&str, std::str::Utf8Error>;
fn into_error(self) -> Result<String, std::string::FromUtf8Error>;
}
pub mod service_id {
pub const ERROR: i32 = -1;
}
pub struct Message<Body> {
pub header: MessageHeader,
pub body: Body,
}
impl<Body> Message<Body> {
pub fn new(header: MessageHeader, body: Body) -> Self {
Self { header, body }
}
pub fn request(request_id: u32, service_id: i32, body: Body) -> Self {
Self::new(MessageHeader::request(request_id, service_id), body)
}
pub fn response(request_id: u32, service_id: i32, body: Body) -> Self {
Self::new(MessageHeader::response(request_id, service_id), body)
}
pub fn error_response(request_id: u32, message: &str) -> Self
where
Body: crate::Body,
{
Self::new(MessageHeader::response(request_id, service_id::ERROR), Body::from_error(message))
}
pub fn requester_update(request_id: u32, service_id: i32, body: Body) -> Self {
Self::new(MessageHeader::requester_update(request_id, service_id), body)
}
pub fn responder_update(request_id: u32, service_id: i32, body: Body) -> Self {
Self::new(MessageHeader::responder_update(request_id, service_id), body)
}
pub fn stream(request_id: u32, service_id: i32, body: Body) -> Self {
Self::new(MessageHeader::stream(request_id, service_id), body)
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MessageType {
Request = 0,
Response = 1,
RequesterUpdate = 2,
ResponderUpdate = 3,
Stream = 4,
}
impl MessageType {
pub fn from_u32(value: u32) -> Result<Self, Error> {
match value {
0 => Ok(Self::Request),
1 => Ok(Self::Response),
2 => Ok(Self::RequesterUpdate),
3 => Ok(Self::ResponderUpdate),
4 => Ok(Self::Stream),
value => Err(InnerError::InvalidMessageType { value }.into()),
}
}
pub fn is_request(self) -> bool {
self == MessageType::Request
}
pub fn is_response(self) -> bool {
self == MessageType::Response
}
pub fn is_requester_update(self) -> bool {
self == MessageType::RequesterUpdate
}
pub fn is_responder_update(self) -> bool {
self == MessageType::ResponderUpdate
}
pub fn is_stream(self) -> bool {
self == MessageType::Stream
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MessageHeader {
pub message_type: MessageType,
pub request_id: u32,
pub service_id: i32,
}
impl MessageHeader {
pub fn request(request_id: u32, service_id: i32) -> Self {
Self {
message_type: MessageType::Request,
request_id,
service_id,
}
}
pub fn response(request_id: u32, service_id: i32) -> Self {
Self {
message_type: MessageType::Response,
request_id,
service_id,
}
}
pub fn error_response(request_id: u32) -> Self {
Self::response(request_id, service_id::ERROR)
}
pub fn requester_update(request_id: u32, service_id: i32) -> Self {
Self {
message_type: MessageType::RequesterUpdate,
request_id,
service_id,
}
}
pub fn responder_update(request_id: u32, service_id: i32) -> Self {
Self {
message_type: MessageType::ResponderUpdate,
request_id,
service_id,
}
}
pub fn stream(request_id: u32, service_id: i32) -> Self {
Self {
message_type: MessageType::Stream,
request_id,
service_id,
}
}
pub fn decode(buffer: &[u8], endian: Endian) -> Result<Self, Error> {
let message_type = endian.read_u32(&buffer[0..]);
let request_id = endian.read_u32(&buffer[4..]);
let service_id = endian.read_i32(&buffer[8..]);
let message_type = MessageType::from_u32(message_type)?;
Ok(Self {
message_type,
request_id,
service_id,
})
}
pub fn encode(&self, buffer: &mut [u8], endian: Endian) {
assert!(buffer.len() >= 12);
endian.write_u32(&mut buffer[0..], self.message_type as u32);
endian.write_u32(&mut buffer[4..], self.request_id);
endian.write_i32(&mut buffer[8..], self.service_id);
}
}
impl<Body> std::fmt::Debug for Message<Body> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Message")
.field("header", &self.header)
.finish_non_exhaustive()
}
}