Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
306 lines (261 sloc) 7.76 KB
//! Serialization for client-server communication.
use std::any::Any;
use std::char;
use std::io::Write;
use std::num::NonZeroU32;
use std::ops::Bound;
use std::str;
pub(super) type Writer = super::buffer::Buffer<u8>;
pub(super) trait Encode<S>: Sized {
fn encode(self, w: &mut Writer, s: &mut S);
}
pub(super) type Reader<'a> = &'a [u8];
pub(super) trait Decode<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s S) -> Self;
}
pub(super) trait DecodeMut<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
}
macro_rules! rpc_encode_decode {
(le $ty:ty) => {
impl<S> Encode<S> for $ty {
fn encode(self, w: &mut Writer, _: &mut S) {
w.write_all(&self.to_le_bytes()).unwrap();
}
}
impl<S> DecodeMut<'_, '_, S> for $ty {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
const N: usize = ::std::mem::size_of::<$ty>();
let mut bytes = [0; N];
bytes.copy_from_slice(&r[..N]);
*r = &r[N..];
Self::from_le_bytes(bytes)
}
}
};
(struct $name:ident { $($field:ident),* $(,)? }) => {
impl<S> Encode<S> for $name {
fn encode(self, w: &mut Writer, s: &mut S) {
$(self.$field.encode(w, s);)*
}
}
impl<S> DecodeMut<'_, '_, S> for $name {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$name {
$($field: DecodeMut::decode(r, s)),*
}
}
}
};
(enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
fn encode(self, w: &mut Writer, s: &mut S) {
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[allow(non_upper_case_globals)]
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
}
match self {
$($name::$variant $(($field))* => {
tag::$variant.encode(w, s);
$($field.encode(w, s);)*
})*
}
}
}
impl<S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
for $name $(<$($T),+>)?
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[allow(non_upper_case_globals)]
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
}
match u8::decode(r, s) {
$(tag::$variant => {
$(let $field = DecodeMut::decode(r, s);)*
$name::$variant $(($field))*
})*
_ => unreachable!(),
}
}
}
}
}
impl<S> Encode<S> for () {
fn encode(self, _: &mut Writer, _: &mut S) {}
}
impl<S> DecodeMut<'_, '_, S> for () {
fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
}
impl<S> Encode<S> for u8 {
fn encode(self, w: &mut Writer, _: &mut S) {
w.write_all(&[self]).unwrap();
}
}
impl<S> DecodeMut<'_, '_, S> for u8 {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
let x = r[0];
*r = &r[1..];
x
}
}
rpc_encode_decode!(le u32);
rpc_encode_decode!(le usize);
impl<S> Encode<S> for bool {
fn encode(self, w: &mut Writer, s: &mut S) {
(self as u8).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for bool {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match u8::decode(r, s) {
0 => false,
1 => true,
_ => unreachable!(),
}
}
}
impl<S> Encode<S> for char {
fn encode(self, w: &mut Writer, s: &mut S) {
(self as u32).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for char {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
char::from_u32(u32::decode(r, s)).unwrap()
}
}
impl<S> Encode<S> for NonZeroU32 {
fn encode(self, w: &mut Writer, s: &mut S) {
self.get().encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for NonZeroU32 {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
Self::new(u32::decode(r, s)).unwrap()
}
}
impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
fn encode(self, w: &mut Writer, s: &mut S) {
self.0.encode(w, s);
self.1.encode(w, s);
}
}
impl<S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S>
for (A, B)
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
(DecodeMut::decode(r, s), DecodeMut::decode(r, s))
}
}
rpc_encode_decode!(
enum Bound<T> {
Included(x),
Excluded(x),
Unbounded,
}
);
rpc_encode_decode!(
enum Option<T> {
None,
Some(x),
}
);
rpc_encode_decode!(
enum Result<T, E> {
Ok(x),
Err(e),
}
);
impl<S> Encode<S> for &[u8] {
fn encode(self, w: &mut Writer, s: &mut S) {
self.len().encode(w, s);
w.write_all(self).unwrap();
}
}
impl<S> DecodeMut<'a, '_, S> for &'a [u8] {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
let len = usize::decode(r, s);
let xs = &r[..len];
*r = &r[len..];
xs
}
}
impl<S> Encode<S> for &str {
fn encode(self, w: &mut Writer, s: &mut S) {
self.as_bytes().encode(w, s);
}
}
impl<S> DecodeMut<'a, '_, S> for &'a str {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
}
}
impl<S> Encode<S> for String {
fn encode(self, w: &mut Writer, s: &mut S) {
self[..].encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for String {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
<&str>::decode(r, s).to_string()
}
}
/// Simplied version of panic payloads, ignoring
/// types other than `&'static str` and `String`.
pub enum PanicMessage {
StaticStr(&'static str),
String(String),
Unknown,
}
impl From<Box<dyn Any + Send>> for PanicMessage {
fn from(payload: Box<dyn Any + Send + 'static>) -> Self {
if let Some(s) = payload.downcast_ref::<&'static str>() {
return PanicMessage::StaticStr(s);
}
if let Ok(s) = payload.downcast::<String>() {
return PanicMessage::String(*s);
}
PanicMessage::Unknown
}
}
impl Into<Box<dyn Any + Send>> for PanicMessage {
fn into(self) -> Box<dyn Any + Send> {
match self {
PanicMessage::StaticStr(s) => Box::new(s),
PanicMessage::String(s) => Box::new(s),
PanicMessage::Unknown => {
struct UnknownPanicMessage;
Box::new(UnknownPanicMessage)
}
}
}
}
impl PanicMessage {
pub fn as_str(&self) -> Option<&str> {
match self {
PanicMessage::StaticStr(s) => Some(s),
PanicMessage::String(s) => Some(s),
PanicMessage::Unknown => None,
}
}
}
impl<S> Encode<S> for PanicMessage {
fn encode(self, w: &mut Writer, s: &mut S) {
self.as_str().encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for PanicMessage {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match Option::<String>::decode(r, s) {
Some(s) => PanicMessage::String(s),
None => PanicMessage::Unknown,
}
}
}
You can’t perform that action at this time.