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)]
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)]
110pub struct FieldType<'a> {
111 kind: FieldKind<'a>,
112 sequence_type: Option<SequenceType<'a>>,
113 annotation: &'a str,
114}
115
116#[cfg_attr(not(feature = "std"), expect(dead_code))]
117#[derive(Debug, Copy, Clone)]
118enum SequenceType<'a> {
119 Optional,
120 Repeated,
121 Map(&'a str),
122}
123
124#[cfg_attr(not(feature = "std"), expect(dead_code))]
125#[derive(Debug, Copy, Clone)]
126enum FieldKind<'a> {
127 Builtin(&'a str),
128 Local(&'a str),
129 External {
130 name: &'a str,
131 import_path: &'static str,
132 },
133 Message(fn() -> MessageDescription<'a>),
134 Tuple(&'a [FieldType<'a>]),
135 KeyValue(&'a [FieldType<'a>; 2]),
136}
137
138impl<'a> FieldType<'a> {
139 pub const fn repeated(mut self) -> Self {
143 assert!(self.sequence_type.is_none());
144 self.sequence_type = Some(SequenceType::Repeated);
145 self
146 }
147
148 pub const fn optional(mut self) -> Self {
152 assert!(self.sequence_type.is_none());
153 self.sequence_type = Some(SequenceType::Optional);
154 self
155 }
156
157 pub const fn annotate(mut self, annotation: &'a str) -> Self {
159 self.annotation = annotation;
160 self
161 }
162
163 pub const fn map(kv: &'a [FieldType<'a>; 2]) -> Self {
171 let [key, value] = kv;
172 if !key.is_sequence() && !value.is_sequence() {
173 if let FieldKind::Builtin(ty) = key.kind {
174 if let b"uint32" | b"int32" | b"sint32" | b"uint64" | b"sint64" | b"int64"
175 | b"fixed32" | b"fixed64" | b"sfixed32" | b"sfixed64" | b"bool" | b"string" =
176 ty.as_bytes()
177 {
178 return Self {
179 kind: value.kind,
180 sequence_type: Some(SequenceType::Map(ty)),
181 annotation: "",
182 };
183 }
184 }
185 }
186 Self {
187 kind: FieldKind::KeyValue(kv),
188 sequence_type: Some(SequenceType::Repeated),
189 annotation: "",
190 }
191 }
192
193 pub const fn message(f: fn() -> MessageDescription<'a>) -> Self {
200 Self {
201 kind: FieldKind::Message(f),
202 sequence_type: None,
203 annotation: "",
204 }
205 }
206
207 pub const fn local(name: &'a str) -> Self {
209 Self {
210 kind: FieldKind::Local(name),
211 sequence_type: None,
212 annotation: "",
213 }
214 }
215
216 pub const fn builtin(name: &'a str) -> Self {
218 Self {
219 kind: FieldKind::Builtin(name),
220 sequence_type: None,
221 annotation: "",
222 }
223 }
224
225 pub const fn tuple(field_types: &'a [Self]) -> Self {
227 match field_types {
229 [] => {
230 return Self::external("google.protobuf.Empty", "google/protobuf/empty.proto");
231 }
232 &[
233 Self {
234 kind: FieldKind::Builtin(ty),
235 sequence_type: None,
236 annotation,
237 },
238 ] if annotation.is_empty() => {
239 let wrapper = match ty.as_bytes() {
240 b"double" => Some("google.protobuf.DoubleValue"),
241 b"float" => Some("google.protobuf.FloatValue"),
242 b"int64" => Some("google.protobuf.Int64Value"),
243 b"uint64" => Some("google.protobuf.UInt64Value"),
244 b"int32" => Some("google.protobuf.Int32Value"),
245 b"uint32" => Some("google.protobuf.UInt32Value"),
246 b"bool" => Some("google.protobuf.BoolValue"),
247 b"string" => Some("google.protobuf.StringValue"),
248 b"bytes" => Some("google.protobuf.BytesValue"),
249 _ => None,
250 };
251 if let Some(wrapper) = wrapper {
252 return Self::external(wrapper, "google/protobuf/wrappers.proto");
253 }
254 }
255 _ => {}
256 }
257 Self {
258 kind: FieldKind::Tuple(field_types),
259 sequence_type: None,
260 annotation: "",
261 }
262 }
263
264 pub const fn external(name: &'a str, import_path: &'static str) -> Self {
267 Self {
268 kind: FieldKind::External { name, import_path },
269 sequence_type: None,
270 annotation: "",
271 }
272 }
273
274 pub const fn is_sequence(&self) -> bool {
276 self.sequence_type.is_some()
277 }
278
279 pub const fn can_pack(&self) -> bool {
282 if self.sequence_type.is_some() {
283 return false;
284 }
285 match self.kind {
286 FieldKind::Builtin(v) => matches!(
287 v.as_bytes(),
288 b"double" | b"float" | b"int64" | b"uint64" | b"int32" | b"uint32" | b"bool"
289 ),
290 _ => false,
291 }
292 }
293}
294
295#[cfg_attr(not(feature = "std"), expect(dead_code))]
297#[derive(Debug, Copy, Clone)]
298pub struct FieldDescriptor<'a> {
299 field_type: FieldType<'a>,
300 field_number: u32,
301 comment: &'a str,
302 name: &'a str,
303}
304
305impl<'a> FieldDescriptor<'a> {
306 pub const fn new(
308 comment: &'a str,
309 field_type: FieldType<'a>,
310 name: &'a str,
311 field_number: u32,
312 ) -> Self {
313 Self {
314 field_type,
315 field_number,
316 comment,
317 name,
318 }
319 }
320}
321
322#[cfg_attr(not(feature = "std"), expect(dead_code))]
324#[derive(Debug, Copy, Clone)]
325pub struct OneofDescriptor<'a> {
326 name: &'a str,
327 variants: &'a [FieldDescriptor<'a>],
328}
329
330impl<'a> OneofDescriptor<'a> {
331 pub const fn new(name: &'a str, variants: &'a [FieldDescriptor<'a>]) -> Self {
333 Self { name, variants }
334 }
335}
336
337#[derive(Debug, Copy, Clone)]
339#[cfg_attr(not(feature = "std"), expect(dead_code))]
340pub struct MessageDescriptor<'a> {
341 comment: &'a str,
342 name: &'a str,
343 fields: &'a [FieldDescriptor<'a>],
344 oneofs: &'a [OneofDescriptor<'a>],
345 messages: &'a [MessageDescriptor<'a>],
346}
347
348impl<'a> MessageDescriptor<'a> {
349 pub const fn new(
351 name: &'a str,
352 comment: &'a str,
353 fields: &'a [FieldDescriptor<'a>],
354 oneofs: &'a [OneofDescriptor<'a>],
355 messages: &'a [MessageDescriptor<'a>],
356 ) -> Self {
357 Self {
358 comment,
359 name,
360 fields,
361 oneofs,
362 messages,
363 }
364 }
365}
366
367#[derive(Debug, Copy, Clone)]
370pub struct TopLevelDescriptor<'a> {
371 package: &'a str,
372 message: &'a MessageDescriptor<'a>,
373}
374
375impl<'a> TopLevelDescriptor<'a> {
376 pub const fn message(package: &'a str, message: &'a MessageDescriptor<'a>) -> Self {
378 Self { package, message }
379 }
380}