diff options
Diffstat (limited to 'third_party/rust/scroll_derive')
-rw-r--r-- | third_party/rust/scroll_derive/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/Cargo.lock | 52 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/Cargo.toml | 35 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/LICENSE | 21 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/README.md | 35 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/examples/main.rs | 28 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/src/lib.rs | 538 | ||||
-rw-r--r-- | third_party/rust/scroll_derive/tests/tests.rs | 213 |
8 files changed, 923 insertions, 0 deletions
diff --git a/third_party/rust/scroll_derive/.cargo-checksum.json b/third_party/rust/scroll_derive/.cargo-checksum.json new file mode 100644 index 0000000000..a86b234ae3 --- /dev/null +++ b/third_party/rust/scroll_derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"1c75a1216efdf3c7b4726138eed43fadf9325750c8d01d2358b4cf4ad742f8c1","Cargo.toml":"36cd9b38e6f4ed4bd807208da809d3803af3b134264fd5c90a29a6f064b3b4d9","LICENSE":"afb11426e09da40a1ae4f8fa17ddcc6b6a52d14df04c29bc5bcd06eb8730624d","README.md":"f89c7768454b0d2b9db816afe05db3a4cea1125bef87f08ed3eefd65e9e2b180","examples/main.rs":"dc2f7f6ba45dcba4e6fe7c8ac100df0c101cb091ddd34f7dfc6599e58cc9e9a7","src/lib.rs":"a9cabe3c0b373f352357745b817f188ab841e9445056014dee9cc83c4d167483","tests/tests.rs":"ab4e6955d2e3bedd003b53b8f3423a6fc48424e37218ca989bf7e0debdf3c3f9"},"package":"bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e"}
\ No newline at end of file diff --git a/third_party/rust/scroll_derive/Cargo.lock b/third_party/rust/scroll_derive/Cargo.lock new file mode 100644 index 0000000000..49119a6c7b --- /dev/null +++ b/third_party/rust/scroll_derive/Cargo.lock @@ -0,0 +1,52 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" + +[[package]] +name = "scroll_derive" +version = "0.11.0" +dependencies = [ + "proc-macro2", + "quote", + "scroll", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/third_party/rust/scroll_derive/Cargo.toml b/third_party/rust/scroll_derive/Cargo.toml new file mode 100644 index 0000000000..98041f2cd0 --- /dev/null +++ b/third_party/rust/scroll_derive/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "scroll_derive" +version = "0.11.0" +authors = ["m4b <m4b.github.io@gmail.com>", "Ted Mielczarek <ted@mielczarek.org>", "Systemcluster <me@systemcluster.me>"] +description = "A macros 1.1 derive implementation for Pread and Pwrite traits from the scroll crate" +documentation = "https://docs.rs/scroll_derive" +readme = "README.md" +keywords = ["derive", "macros", "pread", "pwrite", "bytes"] +license = "MIT" +repository = "https://github.com/m4b/scroll" + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" +[dev-dependencies.scroll] +version = "0.10" diff --git a/third_party/rust/scroll_derive/LICENSE b/third_party/rust/scroll_derive/LICENSE new file mode 100644 index 0000000000..8864d4a396 --- /dev/null +++ b/third_party/rust/scroll_derive/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/scroll_derive/README.md b/third_party/rust/scroll_derive/README.md new file mode 100644 index 0000000000..a7f7e85f0e --- /dev/null +++ b/third_party/rust/scroll_derive/README.md @@ -0,0 +1,35 @@ +# scroll_derive +Macros 1.1 implementing #[derive(Pread, Pwrite)] for https://github.com/m4b/scroll + +Add derive annotations to your POD seamlessly and easily: + +```rust +extern crate scroll; +#[macro_use] +extern crate scroll_derive; + +#[derive(Debug, PartialEq, Pread, Pwrite, IOread, IOwrite, SizeWith)] +#[repr(C)] +struct Data { + id: u32, + timestamp: f64, + arr: [u16; 2], +} + +use scroll::{Pread, Pwrite, Cread, LE}; + +fn main (){ + let bytes = [0xefu8, 0xbe, 0xad, 0xde, 0, 0, 0, 0, 0, 0, 224, 63, 0xad, 0xde, 0xef, 0xbe]; + let data: Data = bytes.pread_with(0, LE).unwrap(); + println!("data: {:?}", &data); + assert_eq!(data.id, 0xdeadbeefu32); + let mut bytes2 = vec![0; ::std::mem::size_of::<Data>()]; + bytes2.pwrite_with(data, 0, LE).unwrap(); + let data: Data = bytes.pread_with(0, LE).unwrap(); + let data2: Data = bytes2.pread_with(0, LE).unwrap(); + assert_eq!(data, data2); + + let data: Data = bytes.cread_with(0, LE); + assert_eq!(data, data2); +} +``` diff --git a/third_party/rust/scroll_derive/examples/main.rs b/third_party/rust/scroll_derive/examples/main.rs new file mode 100644 index 0000000000..faec85300b --- /dev/null +++ b/third_party/rust/scroll_derive/examples/main.rs @@ -0,0 +1,28 @@ +use scroll_derive::{IOread, IOwrite, Pread, Pwrite, SizeWith}; + +#[derive(Debug, PartialEq, Pread, Pwrite, IOread, IOwrite, SizeWith)] +#[repr(C)] +struct Data { + id: u32, + timestamp: f64, + arr: [u16; 2], +} + +use scroll::{Cread, Pread, Pwrite, LE}; + +fn main() { + let bytes = [ + 0xefu8, 0xbe, 0xad, 0xde, 0, 0, 0, 0, 0, 0, 224, 63, 0xad, 0xde, 0xef, 0xbe, + ]; + let data: Data = bytes.pread_with(0, LE).unwrap(); + println!("data: {:?}", &data); + assert_eq!(data.id, 0xdeadbeefu32); + let mut bytes2 = vec![0; ::std::mem::size_of::<Data>()]; + bytes2.pwrite_with(data, 0, LE).unwrap(); + let data: Data = bytes.pread_with(0, LE).unwrap(); + let data2: Data = bytes2.pread_with(0, LE).unwrap(); + assert_eq!(data, data2); + + let data: Data = bytes.cread_with(0, LE); + assert_eq!(data, data2); +} diff --git a/third_party/rust/scroll_derive/src/lib.rs b/third_party/rust/scroll_derive/src/lib.rs new file mode 100644 index 0000000000..a2ba6692df --- /dev/null +++ b/third_party/rust/scroll_derive/src/lib.rs @@ -0,0 +1,538 @@ +#![recursion_limit = "1024"] + +extern crate proc_macro; +use proc_macro2; +use quote::quote; + +use proc_macro::TokenStream; + +fn impl_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream { + match *ty { + syn::Type::Array(ref array) => match array.len { + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(ref int), + .. + }) => { + let size = int.base10_parse::<usize>().unwrap(); + quote! { + #ident: { let mut __tmp: #ty = [0u8.into(); #size]; src.gread_inout_with(offset, &mut __tmp, ctx)?; __tmp } + } + } + _ => panic!("Pread derive with bad array constexpr"), + }, + syn::Type::Group(ref group) => impl_field(ident, &group.elem), + _ => { + quote! { + #ident: src.gread_with::<#ty>(offset, ctx)? + } + } + } +} + +fn impl_struct( + name: &syn::Ident, + fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, + generics: &syn::Generics, +) -> proc_macro2::TokenStream { + let items: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, f)| { + let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({ + let t = proc_macro2::Literal::usize_unsuffixed(i); + quote! {#t} + }); + let ty = &f.ty; + impl_field(ident, ty) + }) + .collect(); + + let gl = &generics.lt_token; + let gp = &generics.params; + let gg = &generics.gt_token; + let gn = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { #ident } + } + p => quote! { #p }, + }); + let gn = quote! { #gl #( #gn ),* #gg }; + let gw = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + #ident : ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian> + ::std::convert::From<u8> + ::std::marker::Copy, + ::scroll::Error : ::std::convert::From<< #ident as ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian>>::Error>, + < #ident as ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian>>::Error : ::std::convert::From<scroll::Error> + } + }, + p => quote! { #p } + }); + quote! { #( #gi ),* , } + } else { + quote! {} + }; + + quote! { + impl<'a, #gp > ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian> for #name #gn where #gw #name #gn : 'a { + type Error = ::scroll::Error; + #[inline] + fn try_from_ctx(src: &'a [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<(Self, usize), Self::Error> { + use ::scroll::Pread; + let offset = &mut 0; + let data = Self { #(#items,)* }; + Ok((data, *offset)) + } + } + } +} + +fn impl_try_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let generics = &ast.generics; + match ast.data { + syn::Data::Struct(ref data) => match data.fields { + syn::Fields::Named(ref fields) => impl_struct(name, &fields.named, generics), + syn::Fields::Unnamed(ref fields) => impl_struct(name, &fields.unnamed, generics), + _ => { + panic!("Pread can not be derived for unit structs") + } + }, + _ => panic!("Pread can only be derived for structs"), + } +} + +#[proc_macro_derive(Pread)] +pub fn derive_pread(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let gen = impl_try_from_ctx(&ast); + gen.into() +} + +fn impl_pwrite_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream { + match ty { + syn::Type::Array(ref array) => match array.len { + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(ref int), + .. + }) => { + let size = int.base10_parse::<usize>().unwrap(); + quote! { + for i in 0..#size { + dst.gwrite_with(&self.#ident[i], offset, ctx)?; + } + } + } + _ => panic!("Pwrite derive with bad array constexpr"), + }, + syn::Type::Group(group) => impl_pwrite_field(ident, &group.elem), + _ => { + quote! { + dst.gwrite_with(&self.#ident, offset, ctx)? + } + } + } +} + +fn impl_try_into_ctx( + name: &syn::Ident, + fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, + generics: &syn::Generics, +) -> proc_macro2::TokenStream { + let items: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, f)| { + let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({ + let t = proc_macro2::Literal::usize_unsuffixed(i); + quote! {#t} + }); + let ty = &f.ty; + impl_pwrite_field(ident, ty) + }) + .collect(); + + let gl = &generics.lt_token; + let gp = &generics.params; + let gg = &generics.gt_token; + let gn = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { #ident } + } + p => quote! { #p }, + }); + let gn = quote! { #gl #( #gn ),* #gg }; + let gwref = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + &'a #ident : ::scroll::ctx::TryIntoCtx<::scroll::Endian>, + ::scroll::Error: ::std::convert::From<<&'a #ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error>, + <&'a #ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error: ::std::convert::From<scroll::Error> + } + }, + p => quote! { #p } + }); + quote! { where #( #gi ),* } + } else { + quote! {} + }; + let gw = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + #ident : ::scroll::ctx::TryIntoCtx<::scroll::Endian>, + ::scroll::Error: ::std::convert::From<<#ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error>, + <#ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error: ::std::convert::From<scroll::Error> + } + }, + p => quote! { #p } + }); + quote! { where Self: ::std::marker::Copy, #( #gi ),* } + } else { + quote! {} + }; + + quote! { + impl<'a, #gp > ::scroll::ctx::TryIntoCtx<::scroll::Endian> for &'a #name #gn #gwref { + type Error = ::scroll::Error; + #[inline] + fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> { + use ::scroll::Pwrite; + let offset = &mut 0; + #(#items;)*; + Ok(*offset) + } + } + + impl #gl #gp #gg ::scroll::ctx::TryIntoCtx<::scroll::Endian> for #name #gn #gw { + type Error = ::scroll::Error; + #[inline] + fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> { + (&self).try_into_ctx(dst, ctx) + } + } + } +} + +fn impl_pwrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let generics = &ast.generics; + match ast.data { + syn::Data::Struct(ref data) => match data.fields { + syn::Fields::Named(ref fields) => impl_try_into_ctx(name, &fields.named, generics), + syn::Fields::Unnamed(ref fields) => impl_try_into_ctx(name, &fields.unnamed, generics), + _ => { + panic!("Pwrite can not be derived for unit structs") + } + }, + _ => panic!("Pwrite can only be derived for structs"), + } +} + +#[proc_macro_derive(Pwrite)] +pub fn derive_pwrite(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let gen = impl_pwrite(&ast); + gen.into() +} + +fn size_with( + name: &syn::Ident, + fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, + generics: &syn::Generics, +) -> proc_macro2::TokenStream { + let items: Vec<_> = fields + .iter() + .map(|f| { + let ty = &f.ty; + match *ty { + syn::Type::Array(ref array) => { + let elem = &array.elem; + match array.len { + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Int(ref int), + .. + }) => { + let size = int.base10_parse::<usize>().unwrap(); + quote! { + (#size * <#elem>::size_with(ctx)) + } + } + _ => panic!("Pread derive with bad array constexpr"), + } + } + _ => { + quote! { + <#ty>::size_with(ctx) + } + } + } + }) + .collect(); + + let gl = &generics.lt_token; + let gp = &generics.params; + let gg = &generics.gt_token; + let gn = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { #ident } + } + p => quote! { #p }, + }); + let gn = quote! { #gl #( #gn ),* #gg }; + let gw = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + #ident : ::scroll::ctx::SizeWith<::scroll::Endian> + } + } + p => quote! { #p }, + }); + quote! { where #( #gi ),* } + } else { + quote! {} + }; + + quote! { + impl #gl #gp #gg ::scroll::ctx::SizeWith<::scroll::Endian> for #name #gn #gw { + #[inline] + fn size_with(ctx: &::scroll::Endian) -> usize { + 0 #(+ #items)* + } + } + } +} + +fn impl_size_with(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let generics = &ast.generics; + match ast.data { + syn::Data::Struct(ref data) => match data.fields { + syn::Fields::Named(ref fields) => size_with(name, &fields.named, generics), + syn::Fields::Unnamed(ref fields) => size_with(name, &fields.unnamed, generics), + _ => { + panic!("SizeWith can not be derived for unit structs") + } + }, + _ => panic!("SizeWith can only be derived for structs"), + } +} + +#[proc_macro_derive(SizeWith)] +pub fn derive_sizewith(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let gen = impl_size_with(&ast); + gen.into() +} + +fn impl_cread_struct( + name: &syn::Ident, + fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, + generics: &syn::Generics, +) -> proc_macro2::TokenStream { + let items: Vec<_> = fields.iter().enumerate().map(|(i, f)| { + let ident = &f.ident.as_ref().map(|i|quote!{#i}).unwrap_or({let t = proc_macro2::Literal::usize_unsuffixed(i); quote!{#t}}); + let ty = &f.ty; + match *ty { + syn::Type::Array(ref array) => { + let arrty = &array.elem; + match array.len { + syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(ref int), ..}) => { + let size = int.base10_parse::<usize>().unwrap(); + let incr = quote! { ::scroll::export::mem::size_of::<#arrty>() }; + quote! { + #ident: { + let mut __tmp: #ty = [0u8.into(); #size]; + for i in 0..__tmp.len() { + __tmp[i] = src.cread_with(*offset, ctx); + *offset += #incr; + } + __tmp + } + } + }, + _ => panic!("IOread derive with bad array constexpr") + } + }, + _ => { + let size = quote! { ::scroll::export::mem::size_of::<#ty>() }; + quote! { + #ident: { let res = src.cread_with::<#ty>(*offset, ctx); *offset += #size; res } + } + } + } + }).collect(); + + let gl = &generics.lt_token; + let gp = &generics.params; + let gg = &generics.gt_token; + let gn = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { #ident } + } + p => quote! { #p }, + }); + let gn = quote! { #gl #( #gn ),* #gg }; + let gw = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + #ident : ::scroll::ctx::FromCtx<::scroll::Endian> + ::std::convert::From<u8> + ::std::marker::Copy + } + }, + p => quote! { #p } + }); + quote! { where #( #gi ),* , } + } else { + quote! {} + }; + + quote! { + impl #gl #gp #gg ::scroll::ctx::FromCtx<::scroll::Endian> for #name #gn #gw { + #[inline] + fn from_ctx(src: &[u8], ctx: ::scroll::Endian) -> Self { + use ::scroll::Cread; + let offset = &mut 0; + let data = Self { #(#items,)* }; + data + } + } + } +} + +fn impl_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let generics = &ast.generics; + match ast.data { + syn::Data::Struct(ref data) => match data.fields { + syn::Fields::Named(ref fields) => impl_cread_struct(name, &fields.named, generics), + syn::Fields::Unnamed(ref fields) => impl_cread_struct(name, &fields.unnamed, generics), + _ => { + panic!("IOread can not be derived for unit structs") + } + }, + _ => panic!("IOread can only be derived for structs"), + } +} + +#[proc_macro_derive(IOread)] +pub fn derive_ioread(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let gen = impl_from_ctx(&ast); + gen.into() +} + +fn impl_into_ctx( + name: &syn::Ident, + fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, + generics: &syn::Generics, +) -> proc_macro2::TokenStream { + let items: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, f)| { + let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({ + let t = proc_macro2::Literal::usize_unsuffixed(i); + quote! {#t} + }); + let ty = &f.ty; + let size = quote! { ::scroll::export::mem::size_of::<#ty>() }; + match *ty { + syn::Type::Array(ref array) => { + let arrty = &array.elem; + quote! { + let size = ::scroll::export::mem::size_of::<#arrty>(); + for i in 0..self.#ident.len() { + dst.cwrite_with(self.#ident[i], *offset, ctx); + *offset += size; + } + } + } + _ => { + quote! { + dst.cwrite_with(self.#ident, *offset, ctx); + *offset += #size; + } + } + } + }) + .collect(); + + let gl = &generics.lt_token; + let gp = &generics.params; + let gg = &generics.gt_token; + let gn = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { #ident } + } + p => quote! { #p }, + }); + let gw = if !gp.is_empty() { + let gi = gp.iter().map(|param: &syn::GenericParam| match param { + syn::GenericParam::Type(ref t) => { + let ident = &t.ident; + quote! { + #ident : ::scroll::ctx::IntoCtx<::scroll::Endian> + ::std::marker::Copy + } + } + p => quote! { #p }, + }); + quote! { where #( #gi ),* } + } else { + quote! {} + }; + let gn = quote! { #gl #( #gn ),* #gg }; + + quote! { + impl<'a, #gp > ::scroll::ctx::IntoCtx<::scroll::Endian> for &'a #name #gn #gw { + #[inline] + fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) { + use ::scroll::Cwrite; + let offset = &mut 0; + #(#items;)*; + () + } + } + + impl #gl #gp #gg ::scroll::ctx::IntoCtx<::scroll::Endian> for #name #gn #gw { + #[inline] + fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) { + (&self).into_ctx(dst, ctx) + } + } + } +} + +fn impl_iowrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &ast.ident; + let generics = &ast.generics; + match ast.data { + syn::Data::Struct(ref data) => match data.fields { + syn::Fields::Named(ref fields) => impl_into_ctx(name, &fields.named, generics), + syn::Fields::Unnamed(ref fields) => impl_into_ctx(name, &fields.unnamed, generics), + _ => { + panic!("IOwrite can not be derived for unit structs") + } + }, + _ => panic!("IOwrite can only be derived for structs"), + } +} + +#[proc_macro_derive(IOwrite)] +pub fn derive_iowrite(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let gen = impl_iowrite(&ast); + gen.into() +} diff --git a/third_party/rust/scroll_derive/tests/tests.rs b/third_party/rust/scroll_derive/tests/tests.rs new file mode 100644 index 0000000000..532ac065e0 --- /dev/null +++ b/third_party/rust/scroll_derive/tests/tests.rs @@ -0,0 +1,213 @@ +use scroll::{Cread, Cwrite, Pread, Pwrite, LE}; +use scroll_derive::{IOread, IOwrite, Pread, Pwrite, SizeWith}; + +use scroll::ctx::SizeWith; + +macro_rules! test { + ( struct $name:ident { $( $field:ident: $t:ty, )* } ) => { + // check we can exist inside a macro_rules + // https://github.com/m4b/scroll/pull/75 + #[derive(Pread, Pwrite)] + pub struct $name { + $( pub $field: $t, )* + } + }; +} + +test! { + struct Test { + field: [u16; 40], + } +} + +#[derive(Debug, PartialEq, Pread, Pwrite)] +struct Data { + id: u32, + timestamp: f64, +} + +#[test] +fn test_data() { + let bytes = [0xefu8, 0xbe, 0xad, 0xde, 0, 0, 0, 0, 0, 0, 224, 63]; + let data: Data = bytes.pread_with(0, LE).unwrap(); + println!("data: {:?}", &data); + assert_eq!(data.id, 0xdeadbeefu32); + assert_eq!(data.timestamp, 0.5f64); + let mut bytes2 = vec![0; ::std::mem::size_of::<Data>()]; + bytes2.pwrite_with(data, 0, LE).unwrap(); + let data: Data = bytes.pread_with(0, LE).unwrap(); + let data2: Data = bytes2.pread_with(0, LE).unwrap(); + assert_eq!(data, data2); +} + +#[derive(Debug, PartialEq, Pread, Pwrite)] +struct Data2 { + name: [u8; 32], +} + +#[test] +fn test_array() { + let bytes = [0u8; 64]; + let data: Data2 = bytes.pread_with(0, LE).unwrap(); + println!("data: {:?}", &data); +} + +#[derive(Debug, PartialEq, Pread, Pwrite, SizeWith)] +struct Data3 { + name: u32, +} + +#[test] +fn test_sizewith() { + let bytes = [0u8; 64]; + let data: Data3 = bytes.gread_with(&mut 0, LE).unwrap(); + println!("data: {:?}", &data); +} + +#[derive(Debug, PartialEq, IOread, IOwrite, SizeWith)] +struct Data4 { + name: u32, + j: u16, + arr: [u8; 2], +} + +#[test] +fn test_ioread() { + let bytes = [0, 1, 2, 3, 0xde, 0xed, 0xbe, 0xaf]; + let data: Data4 = bytes.cread_with(0, LE); + println!("data: {:?}", &data); + assert_eq!(data.name, 50462976); + assert_eq!(data.j, 0xedde); + assert_eq!(data.arr, [0xbe, 0xaf]); +} + +#[test] +fn test_iowrite() { + let bytes = [0, 1, 2, 3, 0xde, 0xed, 0xbe, 0xaf]; + let data: Data4 = bytes.cread_with(0, LE); + println!("data: {:?}", &data); + assert_eq!(data.name, 50462976); + assert_eq!(data.j, 0xedde); + assert_eq!(data.arr, [0xbe, 0xaf]); + + let mut bytes_null = [0u8; 8]; + bytes_null.cwrite_with(&data, 0, LE); + println!("bytes_null: {:?}", &bytes_null); + println!("bytes : {:?}", &bytes); + assert_eq!(bytes_null, bytes); + + let mut bytes_null = [0u8; 8]; + bytes_null.cwrite_with(data, 0, LE); + println!("bytes_null: {:?}", &bytes_null); + println!("bytes : {:?}", &bytes); + assert_eq!(bytes_null, bytes); +} + +#[derive(Debug, PartialEq, Pread, SizeWith)] +#[repr(C)] +struct Data5 { + name: u32, + j: u16, + arr1: [u8; 2], + arr2: [u16; 2], +} + +#[test] +fn test_pread_arrays() { + let bytes = [0, 1, 2, 3, 0, 0, 0xde, 0xed, 0xad, 0xde, 0xef, 0xbe]; + let data: Data5 = bytes.pread_with(0, LE).unwrap(); + println!("data: {:?}", &data); + assert_eq!(data.name, 50462976); + assert_eq!(data.arr1, [0xde, 0xed]); + assert_eq!(data.arr2, [0xdead, 0xbeef]); + let offset = &mut 0; + let data: Data5 = bytes.gread_with(offset, LE).unwrap(); + println!("data: {:?}", &data); + assert_eq!(data.name, 50462976); + assert_eq!(data.arr1, [0xde, 0xed]); + assert_eq!(data.arr2, [0xdead, 0xbeef]); + assert_eq!(*offset, ::std::mem::size_of::<Data5>()); +} + +#[derive(Debug, PartialEq, Pread, SizeWith)] +#[repr(C)] +struct Data6 { + id: u32, + name: [u8; 5], +} + +#[test] +fn test_array_copy() { + let bytes = [0xde, 0xed, 0xef, 0xbe, 0x68, 0x65, 0x6c, 0x6c, 0x0]; + let data: Data6 = bytes.pread_with(0, LE).unwrap(); + let name: &str = data.name.pread(0).unwrap(); + println!("data: {:?}", &data); + println!("data.name: {:?}", name); + assert_eq!(data.id, 0xbeefedde); + assert_eq!(name, "hell"); +} + +#[derive(Debug, PartialEq, Eq, Pread, Pwrite, SizeWith)] +struct Data7A { + pub y: u64, + pub x: u32, +} + +#[derive(Debug, PartialEq, Eq, Pread, Pwrite, SizeWith)] +struct Data7B { + pub a: Data7A, +} + +#[test] +fn test_nested_struct() { + let b = Data7B { + a: Data7A { y: 1, x: 2 }, + }; + let size = Data7B::size_with(&LE); + assert_eq!(size, 12); + let mut bytes = vec![0; size]; + let written = bytes.pwrite_with(&b, 0, LE).unwrap(); + assert_eq!(written, size); + let mut read = 0; + let b2: Data7B = bytes.gread_with(&mut read, LE).unwrap(); + assert_eq!(read, size); + assert_eq!(b, b2); +} + +#[derive(Debug, PartialEq, Eq, Pread, Pwrite, IOread, IOwrite, SizeWith)] +#[repr(C)] +struct Data8<T, Y> { + ids: [T; 3], + xyz: Y, +} + +#[test] +fn test_generics() { + let mut bytes = [0xde, 0xed, 0xef, 0x10, 0x10]; + let data: Data8<u8, u16> = bytes.pread_with(0, LE).unwrap(); + assert_eq!(data.ids, [0xde, 0xed, 0xef]); + assert_eq!(data.xyz, 0x1010); + let data: Data8<u8, u16> = bytes.cread_with(0, LE); + assert_eq!(data.ids, [0xde, 0xed, 0xef]); + assert_eq!(data.xyz, 0x1010); + let size = Data8::<u8, u16>::size_with(&LE); + let written = bytes.pwrite_with(&data, 0, LE).unwrap(); + assert_eq!(written, size); +} + +#[derive(Debug, PartialEq, Eq, Pread, Pwrite, IOread, IOwrite, SizeWith)] +struct Data9(u8, u16); + +#[test] +fn test_newtype() { + let mut bytes = [0xde, 0x10, 0x10]; + let data: Data9 = bytes.pread_with(0, LE).unwrap(); + assert_eq!(data.0, 0xde); + assert_eq!(data.1, 0x1010); + let data: Data9 = bytes.cread_with(0, LE); + assert_eq!(data.0, 0xde); + assert_eq!(data.1, 0x1010); + let size = Data9::size_with(&LE); + let written = bytes.pwrite_with(&data, 0, LE).unwrap(); + assert_eq!(written, size); +} |