Skip to content
Merged

V2 #7

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ed33aef
refactor: v2
john-bv Oct 10, 2021
ac56cd3
chore: work on macros
john-bv Oct 10, 2021
3dbd5fc
chore: more macro stuff
john-bv Oct 11, 2021
f008cd8
chore: Actual working macro
john-bv Oct 12, 2021
9e9d532
chore: Finish up basic v2 bin-stream
john-bv Oct 12, 2021
7214f80
chore: add varint
john-bv Oct 13, 2021
c5456e4
chore: fixes
john-bv Oct 13, 2021
68b51f8
chore: Add write methods to varint
john-bv Oct 14, 2021
3eade59
chore; fix
john-bv Oct 16, 2021
4b504d5
chore: Fix struct reading/writing and change method name conventions
john-bv Oct 17, 2021
b93a49f
chore: Bump version
john-bv Oct 17, 2021
aba94e8
feat(util): Add read/writing for String"
john-bv Oct 18, 2021
c9fd943
chore: Move from util to lib
john-bv Oct 18, 2021
e799bb3
chore: Fix read/write for string
john-bv Oct 18, 2021
9708ce7
feat: Add socketaddr support
john-bv Oct 19, 2021
18ca29e
chore: remove debugging
john-bv Oct 19, 2021
233a995
chore: remove debugging
john-bv Oct 19, 2021
3af1bca
chore: Format
john-bv Oct 19, 2021
8f31ecf
chore: Possibly fix a bug
john-bv Oct 19, 2021
6fbfb2d
chore: Add forced LE
john-bv Oct 19, 2021
cefeaec
chore: Add method to capsulate inner LE element
john-bv Oct 19, 2021
013e5ae
chore: Add more LE stablizations, disable macro tracing
john-bv Oct 19, 2021
45e7115
feat: Add float primitives
john-bv Oct 19, 2021
188aded
feat: Add enums
john-bv Oct 20, 2021
5cd6799
chore: disable logging
john-bv Oct 20, 2021
fccedf3
chore: disable logging
john-bv Oct 20, 2021
3498de9
chore: Add var_int tests
john-bv Oct 20, 2021
11d687b
chore: Docs
john-bv Oct 26, 2021
0318c3f
feat(LE): A few hack fixes and more tests
john-bv Oct 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
target
old
58 changes: 57 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
[package]
name = "binary_utils"
version = "0.1.2"
version = "0.2.0"
authors = ["Bavfalcon9 <olybear9@gmail.com>"]
edition = "2018"
include = ["src/**/*", "README.md"]
include = ["src/**/*", "README.md"]

[dependencies]
byteorder = "1.4.3"
bin_macro = { path = "./bin_macro" }

[features]
47 changes: 47 additions & 0 deletions bin_macro/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions bin_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "bin_macro"
version = "0.1.0"
edition = "2021"
private = true

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.29"
quote = "1.0.10"
syn = { version = "1.0.80", features = [ "full" ] }
13 changes: 13 additions & 0 deletions bin_macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// #![feature(trace_macros)]
// trace_macros!(true);

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
mod stream;

#[proc_macro_derive(BinaryStream)]
pub fn derive_stream(input: TokenStream) -> TokenStream {
stream::stream_parse(parse_macro_input!(input as DeriveInput))
.unwrap()
.into()
}
147 changes: 147 additions & 0 deletions bin_macro/src/stream.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{Attribute, Data, DeriveInput, Error, Fields, Result, Type};

