315 lines
8.1 KiB
Rust
315 lines
8.1 KiB
Rust
//! 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 {
|
|
(uleb128 $ty:ty) => {
|
|
impl<S> Encode<S> for $ty {
|
|
fn encode(mut self, w: &mut Writer, s: &mut S) {
|
|
let mut byte = 0x80;
|
|
while byte & 0x80 != 0 {
|
|
byte = (self & 0x7f) as u8;
|
|
self >>= 7;
|
|
if self != 0 {
|
|
byte |= 0x80;
|
|
}
|
|
byte.encode(w, s);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<S> DecodeMut<'_, '_, S> for $ty {
|
|
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
|
let mut byte = 0x80;
|
|
let mut v = 0;
|
|
let mut shift = 0;
|
|
while byte & 0x80 != 0 {
|
|
byte = u8::decode(r, s);
|
|
v |= ((byte & 0x7f) as Self) << shift;
|
|
shift += 7;
|
|
}
|
|
v
|
|
}
|
|
}
|
|
};
|
|
(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!(uleb128 u32);
|
|
rpc_encode_decode!(uleb128 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,
|
|
}
|
|
}
|
|
}
|