djin_protocol/attributes/mod.rs
1//! Documentation about the attributes available to `#[derive(Protocol)]`.
2//!
3//! Here is an example of `#[derive(Protocol)]`.
4//!
5//! ```
6//! #[macro_use] extern crate djin_protocol_derive;
7//! #[derive(Protocol)]
8//! struct Packet {
9//! version_number: u8,
10//! magic_number: u8,
11//! payload: Vec<u8>,
12//! }
13//! ```
14//!
15//! # Attributes that apply to items
16//!
17//! These attributes apply to structs and enums.
18//!
19//! ## `#[protocol(length_prefix(<kind>(<length prefix field name>)))]`
20//!
21//! This attribute allows variable-sized fields to have their sizes
22//! specified by an arbitrary integer field in the same struct or enum.
23//!
24//! Without this attribute, variable-sized fields default to having 32-bit
25//! unsigned integer length prefixes prefixed immediately before the field
26//! itself.
27//!
28//! ### Length prefix kinds
29//!
30//! #### `bytes`
31//!
32//! When the length prefix type is `bytes`, the length prefix
33//! represents the total number of bytes that make up a field.
34//!
35//! ```
36//! #[macro_use] extern crate djin_protocol_derive;
37//! #[derive(Protocol)]
38//! pub struct Foo {
39//! /// This field specifes the length of the last field `reason`.
40//! ///
41//! /// When values of this type are read, the size of `reason` is
42//! /// assumed to be `reason_length` bytes.
43//! pub reason_length: u16,
44//! pub other_stuff_inbetween: [u16; 16],
45//! pub thingy: bool,
46//! /// This field
47//! #[protocol(length_prefix(bytes(reason_length)))]
48//! pub reason: String,
49//! }
50//! ```
51//!
52//! #### `elements`
53//!
54//! When the length prefix type is 'elements', the length prefix
55//! represents the number of elements in a collection or list.
56//!
57//! ```
58//! #[macro_use] extern crate djin_protocol_derive;
59//! #[derive(Protocol)]
60//! pub struct Bar {
61//! /// This field specifes the number of elements in 'data'.
62//! pub reason_length: u16,
63//! pub other_stuff_inbetween: [u16; 16],
64//! pub thingy: bool,
65//! /// This field
66//! #[protocol(length_prefix(elements(reason_length)))]
67//! pub reason: Vec<(u32, u32)>,
68//! }
69//! ```
70//!
71//! # Notes
72//!
73//! This attribute can only be used with named fields. This means structs like
74//! `struct Hello(u32)` cannot be supported. This is because the length prefix
75//! field must be specified by a name, and therefore only items with named fields
76//! can ever have length prefixes.
77//!
78//! ## Length prefixes placed different structs
79//!
80//! It is possible for a field one one struct to specify the length of a field
81//! in another struct, so long as both structs are fields within a parent struct
82//! and the struct defining the length appears earlier than the one whose length
83//! is being described.
84//!
85//! In this case, the length prefix field must be double quoted.
86//!
87//! `#[protocol(length_prefix(bytes("sibling_field.nested_field.value")))]`
88//!
89//! Example:
90//!
91//! ```
92//! #[macro_use] extern crate djin_protocol_derive;
93//! #[derive(Protocol)]
94//! struct Packet {
95//! /// The length of the adjacent 'reason' field is nested under this field.
96//! pub packet_header: PacketHeader,
97//! /// The length of this field is specified by the packet header.
98//! #[protocol(length_prefix(bytes("packet_header.reason_length")))]
99//! pub reason: String,
100//! }
101//!
102//! #[derive(Protocol)]
103//! pub struct PacketHeader {
104//! pub reason_length: u16,
105//! }
106//! ```
107