exonum_merkledb/
values.rs

1// Copyright 2020 The Exonum Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A definition of `BinaryValue` trait and implementations for common types.
16
17use std::{borrow::Cow, io::Read};
18
19use anyhow::{self, ensure, format_err};
20use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
21use chrono::{DateTime, NaiveDateTime, Utc};
22use rust_decimal::Decimal;
23use uuid::Uuid;
24
25use exonum_crypto::{Hash, PublicKey, HASH_SIZE};
26
27use super::ObjectHash;
28
29/// A type that can be (de)serialized as a value in the blockchain storage.
30///
31/// If you need to implement `BinaryValue` for your types, use little-endian encoding
32/// for integer types for compatibility with modern architectures.
33///
34/// # Examples
35///
36/// Implementing `BinaryValue` for the type:
37///
38/// ```
39/// use std::{borrow::Cow, io::{Read, Write}};
40/// use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};
41/// use exonum_merkledb::BinaryValue;
42///
43/// #[derive(Clone)]
44/// struct Data {
45///     a: i16,
46///     b: u32,
47/// }
48///
49/// impl BinaryValue for Data {
50///     fn to_bytes(&self) -> Vec<u8> {
51///         let mut buf = vec![0_u8; 6];
52///         LittleEndian::write_i16(&mut buf[0..2], self.a);
53///         LittleEndian::write_u32(&mut buf[2..6], self.b);
54///         buf
55///     }
56///
57///     fn from_bytes(bytes: Cow<[u8]>) -> anyhow::Result<Self> {
58///         let mut buf = bytes.as_ref();
59///         let a = buf.read_i16::<LittleEndian>()?;
60///         let b = buf.read_u32::<LittleEndian>()?;
61///         Ok(Self { a, b })
62///     }
63/// }
64/// ```
65pub trait BinaryValue: Sized {
66    /// Serializes the given value to the vector of bytes.
67    fn to_bytes(&self) -> Vec<u8>;
68
69    /// Consumes and serializes the given value to the vector of bytes.
70    /// This method is faster with the wrapped values,
71    /// thus if you wouldn't use value after serialization use it.
72    fn into_bytes(self) -> Vec<u8> {
73        self.to_bytes()
74    }
75
76    /// Deserializes the value from the given bytes array.
77    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self>;
78}
79
80impl_object_hash_for_binary_value! { (), bool, Vec<u8>, String, PublicKey, DateTime<Utc>, Uuid, Decimal }
81
82macro_rules! impl_binary_value_scalar {
83    ($type:tt, $read:ident) => {
84        #[allow(clippy::use_self)]
85        impl BinaryValue for $type {
86            fn to_bytes(&self) -> Vec<u8> {
87                vec![*self as u8]
88            }
89
90            fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
91                use byteorder::ReadBytesExt;
92                bytes.as_ref().$read().map_err(From::from)
93            }
94        }
95
96        impl_object_hash_for_binary_value! { $type }
97    };
98    ($type:tt, $write:ident, $read:ident, $len:expr) => {
99        #[allow(clippy::use_self)]
100        impl BinaryValue for $type {
101            fn to_bytes(&self) -> Vec<u8> {
102                let mut v = vec![0; $len];
103                LittleEndian::$write(&mut v, *self);
104                v
105            }
106
107            fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
108                use byteorder::ReadBytesExt;
109                bytes.as_ref().$read::<LittleEndian>().map_err(From::from)
110            }
111        }
112
113        impl_object_hash_for_binary_value! { $type }
114    };
115}
116
117// Unsigned scalar types
118impl_binary_value_scalar! { u8,  read_u8 }
119impl_binary_value_scalar! { u16, write_u16, read_u16, 2 }
120impl_binary_value_scalar! { u32, write_u32, read_u32, 4 }
121impl_binary_value_scalar! { u64, write_u64, read_u64, 8 }
122impl_binary_value_scalar! { u128, write_u128, read_u128, 16 }
123// Signed scalar types
124impl_binary_value_scalar! { i8,  read_i8 }
125impl_binary_value_scalar! { i16, write_i16, read_i16, 2 }
126impl_binary_value_scalar! { i32, write_i32, read_i32, 4 }
127impl_binary_value_scalar! { i64, write_i64, read_i64, 8 }
128impl_binary_value_scalar! { i128, write_i128, read_i128, 16 }
129
130/// No-op implementation.
131impl BinaryValue for () {
132    fn to_bytes(&self) -> Vec<u8> {
133        Vec::default()
134    }
135
136    fn from_bytes(_bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
137        Ok(())
138    }
139}
140
141#[allow(clippy::use_self)] // false positives
142impl BinaryValue for bool {
143    fn to_bytes(&self) -> Vec<u8> {
144        vec![*self as u8]
145    }
146
147    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
148        let value = bytes.as_ref();
149        assert_eq!(value.len(), 1);
150
151        match value[0] {
152            0 => Ok(false),
153            1 => Ok(true),
154            value => Err(format_err!("Invalid value for bool: {}", value)),
155        }
156    }
157}
158
159impl BinaryValue for Vec<u8> {
160    fn to_bytes(&self) -> Vec<u8> {
161        self.clone()
162    }
163
164    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
165        Ok(bytes.into_owned())
166    }
167}
168
169impl BinaryValue for String {
170    fn to_bytes(&self) -> Vec<u8> {
171        self.as_bytes().to_owned()
172    }
173
174    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
175        Self::from_utf8(bytes.into_owned()).map_err(From::from)
176    }
177}
178
179impl BinaryValue for Hash {
180    fn to_bytes(&self) -> Vec<u8> {
181        self.as_ref().to_vec()
182    }
183
184    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
185        Self::from_slice(bytes.as_ref()).ok_or_else(|| {
186            format_err!("Unable to decode Hash from bytes: buffer size does not match")
187        })
188    }
189}
190
191impl BinaryValue for PublicKey {
192    fn to_bytes(&self) -> Vec<u8> {
193        self.as_ref().to_vec()
194    }
195
196    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
197        Self::from_slice(bytes.as_ref()).ok_or_else(|| {
198            format_err!("Unable to decode PublicKey from bytes: buffer size does not match")
199        })
200    }
201}
202
203// FIXME Maybe we should remove this implementations. [ECR-2775]
204
205impl BinaryValue for DateTime<Utc> {
206    fn to_bytes(&self) -> Vec<u8> {
207        let secs = self.timestamp();
208        let nanos = self.timestamp_subsec_nanos();
209
210        let mut buffer = vec![0; 12];
211        LittleEndian::write_i64(&mut buffer[0..8], secs);
212        LittleEndian::write_u32(&mut buffer[8..12], nanos);
213        buffer
214    }
215
216    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
217        let mut value = bytes.as_ref();
218        let secs = value.read_i64::<LittleEndian>()?;
219        let nanos = value.read_u32::<LittleEndian>()?;
220        Ok(Self::from_utc(
221            NaiveDateTime::from_timestamp(secs, nanos),
222            Utc,
223        ))
224    }
225}
226
227impl BinaryValue for Uuid {
228    fn to_bytes(&self) -> Vec<u8> {
229        self.as_bytes().to_vec()
230    }
231
232    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
233        Self::from_slice(bytes.as_ref()).map_err(From::from)
234    }
235}
236
237impl BinaryValue for Decimal {
238    fn to_bytes(&self) -> Vec<u8> {
239        self.serialize().to_vec()
240    }
241
242    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
243        let mut value = bytes.as_ref();
244        let mut buf: [u8; 16] = [0; 16];
245        value.read_exact(&mut buf)?;
246        Ok(Self::deserialize(buf))
247    }
248}
249
250impl BinaryValue for [u8; HASH_SIZE] {
251    fn to_bytes(&self) -> Vec<u8> {
252        self.to_vec()
253    }
254
255    fn from_bytes(bytes: Cow<'_, [u8]>) -> anyhow::Result<Self> {
256        let bytes = bytes.as_ref();
257        ensure!(
258            bytes.len() == HASH_SIZE,
259            "Unable to decode array from bytes: buffer size does not match"
260        );
261        let mut value = [0_u8; HASH_SIZE];
262        value.copy_from_slice(bytes);
263        Ok(value)
264    }
265}
266
267#[cfg(test)]
268mod tests {
269    use std::fmt::Debug;
270    use std::str::FromStr;
271
272    use chrono::Duration;
273
274    use super::*;
275
276    fn assert_round_trip_eq<T: BinaryValue + PartialEq + Debug>(values: &[T]) {
277        for value in values {
278            let bytes = value.to_bytes();
279            assert_eq!(
280                *value,
281                <T as BinaryValue>::from_bytes(bytes.into()).unwrap()
282            );
283        }
284    }
285
286    macro_rules! impl_test_binary_form_scalar_unsigned {
287        ($name:ident, $type:tt) => {
288            #[test]
289            fn $name() {
290                let values = [$type::min_value(), 1, $type::max_value()];
291                assert_round_trip_eq(&values);
292            }
293        };
294    }
295
296    macro_rules! impl_test_binary_form_scalar_signed {
297        ($name:ident, $type:tt) => {
298            #[test]
299            fn $name() {
300                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
301                assert_round_trip_eq(&values);
302            }
303        };
304    }
305
306    // Impl tests for unsigned scalar types.
307    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
308    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
309    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
310    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }
311    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u128, u128 }
312
313    // Impl tests for signed scalar types.
314    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
315    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
316    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
317    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }
318    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i128, i128 }
319
320    // Tests for the other types.
321
322    #[test]
323    fn test_binary_form_vec_u8() {
324        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
325        assert_round_trip_eq(&values);
326    }
327
328    #[test]
329    fn test_binary_form_bool_correct() {
330        let values = [true, false];
331        assert_round_trip_eq(&values);
332    }
333
334    #[test]
335    #[should_panic(expected = "Invalid value for bool: 2")]
336    fn test_binary_form_bool_incorrect() {
337        let bytes = 2_u8.to_bytes();
338        <bool as BinaryValue>::from_bytes(bytes.into()).unwrap();
339    }
340
341    #[test]
342    fn test_binary_form_string() {
343        let values: Vec<_> = ["", "e", "2", "hello"]
344            .iter()
345            .map(ToString::to_string)
346            .collect();
347        assert_round_trip_eq(&values);
348    }
349
350    #[test]
351    fn test_binary_form_datetime() {
352        use chrono::TimeZone;
353
354        let times = [
355            Utc.timestamp(0, 0),
356            Utc.timestamp(13, 23),
357            Utc::now(),
358            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
359            Utc.timestamp(0, 999_999_999),
360            Utc.timestamp(0, 1_500_000_000), // leap second
361        ];
362        assert_round_trip_eq(&times);
363    }
364
365    #[test]
366    fn test_binary_form_uuid() {
367        let values = [
368            Uuid::nil(),
369            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
370            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
371        ];
372        assert_round_trip_eq(&values);
373    }
374
375    #[test]
376    fn test_binary_form_decimal() {
377        let values = [
378            Decimal::from_str("3.14").unwrap(),
379            Decimal::from_parts(1_102_470_952, 185_874_565, 1_703_060_790, false, 28),
380            Decimal::new(9_497_628_354_687_268, 12),
381            Decimal::from_str("0").unwrap(),
382            Decimal::from_str("-0.000000000000000000019").unwrap(),
383        ];
384        assert_round_trip_eq(&values);
385    }
386
387    #[test]
388    fn test_binary_form_array_hash_size() {
389        let values = [[1; HASH_SIZE]];
390        assert_round_trip_eq(&values);
391    }
392}