iq_cometbft_proto/
lib.rs

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