tendermint_proto/
lib.rs

1//! tendermint-proto library gives the developer access to the Tendermint proto-defined structs.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4#![deny(warnings, trivial_casts, trivial_numeric_casts, unused_import_braces)]
5#![allow(clippy::large_enum_variant)]
6#![forbid(unsafe_code)]
7
8extern crate alloc;
9
10mod error;
11mod prelude;
12mod tendermint;
13
14use bytes::{Buf, BufMut};
15use core::fmt::Display;
16use prost::Message;
17
18pub use error::Error;
19pub use tendermint::*;
20
21pub mod serializers;
22
23use prelude::*;
24
25/// Built-in `prost_types` with slight customization to enable JSON-encoding.
26pub mod google;
27
28/// Allows for easy Google Protocol Buffers encoding and decoding of domain
29/// types with validation.
30///
31/// ## Examples
32///
33/// ```rust
34/// use bytes::BufMut;
35/// use prost::Message;
36/// use core::convert::TryFrom;
37/// use tendermint_proto::Protobuf;
38///
39/// // This struct would ordinarily be automatically generated by prost.
40/// #[derive(Clone, PartialEq, Message)]
41/// pub struct MyRawType {
42///     #[prost(uint64, tag="1")]
43///     pub a: u64,
44///     #[prost(string, tag="2")]
45///     pub b: String,
46/// }
47///
48/// #[derive(Clone)]
49/// pub struct MyDomainType {
50///     a: u64,
51///     b: String,
52/// }
53///
54/// impl MyDomainType {
55///     /// Trivial constructor with basic validation logic.
56///     pub fn new(a: u64, b: String) -> Result<Self, String> {
57///         if a < 1 {
58///             return Err("a must be greater than 0".to_owned());
59///         }
60///         Ok(Self { a, b })
61///     }
62/// }
63///
64/// impl TryFrom<MyRawType> for MyDomainType {
65///     type Error = String;
66///
67///     fn try_from(value: MyRawType) -> Result<Self, Self::Error> {
68///         Self::new(value.a, value.b)
69///     }
70/// }
71///
72/// impl From<MyDomainType> for MyRawType {
73///     fn from(value: MyDomainType) -> Self {
74///         Self { a: value.a, b: value.b }
75///     }
76/// }
77///
78/// impl Protobuf<MyRawType> for MyDomainType {}
79///
80///
81/// // Simulate an incoming valid raw message
82/// let valid_raw = MyRawType { a: 1, b: "Hello!".to_owned() };
83/// let mut valid_raw_bytes: Vec<u8> = Vec::new();
84/// valid_raw.encode(&mut valid_raw_bytes).unwrap();
85/// assert!(!valid_raw_bytes.is_empty());
86///
87/// // Try to decode the simulated incoming message
88/// let valid_domain = MyDomainType::decode(valid_raw_bytes.clone().as_ref()).unwrap();
89/// assert_eq!(1, valid_domain.a);
90/// assert_eq!("Hello!".to_owned(), valid_domain.b);
91///
92/// // Encode it to compare the serialized form to what we received
93/// let mut valid_domain_bytes: Vec<u8> = Vec::new();
94/// valid_domain.encode(&mut valid_domain_bytes).unwrap();
95/// assert_eq!(valid_raw_bytes, valid_domain_bytes);
96///
97/// // Simulate an incoming invalid raw message
98/// let invalid_raw = MyRawType { a: 0, b: "Hello!".to_owned() };
99/// let mut invalid_raw_bytes: Vec<u8> = Vec::new();
100/// invalid_raw.encode(&mut invalid_raw_bytes).unwrap();
101///
102/// // We expect a validation error here
103/// assert!(MyDomainType::decode(invalid_raw_bytes.as_ref()).is_err());
104/// ```
105pub trait Protobuf<T: Message + From<Self> + Default>
106where
107    Self: Sized + Clone + TryFrom<T>,
108    <Self as TryFrom<T>>::Error: Display,
109{
110    /// Encode into a buffer in Protobuf format.
111    ///
112    /// Uses [`prost::Message::encode`] after converting into its counterpart
113    /// Protobuf data structure.
114    ///
115    /// [`prost::Message::encode`]: https://docs.rs/prost/*/prost/trait.Message.html#method.encode
116    fn encode<B: BufMut>(self, buf: &mut B) -> Result<(), Error> {
117        T::from(self).encode(buf).map_err(Error::encode_message)
118    }
119
120    /// Encode with a length-delimiter to a buffer in Protobuf format.
121    ///
122    /// An error will be returned if the buffer does not have sufficient capacity.
123    ///
124    /// Uses [`prost::Message::encode_length_delimited`] after converting into
125    /// its counterpart Protobuf data structure.
126    ///
127    /// [`prost::Message::encode_length_delimited`]: https://docs.rs/prost/*/prost/trait.Message.html#method.encode_length_delimited
128    fn encode_length_delimited<B: BufMut>(self, buf: &mut B) -> Result<(), Error> {
129        T::from(self)
130            .encode_length_delimited(buf)
131            .map_err(Error::encode_message)
132    }
133
134    /// Constructor that attempts to decode an instance from a buffer.
135    ///
136    /// The entire buffer will be consumed.
137    ///
138    /// Similar to [`prost::Message::decode`] but with additional validation
139    /// prior to constructing the destination type.
140    ///
141    /// [`prost::Message::decode`]: https://docs.rs/prost/*/prost/trait.Message.html#method.decode
142    fn decode<B: Buf>(buf: B) -> Result<Self, Error> {
143        let raw = T::decode(buf).map_err(Error::decode_message)?;
144
145        Self::try_from(raw).map_err(Error::try_from::<T, Self, _>)
146    }
147
148    /// Constructor that attempts to decode a length-delimited instance from
149    /// the buffer.
150    ///
151    /// The entire buffer will be consumed.
152    ///
153    /// Similar to [`prost::Message::decode_length_delimited`] but with
154    /// additional validation prior to constructing the destination type.
155    ///
156    /// [`prost::Message::decode_length_delimited`]: https://docs.rs/prost/*/prost/trait.Message.html#method.decode_length_delimited
157    fn decode_length_delimited<B: Buf>(buf: B) -> Result<Self, Error> {
158        let raw = T::decode_length_delimited(buf).map_err(Error::decode_message)?;
159
160        Self::try_from(raw).map_err(Error::try_from::<T, Self, _>)
161    }
162
163    /// Returns the encoded length of the message without a length delimiter.
164    ///
165    /// Uses [`prost::Message::encoded_len`] after converting to its
166    /// counterpart Protobuf data structure.
167    ///
168    /// [`prost::Message::encoded_len`]: https://docs.rs/prost/*/prost/trait.Message.html#method.encoded_len
169    fn encoded_len(self) -> usize {
170        T::from(self).encoded_len()
171    }
172
173    /// Encodes into a Protobuf-encoded `Vec<u8>`.
174    fn encode_vec(self) -> Vec<u8> {
175        T::from(self).encode_to_vec()
176    }
177
178    /// Constructor that attempts to decode a Protobuf-encoded instance from a
179    /// `Vec<u8>` (or equivalent).
180    fn decode_vec(v: &[u8]) -> Result<Self, Error> {
181        Self::decode(v)
182    }
183
184    /// Encode with a length-delimiter to a `Vec<u8>` Protobuf-encoded message.
185    fn encode_length_delimited_vec(self) -> Vec<u8> {
186        T::from(self).encode_length_delimited_to_vec()
187    }
188
189    /// Constructor that attempts to decode a Protobuf-encoded instance with a
190    /// length-delimiter from a `Vec<u8>` or equivalent.
191    fn decode_length_delimited_vec(v: &[u8]) -> Result<Self, Error> {
192        Self::decode_length_delimited(v)
193    }
194}