pub fn stream_parse(input: DeriveInput) -> Result<TokenStream> {
let name = &input.ident;
let attrs = input.attrs;
match input.data {
Data::Struct(v) => {
// iterate through struct fields
let (w, r) = impl_named_fields(v.fields);
let writes = quote!(#(#w)*);
let reads = quote!(#(#r),*);
// get the visibility etc on each field
// return a quote for block impl
Ok(quote! {
#[automatically_derived]
impl Streamable for #name {
fn parse(&self) -> Vec<u8> {
use ::std::io::Write;
use binary_utils::varint::{VarInt, VarIntWriter};
use binary_utils::u24::{u24, u24Writer};
let mut writer = Vec::new();
#writes
writer
}

fn compose(source: &[u8], position: &mut usize) -> Self {
use ::std::io::Read;
use binary_utils::varint::{VarInt, VarIntReader};
use binary_utils::u24::{u24, u24Reader};

Self {
#reads
}
}
}
})
}
Data::Enum(data) => {
let representation = find_one_attr("repr", attrs)
.expect("Enums must have a #[repr] attribute");
let enum_ty = representation.parse_args::<Ident>()
.expect("Enums can only have types as attributes");

if !enum_ty.to_string().starts_with(|v| v == 'u' || v == 'i' || v == 'f') {
return Err(Error::new_spanned(representation, "Representation must be a primitive number"));
}

let (mut writers, mut readers) = (Vec::<TokenStream>::new(), Vec::<TokenStream>::new());

if !data.variants.iter().all(|v| match v.fields.clone() { Fields::Unit => true, Fields::Unnamed(_) => true, _ => false}) {
return Err(Error::new_spanned(data.variants, "Enum Fields must be Uninitialized or Named"));
}

for variant in &data.variants {
// for each field...
let da = variant.discriminant.as_ref().expect("All Fields must have a explicit assignment.").clone();
let discrim = da.1;
let var_name = variant.ident.clone();
match &variant.fields {
Fields::Unit => {
// writers
writers.push(quote!(Self::#var_name => (#discrim as #enum_ty).parse(),));
// readers
readers.push(quote!(#discrim => Self::#var_name,));
},
Fields::Unnamed(_fields) => {
return Err(Error::new_spanned(variant, "Variant fields are not explicitly supported yet."));
// for field in fields.unnamed.iter() {
// dbg!("I am here 2\n\n\\nn\n\n");
// }
},
_ => return Err(Error::new_spanned(variant.clone(), "Variant invalid"))
}
}

Ok(quote!{
#[automatically_derived]
impl Streamable for #name {
fn parse(&self) -> Vec<u8> {
match self {
#(#writers)*
}
}

fn compose(source: &[u8], offset: &mut usize) -> Self {
// get the repr type and read it
let v = <#enum_ty>::compose(source, offset);

match v {
#(#readers)*
_ => panic!("Will not fit in enum!")
}

}
}
})
}
Data::Union(_) => Err(syn::Error::new(
name.span(),
"BinaryStream does not support Type Unions. Use Enums instead.",
)),
}
}

pub fn impl_named_fields(fields: Fields) -> (Vec<TokenStream>, Vec<TokenStream>) {
let mut writers = Vec::<TokenStream>::new();
let mut readers = Vec::<TokenStream>::new();
match fields {
Fields::Named(v) => {
for field in &v.named {
let field_id = field.ident.as_ref().unwrap();
let (writer, reader) = impl_streamable_lazy(field_id, &field.ty);
writers.push(writer);
readers.push(reader);
}
}
Fields::Unnamed(_v) => {
panic!("Can not parse un-named fields at this current point in time.")
}
Fields::Unit => {
panic!("Can not use uninitalized data values.")
}
}
(writers, readers)
}

// pub fn impl_unnamed_fields(_fields: FieldsUnnamed) -> (TokenStream, TokenStream) {

// todo!()
// }

pub fn impl_streamable_lazy(name: &Ident, ty: &Type) -> (TokenStream, TokenStream) {
(
quote! { writer.write(&self.#name.parse()[..]).unwrap(); },
quote!(#name: #ty::compose(&source, position)),
)
}

fn find_one_attr(name: &str, attrs: Vec<Attribute>) -> Option<Attribute> {
let mut iter = attrs.iter().filter(|a| a.path.is_ident(name));
match (iter.next(), iter.next()) {
(Some(v), None) => Some(v.clone()),
_ => None
}
}
Loading