1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! Simple & fast bit-level binary co/dec in Rust.
//!
//! For more information about `#[derive(Protocol)]` and its attributes, see [macro@Protocol].
//!
//! # Example
//!
//! ```
//! # use bin_proto::Protocol;
//! #[derive(Debug, Protocol, PartialEq)]
//! #[protocol(discriminant_type = "u8")]
//! #[protocol(bits = 4)]
//! enum E {
//!     V1 = 1,
//!     #[protocol(discriminant = "4")]
//!     V4,
//! }
//!
//! #[derive(Debug, Protocol, PartialEq)]
//! struct S {
//!     #[protocol(bits = 1)]
//!     bitflag: bool,
//!     #[protocol(bits = 3)]
//!     bitfield: u8,
//!     enum_: E,
//!     #[protocol(write_value = "self.arr.len() as u8")]
//!     arr_len: u8,
//!     #[protocol(length = "arr_len as usize")]
//!     arr: Vec<u8>,
//!     #[protocol(flexible_array_member)]
//!     read_to_end: Vec<u8>,
//! }
//!
//! assert_eq!(
//!     S::from_bytes(&[
//!         0b1000_0000 // bitflag: true (1)
//!        | 0b101_0000 // bitfield: 5 (101)
//!            | 0b0001, // enum_: V1 (0001)
//!         0x02, // arr_len: 2
//!         0x21, 0x37, // arr: [0x21, 0x37]
//!         0x01, 0x02, 0x03, // read_to_end: [0x01, 0x02, 0x03]
//!     ], bin_proto::ByteOrder::BigEndian).unwrap(),
//!     S {
//!         bitflag: true,
//!         bitfield: 5,
//!         enum_: E::V1,
//!         arr_len: 2,
//!         arr: vec![0x21, 0x37],
//!         read_to_end: vec![0x01, 0x02, 0x03],
//!     }
//! );
//! ```

pub use self::bit_field::BitField;
pub use self::bit_read::BitRead;
pub use self::bit_write::BitWrite;
pub use self::byte_order::ByteOrder;
pub use self::enum_ext::EnumExt;
pub use self::error::{Error, Result};
pub use self::externally_length_prefixed::ExternallyLengthPrefixed;
pub use self::flexible_array_member::FlexibleArrayMember;
pub use self::protocol::Protocol;

/// Derive the `Protocol` trait.
///
/// # Attributes
///
/// ## `#[protocol(discriminant_type = "<type>")]`
/// - Applies to: `enum` with `#[derive(Protocol)]`.
/// - `<type>`: an arbitrary type that implements `Protocol`
///
/// Specify if enum variant should be determined by a string or interger
/// representation of its discriminant.
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// #[protocol(discriminant_type = "u8")]
/// enum Example {
///     Variant1 = 1,
///     Variant5 = 5,
/// }
/// ```
///
/// ## `#[protocol(discriminant = "<value>")]`
/// - Applies to: `enum` variant
/// - `<value>`: unique value of the discriminant's type
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// #[protocol(discriminant_type = "u8")]
/// enum Example {
///     #[protocol(discriminant = "1")]
///     Variant1,
///     Variant5 = 5,
/// }
/// ```
///
/// Specify the discriminant for a variant.
///
/// ## `#[protocol(bits = <width>)]`
/// - Applies to: `impl BitField`, `enum` with discriminant that `impl BitField`
///
/// Determine width of field in bits.
///
/// **WARNING**: Bitfields disregard ByteOrder and instead have the same
/// endianness as the underlying `BitRead` / `BitWrite` instance. If you're
/// using bitfields, you almost always want a big endian stream.
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// struct Nibble(#[protocol(bits = 4)] u8);
/// ```
///
/// ## `#[protocol(flexible_array_member)]`
/// - Applies to: `impl FlexibleArrayMember`
///
/// Variable-length field is final field in container, hence lacks a length
/// prefix and should be read until eof.
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// struct ReadToEnd(#[protocol(flexible_array_member)] Vec<u8>);
/// ```
///
/// ## `#[protocol(length = "<expr>")]`
/// - Applies to: `impl ExternallyLengthPrefixed`
/// - `<expr>`: arbitrary `usize` expression. Fields in parent container can be
///   used without prefixing them with `self`.
///
/// Specify length of variable-length field.
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// pub struct WithElementsLength {
///     pub count: u32,
///     pub foo: bool,
///     #[protocol(length = "count as usize")]
///     pub data: Vec<u32>,
/// }
/// ```
///
/// ## `#[protocol(write_value = "<expr>")]`
/// - Applies to: fields
/// - `<expr>`: An expression that can be coerced to the field type, potentially
///   using `self`
///
/// Specify an expression that should be used as the field's value for writing.
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// pub struct WithElementsLengthAuto {
///     #[protocol(write_value = "self.data.len() as u32")]
///     pub count: u32,
///     pub foo: bool,
///     #[protocol(length = "count as usize")]
///     pub data: Vec<u32>,
/// }
/// ```
#[cfg(feature = "derive")]
pub use bin_proto_derive::Protocol;

mod bit_field;
mod bit_read;
mod bit_write;
#[macro_use]
mod externally_length_prefixed;
mod byte_order;
mod flexible_array_member;
mod types;

mod enum_ext;
mod error;
#[macro_use]
mod protocol;
mod util;

pub extern crate bitstream_io;

/// ```compile_fail
/// #[derive(bin_proto::Protocol)]
/// struct MutuallyExclusiveAttrs {
///     pub length: u8,
///     #[protocol(flexible_array_member)]
///     #[protocol(length = "length as usize")]
///     pub reason: String,
/// }
/// ```
#[cfg(all(feature = "derive", doctest))]
#[allow(unused)]
fn compile_fail_if_multiple_exclusive_attrs() {}