[−][src]Macro bin_io::seq
Macro used to generate a write/read tuple from sequence of operations.
Remarks
Due to internal limitations assigning a different name to a variable in the capture is not valid:
ⓘThis example deliberately fails to compile
// Won't compile!! seq!( Bar { a: a1, b: b1 }, a1: be_u8 => b1: be_u8 => )
While reading variables used are owned copies of the values, while writing the values are references to those values, so it's necessary that you always use either as_ref() or to_owned() to collapse the two states into a reference or an owned copy.
use std::io::Cursor; use bin_io::{ seq, count, read }; use bin_io::numbers::{ be_u8, be_i16 }; #[derive(Debug, PartialEq, Eq)] struct Foo { a: Vec<i16> } /* Won't compile let tuple = seq!( Foo { a }, len: be_u8(), a.len() as _ => a: count(be_i16(), len as usize) => ); */ let tuple = seq!( Foo { a }, len: be_u8(), a.len() as _ => a: count(be_i16(), len.to_owned() as usize) => ); let mut vec = vec![ 0x02, 0x00, 0x01, 0x00, 0x02 ]; let mut cursor = Cursor::new(&mut vec); let foo = read(&mut cursor, tuple) .unwrap(); assert_eq!(foo, Foo { a: vec![ 1, 2 ] });
Examples
use std::io::Cursor; use bin_io::{ seq, skip, count, bind, read }; use bin_io::numbers::{ be_u8, be_u16, le_u16, be_i32 }; use bin_io::strings::null_utf16; mod bar { pub struct Foo { pub a: u8, pub b: u16, pub c: Vec<i32>, pub d: String, } } let tuple = seq!( // Here we specify wich variables // are inside Foo bar::Foo { a, b, c, d }, // And now we start the definition bind(be_u8(), 0x50) => a: be_u8() => b: le_u16() => skip(be_u16(), 1557) => c: count(be_i32(), b.to_owned() as usize) => d: null_utf16() => ); let test = read(r, tuple) .unwrap();
seq!
is compatible with multiple data structures
use std::io::Cursor; use bin_io::{ seq, read, bind }; use bin_io::numbers::{ be_i8, be_i16, be_i32, be_i64 }; mod foo { pub struct Bar1; pub struct Bar2(pub i32); pub struct Bar3 { pub a: i64 } } let void = seq!( (), bind(be_i8(), -20) => ); let bar1 = seq!( foo::Bar1, bind(be_i16(), 30) => ); let bar2 = seq!( foo::Bar2(a), a: be_i32() => ); let bar3 = seq!( foo::Bar3 { a }, a: be_i64() => );
Sometimes you need extra variables during reading, but you don't
want them in your final struct (imagine length/value based formats),
with seq!
you can do that too!
use std::io::Cursor; use bin_io::{ seq, read, count }; use bin_io::numbers::{ be_u8, be_i16 }; #[derive(Debug, PartialEq, Eq)] struct Foo { a: Vec<i16> } let tuple = seq!( // Capture everything normally Foo { a }, // Give the field a default value or some expression to initialize it // Remember: this value is only used during writing and not reading length: be_u8(), a.len() as u8 => a: count(be_i16(), length.to_owned() as _) => ); let vec = vec![ 0x2, 0x0, 0x50, 0x0, 0x60 ]; let mut cursor = Cursor::new(vec); let foo = read(&mut cursor, tuple) .unwrap(); assert_eq!(foo, Foo { a: vec![ 0x50, 0x60 ] })