summaryrefslogtreecommitdiffstats
path: root/third_party/rust/scroll_derive
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/scroll_derive')
-rw-r--r--third_party/rust/scroll_derive/.cargo-checksum.json1
-rw-r--r--third_party/rust/scroll_derive/Cargo.lock52
-rw-r--r--third_party/rust/scroll_derive/Cargo.toml35
-rw-r--r--third_party/rust/scroll_derive/LICENSE21
-rw-r--r--third_party/rust/scroll_derive/README.md35
-rw-r--r--third_party/rust/scroll_derive/examples/main.rs28
-rw-r--r--third_party/rust/scroll_derive/src/lib.rs538
-rw-r--r--third_party/rust/scroll_derive/tests/tests.rs213
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);
+}