1 //! `tor-bytes`: Utilities to decode/encode things into bytes.
2 //!
3 //! # Overview
4 //!
5 //! The `tor-bytes` crate is part of
6 //! [Arti](https://gitlab.torproject.org/tpo/core/arti/), a project to
7 //! implement [Tor](https://www.torproject.org/) in Rust.
8 //! Other crates in Arti use it to build and handle all the byte-encoded
9 //! objects from the Tor protocol.  For textual directory items, see
10 //! the [`tor-netdoc`] crate.
11 //!
12 //! This crate is generally useful for encoding and decoding
13 //! byte-oriented formats that are not regular enough to qualify for
14 //! serde, and not complex enough to need a full meta-language.  It is
15 //! probably not suitable for handling anything bigger than a few
16 //! kilobytes in size.
17 //!
18 //! ## Alternatives
19 //!
20 //! The Reader/Writer traits in std::io are more appropriate for
21 //! operations that can fail because of some IO problem.  This crate
22 //! can't handle that: it is for handling things that are already in
23 //! memory.
24 //!
25 //! TODO: Look into using the "bytes" crate more here.
26 //!
27 //! TODO: The "untrusted" crate has similar goals to our [`Reader`],
28 //! but takes more steps to make sure it can never panic. Perhaps we
29 //! should see if we can learn any tricks from it.
30 //!
31 //! TODO: Do we really want to keep `Reader` as a struct and
32 //! `Writer` as a trait?
33 //!
34 //! # Contents and concepts
35 //!
36 //! This crate is structured around four key types:
37 //!
38 //! * [`Reader`]: A view of a byte slice, from which data can be decoded.
39 //! * [`Writer`]: Trait to represent a growable buffer of bytes.
40 //!   (Vec<u8> and [`bytes::BytesMut`] implement this.)
41 //! * [`Writeable`]: Trait for an object that can be encoded onto a [`Writer`]
42 //! * [`Readable`]: Trait for an object that can be decoded from a [`Reader`].
43 //!
44 //! Every object you want to encode or decode should implement
45 //! [`Writeable`] or [`Readable`] respectively.
46 //!
47 //! Once you implement these traits, you can use Reader and Writer to
48 //! handle your type, and other types that are built around it.
49 
50 #![deny(missing_docs)]
51 #![warn(noop_method_call)]
52 #![deny(unreachable_pub)]
53 #![deny(clippy::await_holding_lock)]
54 #![deny(clippy::cargo_common_metadata)]
55 #![deny(clippy::cast_lossless)]
56 #![deny(clippy::checked_conversions)]
57 #![warn(clippy::clone_on_ref_ptr)]
58 #![warn(clippy::cognitive_complexity)]
59 #![deny(clippy::debug_assert_with_mut_call)]
60 #![deny(clippy::exhaustive_enums)]
61 #![deny(clippy::exhaustive_structs)]
62 #![deny(clippy::expl_impl_clone_on_copy)]
63 #![deny(clippy::fallible_impl_from)]
64 #![deny(clippy::implicit_clone)]
65 #![deny(clippy::large_stack_arrays)]
66 #![warn(clippy::manual_ok_or)]
67 #![deny(clippy::missing_docs_in_private_items)]
68 #![deny(clippy::missing_panics_doc)]
69 #![warn(clippy::needless_borrow)]
70 #![warn(clippy::needless_pass_by_value)]
71 #![warn(clippy::option_option)]
72 #![warn(clippy::rc_buffer)]
73 #![deny(clippy::ref_option_ref)]
74 #![warn(clippy::semicolon_if_nothing_returned)]
75 #![warn(clippy::trait_duplication_in_bounds)]
76 #![deny(clippy::unnecessary_wraps)]
77 #![warn(clippy::unseparated_literal_suffix)]
78 #![deny(clippy::unwrap_used)]
79 
80 mod err;
81 mod impls;
82 mod reader;
83 mod writer;
84 
85 pub use err::Error;
86 pub use reader::Reader;
87 pub use writer::Writer;
88 
89 use arrayref::array_ref;
90 
91 /// Result type returned by this crate.
92 pub type Result<T> = std::result::Result<T, Error>;
93 
94 /// Trait for an object that can be encoded onto a Writer by reference.
95 ///
96 /// Implement this trait in order to make an object writeable.
97 ///
98 /// Most code won't need to call this directly, but will instead use
99 /// it implicitly via the Writer::write() method.
100 ///
101 /// # Example
102 ///
103 /// ```
104 /// use tor_bytes::{Writeable, Writer};
105 /// #[derive(Debug, Eq, PartialEq)]
106 /// struct Message {
107 ///   flags: u32,
108 ///   cmd: u8
109 /// }
110 ///
111 /// impl Writeable for Message {
112 ///     fn write_onto<B:Writer+?Sized>(&self, b: &mut B) {
113 ///         // We'll say that a "Message" is encoded as flags, then command.
114 ///         b.write_u32(self.flags);
115 ///         b.write_u8(self.cmd);
116 ///     }
117 /// }
118 ///
119 /// let msg = Message { flags: 0x43, cmd: 0x07 };
120 /// let mut writer: Vec<u8> = Vec::new();
121 /// writer.write(&msg);
122 /// assert_eq!(writer, &[0x00, 0x00, 0x00, 0x43, 0x07 ]);
123 /// ```
124 pub trait Writeable {
125     /// Encode this object into the writer `b`.
write_onto<B: Writer + ?Sized>(&self, b: &mut B)126     fn write_onto<B: Writer + ?Sized>(&self, b: &mut B);
127 }
128 
129 /// Trait for an object that can be encoded and consumed by a Writer.
130 ///
131 /// Implement this trait in order to make an object that can be
132 /// written more efficiently by absorbing it into the writer.
133 ///
134 /// Most code won't need to call this directly, but will instead use
135 /// it implicitly via the Writer::write_and_consume() method.
136 pub trait WriteableOnce {
137     /// Encode this object into the writer `b`, and consume it.
write_into<B: Writer + ?Sized>(self, b: &mut B)138     fn write_into<B: Writer + ?Sized>(self, b: &mut B);
139 }
140 
141 impl<W: Writeable> WriteableOnce for W {
write_into<B: Writer + ?Sized>(self, b: &mut B)142     fn write_into<B: Writer + ?Sized>(self, b: &mut B) {
143         self.write_onto(b);
144     }
145 }
146 
147 // ----------------------------------------------------------------------
148 
149 /// Trait for an object that can be extracted from a Reader.
150 ///
151 /// Implement this trait in order to make an object that can (maybe)
152 /// be decoded from a reader.
153 //
154 /// Most code won't need to call this directly, but will instead use
155 /// it implicitly via the Reader::extract() method.
156 ///
157 /// # Example
158 ///
159 /// ```
160 /// use tor_bytes::{Readable,Reader,Result};
161 /// #[derive(Debug, Eq, PartialEq)]
162 /// struct Message {
163 ///   flags: u32,
164 ///   cmd: u8
165 /// }
166 ///
167 /// impl Readable for Message {
168 ///     fn take_from(r: &mut Reader<'_>) -> Result<Self> {
169 ///         // A "Message" is encoded as flags, then command.
170 ///         let flags = r.take_u32()?;
171 ///         let cmd = r.take_u8()?;
172 ///         Ok(Message{ flags, cmd })
173 ///     }
174 /// }
175 ///
176 /// let encoded = [0x00, 0x00, 0x00, 0x43, 0x07 ];
177 /// let mut reader = Reader::from_slice(&encoded);
178 /// let m: Message = reader.extract()?;
179 /// assert_eq!(m, Message { flags: 0x43, cmd: 0x07 });
180 /// reader.should_be_exhausted()?; // make sure there are no bytes left over
181 /// # Result::Ok(())
182 /// ```
183 pub trait Readable: Sized {
184     /// Try to extract an object of this type from a Reader.
185     ///
186     /// Implementations should generally try to be efficient: this is
187     /// not the right place to check signatures or perform expensive
188     /// operations.  If you have an object that must not be used until
189     /// it is finally validated, consider making this function return
190     /// a wrapped type that can be unwrapped later on once it gets
191     /// checked.
take_from(b: &mut Reader<'_>) -> Result<Self>192     fn take_from(b: &mut Reader<'_>) -> Result<Self>;
193 }
194 
195 // ----------------------------------------------------------------------
196 
197 #[cfg(test)]
198 mod test {
199     use super::*;
200 
201     #[test]
writer()202     fn writer() {
203         let mut v: Vec<u8> = Vec::new();
204         v.write_u8(0x57);
205         v.write_u16(0x6520);
206         v.write_u32(0x68617665);
207         v.write_u64(0x2061206d61636869);
208         v.write_all(b"ne in a plexiglass dome");
209         v.write_zeros(3);
210         assert_eq!(&v[..], &b"We have a machine in a plexiglass dome\0\0\0"[..]);
211     }
212 }
213