forked from nervosnetwork/muta
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(protocol): Protobuf serialize (#6)
* feat(protocol): Add the underlying data structure. * chore(rust-toolchain): bump to nightly-2019-08-01 Fix prost compilation failure. * feat(protocol): add codec trait * feat(protocol): add primitive protobuf structs * feat(protocol): implement conversion for protobuf primitive * feat(protocol): implement ProtocolCodec for protocol primitive * feat(protocol): add transaction protobuf structs * feat(protocol): implement conversion for transaction protobuf * feat(protocol): add *_sync funcs to codec * chore(protocol): rename BytesCodec to ProtocolCodecSync * fix(protocol): clippy warning * chore(protocol): ProtocolCodec::encode now takes mut reference * chore(protocol): add _sync suffix to ProtocolCodecSync funcs * chore(protocol): ProtocolCodec now depends on ProtocolCodecSync Shorten ProtocolCodec trait bound * chore(protocol): rebase to latest master
- Loading branch information
Showing
9 changed files
with
808 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,3 +14,4 @@ bytes = "0.4" | |
sha3 = "0.8" | ||
uint = "0.8" | ||
hex = "0.3" | ||
prost = "0.5" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#[macro_export] | ||
macro_rules! field { | ||
($opt_field:expr, $type:expr, $field:expr) => { | ||
$opt_field.ok_or_else(|| crate::codec::CodecError::MissingField { | ||
r#type: $type, | ||
field: $field, | ||
}) | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! impl_default_bytes_codec_for { | ||
($category:ident, [$($type:ident),+]) => ( | ||
use crate::types::$category; | ||
|
||
$( | ||
impl ProtocolCodecSync for $category::$type { | ||
fn encode_sync(&self) -> ProtocolResult<Bytes> { | ||
let ser_type = $type::from(self.clone()); | ||
let mut buf = Vec::with_capacity(ser_type.encoded_len()); | ||
|
||
ser_type.encode(&mut buf).map_err(CodecError::from)?; | ||
|
||
Ok(Bytes::from(buf)) | ||
} | ||
|
||
fn decode_sync(bytes: Bytes) -> ProtocolResult<Self> { | ||
let ser_type = $type::decode(bytes).map_err(CodecError::from)?; | ||
|
||
$category::$type::try_from(ser_type) | ||
} | ||
} | ||
)+ | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,76 @@ | ||
#[cfg(test)] | ||
mod tests { | ||
#[test] | ||
fn it_works() { | ||
assert_eq!(2 + 2, 4); | ||
// TODO: change Vec<u8> to Bytes | ||
// pin: https://github.com/danburkert/prost/pull/190 | ||
|
||
#[macro_use] | ||
mod r#macro; | ||
pub mod primitive; | ||
pub mod transaction; | ||
|
||
use std::error::Error; | ||
|
||
use async_trait::async_trait; | ||
use bytes::Bytes; | ||
use derive_more::{Display, From}; | ||
|
||
use crate::{ProtocolError, ProtocolErrorKind, ProtocolResult}; | ||
|
||
#[async_trait] | ||
pub trait ProtocolCodec: Sized + Send + ProtocolCodecSync { | ||
// Note: We take mut reference so that it can be pinned. This removes Sync | ||
// requirement. | ||
async fn encode(&mut self) -> ProtocolResult<Bytes>; | ||
|
||
async fn decode<B: Into<Bytes> + Send>(bytes: B) -> ProtocolResult<Self>; | ||
} | ||
|
||
// Sync version is still useful in some cases, for example, use in Stream. | ||
// This also work around #[async_trait] problem inside macro | ||
#[doc(hidden)] | ||
pub trait ProtocolCodecSync: Sized + Send { | ||
fn encode_sync(&self) -> ProtocolResult<Bytes>; | ||
|
||
fn decode_sync(bytes: Bytes) -> ProtocolResult<Self>; | ||
} | ||
|
||
#[async_trait] | ||
impl<T: ProtocolCodecSync + 'static> ProtocolCodec for T { | ||
async fn encode(&mut self) -> ProtocolResult<Bytes> { | ||
<T as ProtocolCodecSync>::encode_sync(self) | ||
} | ||
|
||
async fn decode<B: Into<Bytes> + Send>(bytes: B) -> ProtocolResult<Self> { | ||
let bytes: Bytes = bytes.into(); | ||
|
||
<T as ProtocolCodecSync>::decode_sync(bytes) | ||
} | ||
} | ||
|
||
#[derive(Debug, From, Display)] | ||
pub enum CodecError { | ||
#[display(fmt = "prost encode: {}", _0)] | ||
ProtobufEncode(prost::EncodeError), | ||
|
||
#[display(fmt = "prost decode: {}", _0)] | ||
ProtobufDecode(prost::DecodeError), | ||
|
||
#[display(fmt = "{} missing field {}", r#type, field)] | ||
MissingField { | ||
r#type: &'static str, | ||
field: &'static str, | ||
}, | ||
|
||
#[display(fmt = "invalid contract type {}", _0)] | ||
InvalidContractType(i32), | ||
|
||
#[display(fmt = "wrong bytes length: {{ expect: {}, got: {} }}", expect, real)] | ||
WrongBytesLength { expect: usize, real: usize }, | ||
} | ||
|
||
impl Error for CodecError {} | ||
|
||
// TODO: derive macro | ||
impl From<CodecError> for ProtocolError { | ||
fn from(err: CodecError) -> ProtocolError { | ||
ProtocolError::new(ProtocolErrorKind::Codec, Box::new(err)) | ||
} | ||
} |
Oops, something went wrong.