mesh_protobuf/table/
mod.rs1pub mod decode;
13pub mod encode;
14mod tuple;
15
16use crate::protofile::DescribeField;
17use crate::protofile::DescribeMessage;
18use crate::protofile::FieldType;
19use crate::protofile::MessageDescription;
20
21pub struct TableEncoder;
23
24#[diagnostic::on_unimplemented(
26 message = "`{Self}` is not a stable protobuf type",
27 label = "`{Self}` does not have a mesh package name",
28 note = "consider adding `#[mesh(package = \"my.package.name\")]` to the type"
29)]
30pub trait DescribeTable {
31 const DESCRIPTION: MessageDescription<'static>;
33}
34
35impl<T: DescribeTable> DescribeMessage<T> for TableEncoder {
36 const DESCRIPTION: MessageDescription<'static> = T::DESCRIPTION;
37}
38
39impl<T: DescribeTable> DescribeField<T> for TableEncoder {
40 const FIELD_TYPE: FieldType<'static> = FieldType::message(|| T::DESCRIPTION);
41}
42
43pub unsafe trait StructMetadata {
50 const NUMBERS: &'static [u32]; const OFFSETS: &'static [usize]; }
55
56#[cfg(test)]
57#[expect(clippy::undocumented_unsafe_blocks)]
58mod tests {
59 use super::StructMetadata;
60 use super::TableEncoder;
61 use super::decode::ErasedDecoderEntry;
62 use super::decode::StructDecodeMetadata;
63 use super::encode::ErasedEncoderEntry;
64 use super::encode::StructEncodeMetadata;
65 use crate::FieldDecode;
66 use crate::FieldEncode;
67 use crate::encoding::StringField;
68 use crate::encoding::VarintField;
69 use crate::tests::as_expect_str;
70 use core::mem::offset_of;
71 use expect_test::expect;
72
73 #[derive(PartialEq, Eq, Debug)]
74 struct Foo<'a> {
75 a: u32,
76 b: u64,
77 x: &'a str,
78 }
79
80 unsafe impl<'a> StructMetadata for Foo<'a> {
81 const NUMBERS: &'static [u32] = &[1, 2, 3];
82 const OFFSETS: &'static [usize] = &[
83 offset_of!(Foo<'a>, a),
84 offset_of!(Foo<'a>, b),
85 offset_of!(Foo<'a>, x),
86 ];
87 }
88 unsafe impl<'a, R> StructEncodeMetadata<R> for Foo<'a> {
89 const ENCODERS: &'static [ErasedEncoderEntry] = &[
90 <VarintField as FieldEncode<u32, R>>::ENTRY.erase(),
91 <VarintField as FieldEncode<u64, R>>::ENTRY.erase(),
92 <StringField as FieldEncode<&'a str, R>>::ENTRY.erase(),
93 ];
94 }
95 unsafe impl<'de, R> StructDecodeMetadata<'de, R> for Foo<'de> {
96 const DECODERS: &'static [ErasedDecoderEntry] = &[
97 <VarintField as FieldDecode<'de, u32, R>>::ENTRY.erase(),
98 <VarintField as FieldDecode<'de, u64, R>>::ENTRY.erase(),
99 <StringField as FieldDecode<'de, &'de str, R>>::ENTRY.erase(),
100 ];
101 }
102 impl crate::DefaultEncoding for Foo<'_> {
103 type Encoding = TableEncoder;
104 }
105
106 #[test]
107 fn test_derived_macro() {
108 let data = crate::encode(Foo {
109 a: 1,
110 b: 2,
111 x: "hi",
112 });
113 let expected = expect!([r#"
114 1: varint 1
115 2: varint 2
116 3: string "hi"
117 raw: 080110021a026869"#]);
118 expected.assert_eq(&as_expect_str(&data));
119 let foo = crate::decode::<Foo<'_>>(&data).unwrap();
120 assert_eq!(foo.a, 1);
121 assert_eq!(foo.b, 2);
122 assert_eq!(foo.x, "hi");
123 }
124}