use bilrost::{Message, OwnedMessage};
use std::collections::BTreeMap;
struct CustomEncoding;
struct Tag;
bilrost::encoding_implemented_via_value_encoding!(CustomEncoding);
bilrost::encoding_uses_base_empty_state!(CustomEncoding);
mod crate_defined_structs {
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct AlwaysOdd(u64);
impl AlwaysOdd {
pub fn new(value: u64) -> Result<Self, &'static str> {
if value % 2 == 1 {
Ok(Self(value))
} else {
Err("value is not odd")
}
}
pub fn value(&self) -> u64 {
self.0
}
}
impl TryFrom<u64> for AlwaysOdd {
type Error = &'static str;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::new(value)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct AlwaysEven(u64);
impl AlwaysEven {
pub fn new(value: u64) -> Result<Self, &'static str> {
if value % 2 == 0 {
Ok(Self(value))
} else {
Err("value is not even")
}
}
pub fn value(&self) -> u64 {
self.0
}
}
impl TryFrom<u64> for AlwaysEven {
type Error = &'static str;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::new(value)
}
}
}
mod implement_encoding_for_those_structs {
use crate::crate_defined_structs::{AlwaysEven, AlwaysOdd};
use crate::Tag;
use bilrost::encoding::{DistinguishedProxiable, EmptyState, ForOverwrite, Proxiable};
use bilrost::Canonicity::Canonical;
use bilrost::{Canonicity, DecodeErrorKind};
impl Proxiable for AlwaysEven {
type Proxy = u64;
fn encode_proxy(&self) -> Self::Proxy {
self.value()
}
fn decode_proxy(&mut self, proxy: Self::Proxy) -> Result<(), DecodeErrorKind> {
*self = Self::new(proxy).map_err(|_| DecodeErrorKind::InvalidValue)?;
Ok(())
}
}
impl DistinguishedProxiable for AlwaysEven {
fn decode_proxy_distinguished(
&mut self,
proxy: Self::Proxy,
) -> Result<Canonicity, DecodeErrorKind> {
self.decode_proxy(proxy)?;
Ok(Canonical)
}
}
impl Proxiable<Tag> for AlwaysOdd {
type Proxy = u64;
fn encode_proxy(&self) -> Self::Proxy {
self.value()
}
fn decode_proxy(&mut self, proxy: Self::Proxy) -> Result<(), DecodeErrorKind> {
*self = Self::new(proxy).map_err(|_| DecodeErrorKind::InvalidValue)?;
Ok(())
}
}
impl DistinguishedProxiable<Tag> for AlwaysOdd {
fn decode_proxy_distinguished(
&mut self,
proxy: Self::Proxy,
) -> Result<Canonicity, DecodeErrorKind> {
self.decode_proxy(proxy)?;
Ok(Canonical)
}
}
impl ForOverwrite<(), AlwaysEven> for () {
fn for_overwrite() -> AlwaysEven {
AlwaysEven::new(0).unwrap()
}
}
impl EmptyState<(), AlwaysEven> for () {
fn is_empty(val: &AlwaysEven) -> bool {
val.value() == 0
}
fn clear(val: &mut AlwaysEven) {
*val = AlwaysEven::new(0).unwrap();
}
}
impl ForOverwrite<(), AlwaysOdd> for () {
fn for_overwrite() -> AlwaysOdd {
AlwaysOdd::new(1).unwrap()
}
}
bilrost::delegate_proxied_encoding!(
use encoding (bilrost::encoding::Varint)
to encode proxied type (AlwaysEven)
with general encodings including distinguished
);
bilrost::delegate_proxied_encoding!(
use encoding (bilrost::encoding::Varint)
to encode proxied type (AlwaysOdd) using proxy tag (Tag)
with general encodings including distinguished
);
bilrost::delegate_proxied_encoding!(
use encoding(bilrost::encoding::Fixed)
to encode proxied type (AlwaysEven)
with encoding (super::CustomEncoding) including distinguished
);
bilrost::delegate_proxied_encoding!(
use encoding(bilrost::encoding::Fixed)
to encode proxied type (AlwaysOdd) using proxy tag (Tag)
with encoding (super::CustomEncoding) including distinguished
);
}
fn main() {
use crate_defined_structs::{AlwaysEven, AlwaysOdd};
#[derive(Debug, PartialEq, Message)]
struct MessageWithCustomTypes {
plain: AlwaysEven,
repeated: Vec<AlwaysEven>,
values: BTreeMap<String, AlwaysEven>,
must_be_wrapped: Option<AlwaysOdd>,
#[bilrost(encoding(CustomEncoding))]
encoded_customly: Option<AlwaysOdd>,
}
#[derive(Message)]
struct EncodesSingle<T>(T);
#[derive(Message)]
struct EncodesPacked<T>(#[bilrost(encoding(packed))] T);
static_assertions::assert_not_impl_any!(EncodesSingle<AlwaysOdd>: Message);
static_assertions::assert_not_impl_any!(EncodesPacked<[AlwaysOdd; 5]>: Message);
static_assertions::assert_impl_all!(EncodesSingle<Option<AlwaysOdd>>: Message);
static_assertions::assert_impl_all!(EncodesPacked<Option<[AlwaysOdd; 5]>>: Message);
static_assertions::assert_impl_all!(EncodesSingle<Vec<AlwaysOdd>>: Message);
static_assertions::assert_impl_all!(EncodesSingle<BTreeMap<String, AlwaysOdd>>: Message);
let msg = MessageWithCustomTypes {
plain: 2.try_into().unwrap(),
repeated: [10, 12, 16, 22]
.into_iter()
.map(|i| i.try_into().unwrap())
.collect(),
values: BTreeMap::from_iter([
("hundred".to_owned(), 100.try_into().unwrap()),
("thousand".to_owned(), 1000.try_into().unwrap()),
("six".to_owned(), 6.try_into().unwrap()),
]),
must_be_wrapped: None,
encoded_customly: Some(13.try_into().unwrap()),
};
let encoded = msg.encode_to_vec();
println!("encoded bytes: {encoded:02x?}");
let round_tripped = MessageWithCustomTypes::decode(encoded.as_slice());
println!("decoded: {round_tripped:#?}");
assert_eq!(round_tripped.as_ref(), Ok(&msg));
use bilrost::encoding::opaque::{OpaqueMessage, OpaqueValue};
let message_with_invalid_data =
OpaqueMessage::from_iter([(1, OpaqueValue::u64(1))]).encode_to_vec();
let decode_error = MessageWithCustomTypes::decode(message_with_invalid_data.as_slice())
.expect_err("invalid message should not decode without error");
assert_eq!(decode_error.kind(), bilrost::DecodeErrorKind::InvalidValue);
println!("got the expected invalid value error -- {decode_error}");
}