1mod writer;
9
10#[cfg(feature = "std")]
11pub use writer::DescriptorWriter;
12
13use crate::DefaultEncoding;
14use core::fmt::Display;
15
16pub trait DescribeField<T> {
18 const FIELD_TYPE: FieldType<'static>;
20 const PACKED_TYPE: Option<&'static str> = None;
22}
23
24pub trait DescribeMessage<T> {
29 const DESCRIPTION: MessageDescription<'static>;
31}
32
33#[derive(Copy, Clone)]
35pub enum MessageDescription<'a> {
36 Internal(&'a TopLevelDescriptor<'a>),
38 External {
40 name: &'a str,
42 import_path: &'a str,
44 },
45}
46
47#[derive(Debug, Copy, Clone, PartialEq, Eq)]
50pub struct TypeUrl<'a> {
51 package: &'a str,
52 name: &'a str,
53}
54
55impl TypeUrl<'_> {
56 fn eq(&self, type_url: &str) -> bool {
57 let type_url = type_url.strip_prefix("https://").unwrap_or(type_url);
58 if let Some((package, name)) = type_url
59 .strip_prefix("type.googleapis.com/")
60 .and_then(|ty| ty.rsplit_once('.'))
61 {
62 self.package == package && self.name == name
63 } else {
64 false
65 }
66 }
67}
68
69impl Display for TypeUrl<'_> {
70 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71 write!(f, "type.googleapis.com/{}.{}", self.package, self.name)
72 }
73}
74
75impl PartialEq<str> for TypeUrl<'_> {
76 fn eq(&self, other: &str) -> bool {
77 self.eq(other)
78 }
79}
80
81impl PartialEq<TypeUrl<'_>> for str {
82 fn eq(&self, other: &TypeUrl<'_>) -> bool {
83 other.eq(self)
84 }
85}
86
87impl MessageDescription<'_> {
88 pub const fn type_url(&self) -> TypeUrl<'_> {
90 match *self {
91 MessageDescription::Internal(tld) => TypeUrl {
92 package: tld.package,
93 name: tld.message.name,
94 },
95 MessageDescription::External { name, .. } => TypeUrl { package: "", name },
96 }
97 }
98}
99
100pub const fn message_description<T: DefaultEncoding>() -> MessageDescription<'static>
102where
103 T::Encoding: DescribeMessage<T>,
104{
105 <T::Encoding as DescribeMessage<T>>::DESCRIPTION
106}
107
108#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
110pub struct FieldType<'a> {
111 kind: FieldKind<'a>,
112 sequence_type: Option<SequenceType<'a>>,
113 annotation: &'a str,
114}
115
116#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
117enum SequenceType<'a> {
118 Optional,
119 Repeated,
120 Map(&'a str),
121}
122
123#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
124enum FieldKind<'a> {
125 Builtin(&'a str),
126 Local(&'a str),
127 External {
128 name: &'a str,
129 import_path: &'static str,
130 },
131 Message(fn() -> MessageDescription<'a>),
132 Tuple(&'a [FieldType<'a>]),
133 KeyValue(&'a [FieldType<'a>; 2]),
134}
135
136impl<'a> FieldType<'a> {
137 pub const fn repeated(mut self) -> Self {
141 assert!(self.sequence_type.is_none());
142 self.sequence_type = Some(SequenceType::Repeated);
143 self
144 }
145
146 pub const fn optional(mut self) -> Self {
150 assert!(self.sequence_type.is_none());
151 self.sequence_type = Some(SequenceType::Optional);
152 self
153 }
154
155 pub const fn annotate(mut self, annotation: &'a str) -> Self {
157 self.annotation = annotation;
158 self
159 }
160
161 pub const fn map(kv: &'a [FieldType<'a>; 2]) -> Self {
169 let [key, value] = kv;
170 if !key.is_sequence() && !value.is_sequence() {
171 if let FieldKind::Builtin(ty) = key.kind {
172 if let b"uint32" | b"int32" | b"sint32" | b"uint64" | b"sint64" | b"int64"
173 | b"fixed32" | b"fixed64" | b"sfixed32" | b"sfixed64" | b"bool" | b"string" =
174 ty.as_bytes()
175 {
176 return Self {
177 kind: value.kind,
178 sequence_type: Some(SequenceType::Map(ty)),
179 annotation: "",
180 };
181 }
182 }
183 }
184 Self {
185 kind: FieldKind::KeyValue(kv),
186 sequence_type: Some(SequenceType::Repeated),
187 annotation: "",
188 }
189 }
190
191 pub const fn message(f: fn() -> MessageDescription<'a>) -> Self {
198 Self {
199 kind: FieldKind::Message(f),
200 sequence_type: None,
201 annotation: "",
202 }
203 }
204
205 pub const fn local(name: &'a str) -> Self {
207 Self {
208 kind: FieldKind::Local(name),
209 sequence_type: None,
210 annotation: "",
211 }
212 }
213
214 pub const fn builtin(name: &'a str) -> Self {
216 Self {
217 kind: FieldKind::Builtin(name),
218 sequence_type: None,
219 annotation: "",
220 }
221 }
222
223 pub const fn tuple(field_types: &'a [Self]) -> Self {
225 match field_types {
227 [] => {
228 return Self::external("google.protobuf.Empty", "google/protobuf/empty.proto");
229 }
230 &[
231 Self {
232 kind: FieldKind::Builtin(ty),
233 sequence_type: None,
234 annotation,
235 },
236 ] if annotation.is_empty() => {
237 let wrapper = match ty.as_bytes() {
238 b"double" => Some("google.protobuf.DoubleValue"),
239 b"float" => Some("google.protobuf.FloatValue"),
240 b"int64" => Some("google.protobuf.Int64Value"),
241 b"uint64" => Some("google.protobuf.UInt64Value"),
242 b"int32" => Some("google.protobuf.Int32Value"),
243 b"uint32" => Some("google.protobuf.UInt32Value"),
244 b"bool" => Some("google.protobuf.BoolValue"),
245 b"string" => Some("google.protobuf.StringValue"),
246 b"bytes" => Some("google.protobuf.BytesValue"),
247 _ => None,
248 };
249 if let Some(wrapper) = wrapper {
250 return Self::external(wrapper, "google/protobuf/wrappers.proto");
251 }
252 }
253 _ => {}
254 }
255 Self {
256 kind: FieldKind::Tuple(field_types),
257 sequence_type: None,
258 annotation: "",
259 }
260 }
261
262 pub const fn external(name: &'a str, import_path: &'static str) -> Self {
265 Self {
266 kind: FieldKind::External { name, import_path },
267 sequence_type: None,
268 annotation: "",
269 }
270 }
271
272 pub const fn is_sequence(&self) -> bool {
274 self.sequence_type.is_some()
275 }
276
277 pub const fn can_pack(&self) -> bool {
280 if self.sequence_type.is_some() {
281 return false;
282 }
283 match self.kind {
284 FieldKind::Builtin(v) => matches!(
285 v.as_bytes(),
286 b"double" | b"float" | b"int64" | b"uint64" | b"int32" | b"uint32" | b"bool"
287 ),
288 _ => false,
289 }
290 }
291}
292
293#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
295pub struct FieldDescriptor<'a> {
296 field_type: FieldType<'a>,
297 field_number: u32,
298 comment: &'a str,
299 name: &'a str,
300}
301
302impl<'a> FieldDescriptor<'a> {
303 pub const fn new(
305 comment: &'a str,
306 field_type: FieldType<'a>,
307 name: &'a str,
308 field_number: u32,
309 ) -> Self {
310 Self {
311 field_type,
312 field_number,
313 comment,
314 name,
315 }
316 }
317}
318
319#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
321pub struct OneofDescriptor<'a> {
322 name: &'a str,
323 variants: &'a [FieldDescriptor<'a>],
324}
325
326impl<'a> OneofDescriptor<'a> {
327 pub const fn new(name: &'a str, variants: &'a [FieldDescriptor<'a>]) -> Self {
329 Self { name, variants }
330 }
331}
332
333#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
335pub struct MessageDescriptor<'a> {
336 comment: &'a str,
337 name: &'a str,
338 fields: &'a [FieldDescriptor<'a>],
339 oneofs: &'a [OneofDescriptor<'a>],
340 messages: &'a [MessageDescriptor<'a>],
341}
342
343impl<'a> MessageDescriptor<'a> {
344 pub const fn new(
346 name: &'a str,
347 comment: &'a str,
348 fields: &'a [FieldDescriptor<'a>],
349 oneofs: &'a [OneofDescriptor<'a>],
350 messages: &'a [MessageDescriptor<'a>],
351 ) -> Self {
352 Self {
353 comment,
354 name,
355 fields,
356 oneofs,
357 messages,
358 }
359 }
360}
361
362#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
365pub struct TopLevelDescriptor<'a> {
366 package: &'a str,
367 message: &'a MessageDescriptor<'a>,
368}
369
370impl<'a> TopLevelDescriptor<'a> {
371 pub const fn message(package: &'a str, message: &'a MessageDescriptor<'a>) -> Self {
373 Self { package, message }
374 }
375}