irontide_bencode/lib.rs
1#![warn(missing_docs)]
2//! Serde-based bencode codec for BitTorrent.
3//!
4//! Bencode is the serialization format used throughout BitTorrent for .torrent
5//! files, tracker responses, and DHT messages. It has four types:
6//!
7//! - **Integers**: `i42e`, `i-1e`, `i0e`
8//! - **Byte strings**: `4:spam` (length-prefixed)
9//! - **Lists**: `l<values>e`
10//! - **Dictionaries**: `d<key><value>...e` (keys are byte strings, sorted)
11//!
12//! # Usage
13//!
14//! ```
15//! use serde::{Serialize, Deserialize};
16//! use irontide_bencode::{to_bytes, from_bytes};
17//!
18//! #[derive(Serialize, Deserialize, PartialEq, Debug)]
19//! struct Torrent {
20//! announce: String,
21//! #[serde(rename = "piece length")]
22//! piece_length: i64,
23//! }
24//!
25//! let torrent = Torrent {
26//! announce: "http://tracker.example.com/announce".into(),
27//! piece_length: 262144,
28//! };
29//!
30//! let encoded = to_bytes(&torrent).unwrap();
31//! let decoded: Torrent = from_bytes(&encoded).unwrap();
32//! assert_eq!(torrent, decoded);
33//! ```
34
35mod de;
36mod error;
37mod ser;
38mod span;
39mod value;
40
41pub use de::Deserializer;
42pub use error::{Error, Result};
43pub use ser::Serializer;
44pub use span::find_dict_key_span;
45pub use value::BencodeValue;
46
47/// Serialize a value to bencode bytes.
48pub fn to_bytes<T: serde::Serialize + ?Sized>(value: &T) -> Result<Vec<u8>> {
49 let mut buf = Vec::new();
50 let mut serializer = Serializer::new(&mut buf);
51 serde::Serialize::serialize(value, &mut serializer)?;
52 Ok(buf)
53}
54
55/// Deserialize a value from bencode bytes.
56///
57/// Enforces BEP 3 dictionary key ordering. Use [`from_bytes_lenient`] for
58/// peer wire messages where real-world clients may send unsorted keys.
59pub fn from_bytes<'de, T: serde::Deserialize<'de>>(bytes: &'de [u8]) -> Result<T> {
60 let mut deserializer = Deserializer::new(bytes);
61 let value = serde::Deserialize::deserialize(&mut deserializer)?;
62 deserializer.finish()?;
63 Ok(value)
64}
65
66/// Deserialize a value from bencode bytes, accepting unsorted dictionary keys.
67///
68/// Many real-world BitTorrent clients send extension handshakes and other
69/// messages with unsorted dictionary keys. This function accepts such input
70/// while still correctly parsing all bencode types.
71pub fn from_bytes_lenient<'de, T: serde::Deserialize<'de>>(bytes: &'de [u8]) -> Result<T> {
72 let mut deserializer = Deserializer::lenient(bytes);
73 let value = serde::Deserialize::deserialize(&mut deserializer)?;
74 deserializer.finish()?;
75 Ok(value)
76}