Created
May 12, 2025 10:12
-
-
Save muhamadazmy/e5973a1cd6d9849e3c9a168e00a2ec5d to your computer and use it in GitHub Desktop.
Implement a custom encoder for a foreign type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ops::RangeInclusive; | |
use bilrost::{ | |
buf::ReverseBuf, | |
encoding::{ | |
Capped, DecodeContext, Decoder, EmptyState, Encoder, ForOverwrite, General, TagMeasurer, | |
TagRevWriter, TagWriter, WireType, Wiretyped, | |
}, | |
DecodeError, Message, OwnedMessage, | |
}; | |
use bytes::Bytes; | |
#[derive(bilrost::Message)] | |
struct MyMessage { | |
#[bilrost(encoding(Range))] | |
range: RangeInclusive<u64>, | |
} | |
struct Range; | |
impl<T> Encoder<Range> for RangeInclusive<T> | |
where | |
T: Copy + Default, | |
(T, T): Encoder<General>, | |
{ | |
fn encode<B: bytes::BufMut + ?Sized>(tag: u32, value: &Self, buf: &mut B, tw: &mut TagWriter) { | |
let v = (*value.start(), *value.end()); | |
<(T, T) as Encoder<General>>::encode(tag, &v, buf, tw) | |
} | |
fn prepend_encode<B: ReverseBuf + ?Sized>( | |
tag: u32, | |
value: &Self, | |
buf: &mut B, | |
tw: &mut TagRevWriter, | |
) { | |
let v = (*value.start(), *value.end()); | |
<(T, T) as Encoder<General>>::prepend_encode(tag, &v, buf, tw) | |
} | |
fn encoded_len(tag: u32, value: &Self, tm: &mut impl TagMeasurer) -> usize { | |
let v = (*value.start(), *value.end()); | |
<(T, T) as Encoder<General>>::encoded_len(tag, &v, tm) | |
} | |
} | |
impl<T> Decoder<Range> for RangeInclusive<T> | |
where | |
T: Default + Copy, | |
(T, T): Decoder<General>, | |
{ | |
fn decode<B: bytes::Buf + ?Sized>( | |
wire_type: WireType, | |
value: &mut Self, | |
buf: Capped<B>, | |
ctx: DecodeContext, | |
) -> Result<(), DecodeError> { | |
let mut v = (T::default(), T::default()); | |
<(T, T) as Decoder<General>>::decode(wire_type, &mut v, buf, ctx)?; | |
*value = Self::new(v.0, v.1); | |
Ok(()) | |
} | |
} | |
impl<T> Wiretyped<Range> for RangeInclusive<T> | |
where | |
(T, T): Wiretyped<General>, | |
{ | |
const WIRE_TYPE: WireType = <(T, T) as Wiretyped<General>>::WIRE_TYPE; | |
} | |
impl<T> EmptyState<Range> for RangeInclusive<T> | |
where | |
T: Default + Copy + PartialEq, | |
{ | |
fn clear(&mut self) { | |
*self = Self::new(T::default(), T::default()); | |
} | |
fn is_empty(&self) -> bool { | |
self.start() == self.end() | |
} | |
fn empty() -> Self | |
where | |
Self: Sized, | |
{ | |
Self::new(T::default(), T::default()) | |
} | |
} | |
impl<T> ForOverwrite<Range> for RangeInclusive<T> | |
where | |
T: Default, | |
{ | |
fn for_overwrite() -> Self | |
where | |
Self: Sized, | |
{ | |
Self::new(T::default(), T::default()) | |
} | |
} | |
fn main() { | |
let m = MyMessage { range: 1..=10 }; | |
let v = m.encode_to_vec(); | |
let m2 = <MyMessage as OwnedMessage>::decode(Bytes::from(v)).unwrap(); | |
assert_eq!(m.range, m2.range); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment