use anyhow::Context;
use rmp::decode;
use serde::{de::DeserializeOwned, Deserialize, Serializer};
use std::error::Error as StdError;
use std::ops::RangeFrom;
pub const REQUEST: u32 = 0; pub const RESPONSE: u32 = 1; pub const NOTIFY: u32 = 2; pub const RESPONSE_STREAM: u32 = 3;
pub struct Packet {
pub(crate) meta: PackMeta,
pack: Vec<u8>,
dref: RangeFrom<usize>,
}
pub type Method = serde_value::Value;
#[doc(hidden)]
#[derive(Debug, Clone)]
pub enum PackMeta {
Notify { method: Method },
Request { method: Method, req: u32 },
Response { req: u32, error: Option<Box<str>> },
Stream { req: u32, finished: bool },
}
impl Packet {
pub fn from_pack(pack: Vec<u8>) -> anyhow::Result<Self> {
let mut reader = &pack[..];
let start_ptr = reader.as_ptr() as usize;
let len = decode::read_array_len(&mut reader).context("len")?;
let pack_type: u32 = decode::read_int(&mut reader).context("type")?;
Ok(match pack_type {
REQUEST => {
assert_eq!(len, 4);
let req: u32 = decode::read_int(&mut reader).context("reqid")?;
let method = rmp_serde::decode::from_read(&mut reader).context("method")?;
Self {
meta: PackMeta::Request { method, req },
dref: reader.as_ptr() as usize - start_ptr..,
pack,
}
}
NOTIFY => {
assert_eq!(len, 3);
let method = rmp_serde::decode::from_read(&mut reader).context("method")?;
Self {
meta: PackMeta::Notify { method },
dref: reader.as_ptr() as usize - start_ptr..,
pack,
}
}
RESPONSE => {
assert_eq!(len, 4);
let req: u32 = decode::read_int(&mut reader).context("reqid")?;
let error = rmpv::decode::read_value(&mut reader).context("method")?;
Self {
meta: PackMeta::Response {
req,
error: error.as_str().map(Into::into),
},
dref: reader.as_ptr() as usize - start_ptr..,
pack,
}
}
RESPONSE_STREAM => {
assert_eq!(len, 4);
let req: u32 = decode::read_int(&mut reader).context("reqid")?;
let finished = decode::read_bool(&mut reader).context("finished")?;
Self {
meta: PackMeta::Stream { req, finished },
dref: reader.as_ptr() as usize - start_ptr..,
pack,
}
}
_ => unreachable!(),
})
}
#[inline(always)]
pub fn data(&self) -> &[u8] {
&self.pack[self.dref.clone()]
}
pub fn error(&self) -> Option<&str> {
match &self.meta {
PackMeta::Response { error, .. } => error.as_ref().map(AsRef::as_ref),
_ => None,
}
}
#[inline(always)]
pub fn decode<'a, T: Deserialize<'a>>(&'a self) -> Result<T, impl StdError> {
rmp_serde::from_slice(self.data())
}
#[inline(always)]
pub fn decode_to<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serde_transcode::transcode(&mut rmp_serde::Deserializer::new(self.data()), s)
}
pub fn method(&self) -> Option<&Method> {
match &self.meta {
PackMeta::Notify { method } => Some(method),
PackMeta::Request { method, .. } => Some(method),
_ => None,
}
}
pub fn request_id(&self) -> Option<u32> {
match self.meta {
PackMeta::Request { req, .. } => Some(req),
PackMeta::Response { req, .. } => Some(req),
_ => None,
}
}
}
pub trait FromPacket: Sized {
fn from_packet(pack: Packet) -> anyhow::Result<Self>;
}
impl<T: DeserializeOwned + 'static> FromPacket for T {
fn from_packet(pack: Packet) -> anyhow::Result<Self> {
match pack.error() {
Some(err) => Err(anyhow::Error::msg(err.to_string())),
None => Ok(pack.decode()?),
}
}
}
impl FromPacket for Packet {
fn from_packet(pack: Packet) -> anyhow::Result<Self> {
Ok(pack)
}
}