binary_tuples/
lib.rs

1extern crate byteorder;
2extern crate uuid;
3
4pub mod segment;
5mod constants;
6mod utils;
7mod errors;
8
9use uuid::Uuid;
10use segment::Segment;
11use errors::TupleError;
12
13#[derive(Clone)]
14/// A builder for serialized tuples
15pub struct Tuple {
16    buffer: Vec<u8>
17}
18
19impl Tuple {
20    /// Create a new tuple
21    pub fn new() -> Tuple {
22        Tuple {
23            buffer: Vec::with_capacity(128)
24        }
25    }
26
27    /// Create a new tuple with a fixed backing capacity
28    pub fn with_capacity(capacity: usize) -> Tuple {
29        Tuple {
30            buffer: Vec::with_capacity(capacity)
31        }
32    }
33
34    /// Create a new tuple from an existing byte array
35    ///
36    /// This can be used with `as_segments` to parse an existing tuple into a list of segments
37    ///
38    /// Examples
39    /// ```
40    /// use binary_tuples::{Tuple, segment::Segment};
41    ///
42    /// let binary = vec![2, 117, 115, 101, 114, 115, 0, 21, 1];
43    ///
44    /// let tuple = Tuple::from_bytes(&binary)
45    ///     .as_segments()
46    ///     .unwrap();
47    ///
48    /// assert_eq!(tuple, vec![Segment::String(String::from("users")), Segment::Integer(1)]);
49    /// ```
50    pub fn from_bytes(bytes: &[u8]) -> Tuple {
51        Tuple {
52            buffer: Vec::from(bytes)
53        }
54    }
55
56    /// Add an individual segment to this tuple.
57    ///
58    /// ## Notes
59    /// It is recommended to import AddToTuple as it greatly simplifies this API
60    pub fn add_segment(&mut self, input: &Segment) {
61        input.encode(&mut self.buffer);
62    }
63
64    /// Directly embed the contents of another tuple builder in this builder
65    ///
66    /// ## Notes
67    /// This is more efficient than adding a segment slice as the backing buffer can be memcopied.
68    pub fn add_builder(&mut self, input: &Tuple) {
69        self.buffer.extend_from_slice(&input.buffer);
70    }
71
72    /// Return a serialized tuple
73    pub fn into_bytes(self) -> Vec<u8> {
74        self.buffer
75    }
76
77    /// Return a serialized tuple
78    pub fn as_bytes(&self) -> &[u8] {
79        &self.buffer
80    }
81
82    /// Deserialize the segments which make up this tuple
83    pub fn as_segments(&self) -> Result<Vec<Segment>, TupleError> {
84        Segment::decode(&self.buffer)
85    }
86}
87
88/// An extension trait to simplify working with segments
89pub trait AddToTuple<T> where Self : Sized {
90
91    /// Add a new segment to a tuple
92    fn add(&mut self, input: T);
93
94    /// A fluent interface for adding a new segment to a tuple
95    ///
96    /// Examples
97    /// ```
98    /// use binary_tuples::*;
99    ///
100    /// let user_1 = 1;
101    ///
102    /// let tuple = Tuple::new()
103    ///     .with("users")
104    ///     .with(user_1)
105    ///     .into_bytes();
106    ///
107    /// assert_eq!(tuple, vec![2, 117, 115, 101, 114, 115, 0, 21, 1]);
108    /// ```
109    fn with(mut self, input: T) -> Self {
110        self.add(input);
111
112        self
113    }
114}
115
116impl AddToTuple<i64> for Tuple {
117    fn add(&mut self, v: i64) {
118        self.add_segment(&Segment::Integer(v));
119    }
120}
121
122impl AddToTuple<String> for Tuple {
123    fn add(&mut self, v: String) {
124        self.add_segment(&Segment::String(v));
125    }
126}
127
128impl<'a> AddToTuple<&'a [u8]> for Tuple {
129    fn add(&mut self, v: &'a [u8]) {
130        self.add_segment(&Segment::Bytes(Vec::from(v)));
131    }
132}
133
134impl<'a> AddToTuple<&'a Vec<u8>> for Tuple {
135    fn add(&mut self, v: &'a Vec<u8>) {
136        self.add_segment(&Segment::Bytes(v.clone()));
137    }
138}
139
140impl AddToTuple<f32> for Tuple {
141    fn add(&mut self, v: f32) {
142        self.add_segment(&Segment::Float(v));
143    }
144}
145
146impl AddToTuple<f64> for Tuple {
147    fn add(&mut self, v: f64) {
148        self.add_segment(&Segment::Double(v));
149    }
150}
151
152impl AddToTuple<Vec<u8>> for Tuple {
153    fn add(&mut self, v: Vec<u8>) {
154        self.add_segment(&Segment::Bytes(v));
155    }
156}
157
158impl AddToTuple<&'static str> for Tuple {
159    fn add(&mut self, v: &'static str) {
160        self.add_segment(&Segment::Const(v));
161    }
162}
163
164impl AddToTuple<Uuid> for Tuple {
165    fn add(&mut self, v: Uuid) {
166        self.add_segment(&Segment::UUID(v));
167    }
168}
169
170impl AddToTuple<Vec<Segment>> for Tuple {
171    fn add(&mut self, v: Vec<Segment>) {
172        self.add_segment(&Segment::Nested(v));
173    }
174}
175
176impl<'a> AddToTuple<&'a Tuple> for Tuple {
177    fn add(&mut self, v: &'a Tuple) {
178        self.add_builder(&v);
179    }
180}
181
182impl AddToTuple<Tuple> for Tuple {
183    fn add(&mut self, v: Tuple) {
184        self.add_builder(&v);
185    }
186}
187
188#[macro_export]
189/// A macro for creating a serialized tuple
190///
191/// Supports all types of segments as plain values - these are wrapped in TupleSegments before
192/// being serialized.
193/// The easiest way to create tuples is using the exposed `tuple!` macro:
194///
195///```
196/// #[macro_use] extern crate binary_tuples;
197/// let user_id = 1;
198/// let value = tuple!("users", user_id, "posts");
199///
200/// // Returns as a byte array
201/// let bytes = value.into_bytes();
202///```
203///
204/// Tuples can reused as efficient prefixes for other tuples
205/// ```
206/// #[macro_use] extern crate binary_tuples;
207///
208/// let user_id = 1;
209/// let post_id_1 = 1;
210/// let post_id_2 = 2;
211/// let users_tuple = tuple!("users", user_id, "posts");
212///
213/// let post_1 = tuple!(&users_tuple, post_id_1);
214/// let post_2 = tuple!(&users_tuple, post_id_2);
215///
216/// assert_eq!(post_1.into_bytes(), vec![2, 117, 115, 101, 114, 115, 0, 21, 1, 2, 112, 111, 115, 116, 115, 0, 21, 1]);
217/// assert_eq!(post_2.into_bytes(), vec![2, 117, 115, 101, 114, 115, 0, 21, 1, 2, 112, 111, 115, 116, 115, 0, 21, 2]);
218/// ```
219macro_rules! tuple {
220    ($( $x:expr ),*) => {
221        {
222            use $crate::{Tuple, AddToTuple};
223
224            let mut builder = Tuple::new();
225            $(
226                builder.add($x);
227            )*
228            builder
229        }
230    };
231}
232
233#[cfg(test)]
234mod tests {
235    #[test]
236    fn test_tuple_macro() {
237        let result = tuple!("Test").into_bytes();
238
239        assert_eq!(result, vec![2, 84, 101, 115, 116, 0]);
240    }
241
242    #[test]
243    fn test_tuple_macro_prefix() {
244        let base_tuple = tuple!("user");
245        let result = tuple!(&base_tuple, "Test");
246
247        assert_eq!(result.into_bytes(), vec![2, 117, 115, 101, 114, 0, 2, 84, 101, 115, 116, 0]);
248    }
249
250    #[test]
251    fn test_vec_support() {
252        let tuple = tuple!(vec![1, 2, 3]);
253
254        assert_eq!(tuple.into_bytes(), vec![1, 1, 2, 3, 0]);
255    }
256
257    #[test]
258    fn test_u8_support() {
259        let binary: Vec<u8> = vec![1, 2, 3];
260        let tuple = tuple!(&binary);
261
262        assert_eq!(tuple.into_bytes(), vec![1, 1, 2, 3, 0]);
263    }
264}