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}