Skip to content

Commit f56798d

Browse files
committed
Add msgpacker-derive
1 parent b1b7476 commit f56798d

13 files changed

Lines changed: 1327 additions & 254 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
[workspace]
22
members = [
33
"msgpacker",
4-
"msgpacker-bench"
4+
"msgpacker-bench",
5+
"msgpacker-derive"
56
]
67

78
[profile.bench]

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,49 @@ We have two main structures available:
1313
* Message - Owned parsed values
1414
* MessageRef - Message parsed by reference and bound to the lifetime of the readers source
1515

16+
For convenience, a derive macro is available to implement `Packable` and `Unpackable` for the types. These implementations will allow the types to be sent and received from `MessagePacker` and `MessageUnpacker` implementations, such as `CursorPacker`.
17+
1618
## Example
1719

20+
```rust
21+
use msgpacker::prelude::*;
22+
23+
#[derive(MsgPacker, Debug, Clone, PartialEq, Eq)]
24+
pub struct Foo {
25+
val: u64,
26+
text: String,
27+
flag: bool,
28+
bar: Bar,
29+
}
30+
31+
#[derive(MsgPacker, Debug, Clone, PartialEq, Eq)]
32+
pub struct Bar {
33+
arr: [u8; 32],
34+
}
35+
36+
let bar = Bar { arr: [0xff; 32] };
37+
let foo = Foo {
38+
val: 15,
39+
text: String::from("Hello, world!"),
40+
flag: true,
41+
bar,
42+
};
43+
44+
// Create a new bytes buffer
45+
let mut buffer: Vec<u8> = vec![];
46+
47+
// Pack the message into the buffer
48+
CursorPacker::new(&mut buffer).pack(foo.clone()).expect("failed to pack `Foo`");
49+
50+
// Unpack the message from the buffer
51+
let foo_p = CursorPacker::new(&buffer).unpack::<Foo>().expect("failed to unpack `Foo`");
52+
53+
// Assert the unpacked message is exactly the same as the original
54+
assert_eq!(foo, foo_p);
55+
```
56+
57+
## Example of manual implementation
58+
1859
```rust
1960
use msgpacker::prelude::*;
2061
use std::io::{Cursor, Seek};

msgpacker-derive/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "msgpacker-derive"
3+
version = "0.1.0"
4+
authors = ["Victor Lopez <victor@codx.io>"]
5+
categories = ["compression", "encoding", "parser-implementations"]
6+
edition = "2021"
7+
keywords = ["messagepack", "msgpack"]
8+
license = "MIT/Apache-2.0"
9+
readme = "README.md"
10+
repository = "https://github.com/codx-dev/msgpacker"
11+
description = "Derive macros for the MessagePack protocol implementation for Rust."
12+
13+
[lib]
14+
proc-macro = true
15+
16+
[dependencies]
17+
quote = "1.0"
18+
syn = { version = "1.0", features = ["full"] }

msgpacker-derive/LICENSE-APACHE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE-APACHE

msgpacker-derive/LICENSE-MIT

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE-MIT

msgpacker-derive/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../README.md

msgpacker-derive/src/lib.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![crate_type = "proc-macro"]
2+
extern crate proc_macro;
3+
4+
use proc_macro::TokenStream;
5+
use quote::quote;
6+
use syn::punctuated::Punctuated;
7+
use syn::{
8+
parse_macro_input, parse_quote, Block, Data, DeriveInput, FieldValue, Fields, Member, Token,
9+
};
10+
11+
#[proc_macro_derive(MsgPacker)]
12+
pub fn msg_packer(input: TokenStream) -> TokenStream {
13+
let input = parse_macro_input!(input as DeriveInput);
14+
15+
let name = input.ident;
16+
let data = input.data;
17+
18+
let mut values: Punctuated<FieldValue, Token![,]> = Punctuated::new();
19+
let block: Block = match data {
20+
Data::Struct(syn::DataStruct {
21+
struct_token: _,
22+
fields: Fields::Named(f),
23+
semi_token: _,
24+
}) => f
25+
.named
26+
.into_pairs()
27+
.map(|p| p.into_value())
28+
.fold(syn::parse_str("{}").unwrap(), |mut block, field| {
29+
let ident = field.ident.as_ref().cloned().unwrap();
30+
let ty = field.ty;
31+
32+
block.stmts.push(parse_quote! {
33+
n += <#ty as msgpacker::prelude::Packable>::pack(&self.#ident, packer.by_ref())?;
34+
});
35+
36+
let fv = FieldValue {
37+
attrs: vec![],
38+
member: Member::Named(ident.clone()),
39+
colon_token: Some(<Token![:]>::default()),
40+
expr: parse_quote! {
41+
<#ty as msgpacker::prelude::Unpackable>::unpack(unpacker.by_ref())?
42+
},
43+
};
44+
values.push(fv);
45+
46+
block
47+
}),
48+
_ => todo!(),
49+
};
50+
51+
let expanded = quote! {
52+
impl msgpacker::prelude::Packable for #name {
53+
fn pack<W>(&self, mut packer: W) -> std::io::Result<usize>
54+
where
55+
W: std::io::Write
56+
{
57+
let mut n = 0;
58+
59+
#block
60+
61+
Ok(n)
62+
}
63+
}
64+
65+
impl msgpacker::prelude::Unpackable for #name {
66+
fn unpack<R>(mut unpacker: R) -> std::io::Result<Self>
67+
where
68+
R: std::io::BufRead,
69+
{
70+
Ok(Self {
71+
#values
72+
})
73+
}
74+
}
75+
};
76+
77+
TokenStream::from(expanded)
78+
}

msgpacker/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "msgpacker"
3-
version = "0.1.7"
3+
version = "0.2.0"
44
authors = ["Victor Lopez <victor@codx.io>"]
55
categories = ["compression", "encoding", "parser-implementations"]
66
edition = "2021"
@@ -11,3 +11,8 @@ repository = "https://github.com/codx-dev/msgpacker"
1111
description = "MessagePack protocol implementation for Rust."
1212

1313
[dependencies]
14+
msgpacker-derive = { version = "0.1", optional = true }
15+
16+
[features]
17+
default = ["derive"]
18+
derive = ["msgpacker-derive"]

msgpacker/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod integer;
99
mod map;
1010
mod message;
1111
mod message_ref;
12+
mod packer;
1213

1314
pub use message::Message;
1415
pub use message_ref::MessageRef;
@@ -26,5 +27,9 @@ pub mod types {
2627
pub mod prelude {
2728
pub use crate::message::Message;
2829
pub use crate::message_ref::MessageRef;
30+
pub use crate::packer::{CursorPacker, MessagePacker, MessageUnpacker, Packable, Unpackable};
2931
pub use crate::types::*;
32+
33+
#[cfg(feature = "derive")]
34+
pub use msgpacker_derive::MsgPacker;
3035
}

msgpacker/src/message.rs

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -763,138 +763,6 @@ impl Message {
763763
}
764764
}
765765

766-
impl From<Integer> for Message {
767-
fn from(i: Integer) -> Self {
768-
Self::Integer(i)
769-
}
770-
}
771-
772-
impl From<u8> for Message {
773-
fn from(i: u8) -> Self {
774-
Self::Integer(Integer::unsigned(i))
775-
}
776-
}
777-
778-
impl From<u16> for Message {
779-
fn from(i: u16) -> Self {
780-
Self::Integer(Integer::unsigned(i))
781-
}
782-
}
783-
784-
impl From<u32> for Message {
785-
fn from(i: u32) -> Self {
786-
Self::Integer(Integer::unsigned(i))
787-
}
788-
}
789-
790-
impl From<u64> for Message {
791-
fn from(i: u64) -> Self {
792-
Self::Integer(Integer::unsigned(i))
793-
}
794-
}
795-
796-
impl From<i8> for Message {
797-
fn from(i: i8) -> Self {
798-
Self::Integer(Integer::signed(i))
799-
}
800-
}
801-
802-
impl From<i16> for Message {
803-
fn from(i: i16) -> Self {
804-
Self::Integer(Integer::signed(i))
805-
}
806-
}
807-
808-
impl From<i32> for Message {
809-
fn from(i: i32) -> Self {
810-
Self::Integer(Integer::signed(i))
811-
}
812-
}
813-
814-
impl From<i64> for Message {
815-
fn from(i: i64) -> Self {
816-
Self::Integer(Integer::signed(i))
817-
}
818-
}
819-
820-
impl From<bool> for Message {
821-
fn from(b: bool) -> Self {
822-
Self::Boolean(b)
823-
}
824-
}
825-
826-
impl From<Float> for Message {
827-
fn from(f: Float) -> Self {
828-
Self::Float(f)
829-
}
830-
}
831-
832-
impl From<f32> for Message {
833-
fn from(f: f32) -> Self {
834-
Self::Float(Float::f32(f))
835-
}
836-
}
837-
838-
impl From<f64> for Message {
839-
fn from(f: f64) -> Self {
840-
Self::Float(Float::f64(f))
841-
}
842-
}
843-
844-
impl From<&str> for Message {
845-
fn from(s: &str) -> Self {
846-
Self::String(s.to_owned())
847-
}
848-
}
849-
850-
impl From<String> for Message {
851-
fn from(s: String) -> Self {
852-
Self::String(s)
853-
}
854-
}
855-
856-
impl From<Vec<u8>> for Message {
857-
fn from(b: Vec<u8>) -> Self {
858-
Self::Bin(b)
859-
}
860-
}
861-
862-
impl FromIterator<u8> for Message {
863-
fn from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Self {
864-
iter.into_iter().collect::<Vec<u8>>().into()
865-
}
866-
}
867-
868-
impl From<Vec<Message>> for Message {
869-
fn from(a: Vec<Message>) -> Self {
870-
Self::Array(a)
871-
}
872-
}
873-
874-
impl FromIterator<Message> for Message {
875-
fn from_iter<I: IntoIterator<Item = Message>>(iter: I) -> Self {
876-
iter.into_iter().collect::<Vec<Message>>().into()
877-
}
878-
}
879-
880-
impl From<Vec<MapEntry>> for Message {
881-
fn from(m: Vec<MapEntry>) -> Self {
882-
Self::Map(m)
883-
}
884-
}
885-
886-
impl FromIterator<MapEntry> for Message {
887-
fn from_iter<I: IntoIterator<Item = MapEntry>>(iter: I) -> Self {
888-
iter.into_iter().collect::<Vec<MapEntry>>().into()
889-
}
890-
}
891-
892-
impl From<Extension> for Message {
893-
fn from(e: Extension) -> Self {
894-
Self::Extension(e)
895-
}
896-
}
897-
898766
impl<M: Into<Message>> Index<M> for Message {
899767
type Output = Message;
900768

0 commit comments

Comments
 (0)