Started working on bincode_derive
This commit is contained in:
parent
a6435388a1
commit
bab0cf4bd1
11
Cargo.toml
11
Cargo.toml
|
|
@ -15,4 +15,13 @@ keywords = ["binary", "encode", "decode", "serialize", "deserialize"]
|
|||
license = "MIT"
|
||||
description = "A binary serialization / deserialization strategy for transforming structs into bytes and vice versa!"
|
||||
|
||||
edition = "2018"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
alloc = []
|
||||
|
||||
[dependencies]
|
||||
bincode_derive = { path = "derive" }
|
||||
# serde = { version = "1.0.130", optional = true }
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
target
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "bincode_derive"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.9"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0.74"
|
||||
default-features = false
|
||||
features = ["parsing", "derive", "proc-macro", "printing"]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
use crate::Result;
|
||||
use proc_macro::TokenStream;
|
||||
use syn::Ident;
|
||||
|
||||
pub struct DeriveEnum {}
|
||||
|
||||
impl DeriveEnum {
|
||||
pub fn parse(_name: Ident, _en: syn::DataEnum) -> Result<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn to_encodable(self) -> Result<TokenStream> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn to_decodable(self) -> Result<TokenStream> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
use crate::Result;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
pub struct DeriveStruct {
|
||||
name: Ident,
|
||||
fields: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl DeriveStruct {
|
||||
pub fn parse(name: Ident, str: syn::DataStruct) -> Result<Self> {
|
||||
let fields = match str.fields {
|
||||
syn::Fields::Named(fields) => fields
|
||||
.named
|
||||
.iter()
|
||||
.map(|f| f.ident.clone().unwrap())
|
||||
.collect(),
|
||||
syn::Fields::Unnamed(fields) => fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| Ident::new(&i.to_string(), field.ty.span()))
|
||||
.collect(),
|
||||
syn::Fields::Unit => Vec::new(),
|
||||
};
|
||||
Ok(Self { name, fields })
|
||||
}
|
||||
|
||||
pub fn to_encodable(self) -> Result<TokenStream> {
|
||||
let DeriveStruct { name, fields } = self;
|
||||
|
||||
let fields = fields
|
||||
.into_iter()
|
||||
.map(|field| {
|
||||
quote! {
|
||||
bincode::enc::Encodeable::encode(&self. #field, &mut encoder)?;
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = quote! {
|
||||
impl bincode::enc::Encodeable for #name {
|
||||
fn encode<E: bincode::enc::Encode>(&self, mut encoder: E) -> Result<(), bincode::error::Error> {
|
||||
#(#fields)*
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
Ok(result.into())
|
||||
}
|
||||
|
||||
pub fn to_decodable(self) -> Result<TokenStream> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::__private::Span;
|
||||
use std::fmt;
|
||||
|
||||
pub enum Error {
|
||||
UnionNotSupported,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::UnionNotSupported => write!(fmt, "Unions are not supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn into_token_stream(self) -> TokenStream {
|
||||
self.into_token_stream_with_span(Span::call_site())
|
||||
}
|
||||
pub fn into_token_stream_with_span(self, span: Span) -> TokenStream {
|
||||
syn::Error::new(span, self).into_compile_error().into()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
mod derive_enum;
|
||||
mod derive_struct;
|
||||
mod error;
|
||||
|
||||
use derive_enum::DeriveEnum;
|
||||
use derive_struct::DeriveStruct;
|
||||
use error::Error;
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
type Result<T = ()> = std::result::Result<T, Error>;
|
||||
|
||||
#[proc_macro_derive(Encodable)]
|
||||
pub fn derive_encodable(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
derive_encodable_inner(input).unwrap_or_else(|e| e.into_token_stream())
|
||||
}
|
||||
|
||||
fn derive_encodable_inner(input: DeriveInput) -> Result<TokenStream> {
|
||||
match input.data {
|
||||
syn::Data::Struct(struct_definition) => {
|
||||
DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_encodable())
|
||||
}
|
||||
syn::Data::Enum(enum_definition) => {
|
||||
DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_encodable())
|
||||
}
|
||||
syn::Data::Union(_) => Err(Error::UnionNotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Decodable)]
|
||||
pub fn derive_decodable(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
derive_decodable_inner(input).unwrap_or_else(|e| e.into_token_stream())
|
||||
}
|
||||
|
||||
fn derive_decodable_inner(input: DeriveInput) -> Result<TokenStream> {
|
||||
match input.data {
|
||||
syn::Data::Struct(struct_definition) => {
|
||||
DeriveStruct::parse(input.ident, struct_definition).and_then(|str| str.to_decodable())
|
||||
}
|
||||
syn::Data::Enum(enum_definition) => {
|
||||
DeriveEnum::parse(input.ident, enum_definition).and_then(|str| str.to_decodable())
|
||||
}
|
||||
syn::Data::Union(_) => Err(Error::UnionNotSupported),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Serialization specification
|
||||
|
||||
*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization is done by `serde-derive` instead. `serde-derive` has the same guarantees as `bincode_derive` for now.
|
||||
*NOTE*: Serialization is done by `bincode_derive` by default. If you enable the `serde` flag, serialization with `serde-derive` is supported as well. `serde-derive` has the same guarantees as `bincode_derive` for now.
|
||||
|
||||
Related issue: https://github.com/serde-rs/serde/issues/1756#issuecomment-689682123
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ Enums are encoded with their variant first, followed by optionally the variant f
|
|||
Both named and unnamed fields are serialized with their values only, and therefor encode to the same value.
|
||||
|
||||
```rs
|
||||
#[derive(bincode::Serialize)]
|
||||
#[derive(bincode::Encodable)]
|
||||
pub enum SomeEnum {
|
||||
A,
|
||||
B(u32),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use super::{Decode, Decodable};
|
||||
use super::{Decodable, Decode};
|
||||
use crate::error::Error;
|
||||
|
||||
impl Decodable for u32 {
|
||||
fn decode<D: Decode>(mut decoder: D) -> Result<Self, Error> {
|
||||
decoder.decode_u32()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ use read::Reader;
|
|||
mod impls;
|
||||
pub mod read;
|
||||
|
||||
|
||||
|
||||
pub trait Decodable: Sized {
|
||||
fn decode<D: Decode>(decoder: D) -> Result<Self, Error>;
|
||||
}
|
||||
|
|
@ -44,5 +42,3 @@ impl<'a, 'de, R: Reader<'de>, C: Config> Decode for &'a mut Decoder<R, C> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<'storage> SliceReader<'storage> {
|
|||
|
||||
impl<'storage> Reader<'storage> for SliceReader<'storage> {
|
||||
#[inline(always)]
|
||||
fn read<'a>(&'a mut self, bytes: &mut [u8]) -> Result<(), Error> {
|
||||
fn read(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
|
||||
if bytes.len() > self.slice.len() {
|
||||
return Err(Error::UnexpectedEnd);
|
||||
}
|
||||
|
|
@ -48,4 +48,4 @@ impl<'storage> Reader<'storage> for SliceReader<'storage> {
|
|||
{
|
||||
Ok(visitor(self.get_byte_slice(length)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
use super::{Encode, Encodeable};
|
||||
use crate::error::Error;
|
||||
|
||||
impl Encodeable for u8 {
|
||||
fn encode<E: Encode>(&self, mut encoder: E) -> Result<(), Error> {
|
||||
encoder.encode_u8(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodeable for u32 {
|
||||
fn encode<E: Encode>(&self, mut encoder: E) -> Result<(), Error> {
|
||||
encoder.encode_u32(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodeable for i32 {
|
||||
fn encode<E: Encode>(&self, mut encoder: E) -> Result<(), Error> {
|
||||
encoder.encode_i32(*self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,28 @@ use write::Writer;
|
|||
mod impls;
|
||||
pub mod write;
|
||||
|
||||
|
||||
pub trait Encodeable {
|
||||
fn encode<E: Encode>(&self, encoder: E) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait Encode {
|
||||
fn encode_u8(&mut self, val: u8) -> Result<(), Error>;
|
||||
fn encode_u32(&mut self, val: u32) -> Result<(), Error>;
|
||||
fn encode_i32(&mut self, val: i32) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl<'a, T> Encode for &'a mut T
|
||||
where
|
||||
T: Encode,
|
||||
{
|
||||
fn encode_u8(&mut self, val: u8) -> Result<(), Error> {
|
||||
T::encode_u8(self, val)
|
||||
}
|
||||
fn encode_u32(&mut self, val: u32) -> Result<(), Error> {
|
||||
T::encode_u32(self, val)
|
||||
}
|
||||
fn encode_i32(&mut self, val: i32) -> Result<(), Error> {
|
||||
T::encode_i32(self, val)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Encoder<W: Writer, C: Config> {
|
||||
|
|
@ -30,9 +45,17 @@ impl<W: Writer, C: Config> Encoder<W, C> {
|
|||
config: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_writer(self) -> W {
|
||||
self.writer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder<W, C> {
|
||||
fn encode_u8(&mut self, val: u8) -> Result<(), Error> {
|
||||
self.writer.write(&[val])
|
||||
}
|
||||
|
||||
fn encode_u32(&mut self, val: u32) -> Result<(), Error> {
|
||||
let bytes = match C::ENDIAN {
|
||||
Endian::Little => val.to_le_bytes(),
|
||||
|
|
@ -41,4 +64,13 @@ impl<'a, W: Writer, C: Config> Encode for &'a mut Encoder<W, C> {
|
|||
|
||||
self.writer.write(&bytes)
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_i32(&mut self, val: i32) -> Result<(), Error> {
|
||||
let bytes = match C::ENDIAN {
|
||||
Endian::Little => val.to_le_bytes(),
|
||||
Endian::Big => val.to_be_bytes(),
|
||||
};
|
||||
|
||||
self.writer.write(&bytes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,25 +6,31 @@ pub trait Writer {
|
|||
|
||||
pub struct SliceWriter<'storage> {
|
||||
slice: &'storage mut [u8],
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl<'storage> SliceWriter<'storage> {
|
||||
pub(crate) fn new(bytes: &'storage mut [u8]) -> SliceWriter<'storage> {
|
||||
SliceWriter {
|
||||
slice: bytes,
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bytes_written(&self) -> usize {
|
||||
self.idx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'storage> Writer for SliceWriter<'storage> {
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
|
||||
if bytes.len() > self.slice.len() {
|
||||
let remaining = &mut self.slice[self.idx..];
|
||||
if bytes.len() > remaining.len() {
|
||||
return Err(Error::UnexpectedEnd);
|
||||
}
|
||||
let data = core::mem::take(&mut self.slice);
|
||||
let (write_slice, remaining) = data.split_at_mut(bytes.len());
|
||||
self.idx += bytes.len();
|
||||
let write_slice = &mut remaining[..bytes.len()];
|
||||
write_slice.copy_from_slice(bytes);
|
||||
self.slice = remaining;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{error::Error, enc::write::Writer};
|
||||
use crate::{enc::write::Writer, error::Error};
|
||||
|
||||
pub trait IntEncoding {
|
||||
fn encode_u32<W: Writer>(writer: &mut W, val: u32) -> Result<(), Error>;
|
||||
|
|
|
|||
12
src/lib.rs
12
src/lib.rs
|
|
@ -17,15 +17,21 @@ extern crate std;
|
|||
|
||||
pub mod config;
|
||||
pub mod de;
|
||||
pub mod error;
|
||||
pub mod enc;
|
||||
pub mod error;
|
||||
|
||||
pub use bincode_derive::{Decodable, Encodable};
|
||||
|
||||
pub(crate) mod int_encoding;
|
||||
|
||||
pub fn encode_into_slice<E: enc::Encodeable>(val: E, dst: &mut [u8]) -> Result<(), error::Error> {
|
||||
pub fn encode_into_slice<E: enc::Encodeable>(
|
||||
val: E,
|
||||
dst: &mut [u8],
|
||||
) -> Result<usize, error::Error> {
|
||||
let writer = enc::write::SliceWriter::new(dst);
|
||||
let mut encoder = enc::Encoder::<_, config::Default>::new(writer);
|
||||
val.encode(&mut encoder)
|
||||
val.encode(&mut encoder)?;
|
||||
Ok(encoder.into_writer().bytes_written())
|
||||
}
|
||||
|
||||
pub fn decode<D: de::Decodable>(src: &mut [u8]) -> Result<D, error::Error> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#[derive(bincode::Encodable, PartialEq, Debug)]
|
||||
pub struct Test {
|
||||
a: i32,
|
||||
b: u32,
|
||||
c: u8,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
let start = Test {
|
||||
a: 5i32,
|
||||
b: 10u32,
|
||||
c: 20u8,
|
||||
};
|
||||
let mut slice = [0u8; 1024];
|
||||
let bytes_written = bincode::encode_into_slice(start, &mut slice).unwrap();
|
||||
assert_eq!(bytes_written, 9);
|
||||
assert_eq!(&slice[..bytes_written], &[5, 0, 0, 0, 10, 0, 0, 0, 20]);
|
||||
}
|
||||
Loading…
Reference in New Issue