tenderdash_proto/
lib.rs

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