use bytes::Buf;
use proto_rs::ProtoDecode;
use proto_rs::ProtoDecoder;
use proto_rs::ProtoDefault;
use proto_rs::ProtoEncode;
use proto_rs::RevWriter;
use proto_rs::encoding::DecodeContext;
use proto_rs::encoding::WireType;
use proto_rs::proto_message;
#[proto_message(transparent)]
#[derive(Debug, PartialEq, Eq)]
pub struct UserIdTuple(u64);
#[proto_message(transparent)]
#[derive(Debug, PartialEq, Eq)]
pub struct UserIdNamed {
pub id: u64,
}
#[proto_message]
#[derive(Debug, PartialEq, Eq)]
pub struct UserWithId {
#[proto(rename = "optional uint32")]
pub id1: UserIdNamed,
#[proto(rename = "uint64")]
pub id2: UserIdNamed,
#[proto(rename = u8)]
pub id3: UserIdNamed,
#[proto(rename = Vec<u8>)]
pub id4: UserIdNamed,
}
pub type ComplexType = proto_rs::alloc::collections::BTreeMap<u64, u64>;
pub type ComplexType2 = std::collections::HashMap<u64, u64, std::hash::RandomState>;
#[proto_message]
#[derive(Debug, PartialEq, Eq)]
pub struct UserIdTreatAs {
#[proto(treat_as = "proto_rs::alloc::collections::BTreeMap<u64, u64>")]
pub id: ComplexType,
#[proto(treat_as = "std::collections::HashMap<u64, u64>")]
pub id2: ComplexType2,
}
#[proto_message]
#[derive(Debug, PartialEq, Eq)]
pub struct Holder {
#[proto(tag = 1)]
pub tuple: UserIdTuple,
#[proto(tag = 2)]
pub named: UserIdNamed,
}
#[proto_message]
#[derive(Debug, PartialEq, Eq)]
pub struct InnerMessage {
#[proto(tag = 1)]
pub value: u32,
}
#[proto_message(transparent)]
#[derive(Debug, PartialEq, Eq)]
pub struct MessageWrapper(InnerMessage);
#[test]
fn transparent_tuple_roundtrip() {
let original = UserIdTuple(123);
let shadow = <<UserIdTuple as ProtoEncode>::Shadow<'_> as proto_rs::ProtoShadowEncode<'_, UserIdTuple>>::from_sun(&original);
let mut writer = proto_rs::RevVec::with_capacity(8);
<<UserIdTuple as ProtoEncode>::Shadow<'_> as proto_rs::ProtoArchive>::archive::<0>(&shadow, &mut writer);
let buf = writer.finish_tight();
assert_eq!(buf.as_slice(), vec![123]);
let mut decoded = <UserIdTuple as ProtoDefault>::proto_default();
<UserIdTuple as ProtoDecoder>::merge(&mut decoded, WireType::Varint, &mut buf.as_slice(), DecodeContext::default()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn transparent_named_roundtrip() {
let original = UserIdNamed { id: 77 };
let shadow = <<UserIdNamed as ProtoEncode>::Shadow<'_> as proto_rs::ProtoShadowEncode<'_, UserIdNamed>>::from_sun(&original);
let mut writer = proto_rs::RevVec::with_capacity(8);
<<UserIdNamed as ProtoEncode>::Shadow<'_> as proto_rs::ProtoArchive>::archive::<0>(&shadow, &mut writer);
let buf = writer.finish_tight();
assert_eq!(buf.as_slice(), vec![77]);
let mut decoded = <UserIdNamed as ProtoDefault>::proto_default();
<UserIdNamed as ProtoDecoder>::merge(&mut decoded, WireType::Varint, &mut buf.as_slice(), DecodeContext::default()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn transparent_in_holder_encodes_inner_once() {
let holder = Holder {
tuple: UserIdTuple(5),
named: UserIdNamed { id: 9 },
};
let shadow = <<Holder as ProtoEncode>::Shadow<'_> as proto_rs::ProtoShadowEncode<'_, Holder>>::from_sun(&holder);
let mut writer = proto_rs::RevVec::with_capacity(16);
<<Holder as ProtoEncode>::Shadow<'_> as proto_rs::ProtoArchive>::archive::<0>(&shadow, &mut writer);
let buf = writer.finish_tight();
assert_eq!(buf.as_slice(), vec![0x08, 0x05, 0x10, 0x09]);
}
#[test]
fn transparent_message_roundtrip_top_level() {
let original = MessageWrapper(InnerMessage { value: 42 });
let buf = <MessageWrapper as ProtoEncode>::encode_to_vec(&original);
let decoded = <MessageWrapper as ProtoDecode>::decode(&buf[..], DecodeContext::default()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn transparent_message_decode_length_delimited_body() {
let body = [0x02, 0x08, 0x2A];
let mut buf = &body[..];
let len = proto_rs::decode_length_delimiter(&mut buf).expect("decode length");
let slice = Buf::take(&mut buf, len);
let decoded = <MessageWrapper as ProtoDecode>::decode(slice, DecodeContext::default()).unwrap();
assert_eq!(decoded, MessageWrapper(InnerMessage { value: 42 }));
}
#[proto_message(transparent)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct IdGenericTransparent<T> {
pub id: T,
}
#[test]
fn transparent_generic_roundtrip() {
let original: IdGenericTransparent<u64> = IdGenericTransparent { id: 12345 };
let buf = <IdGenericTransparent<u64> as ProtoEncode>::encode_to_vec(&original);
println!("Encoded buffer: {:?}, len: {}", buf, buf.len());
let mut decoded = <IdGenericTransparent<u64> as ProtoDefault>::proto_default();
<IdGenericTransparent<u64> as ProtoDecoder>::merge(&mut decoded, WireType::Varint, &mut &buf[..], DecodeContext::default()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn transparent_generic_with_message_roundtrip() {
let original: IdGenericTransparent<InnerMessage> = IdGenericTransparent {
id: InnerMessage { value: 999 },
};
let buf = <IdGenericTransparent<InnerMessage> as ProtoEncode>::encode_to_vec(&original);
let decoded = <IdGenericTransparent<InnerMessage> as ProtoDecode>::decode(&buf[..], DecodeContext::default()).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn transparent_generic_merge_field_forwards_correctly() {
let original: IdGenericTransparent<InnerMessage> = IdGenericTransparent {
id: InnerMessage { value: 42 },
};
let buf = <IdGenericTransparent<InnerMessage> as ProtoEncode>::encode_to_vec(&original);
let mut decoded = <IdGenericTransparent<InnerMessage> as ProtoDefault>::proto_default();
let mut buf_slice = &buf[..];
while buf_slice.has_remaining() {
let (tag, wire_type) = proto_rs::encoding::decode_key(&mut buf_slice).unwrap();
<IdGenericTransparent<InnerMessage> as ProtoDecoder>::merge_field(
&mut decoded,
tag,
wire_type,
&mut buf_slice,
DecodeContext::default(),
)
.unwrap();
}
assert_eq!(decoded, original);
}