cookie-factory-0.3.0/Cargo.toml.orig010064400007670000024000000022721354262444600155550ustar0000000000000000[package] name = "cookie-factory" version = "0.3.0" authors = ["Geoffroy Couprie ", "Pierre Chifflier "] license = "MIT" repository = "https://github.com/rust-bakery/cookie-factory" readme = "README.md" documentation = "http://docs.rs/cookie-factory" description = "nom inspired serialization library" categories = ["encoding"] keywords = ["encoding", "serialization", "nom"] edition = "2018" include = [ "Cargo.toml", "LICENSE", "README.md", ".gitignore", "src/*.rs", "src/combinator/*.rs", "example/*.rs" ] [features] default = ["std"] std = [] [dev-dependencies] maplit = "^1.0" [profile.bench] debug = true lto = true codegen-units = 1 #[[example]] #name = "cursor" #required-features = ["std"] #path = "cursor.rs" #[[example]] #name = "json" #path = "json.rs" [[example]] name = "http" required-features = ["std"] path = "examples/http.rs" [[test]] name = "http" required-features = ["std"] path = "tests/http.rs" #[[test]] #name = "pouet" #path = "pouet.rs" #[[test]] #name = "combinators-json" #path = "combinators-json.rs" [badges] travis-ci = { repository = "Geal/cookie-factory" } maintenance = { status = "actively-developed" } cookie-factory-0.3.0/Cargo.toml0000644000000027100000000000000120070ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "cookie-factory" version = "0.3.0" authors = ["Geoffroy Couprie ", "Pierre Chifflier "] include = ["Cargo.toml", "LICENSE", "README.md", ".gitignore", "src/*.rs", "src/combinator/*.rs", "example/*.rs"] description = "nom inspired serialization library" documentation = "http://docs.rs/cookie-factory" readme = "README.md" keywords = ["encoding", "serialization", "nom"] categories = ["encoding"] license = "MIT" repository = "https://github.com/rust-bakery/cookie-factory" [profile.bench] lto = true codegen-units = 1 debug = true [[example]] name = "http" path = "examples/http.rs" required-features = ["std"] [[test]] name = "http" path = "tests/http.rs" required-features = ["std"] [dev-dependencies.maplit] version = "^1.0" [features] default = ["std"] std = [] [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "Geal/cookie-factory" cookie-factory-0.3.0/LICENSE010064400007670000024000000020511346654720000136630ustar0000000000000000Copyright (c) 2017-2019 Geoffroy Couprie 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. cookie-factory-0.3.0/README.md010064400007670000024000000015761354262445600141540ustar0000000000000000# cookie-factory [![LICENSE](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Build Status](https://travis-ci.org/rust-bakery/cookie-factory.svg?branch=master)](https://travis-ci.org/rust-bakery/cookie-factory) [![Crates.io Version](https://img.shields.io/crates/v/cookie-factory.svg)](https://crates.io/crates/cookie-factory) serialization library built with a combinator design similar to the [nom parser combinators library](https://github.com/geal/nom). Serializers are built up from single purpose serializers, like `slice` to write a raw byte slice, or `be_u16` to write a `u16` integer in big endian form. Those small serializers can then be assembled by using combinators. As an example, `all(["abcd", "efgh", "ijkl"].iter().map(string))(output)` will write `"abcdefghijkl"` to `output`. Reference documentation is available [here](https://docs.rs/cookie-factory/). cookie-factory-0.3.0/src/bytes.rs010064400007670000024000000272221354243207100151420ustar0000000000000000//! bytes and numbers related serialization functions use crate::internal::{SerializeFn, WriteContext, GenError}; use crate::lib::std::io::Write; macro_rules! try_write(($out:ident, $len:ident, $data:expr) => ( match $out.write($data) { Err(io) => Err(GenError::IoError(io)), Ok(n) if n < $len => Err(GenError::BufferTooSmall($len - n)), Ok(_) => Ok($out) } )); /// Writes an `u8` to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_u8}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_u8(1u8), &mut buf[..]).unwrap(); /// assert_eq!(pos, 1); /// assert_eq!(buf.len(), 100 - 1); /// } /// /// assert_eq!(&buf[..1], &[1u8][..]); /// ``` pub fn be_u8(i: u8) -> impl SerializeFn { let len = 1; move |mut out: WriteContext| try_write!(out, len, &i.to_be_bytes()[..]) } /// Writes an `u16` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_u16}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_u16(1u16), &mut buf[..]).unwrap(); /// assert_eq!(pos, 2); /// assert_eq!(buf.len(), 100 - 2); /// } /// /// assert_eq!(&buf[..2], &[0u8, 1u8][..]); /// ``` pub fn be_u16(i: u16) -> impl SerializeFn { let len = 2; move |mut out: WriteContext| try_write!(out, len, &i.to_be_bytes()[..]) } /// Writes the lower 24 bit of an `u32` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_u24}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_u24(1u32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 3); /// assert_eq!(buf.len(), 100 - 3); /// } /// /// assert_eq!(&buf[..3], &[0u8, 0u8, 1u8][..]); /// ``` pub fn be_u24(i: u32) -> impl SerializeFn { let len = 3; move |mut out: WriteContext| try_write!(out, len, &i.to_be_bytes()[1..]) } /// Writes an `u32` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_u32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_u32(1u32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[0u8, 0u8, 0u8, 1u8][..]); /// ``` pub fn be_u32(i: u32) -> impl SerializeFn { let len = 4; move |mut out: WriteContext| try_write!(out, len, &i.to_be_bytes()[..]) } /// Writes an `u64` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_u64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_u64(1u64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8][..]); /// ``` pub fn be_u64(i: u64) -> impl SerializeFn { let len = 8; move |mut out: WriteContext| try_write!(out, len, &i.to_be_bytes()[..]) } /// Writes an `i8` to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_i8}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_i8(1i8), &mut buf[..]).unwrap(); /// assert_eq!(pos, 1); /// assert_eq!(buf.len(), 100 - 1); /// } /// /// assert_eq!(&buf[..1], &[1u8][..]); /// ``` pub fn be_i8(i: i8) -> impl SerializeFn { be_u8(i as u8) } /// Writes an `i16` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_i16}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_i16(1i16), &mut buf[..]).unwrap(); /// assert_eq!(pos, 2); /// assert_eq!(buf.len(), 100 - 2); /// } /// /// assert_eq!(&buf[..2], &[0u8, 1u8][..]); /// ``` pub fn be_i16(i: i16) -> impl SerializeFn { be_u16(i as u16) } /// Writes the lower 24 bit of an `i32` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_i24}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_i24(1i32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 3); /// assert_eq!(buf.len(), 100 - 3); /// } /// /// assert_eq!(&buf[..3], &[0u8, 0u8, 1u8][..]); /// ``` pub fn be_i24(i: i32) -> impl SerializeFn { be_u24(i as u32) } /// Writes an `i32` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_i32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_i32(1i32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[0u8, 0u8, 0u8, 1u8][..]); /// ``` pub fn be_i32(i: i32) -> impl SerializeFn { be_u32(i as u32) } /// Writes an `i64` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_i64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_i64(1i64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8][..]); /// ``` pub fn be_i64(i: i64) -> impl SerializeFn { be_u64(i as u64) } /// Writes an `f32` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_f32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_f32(1.0f32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[63u8, 128u8, 0u8, 0u8][..]); /// ``` pub fn be_f32(i: f32) -> impl SerializeFn { be_u32(i.to_bits()) } /// Writes an `f64` in big endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::be_f64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(be_f64(1.0f64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[63u8, 240u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8][..]); /// ``` pub fn be_f64(i: f64) -> impl SerializeFn { be_u64(i.to_bits()) } /// Writes an `u8` to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_u8}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_u8(1u8), &mut buf[..]).unwrap(); /// assert_eq!(pos, 1); /// assert_eq!(buf.len(), 100 - 1); /// } /// /// assert_eq!(&buf[..1], &[1u8][..]); /// ``` pub fn le_u8(i: u8) -> impl SerializeFn { let len = 1; move |mut out: WriteContext| try_write!(out, len, &i.to_le_bytes()[..]) } /// Writes an `u16` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_u16}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_u16(1u16), &mut buf[..]).unwrap(); /// assert_eq!(pos, 2); /// assert_eq!(buf.len(), 100 - 2); /// } /// /// assert_eq!(&buf[..2], &[1u8, 0u8][..]); /// ``` pub fn le_u16(i: u16) -> impl SerializeFn { let len = 2; move |mut out: WriteContext| try_write!(out, len, &i.to_le_bytes()[..]) } /// Writes the lower 24 bit of an `u32` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_u24}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_u24(1u32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 3); /// assert_eq!(buf.len(), 100 - 3); /// } /// /// assert_eq!(&buf[..3], &[1u8, 0u8, 0u8][..]); /// ``` pub fn le_u24(i: u32) -> impl SerializeFn { let len = 3; move |mut out: WriteContext| try_write!(out, len, &i.to_le_bytes()[0..3]) } /// Writes an `u32` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_u32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_u32(1u32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[1u8, 0u8, 0u8, 0u8][..]); /// ``` pub fn le_u32(i: u32) -> impl SerializeFn { let len = 4; move |mut out: WriteContext| try_write!(out, len, &i.to_le_bytes()[..]) } /// Writes an `u64` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_u64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_u64(1u64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8][..]); /// ``` pub fn le_u64(i: u64) -> impl SerializeFn { let len = 8; move |mut out: WriteContext| try_write!(out, len, &i.to_le_bytes()[..]) } /// Writes an `i8` to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_i8}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_i8(1i8), &mut buf[..]).unwrap(); /// assert_eq!(pos, 1); /// assert_eq!(buf.len(), 100 - 1); /// } /// /// assert_eq!(&buf[..1], &[1u8][..]); /// ``` pub fn le_i8(i: i8) -> impl SerializeFn { le_u8(i as u8) } /// Writes an `o16` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_i16}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_i16(1i16), &mut buf[..]).unwrap(); /// assert_eq!(pos, 2); /// assert_eq!(buf.len(), 100 - 2); /// } /// /// assert_eq!(&buf[..2], &[1u8, 0u8][..]); /// ``` pub fn le_i16(i: i16) -> impl SerializeFn { le_u16(i as u16) } /// Writes the lower 24 bit of an `i32` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_i24}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_i24(1i32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 3); /// assert_eq!(buf.len(), 100 - 3); /// } /// /// assert_eq!(&buf[..3], &[1u8, 0u8, 0u8][..]); /// ``` pub fn le_i24(i: i32) -> impl SerializeFn { le_u24(i as u32) } /// Writes an `i32` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_i32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_i32(1i32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[1u8, 0u8, 0u8, 0u8][..]); /// ``` pub fn le_i32(i: i32) -> impl SerializeFn { le_u32(i as u32) } /// Writes an `i64` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_i64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_i64(1i64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8][..]); /// ``` pub fn le_i64(i: i64) -> impl SerializeFn { le_u64(i as u64) } /// Writes an `f32` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_f32}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_f32(1.0f32), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &[0u8, 0u8, 128u8, 63u8][..]); /// ``` pub fn le_f32(i: f32) -> impl SerializeFn { le_u32(i.to_bits()) } /// Writes an `f64` in little endian byte order to the output /// /// ```rust /// use cookie_factory::{gen, bytes::le_f64}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(le_f64(1.0f64), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 240u8, 63u8][..]); /// ``` pub fn le_f64(i: f64) -> impl SerializeFn { le_u64(i.to_bits()) } cookie-factory-0.3.0/src/combinator.rs010064400007670000024000000164541354243310700161570ustar0000000000000000//! basic serializers use crate::internal::*; use crate::lib::std::io::Write; macro_rules! try_write(($out:ident, $len:ident, $data:expr) => ( match $out.write($data) { Err(io) => Err(GenError::IoError(io)), Ok(n) if n < $len => Err(GenError::BufferTooSmall($len - n)), Ok(_) => Ok($out) } )); /// Writes a byte slice to the output /// /// ```rust /// use cookie_factory::{gen, combinator::slice}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(slice(&b"abcd"[..]), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &b"abcd"[..]); /// ``` pub fn slice, W: Write>(data: S) -> impl SerializeFn { let len = data.as_ref().len(); move |mut out: WriteContext| try_write!(out, len, data.as_ref()) } /// Writes a string slice to the output /// /// ```rust /// use cookie_factory::{gen, combinator::string}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(string("abcd"), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &b"abcd"[..]); /// ``` pub fn string, W: Write>(data: S) -> impl SerializeFn { let len = data.as_ref().len(); move |mut out: WriteContext| try_write!(out, len, data.as_ref().as_bytes()) } /// Writes an hex string to the output #[cfg(feature = "std")] /// ```rust /// use cookie_factory::{gen, combinator::hex}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(hex(0x2A), &mut buf[..]).unwrap(); /// assert_eq!(pos, 2); /// assert_eq!(buf.len(), 100 - 2); /// } /// /// assert_eq!(&buf[..2], &b"2A"[..]); /// ``` pub fn hex(data: S) -> impl SerializeFn { move |mut out: WriteContext| match write!(out, "{:X}", data) { Err(io) => Err(GenError::IoError(io)), Ok(()) => Ok(out), } } /// Skips over some input bytes without writing anything /// /// ```rust /// use cookie_factory::{gen, combinator::skip}; /// /// let mut buf = [0u8; 100]; /// /// let (out, pos) = gen(skip(2), &mut buf[..]).unwrap(); /// /// assert_eq!(pos, 2); /// assert_eq!(out.len(), 98); /// ``` pub fn skip(len: usize) -> impl SerializeFn { move |out: WriteContext| W::skip(out, len) } /// Applies a serializer if the condition is true /// /// ```rust /// use cookie_factory::{gen, combinator::{cond, string}}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(cond(true, string("abcd")), &mut buf[..]).unwrap(); /// assert_eq!(pos, 4); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &b"abcd"[..]); /// ``` pub fn cond(condition: bool, f: F) -> impl SerializeFn where F: SerializeFn, { move |out: WriteContext| { if condition { f(out) } else { Ok(out) } } } /// Reserves space for the `Before` combinator, applies the `Gen` combinator, /// then applies the `Before` combinator with the output from `Gen` onto the /// reserved space. /// /// ```rust /// use cookie_factory::{gen, gen_simple, sequence::tuple, combinator::{back_to_the_buffer, string}, bytes::be_u8, bytes::be_u32}; /// /// let mut buf = [0; 9]; /// gen_simple(tuple(( /// back_to_the_buffer( /// 4, /// move |buf| gen(string("test"), buf), /// move |buf, len| gen_simple(be_u32(len as u32), buf) /// ), /// be_u8(42) /// )), &mut buf[..]).unwrap(); /// assert_eq!(&buf, &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42]); /// ``` pub fn back_to_the_buffer( reserved: usize, gen: Gen, before: Before, ) -> impl SerializeFn where Gen: Fn(WriteContext) -> Result<(WriteContext, Tmp), GenError>, Before: Fn(WriteContext, Tmp) -> GenResult, { move |w: WriteContext| W::reserve_write_use(w, reserved, &gen, &before) } //missing combinators: //or //empty //then //stream //length_value //text print //text upperhex //text lowerhex #[cfg(test)] mod test { use super::*; use crate::bytes::{be_u32, be_u8}; use crate::sequence::tuple; #[test] fn test_gen_with_length() { let mut buf = [0; 8]; { let (len_buf, buf) = buf.split_at_mut(4); let (_, pos) = gen(string("test"), buf).unwrap(); gen(be_u32(pos as u32), len_buf).unwrap(); } assert_eq!( &buf, &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8] ); } #[test] fn test_back_to_the_buffer() { let mut buf = [0; 9]; let new_buf = gen_simple( tuple(( back_to_the_buffer( 4, move |buf| gen(string("test"), buf), move |buf, len| gen_simple(be_u32(len as u32), buf), ), be_u8(42), )), &mut buf[..], ) .unwrap(); assert!(new_buf.is_empty()); assert_eq!( &buf, &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42] ); } #[cfg(feature = "std")] #[test] fn test_back_to_the_buffer_vec() { let buf = Vec::new(); let buf = gen_simple( tuple(( back_to_the_buffer( 4, move |buf| gen(string("test"), buf), move |buf, len| gen_simple(be_u32(len as u32), buf), ), be_u8(42), )), buf, ) .unwrap(); assert_eq!( &buf[..], &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42] ); } #[test] fn test_back_to_the_buffer_cursor() { let mut buf = [0; 9]; { let cursor = crate::lib::std::io::Cursor::new(&mut buf[..]); let cursor = gen_simple( tuple(( back_to_the_buffer( 4, move |buf| gen(string("test"), buf), move |buf, len| gen_simple(be_u32(len as u32), buf), ), be_u8(42), )), cursor, ) .unwrap(); assert_eq!(cursor.position(), 9); } assert_eq!( &buf, &[0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42] ); } #[test] fn test_back_to_the_buffer_cursor_counter() { let mut buf = [0; 10]; { let cursor = crate::lib::std::io::Cursor::new(&mut buf[..]); let (cursor, pos) = gen( tuple(( be_u8(64), back_to_the_buffer( 4, &move |buf| gen(string("test"), buf), &move |buf, len| gen_simple(be_u32(len as u32), buf), ), be_u8(42), )), cursor, ) .unwrap(); assert_eq!(pos, 10); assert_eq!(cursor.position(), 10); } assert_eq!( &buf, &[64, 0, 0, 0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8, 42] ); } } cookie-factory-0.3.0/src/gen.rs010064400007670000024000000675151354243301100145710ustar0000000000000000//! legacy serializers, kept for backwards compatibility from previous cookie factory versions use crate::bytes::*; use crate::internal::*; use crate::lib::std::io; pub fn legacy_wrap<'a, G>( gen: G, x: (&'a mut [u8], usize), ) -> Result<(&'a mut [u8], usize), GenError> where G: SerializeFn>, { let (buf, offset) = x; let (buf, offset) = { let mut cursor = io::Cursor::new(buf); cursor.set_position(offset as u64); let cursor = gen_simple(gen, cursor)?; let position = cursor.position(); (cursor.into_inner(), position) }; Ok((buf, offset as usize)) } /// Write an unsigned 1 byte integer. Equivalent to `gen_be_u8!(v)` #[inline] pub fn set_be_u8(x: (&mut [u8], usize), v: u8) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(be_u8(v), x) } /// Write an unsigned 2 bytes integer (big-endian order). Equivalent to `gen_be_u16!(v)` #[inline] pub fn set_be_u16(x: (&mut [u8], usize), v: u16) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(be_u16(v), x) } /// Write an unsigned 4 bytes integer (big-endian order). Equivalent to `gen_be_u32!(v)` #[inline] pub fn set_be_u32(x: (&mut [u8], usize), v: u32) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(be_u32(v), x) } /// Write an unsigned 8 bytes integer (big-endian order). Equivalent to `gen_be_u64!(v)` #[inline] pub fn set_be_u64(x: (&mut [u8], usize), v: u64) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(be_u64(v), x) } /// Write an unsigned 1 byte integer. Equivalent to `gen_le_u8!(v)` #[inline] pub fn set_le_u8(x: (&mut [u8], usize), v: u8) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(le_u8(v), x) } /// Write an unsigned 2 bytes integer (little-endian order). Equivalent to `gen_le_u16!(v)` #[inline] pub fn set_le_u16(x: (&mut [u8], usize), v: u16) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(le_u16(v), x) } /// Write an unsigned 4 bytes integer (little-endian order). Equivalent to `gen_le_u32!(v)` #[inline] pub fn set_le_u32(x: (&mut [u8], usize), v: u32) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(le_u32(v), x) } /// Write an unsigned 8 bytes integer (little-endian order). Equivalent to `gen_le_u64!(v)` #[inline] pub fn set_le_u64(x: (&mut [u8], usize), v: u64) -> Result<(&mut [u8], usize), GenError> { legacy_wrap(le_u64(v), x) } /// `gen_align!(I, u8) => I -> Result` /// Align the output buffer to the next multiple of specified value. /// /// Does not modify the output buffer, but increments the output index. #[macro_export] macro_rules! gen_align( (($i:expr, $idx:expr), $val:expr) => ( { let aligned = $val - ($idx % $val); match $i.len() <= $idx+aligned { true => Err(GenError::BufferTooSmall($idx+aligned - $i.len())), false => { Ok(($i,($idx+aligned))) }, } } ); ($i:expr, $val:expr) => ( gen_align!(($i.0, $i.1), $val) ); ); /// `gen_skip!(I, u8) => I -> Result` /// Skip the specified number of bytes. /// /// Does not modify the output buffer, but increments the output index. #[macro_export] macro_rules! gen_skip( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::combinator::skip($val as usize), $i) ); ); /// `gen_be_u8!(I, u8) => I -> Result` /// Write an unsigned 1 byte integer. #[macro_export] macro_rules! gen_be_u8( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_u8($val), $i) ); ); /// `gen_be_u16!(I, u8) => I -> Result` /// Write an unsigned 2 bytes integer (using big-endian order). #[macro_export] macro_rules! gen_be_u16( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_u16($val), $i) ); ); /// `gen_be_u24!(I, u8) => I -> Result` /// Write an unsigned 3 bytes integer (using big-endian order). #[macro_export] macro_rules! gen_be_u24( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_u24($val), $i) ); ); /// `gen_be_u32!(I, u8) => I -> Result` /// Write an unsigned 4 bytes integer (using big-endian order). #[macro_export] macro_rules! gen_be_u32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_u32($val), $i) ); ); /// `gen_be_u64!(I, u8) => I -> Result` /// Write an unsigned 8 bytes integer (using big-endian order). /// ```rust,ignore /// let r = gen_be_u64!((&mut mem,0),0x0102030405060708u64); /// ``` #[macro_export] macro_rules! gen_be_u64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_u64($val), $i) ); ); /// `gen_be_i8!(I, i8) => I -> Result` /// Write a signed 1 byte integer. #[macro_export] macro_rules! gen_be_i8( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_i8($val), $i) ); ); /// `gen_be_i16!(I, i16) => I -> Result` /// Write a signed 2 byte integer. #[macro_export] macro_rules! gen_be_i16( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_i16($val), $i) ); ); /// `gen_be_i24!(I, i24) => I -> Result` /// Write a signed 3 byte integer. #[macro_export] macro_rules! gen_be_i24( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_i24($val), $i) ); ); /// `gen_be_i32!(I, i32) => I -> Result` /// Write a signed 4 byte integer. #[macro_export] macro_rules! gen_be_i32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_i32($val), $i) ); ); /// `gen_be_i64!(I, i64) => I -> Result` /// Write a signed 8 byte integer. #[macro_export] macro_rules! gen_be_i64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_i64($val), $i) ); ); /// `gen_be_f32!(I, f32) => I -> Result` /// Write a 4 byte float. #[macro_export] macro_rules! gen_be_f32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_f32($val), $i) ); ); /// `gen_be_f64!(I, f64) => I -> Result` /// Write a 8 byte float. #[macro_export] macro_rules! gen_be_f64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::be_f64($val), $i) ); ); /// `gen_le_u8!(I, u8) => I -> Result` /// Write an unsigned 1 byte integer. #[macro_export] macro_rules! gen_le_u8( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_u8($val), $i) ); ); /// `gen_le_u16!(I, u8) => I -> Result` /// Write an unsigned 2 bytes integer (using little-endian order). #[macro_export] macro_rules! gen_le_u16( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_u16($val), $i) ); ); /// `gen_le_u24!(I, u8) => I -> Result` /// Write an unsigned 3 bytes integer (using little-endian order). #[macro_export] macro_rules! gen_le_u24( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_u24($val), $i) ); ); /// `gen_le_u32!(I, u8) => I -> Result` /// Write an unsigned 4 bytes integer (using little-endian order). #[macro_export] macro_rules! gen_le_u32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_u32($val), $i) ); ); /// `gen_le_u64!(I, u8) => I -> Result` /// Write an unsigned 8 bytes integer (using little-endian order). /// ```rust,ignore /// let r = gen_le_u64!((&mut mem,0),0x0102030405060708u64); /// ``` #[macro_export] macro_rules! gen_le_u64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_u64($val), $i) ); ); /// `gen_le_i8!(I, i8) => I -> Result` /// Write a signed 1 byte integer. #[macro_export] macro_rules! gen_le_i8( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_i8($val), $i) ); ); /// `gen_le_i16!(I, i16) => I -> Result` /// Write a signed 2 byte integer. #[macro_export] macro_rules! gen_le_i16( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_i16($val), $i) ); ); /// `gen_le_i24!(I, i24) => I -> Result` /// Write a signed 3 byte integer. #[macro_export] macro_rules! gen_le_i24( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_i24($val), $i) ); ); /// `gen_le_i32!(I, i32) => I -> Result` /// Write a signed 4 byte integer. #[macro_export] macro_rules! gen_le_i32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_i32($val), $i) ); ); /// `gen_le_i64!(I, i64) => I -> Result` /// Write a signed 8 byte integer. #[macro_export] macro_rules! gen_le_i64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_i64($val), $i) ); ); /// `gen_le_f32!(I, f32) => I -> Result` /// Write a 4 byte float. #[macro_export] macro_rules! gen_le_f32( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_f32($val), $i) ); ); /// `gen_le_f64!(I, f64) => I -> Result` /// Write a 8 byte float. #[macro_export] macro_rules! gen_le_f64( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::bytes::le_f64($val), $i) ); ); /// `gen_copy!(I, &[u8], u8) => I -> Result` /// Writes a slice, copying only the specified number of bytes to the output buffer. #[macro_export] macro_rules! gen_copy( (($i:expr, $idx:expr), $val:expr, $l:expr) => ( match $i.len() < $idx+$l { true => Err(GenError::BufferTooSmall($idx+$l - $i.len())), false => { $i[$idx..$idx+$l].clone_from_slice(&$val[0..$l]); Ok(($i,($idx+$l))) } } ); ($i:expr, $val:expr, $l:expr) => ( gen_copy!(($i.0,$i.1), $val, $l) ); ); /// `gen_slice!(I, &[u8]) => I -> Result` /// Writes a slice, copying it entirely to the output buffer. #[macro_export] macro_rules! gen_slice( ($i:expr, $val:expr) => ( $crate::gen::legacy_wrap($crate::combinator::slice($val), $i) ); ); #[macro_export] macro_rules! gen_length_slice( (($i:expr, $idx:expr), $lf:ident, $val:expr) => ( do_gen!(($i,$idx), $lf($val.len()) >> gen_slice!($val) ) ); (($i:expr, $idx:expr), $lsubmac:ident >> $val:expr) => ( do_gen!(($i,$idx), $lsubmac!($val.len()) >> gen_slice!($val) ) ); ); /// Used to wrap common expressions and function as macros /// /// ```rust,no_run /// # #[macro_use] extern crate cookie_factory; /// # use cookie_factory::{*, gen::set_be_u8}; /// # fn main() { /// // will make a generator setting an u8 /// fn gen0(x:(&mut [u8],usize),v:u8) -> Result<(&mut [u8],usize),GenError> { /// gen_call!((x.0,x.1), set_be_u8, v) /// } /// # } /// ``` #[macro_export] macro_rules! gen_call( (($i:expr, $idx:expr), $fun:expr) => ( $fun( ($i,$idx) ) ); (($i:expr, $idx:expr), $fun:expr, $($args:expr),* ) => ( $fun( ($i,$idx), $($args),* ) ); ); /// Applies sub-generators in a sequence. /// /// `do_gen!( I, /// I -> Result >> I-> Result >> ... >> I->Result) /// => I -> Result /// with I = (&[u8],usize) and E = GenError /// ` /// /// The input type is a tuple (slice,index). The index is incremented by each generator, to reflect /// the number of bytes written. /// /// If the input slice is not big enough, an error `GenError::BufferTooSmall(n)` is returned, `n` /// being the index that was required. /// /// ```rust,no_run /// # #[macro_use] extern crate cookie_factory; /// # use cookie_factory::*; /// /// fn gen0(x:(&mut [u8],usize),v:u8,w:u8) -> Result<(&mut [u8],usize),GenError> { /// do_gen!((x.0,x.1), gen_be_u8!(v) >> gen_be_u8!(w)) /// } /// /// # fn main() { /// let mut mem : [u8; 2] = [0; 2]; /// let s = &mut mem[..]; /// let expected = [1, 2]; /// /// match gen0((s,0), 1, 2) { /// Ok((b,idx)) => { /// assert_eq!(idx,expected.len()); /// assert_eq!(&b[..],&expected[..]); /// }, /// Err(e) => panic!("error {:?}",e), /// } /// # } /// ``` #[macro_export] macro_rules! do_gen( (__impl $i:expr, $idx:expr, ( $($rest:expr),* )) => ( { $($rest)*; Ok(($i,$idx)) } ); (__impl $i:expr, $idx:expr, $e:ident( $($args:tt)* )) => ( do_gen!(__impl $i, $idx, gen_call!($e,$($args)*)) ); (__impl $i:expr, $idx:expr, $submac:ident!( $($args:tt)* )) => ( $submac!(($i,$idx), $($args)*) ); (__impl $i:expr, $idx:expr, $e:ident >> $($rest:tt)*) => ( do_gen!(__impl $i, $idx, gen_call!($e) >> $($rest)*) ); (__impl $i:expr, $idx:expr, $e:ident( $($args:tt)* ) >> $($rest:tt)*) => ( do_gen!(__impl $i, $idx, gen_call!($e,$($args)*) >> $($rest)*) ); (__impl $i:expr, $idx:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( { match $submac!(($i,$idx), $($args)*) { Ok((j,idx2)) => { do_gen!(__impl j, idx2, $($rest)*) }, Err(e) => Err(e), } } ); (__impl $i:expr, $idx:expr, $e:ident : $($rest:tt)*) => ( { let $e = $idx; do_gen!(__impl $i, $idx, $($rest)*) } ); ( ($i:expr, $idx:expr), $($rest:tt)*) => ( do_gen!(__impl $i, $idx, $($rest)*) ); ( $i:expr, $($rest:tt)*) => ( do_gen!(__impl $i.0, $i.1, $($rest)*) ); ); /// `gen_cond!(bool, I -> Result) => I -> Result` /// Conditional combinator /// /// Wraps another generator and calls it if the /// condition is met. This combinator returns /// the return value of the child generator. /// #[macro_export] macro_rules! gen_cond( (($i:expr, $idx:expr), $cond:expr, $submac:ident!( $($args:tt)* )) => ( { if $cond { $submac!(($i,$idx), $($args)*) } else { Ok(($i,$idx)) } } ); (($i:expr, $idx:expr), $cond:expr, $f:expr) => ( gen_cond!(($i,$idx), $cond, gen_call!($f)) ); ); /// `gen_if_else!(bool, I -> Result, I -> Result) => I -> Result` /// Conditional combinator, with alternate generator. /// /// Wraps another generator and calls it if the /// condition is met. This combinator returns /// the return value of the child generator. /// /// If the condition is not satisfied, calls the alternate generator. /// #[macro_export] macro_rules! gen_if_else( (($i:expr, $idx:expr), $cond:expr, $submac_if:ident!( $($args_if:tt)* ), $submac_else:ident!( $($args_else:tt)* )) => ( { if $cond { $submac_if!(($i,$idx), $($args_if)*) } else { $submac_else!(($i,$idx), $($args_else)*) } } ); (($i:expr, $idx:expr), $cond:expr, $f:expr, $g:expr) => ( gen_cond!(($i,$idx), $cond, gen_call!($f), gen_call!($g)) ); ); /// `gen_many_ref!(I, Iterable, Fn(I,V)) => I -> Result` /// Applies the generator `$f` to every element of `$l`, passing arguments by reference. #[macro_export] macro_rules! gen_many_ref( (($i:expr, $idx:expr), $l:expr, $f:expr) => ( $l.into_iter().fold( Ok(($i,$idx)), |r,ref v| { match r { Err(e) => Err(e), Ok(x) => { $f(x, v) }, } } ) ); ); /// `gen_many_byref!(I, Iterable, Fn(I,V)) => I -> Result` /// Applies the generator `$f` to every element of `$l`, where arguments of $l are references #[macro_export] macro_rules! gen_many_byref( (($i:expr, $idx:expr), $l:expr, $f:expr) => ( $l.into_iter().fold( Ok(($i,$idx)), |r,&v| { match r { Err(e) => Err(e), Ok(x) => { $f(x, v) }, } } ) ); ); /// `gen_many!(I, Iterable, Fn(I,V)) => I -> Result` /// Applies the generator `$f` to every element of `$l`, passing arguments by value. #[macro_export] macro_rules! gen_many( (($i:expr, $idx:expr), $l:expr, $f:expr) => ( $l.into_iter().fold( Ok(($i,$idx)), |r,v| { match r { Err(e) => Err(e), Ok(x) => { $f(x, v) }, } } ) ); ); /// `gen_at_offset!(usize, I -> Result) => I -> Result` /// Combinator to call generator at an absolute offset. /// /// Wraps another generator and calls it using a different index /// from the current position. If this combinator succeeds, it returns /// the current index (instead of the one returned by the child generator). /// If the child generator fails, returns the error. /// #[macro_export] macro_rules! gen_at_offset( (($i:expr, $idx:expr), $offset:expr, $f:ident( $($args:tt)* )) => ( match $i.len() < $offset { false => { match $f(($i,$offset), $($args)*) { Ok((r,_)) => Ok((r,($idx))), Err(e) => Err(e), } }, true => Err(GenError::BufferTooSmall($offset - $i.len())), } ); (($i:expr, $idx:expr), $offset:expr, $submac:ident!( $($args:tt)* )) => ( match $i.len() < $offset { false => { match $submac!(($i,$offset), $($args)*) { Ok((r,_)) => Ok((r,($idx))), Err(e) => Err(e), } }, true => Err(GenError::BufferTooSmall($offset - $i.len())), } ); ); /// `gen_at_offset!(usize, I -> Result) => I -> Result` /// Combinator to call generator at a relative offset. /// /// Wraps another generator and calls it using a different index /// from the current position. If this combinator succeeds, it returns /// the current index (instead of the one returned by the child generator). /// If the child generator fails, returns the error. /// #[macro_export] macro_rules! gen_at_rel_offset( (($i:expr, $idx:expr), $rel_offset:expr, $f:ident( $($args:tt)* )) => ( match ($rel_offset as i32).overflowing_add($idx as i32).1 { (s,false) if s > 0 => { gen_at_offset!(($i,$idx),s as usize,$f($($args)*)) }, _ => Err(GenError::InvalidOffset), } ); (($i:expr, $idx:expr), $rel_offset:expr, $submac:ident!( $($args:tt)* )) => ( match ($rel_offset as i32).overflowing_add($idx as i32) { (s,false) if s > 0 => { gen_at_offset!(($i,$idx),s as usize,$submac!($($args)*)) }, _ => Err(GenError::InvalidOffset), } ); ); #[cfg(test)] mod tests { use super::*; #[test] fn test_do_gen() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 2, 3, 4, 5, 6, 7, 8]; let r = do_gen!( (s, 0), gen_be_u8!(1) >> gen_be_u8!(2) >> gen_be_u16!(0x0304) >> gen_be_u32!(0x05060708) ); match r { Ok((b, idx)) => { assert_eq!(idx, 8); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_do_gen_vector() { let mut data = [0; 8]; let expected = [1, 2, 3, 4, 5, 6, 7, 8]; let r = do_gen!( (&mut data, 0), gen_be_u8!(1) >> gen_be_u8!(2) >> gen_be_u16!(0x0304) >> gen_be_u32!(0x05060708) ); match r { Ok((b, idx)) => { assert_eq!(idx, 8); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_skip() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [0, 0, 0, 0, 0, 0, 0, 0]; let r = gen_skip!((s, 0), 5); match r { Ok((b, idx)) => { assert_eq!(idx, 5); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_be_u8() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 2, 0, 0, 0, 0, 0, 0]; let r = do_gen!((s, 0), gen_be_u8!(1) >> gen_be_u8!(2)); match r { Ok((b, idx)) => { assert_eq!(idx, 2); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_le_u8() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 2, 0, 0, 0, 0, 0, 0]; let r = do_gen!((s, 0), gen_le_u8!(1) >> gen_le_u8!(2)); match r { Ok((b, idx)) => { assert_eq!(idx, 2); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_be_i32() { let mut mem: [u8; 8] = [0; 8]; let expected = [0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0]; let r = gen_be_i32!((&mut mem, 0), -1i32); match r { Ok((b, idx)) => { assert_eq!(idx, 4); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_be_u64() { let mut mem: [u8; 8] = [0; 8]; let expected = [1, 2, 3, 4, 5, 6, 7, 8]; let r = gen_be_u64!((&mut mem, 0), 0x0102030405060708u64); match r { Ok((b, idx)) => { assert_eq!(idx, 8); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_be_u64_very_short_buffer() { let mut mem = [0; 3]; let r = gen_be_u64!((&mut mem, 0), 0x0102030405060708u64); match r { Ok((b, idx)) => panic!("should have failed, but wrote {} bytes: {:?}", idx, b), Err(GenError::BufferTooSmall(sz)) => assert_eq!(sz, 5), Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_be_u64_slightly_short_buffer() { let mut mem = [0; 7]; let r = gen_be_u64!((&mut mem, 0), 0x0102030405060708u64); match r { Ok((b, idx)) => panic!("should have failed, but wrote {} bytes: {:?}", idx, b), Err(GenError::BufferTooSmall(sz)) => assert_eq!(sz, 1), Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_le_u64() { let mut mem: [u8; 8] = [0; 8]; let expected = [8, 7, 6, 5, 4, 3, 2, 1]; let r = gen_le_u64!((&mut mem, 0), 0x0102030405060708u64); match r { Ok((b, idx)) => { assert_eq!(idx, 8); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_set_be_u8() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 2, 0, 0, 0, 0, 0, 0]; let r = do_gen!((s, 0), set_be_u8(1) >> set_be_u8(2)); match r { Ok((b, idx)) => { assert_eq!(idx, 2); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_align() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 0, 0, 0, 1, 0, 0, 0]; let r = do_gen!((s, 0), gen_be_u8!(1) >> gen_align!(4) >> gen_be_u8!(1)); match r { Ok((b, idx)) => { assert_eq!(idx, 5); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] #[cfg(feature = "std")] fn test_gen_many() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let v: Vec = vec![1, 2, 3, 4]; let expected = [0, 1, 0, 2, 0, 3, 0, 4]; let r = gen_many!((s, 0), v, set_be_u16); match r { Ok((b, idx)) => { assert_eq!(idx, 8); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_copy() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let v = [1, 2, 3, 4]; let expected = [1, 2, 3, 4, 0, 0, 0, 0]; let r = gen_copy!((s, 0), v, v.len()); match r { Ok((b, idx)) => { assert_eq!(idx, 4); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_copy_buffer_too_small() { let mut mem: [u8; 7] = [0; 7]; let s = &mut mem[..]; let v = [0, 1, 2, 3, 4, 5, 6, 7]; let r = gen_copy!((s, 0), v, v.len()); match r { Ok(_) => { panic!("buffer shouldn't have had enough space"); } Err(GenError::BufferTooSmall(sz)) => { if sz != 1 { panic!("invalid max index returned, expected {} got {}", 1, sz); } } Err(e) => { panic!("error {:?}", e); } } } #[test] fn test_gen_slice() { let mut mem: [u8; 0] = [0; 0]; let s = &mut mem[..]; let v = []; let expected = []; let r = gen_slice!((s, 0), v); match r { Ok((b, idx)) => { assert_eq!(idx, 0); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_slice_buffer_too_small() { let mut mem: [u8; 7] = [0; 7]; let s = &mut mem[..]; let v = [0, 1, 2, 3, 4, 5, 6, 7]; let r = gen_slice!((s, 0), v); match r { Ok(_) => { panic!("buffer shouldn't have had enough space"); } Err(GenError::BufferTooSmall(sz)) => { if sz != 1 { panic!("invalid max index returned, expected {} got {}", 1, sz); } } Err(e) => { panic!("error {:?}", e); } } } #[test] fn test_gen_length_slice() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let v = [1, 2, 3, 4]; let expected = [0, 4, 1, 2, 3, 4, 0, 0]; macro_rules! gen_be_usize_as_u16( ($i:expr, $val:expr) => ( set_be_u16($i, $val as u16) ); ); let r = do_gen!((s, 0), gen_length_slice!(gen_be_usize_as_u16 >> v)); match r { Ok((b, idx)) => { assert_eq!(idx, 6); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_checkpoint() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [1, 0, 0, 0, 0, 4, 0, 0]; let r = do_gen!( (s, 0), start: gen_be_u8!(1) >> gen_align!(4) >> end: gen_be_u16!((end - start) as u16) ); match r { Ok((b, idx)) => { assert_eq!(idx, 6); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_at_offset() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [0, 0, 0, 0, 0, 4, 0, 0]; let r = do_gen!((s, 0), gen_skip!(2) >> gen_at_offset!(4, gen_be_u16!(4))); match r { Ok((b, idx)) => { assert_eq!(idx, 2); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_at_rel_offset() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let expected = [0, 0, 0, 0, 0, 0, 0, 4]; let r = do_gen!( (s, 0), gen_skip!(2) >> gen_at_rel_offset!(4, gen_be_u16!(4)) ); match r { Ok((b, idx)) => { assert_eq!(idx, 2); assert_eq!(b, &expected); } Err(e) => panic!("error {:?}", e), } } #[test] fn test_gen_at_rel_offset_fail() { let mut mem: [u8; 8] = [0; 8]; let s = &mut mem[..]; let r = do_gen!( (s, 0), gen_skip!(2) >> gen_at_rel_offset!(-4, gen_be_u16!(4)) ); if let Err(GenError::InvalidOffset) = r { } else { panic!("unexpected result {:?}", r) }; } } cookie-factory-0.3.0/src/internal.rs010064400007670000024000000222171354243250700156330ustar0000000000000000//! main structures and traits used to build serializers use crate::lib::std::{fmt, io::{self, Seek as _, SeekFrom, Write}}; /// Holds the result of serializing functions /// /// The `Ok` case returns the `Write` used for writing, in the `Err` case an instance of /// `cookie_factory::GenError` is returned. pub type GenResult = Result, GenError>; /// Base type for generator errors #[derive(Debug)] pub enum GenError { /// Input buffer is too small. Argument is the maximum index that is required BufferTooSmall(usize), /// We expected to fill the whole buffer but there is some space left BufferTooBig(usize), /// Operation asked for accessing an invalid index InvalidOffset, /// IoError returned by Write IoError(io::Error), /// Allocated for custom errors CustomError(u32), /// Generator or function not yet implemented NotYetImplemented, } impl fmt::Display for GenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "std")] impl std::error::Error for GenError {} impl From for GenError { fn from(err: io::Error) -> Self { GenError::IoError(err) } } /// Trait for serializing functions /// /// Serializing functions take one input `W` that is the target of writing and return an instance /// of `cookie_factory::GenResult`. /// /// This trait is implemented for all `Fn(W) -> GenResult`. pub trait SerializeFn: Fn(WriteContext) -> GenResult {} impl) -> GenResult> SerializeFn for F {} /// Context around a `Write` impl that is passed through serializing functions /// /// Currently this only keeps track of the current write position since the start of serialization. pub struct WriteContext { pub write: W, pub position: u64, } impl From for WriteContext { fn from(write: W) -> Self { Self { write, position: 0 } } } impl WriteContext { /// Returns the contained `Write` and the current position pub fn into_inner(self) -> (W, u64) { (self.write, self.position) } } impl Write for WriteContext { fn write(&mut self, data: &[u8]) -> crate::lib::std::io::Result { let amt = self.write.write(data)?; self.position += amt as u64; Ok(amt) } #[cfg(feature = "std")] fn flush(&mut self) -> io::Result<()> { self.write.flush() } } impl io::Seek for WriteContext { fn seek(&mut self, pos: SeekFrom) -> io::Result { let old_pos = self.write.seek(SeekFrom::Current(0))?; let new_pos = self.write.seek(pos)?; if new_pos >= old_pos { self.position += new_pos - old_pos; } else { self.position -= old_pos - new_pos; } Ok(new_pos) } } /// Runs the given serializer `f` with the `Write` impl `w` and returns the result /// /// This internally wraps `w` in a `WriteContext`, starting at position 0. /// /// ```rust /// use cookie_factory::{gen, combinator::slice}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(slice(&b"abcd"[..]), &mut buf[..]).unwrap(); /// assert_eq!(buf.len(), 100 - 4); /// assert_eq!(pos, 4); /// } /// /// assert_eq!(&buf[..4], &b"abcd"[..]); /// ``` pub fn gen>(f: F, w: W) -> Result<(W, u64), GenError> { f(WriteContext::from(w)).map(|ctx| ctx.into_inner()) } /// Runs the given serializer `f` with the `Write` impl `w` and returns the updated `w` /// /// This internally wraps `w` in a `WriteContext`, starting at position 0. /// /// ```rust /// use cookie_factory::{gen_simple, combinator::slice}; /// /// let mut buf = [0u8; 100]; /// /// { /// let buf = gen_simple(slice(&b"abcd"[..]), &mut buf[..]).unwrap(); /// assert_eq!(buf.len(), 100 - 4); /// } /// /// assert_eq!(&buf[..4], &b"abcd"[..]); /// ``` pub fn gen_simple>(f: F, w: W) -> Result { f(WriteContext::from(w)).map(|ctx| ctx.into_inner().0) } /// Trait for `Write` types that allow skipping over the data pub trait Skip: Write { fn skip(s: WriteContext, s: usize) -> GenResult where Self: Sized; } /// Trait for `Write` types that allow skipping and reserving a slice, then writing some data, /// then write something in the slice we reserved using the return for our data write. pub trait BackToTheBuffer: Write { fn reserve_write_use< Tmp, Gen: Fn(WriteContext) -> Result<(WriteContext, Tmp), GenError>, Before: Fn(WriteContext, Tmp) -> GenResult, >( s: WriteContext, reserved: usize, gen: &Gen, before: &Before, ) -> Result, GenError> where Self: Sized; } /// Trait for `Seek` types that want to automatically implement `BackToTheBuffer` pub trait Seek: Write + io::Seek {} impl Seek for io::Cursor<&mut [u8]> {} impl BackToTheBuffer for W { fn reserve_write_use< Tmp, Gen: Fn(WriteContext) -> Result<(WriteContext, Tmp), GenError>, Before: Fn(WriteContext, Tmp) -> GenResult, >( mut s: WriteContext, reserved: usize, gen: &Gen, before: &Before, ) -> Result, GenError> { let start = s.seek(SeekFrom::Current(0))?; let begin = s.seek(SeekFrom::Current(reserved as i64))?; let (mut buf, tmp) = gen(s)?; let end = buf.seek(SeekFrom::Current(0))?; buf.seek(SeekFrom::Start(start))?; let mut buf = before(buf, tmp)?; let pos = buf.seek(SeekFrom::Current(0))?; if pos != begin { return Err(GenError::BufferTooBig((begin - pos) as usize)); } buf.seek(SeekFrom::Start(end))?; Ok(buf) } } impl Skip for &mut [u8] { fn skip(s: WriteContext, len: usize) -> Result, GenError> { if s.write.len() < len { Err(GenError::BufferTooSmall(len - s.write.len())) } else { Ok(WriteContext { write: &mut s.write[len..], position: s.position + len as u64, }) } } } impl Skip for io::Cursor<&mut [u8]> { fn skip(mut s: WriteContext, len: usize) -> GenResult { let remaining = s .write .get_ref() .len() .saturating_sub(s.write.position() as usize); if remaining < len { Err(GenError::BufferTooSmall(len - remaining)) } else { let cursor_position = s.write.position(); s.write.set_position(cursor_position + len as u64); s.position += len as u64; Ok(s) } } } impl BackToTheBuffer for &mut [u8] { fn reserve_write_use< Tmp, Gen: Fn(WriteContext) -> Result<(WriteContext, Tmp), GenError>, Before: Fn(WriteContext, Tmp) -> GenResult, >( s: WriteContext, reserved: usize, gen: &Gen, before: &Before, ) -> Result, GenError> { let WriteContext { write: slice, position: original_position, } = s; let (res, buf) = slice.split_at_mut(reserved); let (new_context, tmp) = gen(WriteContext { write: buf, position: original_position + reserved as u64, })?; let res = before( WriteContext { write: res, position: original_position, }, tmp, )?; if !res.write.is_empty() { return Err(GenError::BufferTooBig(res.write.len())); } Ok(new_context) } } #[cfg(feature = "std")] impl BackToTheBuffer for Vec { fn reserve_write_use< Tmp, Gen: Fn(WriteContext) -> Result<(WriteContext, Tmp), GenError>, Before: Fn(WriteContext, Tmp) -> GenResult, >( s: WriteContext, reserved: usize, gen: &Gen, before: &Before, ) -> Result, GenError> { let WriteContext { write: mut vec, position: original_position, } = s; let start_len = vec.len(); vec.extend(std::iter::repeat(0).take(reserved)); let (mut new_context, tmp) = gen(WriteContext { write: vec, position: original_position + reserved as u64, })?; let tmp_context = before( WriteContext { write: Vec::new(), position: original_position, }, tmp, )?; let tmp_written = tmp_context.write.len(); if tmp_written != reserved { return Err(GenError::BufferTooBig(reserved - tmp_written)); } // FIXME?: find a way to do that without copying // Vec::from_raw_parts + core::mem::forget makes it work, but // if `before` writes more than `reserved`, realloc will cause troubles new_context.write[start_len..(start_len + reserved)] .copy_from_slice(&tmp_context.write[..]); Ok(new_context) } } cookie-factory-0.3.0/src/io_compat.rs010064400007670000024000000041021354243120300157520ustar0000000000000000// there's no real io error on a byte slice pub type Error = (); pub type Result = core::result::Result; pub trait Write { fn write(&mut self, buf: &[u8]) -> Result; } impl Write for &mut [u8] { fn write(&mut self, data: &[u8]) -> Result { let amt = core::cmp::min(data.len(), self.len()); let (a, b) = core::mem::replace(self, &mut []).split_at_mut(amt); a.copy_from_slice(&data[..amt]); *self = b; Ok(amt) } } pub enum SeekFrom { Start(u64), Current(i64), } pub trait Seek { fn seek(&mut self, pos: SeekFrom) -> Result; } // Minimal re-implementation of std::io::Cursor so it // also works in non-std environments pub struct Cursor(T, u64); impl<'a> Cursor<&'a mut [u8]> { pub fn new(inner: &'a mut [u8]) -> Self { Self(inner, 0) } pub fn into_inner(self) -> &'a mut [u8] { self.0 } pub fn position(&self) -> u64 { self.1 as u64 } pub fn set_position(&mut self, pos: u64) { self.1 = pos; } pub fn get_mut(&mut self) -> &mut [u8] { self.0 } pub fn get_ref(&self) -> &[u8] { self.0 } } impl<'a> Write for Cursor<&'a mut [u8]> { fn write(&mut self, data: &[u8]) -> Result { let amt = (&mut self.0[(self.1 as usize)..]).write(data)?; self.1 += amt as u64; Ok(amt) } } impl<'a> Seek for Cursor<&'a mut [u8]> { fn seek(&mut self, pos: SeekFrom) -> Result { let (start, offset) = match pos { SeekFrom::Start(n) => { self.1 = n; return Ok(n); } SeekFrom::Current(n) => (self.1 as u64, n), }; let new_pos = if offset >= 0 { start.checked_add(offset as u64) } else { start.checked_sub((offset.wrapping_neg()) as u64) }; match new_pos { Some(n) => { self.1 = n; Ok(n) } None => panic!("invalid seek to a negative or overflowing position"), } } } cookie-factory-0.3.0/src/lib.rs010064400007670000024000000022611354243177300145660ustar0000000000000000//! serialization library built with a combinator design similar to nom. //! //! Serializers are built up from single purpose serializers, like `slice` //! to write a raw byte slice, or `be_u16` to write a `u16` integer in big //! endian form. //! //! Those small serializers can then be assembled by using combinators. //! As an example, `all(["abcd", "efgh", "ijkl"].iter().map(string))(output)` //! will write `"abcdefghijkl"` to `output`. #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] mod io_compat; /// lib module necessary to reexport what we need from std in `no_std` mode pub mod lib { #[cfg(feature = "std")] pub mod std { pub mod io { pub use std::io::{Cursor, Error, Result, Seek, SeekFrom, Write}; } pub use std::{cmp, fmt, iter, mem, result, slice}; } #[cfg(not(feature = "std"))] pub mod std { pub use core::{cmp, iter, mem, result, slice}; #[macro_use] pub use core::fmt; pub mod io { pub use io_compat::*; } } } #[macro_use] pub mod gen; mod internal; pub use internal::*; pub mod bytes; pub mod combinator; pub mod multi; pub mod sequence; cookie-factory-0.3.0/src/multi.rs010064400007670000024000000053311354243165300151500ustar0000000000000000//! serializers working on a list of elements (vectors, iterators, etc) use crate::internal::{SerializeFn, WriteContext}; use crate::lib::std::io::Write; /// Applies an iterator of serializers of the same type /// /// ```rust /// use cookie_factory::{gen, multi::all, combinator::string}; /// /// let mut buf = [0u8; 100]; /// /// let data = vec!["abcd", "efgh", "ijkl"]; /// { /// let (buf, pos) = gen(all(data.iter().map(string)), &mut buf[..]).unwrap(); /// assert_eq!(pos, 12); /// assert_eq!(buf.len(), 100 - 12); /// } /// /// assert_eq!(&buf[..12], &b"abcdefghijkl"[..]); /// ``` pub fn all(values: It) -> impl SerializeFn where G: SerializeFn, It: Clone + Iterator, { move |mut out: WriteContext| { let it = values.clone(); for v in it { out = v(out)?; } Ok(out) } } /// Applies an iterator of serializers of the same type with a separator between each serializer /// /// ```rust /// use cookie_factory::{gen, multi::separated_list, combinator::string}; /// /// let mut buf = [0u8; 100]; /// /// let data = vec!["abcd", "efgh", "ijkl"]; /// { /// let (buf, pos) = gen(separated_list(string(","), data.iter().map(string)), &mut buf[..]).unwrap(); /// assert_eq!(pos, 14); /// assert_eq!(buf.len(), 100 - 14); /// } /// /// assert_eq!(&buf[..14], &b"abcd,efgh,ijkl"[..]); /// ``` pub fn separated_list(sep: F, values: It) -> impl SerializeFn where F: SerializeFn, G: SerializeFn, It: Clone + Iterator, { move |mut out: WriteContext| { let mut it = values.clone(); match it.next() { None => return Ok(out), Some(first) => { out = first(out)?; } } for v in it { out = sep(out).and_then(v)?; } Ok(out) } } /// Applies a generator over an iterator of values, and applies the serializers generated /// /// ```rust /// use cookie_factory::{gen, multi::many_ref, combinator::string}; /// /// let mut buf = [0u8; 100]; /// /// let data = vec!["abcd", "efgh", "ijkl"]; /// { /// let (buf, pos) = gen(many_ref(&data, string), &mut buf[..]).unwrap(); /// assert_eq!(pos, 12); /// assert_eq!(buf.len(), 100 - 12); /// } /// /// assert_eq!(&buf[..12], &b"abcdefghijkl"[..]); /// ``` pub fn many_ref(items: I, generator: F) -> impl SerializeFn where It: Iterator + Clone, I: IntoIterator, F: Fn(E) -> G, G: SerializeFn, { let items = items.into_iter(); move |mut out: WriteContext| { for item in items.clone() { out = generator(item)(out)?; } Ok(out) } } cookie-factory-0.3.0/src/sequence.rs010064400007670000024000000135371354243170400156320ustar0000000000000000//! serializers working a sequence of objects (pairs, tuples, etc) use crate::internal::{GenResult, SerializeFn, WriteContext}; use crate::lib::std::io::Write; /// Applies 2 serializers in sequence /// /// ```rust /// use cookie_factory::{gen, sequence::pair, combinator::string}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen(pair(string("abcd"), string("efgh")), &mut buf[..]).unwrap(); /// assert_eq!(pos, 8); /// assert_eq!(buf.len(), 100 - 8); /// } /// /// assert_eq!(&buf[..8], &b"abcdefgh"[..]); /// ``` pub fn pair(first: F, second: G) -> impl SerializeFn where F: SerializeFn, G: SerializeFn, { move |out: WriteContext| first(out).and_then(&second) } /// Helper trait for the `tuple` combinator pub trait Tuple { fn serialize(&self, w: WriteContext) -> GenResult; } impl> Tuple for (A,) { fn serialize(&self, w: WriteContext) -> GenResult { self.0(w) } } // Generates all the Tuple impls for tuples of arbitrary sizes based on a list of type // parameters like FnA FnB FnC. It would generate the impl then for (FnA, FnB) // and (FnA, FnB, FnC). macro_rules! tuple_trait( ($name1:ident, $name2: ident, $($name:ident),*) => ( tuple_trait!(__impl $name1, $name2; $($name),*); ); (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( tuple_trait_impl!($($name),+); tuple_trait!(__impl $($name),+ , $name1; $($name2),*); ); (__impl $($name:ident),+; $name1:ident) => ( tuple_trait_impl!($($name),+); tuple_trait_impl!($($name),+, $name1); ); ); // Generates the impl block for Tuple on tuples or arbitrary sizes based on its // arguments. Takes a list of type parameters as parameters, e.g. FnA FnB FnC // and then implements the trait on (FnA, FnB, FnC). macro_rules! tuple_trait_impl( ($($name:ident),+) => ( impl),+> Tuple for ( $($name),+ ) { fn serialize(&self, w: WriteContext) -> GenResult { tuple_trait_inner!(0, self, w, $($name)+) } } ); ); // Generates the inner part of the Tuple::serialize() implementation, which will // basically look as follows: // // let w = self.0(w)?; // let w = self.1(w)?; // [...] // let w = self.N(w)?; // // Ok(w) macro_rules! tuple_trait_inner( ($it:tt, $self:expr, $w:ident, $head:ident $($id:ident)+) => ({ let w = $self.$it($w)?; succ!($it, tuple_trait_inner!($self, w, $($id)+)) }); ($it:tt, $self:expr, $w:ident, $head:ident) => ({ let w = $self.$it($w)?; Ok(w) }); ); // Takes an integer and a macro invocation, and changes the macro invocation // to take the incremented integer as the first argument // // Works for integers between 0 and 19. #[doc(hidden)] macro_rules! succ ( (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*)); (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*)); (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*)); (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*)); (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*)); (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*)); (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*)); (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*)); (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*)); (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*)); (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*)); (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*)); (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*)); (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*)); (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*)); (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*)); (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*)); (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*)); (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*)); (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*)); ); tuple_trait!( FnA, FnB, FnC, FnD, FnE, FnF, FnG, FnH, FnI, FnJ, FnK, FnL, FnM, FnN, FnO, FnP, FnQ, FnR, FnS, FnT, FnU ); /// Applies multiple serializers in sequence /// /// Currently tuples up to 20 elements are supported. /// /// ```rust /// use cookie_factory::{gen, sequence::tuple, combinator::string, bytes::be_u16}; /// /// let mut buf = [0u8; 100]; /// /// { /// let (buf, pos) = gen( /// tuple(( /// string("abcd"), /// be_u16(0x20), /// string("efgh"), /// )), /// &mut buf[..] /// ).unwrap(); /// assert_eq!(pos, 10); /// assert_eq!(buf.len(), 100 - 10); /// } /// /// assert_eq!(&buf[..10], &b"abcd\x00\x20efgh"[..]); /// ``` pub fn tuple>(l: List) -> impl SerializeFn { move |w: WriteContext| l.serialize(w) } #[cfg(test)] mod test { use super::*; use crate::combinator::string; use crate::internal::gen_simple; #[test] fn test_pair_with_cursor() { let mut buf = [0u8; 8]; { use crate::lib::std::io::Cursor; let cursor = Cursor::new(&mut buf[..]); let serializer = pair(string("1234"), string("5678")); let cursor = gen_simple(serializer, cursor).unwrap(); assert_eq!(cursor.position(), 8); } assert_eq!(&buf[..], b"12345678"); } #[test] fn test_tuple() { let mut buf = [0u8; 12]; { use crate::lib::std::io::Cursor; let cursor = Cursor::new(&mut buf[..]); let serializer = tuple((string("1234"), string("5678"), tuple((string("0123"),)))); let cursor = gen_simple(serializer, cursor).unwrap(); assert_eq!(cursor.position(), 12); } assert_eq!(&buf[..], b"123456780123"); } } cookie-factory-0.3.0/.cargo_vcs_info.json0000644000000001120000000000000140030ustar00{ "git": { "sha1": "941de1c20df6d13e47d6eb4bca0a847634d26b28" } } cookie-factory-0.3.0/Cargo.lock0000644000000007760000000000000117760ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "cookie-factory" version = "0.3.0" dependencies = [ "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"