structure/lib.rs
1//! Use format strings to create strongly-typed data pack/unpack interfaces (inspired by Python's `struct` library).
2//!
3//!
4//! # Installation
5//!
6//! Add this to your `Cargo.toml`:
7//!
8//! ```toml
9//! [dependencies]
10//! structure = "0.1"
11//! ```
12//!
13//! And this to your crate root:
14//!
15//! ```rust
16//! #[macro_use]
17//! extern crate structure;
18//!
19//! # fn main() {}
20//! ```
21//!
22//! # Examples
23//!
24//! ```rust
25//! # #[macro_use]
26//! # extern crate structure;
27//! # fn foo() -> std::io::Result<()> {
28//! // Two `u32` and one `u8`
29//! let s = structure!("2IB");
30//! let buf: Vec<u8> = s.pack(1, 2, 3)?;
31//! assert_eq!(buf, vec![0, 0, 0, 1, 0, 0, 0, 2, 3]);
32//! assert_eq!(s.unpack(buf)?, (1, 2, 3));
33//! # Ok(())
34//! # }
35//! # fn main() {
36//! # foo().unwrap();
37//! # }
38//! ```
39//!
40//! It's useful to use `pack_into` and `unpack_from` when using types that implement `Write` or `Read`.
41//! The following example shows how to send a `u32` and a `u8` through sockets:
42//!
43//! ```rust
44//! # #[macro_use]
45//! # extern crate structure;
46//! # fn foo() -> std::io::Result<()> {
47//! use std::net::{TcpListener, TcpStream};
48//! let listener = TcpListener::bind("127.0.0.1:0")?;
49//! let mut client = TcpStream::connect(listener.local_addr()?)?;
50//! let (mut server, _) = listener.accept()?;
51//! let s = structure!("IB");
52//! s.pack_into(&mut client, 1u32, 2u8)?;
53//! let (n, n2) = s.unpack_from(&mut server)?;
54//! assert_eq!((n, n2), (1u32, 2u8));
55//! # Ok(())
56//! # }
57//! # fn main() {
58//! # foo().unwrap();
59//! # }
60//! ```
61//!
62//! # Format Strings
63//!
64//! ## Endianness
65//!
66//! By default, the endianness is big-endian. It could be determined by specifying one of the
67//! following characters at the beginning of the format:
68//!
69//! Character | Endianness
70//! --------- | ----------
71//! '=' | native (target endian)
72//! '<' | little-endian
73//! '>' | big-endian
74//! '!' | network (= big-endian)
75//!
76//! ## Types
77//!
78//! Character | Type
79//! --------- | ----
80//! 'b' | `i8`
81//! 'B' | `u8`
82//! '?' | `bool`
83//! 'h' | `i16`
84//! 'H' | `u16`
85//! 'i' | `i32`
86//! 'I' | `u32`
87//! 'q' | `i64`
88//! 'Q' | `u64`
89//! 'f' | `f32`
90//! 'd' | `f64`
91//! 's' | `&[u8]`
92//! 'S' | `&[u8]`
93//! 'P' | `*const c_void`
94//! 'x' | padding (1 byte)
95//!
96//! * Any format character may be preceded by an integral repeat count. For example, the format string '4h'
97//! means exactly the same as 'hhhh'.
98//! * 'P' may be follow by a `<type>`, so `"P<u32>"` means a pointer to u32 (`*const u32`).
99//! * When 's' is packed, its value can be smaller than the size specified in the format,
100//! and the rest will be filled with zeros. For instance:
101//!
102//! ```rust
103//! # #[macro_use]
104//! # extern crate structure;
105//! # fn foo() -> std::io::Result<()> {
106//! assert_eq!(structure!("3s").pack(&[8, 9])?, vec![8, 9, 0]);
107//! # Ok(())
108//! # }
109//! # fn main() {
110//! # foo().unwrap();
111//! # }
112//! ```
113//!
114//! * Unlike 's', 'S' is a fixed-size buffer, so the size of its value must be exactly the size
115//! specified in the format.
116//! * By default, 's' and 'S' are buffers of one byte. To create a fixed-sized buffer with ten bytes,
117//! the format would be "10S".
118//! * On unpack, 'x' skips a byte. On pack, 'x' always writes a null byte. To skip multiple bytes,
119//! prepend the length like in "10x".
120//!
121//! # Differences from Python struct library
122//!
123//! While the format strings look very similar to Python's `struct` library, there are a few differences:
124//!
125//! * Numbers' byte order is big-endian by default (e.g. u32, f64...).
126//! * There is no alignment support.
127//! * In addition to 's' (buffer) format character, that when packed, its value can be smaller than
128//! the size specified in the format, there is the 'S' format character, that the size of its value must
129//! be exactly the size specified in the format.
130//! * The type of a pointer is `c_void` by default, but can be changed.
131//! * 32 bit integer format character is only 'I'/'i' (and not 'L'/'l').
132//! * structure!() macro takes a literal string as an argument.
133//! * It's called `structure` because `struct` is a reserved keyword in Rust.
134
135#[macro_use]
136extern crate proc_macro_hack;
137
138#[doc(hidden)]
139pub extern crate byteorder;
140
141
142// Allow the "unused" #[macro_use] because there is a different un-ignorable
143// warning otherwise:
144//
145// proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
146#[allow(unused_imports)]
147#[macro_use]
148extern crate structure_macro_impl;
149#[doc(hidden)]
150pub use structure_macro_impl::*;
151
152proc_macro_expr_decl! {
153 structure! => structure_impl
154}