summaryrefslogtreecommitdiffstats
path: root/rust/vendor/bendy/src/encoding.rs
blob: 9f4fddb1b47e6872e76130b2f6a332216a9035ee (plain)
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
//! An encoder for bencode. Guarantees that the output string is valid bencode
//!
//! # Encoding a structure
//!
//! The easiest way to encode a structure is to implement [`ToBencode`] for it. For most structures,
//! this should be very simple:
//!
//! ```
//! # use bendy::encoding::{ToBencode, SingleItemEncoder, Error};
//!
//! struct Message {
//!     foo: i32,
//!     bar: String,
//! }
//!
//! impl ToBencode for Message {
//!     // Atoms have depth one. The struct wrapper adds one level to that
//!     const MAX_DEPTH: usize = 1;
//!
//!     fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
//!         encoder.emit_dict(|mut e| {
//!             // Use e to emit the values
//!             e.emit_pair(b"bar", &self.bar)?;
//!             e.emit_pair(b"foo", &self.foo)
//!         })?;
//!         Ok(())
//!     }
//! }
//! #
//! # fn main() -> Result<(), Error> {
//! #    let message = Message{
//! #      foo: 1,
//! #      bar: "quux".to_string(),
//! #    };
//! #
//! #   message.to_bencode().map(|_| ())
//! # }
//! ```
//!
//! Then, messages can be serialized using [`ToBencode::to_bencode`]:
//!
//! ```
//! # use bendy::encoding::{ToBencode, SingleItemEncoder, Error};
//! #
//! # struct Message {
//! #    foo: i32,
//! #    bar: String,
//! # }
//! #
//! # impl ToBencode for Message {
//! #     // Atoms have depth zero. The struct wrapper adds one level to that
//! #     const MAX_DEPTH: usize = 1;
//! #
//! #     fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
//! #         encoder.emit_dict(|mut e| {
//! #             // Use e to emit the values. They must be in sorted order here.
//! #             // If sorting the dict first is annoying, you can also use
//! #             // encoder.emit_and_sort_dict
//! #             e.emit_pair(b"bar", &self.bar)?;
//! #             e.emit_pair(b"foo", &self.foo)
//! #         })?;
//! #         Ok(())
//! #     }
//! # }
//! #
//! # fn main() -> Result<(), Error> {
//! let message = Message {
//!     foo: 1,
//!     bar: "quux".to_string(),
//! };
//!
//! message.to_bencode()
//! #    .map(|_| ())
//! # }
//! ```
//!
//! Most primitive types already implement [`ToBencode`].
//!
//! # Nesting depth limits
//!
//! To allow this to be used on limited platforms, all implementations of [`ToBencode`] include a
//! maximum nesting depth. Atoms (integers and byte strings) are considered to have depth 0. An
//! object (a list or dict) containing only atoms has depth 1, and in general, an object has a depth
//! equal to the depth of its deepest member plus one. In some cases, an object doesn't have a
//! statically known depth. For example, ASTs may be arbitrarily nested. Such objects should
//! have their depth set to 0, and callers should construct the Encoder manually, adding an
//! appropriate buffer for the depth:
//!
//! ```
//! # use bendy::encoding::{ToBencode, Encoder, Error};
//! #
//! # type ObjectType = u32;
//! # static OBJECT: u32 = 0;
//! #
//! # fn main() -> Result<(), Error> {
//! let mut encoder = Encoder::new().with_max_depth(ObjectType::MAX_DEPTH + 10);
//!
//! encoder.emit(OBJECT)?;
//! encoder.get_output()
//! #     .map_err(Error::from)
//! #     .map(|_| ()) // ignore a success return value
//! # }
//! ```
//!
//! # Error handling
//!
//! Once an error occurs during encoding, all future calls to the same encoding stream will fail
//! early with the same error. It is not defined whether any callback or implementation of
//! [`ToBencode::encode`] is called before returning an error; such callbacks should
//! respond to failure by bailing out as quickly as possible.
//!
//! Not all values in [`Error`] can be caused by an encoding operation. Specifically, you only need
//! to worry about [`UnsortedKeys`] and [`NestingTooDeep`].
//!
//! [`ToBencode::encode`]: self::ToBencode::encode
//! [`UnsortedKeys`]: self::Error#UnsortedKeys
//! [`NestingTooDeep`]: self::Error#NestingTooDeep

mod encoder;
mod error;
mod printable_integer;
mod to_bencode;

pub use self::{
    encoder::{Encoder, SingleItemEncoder, SortedDictEncoder, UnsortedDictEncoder},
    error::{Error, ErrorKind},
    printable_integer::PrintableInteger,
    to_bencode::{AsString, ToBencode},
};