celestia_tendermint_proto/
lib.rs

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