-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(xdr): initial commit for rust xdr serialization work
This repo is a response to the limitations found in the serde format and rust language when handling XDR serialization. The end goal is to allow a user to manipulate normal rust objects that can than be properly serialized into the XDR format. The primary hangup with serde and other implementations is the lack of support for fixed length xdr array values. The built in rust array type is quite limited. See: https://stackoverflow.com/questions/30901965/implement-debug-trait-for-large-array-type serde-rs/serde#573 To work around this I've used Vec<T> as the type for both fixed and variable length xdr arrays allowing a user to add a macro attribute to distinguish between fixed/variable length while defaulting to a max sized variable length array. Current progress is tracked in the README.md for now, with most of the serialization work completed and all of the deserialization work to go still. Breaks nothing.
- Loading branch information
0 parents
commit 7d7446c
Showing
7 changed files
with
516 additions
and
0 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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/target | ||
**/*.rs.bk | ||
Cargo.lock |
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,8 @@ | ||
[package] | ||
name = "ex-dee" | ||
version = "0.1.0" | ||
authors = ["Kyle Bartush <[email protected]>"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
ex-dee-derive = { path = "ex-dee-derive" } |
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,22 @@ | ||
# Spec Notes | ||
|
||
## Types | ||
|
||
- Integer [ser] | ||
- Unsigned Integer [ser] | ||
- Enumeration [] | ||
- Boolean [ser] | ||
- Hyper Integer [ser] | ||
- Hyper Unsigned Integer [ser] | ||
- Floating-Point [ser] | ||
- Double-Precision Floating-Point [ser] | ||
- Quadruple-Precision Floating Point [] | ||
- Fixed Length Opaque [ser] | ||
- Variable-Length Opaque [ser] | ||
- String [ser] | ||
- Fixed-Length Array [ser] | ||
- Variable-Length Array [ser] | ||
- Structure [ser] | ||
- Discriminated Union [] | ||
- Void [ser] | ||
- Optional-Data [] |
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,3 @@ | ||
/target | ||
**/*.rs.bk | ||
Cargo.lock |
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,13 @@ | ||
[package] | ||
name = "ex-dee-derive" | ||
version = "0.1.0" | ||
authors = ["Kyle Bartush <[email protected]>"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
syn = { version = "0.15.12" , features = ["full", "extra-traits", "parsing"] } | ||
quote = "0.6.8" | ||
proc-macro2 = "0.4" | ||
|
||
[lib] | ||
proc-macro = true |
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,105 @@ | ||
#![recursion_limit = "128"] | ||
|
||
extern crate proc_macro; | ||
|
||
use crate::proc_macro::TokenStream; | ||
use quote::quote; | ||
use syn; | ||
use syn::Meta::{List, NameValue}; | ||
use syn::NestedMeta::Meta; | ||
|
||
#[proc_macro_derive(XDROut, attributes(array))] | ||
pub fn xdr_out_macro_derive(input: TokenStream) -> TokenStream { | ||
let ast = syn::parse(input).unwrap(); | ||
|
||
impl_xdr_out_macro(&ast) | ||
} | ||
|
||
#[derive(Debug)] | ||
struct Member { | ||
pub name: proc_macro2::Ident, | ||
pub fixed: u32, | ||
pub var: u32, | ||
} | ||
|
||
fn get_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> { | ||
if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "array" { | ||
match attr.interpret_meta() { | ||
Some(List(ref meta)) => Some(meta.nested.iter().cloned().collect()), | ||
_ => None, | ||
} | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
fn get_members(fields: &syn::Fields) -> Result<Vec<Member>, ()> { | ||
match fields { | ||
syn::Fields::Named(ref named) => { | ||
let mut result = Vec::new(); | ||
for field in named.named.iter() { | ||
let mut fixed: u32 = 0; | ||
let mut var: u32 = 0; | ||
for meta_items in field.attrs.iter().filter_map(get_meta_items) { | ||
for meta_item in meta_items { | ||
match meta_item { | ||
Meta(NameValue(ref m)) if m.ident == "fixed" => match m.lit { | ||
syn::Lit::Int(ref val) => { | ||
fixed = val.value() as u32; | ||
} | ||
_ => {} | ||
}, | ||
Meta(NameValue(ref m)) if m.ident == "var" => match m.lit { | ||
syn::Lit::Int(ref val) => { | ||
var = val.value() as u32; | ||
} | ||
_ => {} | ||
}, | ||
_ => {} | ||
}; | ||
} | ||
} | ||
result.push(Member { | ||
name: field.ident.clone().unwrap(), | ||
fixed: fixed, | ||
var: var, | ||
}); | ||
} | ||
Ok(result) | ||
} | ||
_ => Err(()), | ||
} | ||
} | ||
|
||
fn impl_xdr_out_macro(ast: &syn::DeriveInput) -> TokenStream { | ||
let name = &ast.ident; | ||
let members = match &ast.data { | ||
syn::Data::Struct(data_struct) => get_members(&data_struct.fields).unwrap(), | ||
_ => panic!("Contract macro only works with trait declarations!"), | ||
}; | ||
let calls: Vec<proc_macro2::TokenStream> = members | ||
.iter() | ||
.map(|i| match (&i.name, i.fixed, i.var) { | ||
(name, 0, 0) => format!("written += self.{}.write_xdr(out)?;", name) | ||
.parse() | ||
.unwrap(), | ||
(name, fixed, 0) => format!( | ||
"written += write_fixed_array(&self.{}, {}, out)?;", | ||
name, fixed | ||
) | ||
.parse() | ||
.unwrap(), | ||
_ => "asdf".to_string().parse().unwrap(), | ||
}) | ||
.collect(); | ||
let gen = quote! { | ||
impl<Out: Write> XDROut<Out> for #name { | ||
fn write_xdr(&self, out: &mut Out) -> Result<u64, Error> { | ||
let mut written: u64 = 0; | ||
#(#calls)* | ||
Ok(written) | ||
} | ||
} | ||
}; | ||
gen.into() | ||
} |
Oops, something went wrong.