1use std::ops::RangeInclusive;
2use std::path::PathBuf;
3
4use indexmap::IndexMap;
5use proc_macro2::Span;
6use syn::punctuated::Punctuated;
7use syn::spanned::Spanned;
8use syn::Ident;
9use syn::LitBool;
10use syn::LitFloat;
11use syn::LitInt;
12use syn::LitStr;
13use syn::Token;
14use syn_prelude::ToIdent;
15use syn_prelude::ToLitStr;
16
17use crate::dep::Deps;
18
19#[derive(Debug, Clone, Hash, PartialEq, Eq)]
20pub struct ProtobufPath {
21 pub segments: Punctuated<Ident, Token![.]>,
22}
23
24impl ProtobufPath {
25 pub fn from_ident(name: Ident) -> Self {
26 let mut slf = Self {
27 segments: Punctuated::new(),
28 };
29 slf.segments.push(name);
30 slf
31 }
32
33 pub fn new_empty(span: Span) -> Self {
34 let mut segments = Punctuated::new();
35 segments.push_value(("google", span).to_ident());
36 segments.push_punct(Token);
37 segments.push_value(("protobuf", span).to_ident());
38 segments.push_punct(Token);
39 segments.push(("Empty", span).to_ident());
40 Self { segments }
41 }
42}
43
44impl ProtobufPath {
45 pub fn local_name(&self) -> &Ident {
46 if let Some(last) = self.segments.last() {
47 return last;
48 } else {
49 unreachable!()
50 }
51 }
52}
53
54#[derive(Debug, Clone, Copy)]
56pub enum Syntax {
57 Proto2(Span),
59 Proto3(Option<Span>),
61}
62
63impl Syntax {
64 pub fn version(&self) -> usize {
65 match self {
66 Self::Proto2(_) => 2,
67 Self::Proto3(_) => 3,
68 }
69 }
70}
71
72#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
74pub enum Modifier {
75 Optional,
77 Repeated,
80 Required,
82}
83
84#[derive(Debug, Clone)]
86pub struct Group {
87 pub name: Ident,
89 pub fields: Vec<Field>,
90}
91
92#[derive(Debug, Clone)]
94pub enum FieldType {
95 Int32(Span),
102 Int64(Span),
109 Uint32(Span),
115 Uint64(Span),
121 Sint32(Span),
128 Sint64(Span),
135 Bool(Span),
137 Fixed64(Span),
143 Sfixed64(Span),
149 Double(Span),
151 String(Span),
157 Bytes(Span),
163 Fixed32(Span),
169 Sfixed32(Span),
175 Float(Span),
177 MessageOrEnum(Type),
179 Map(MapType),
181 Group(Group),
183}
184
185#[derive(Debug, Clone)]
186pub struct MapType {
187 pub span: Span,
188 pub key: Box<FieldType>,
189 pub value: Box<FieldType>,
190}
191
192impl FieldType {
193 #[allow(unused)]
194 pub fn span(&self) -> Span {
195 match self {
196 Self::Int32(span) => *span,
197 Self::Int64(span) => *span,
198 Self::Uint32(span) => *span,
199 Self::Uint64(span) => *span,
200 Self::Sint32(span) => *span,
201 Self::Sint64(span) => *span,
202 Self::Bool(span) => *span,
203 Self::Fixed64(span) => *span,
204 Self::Sfixed64(span) => *span,
205 Self::Double(span) => *span,
206 Self::String(span) => *span,
207 Self::Bytes(span) => *span,
208 Self::Fixed32(span) => *span,
209 Self::Sfixed32(span) => *span,
210 Self::Float(span) => *span,
211 Self::MessageOrEnum(t) => t.type_path.span(),
212 Self::Map(map) => map.span,
213 Self::Group(group) => group.name.span(),
214 }
215 }
216 pub fn is_message(&self) -> bool {
217 match self {
218 Self::MessageOrEnum(t) => t.target_is_message,
219 _ => false,
220 }
221 }
222}
223
224#[derive(Debug, Clone)]
225pub struct Type {
226 pub type_path: ProtobufPath,
227 pub target_is_message: bool,
228 pub ty: syn::Type,
229}
230
231#[derive(Debug, Clone)]
232pub enum TagValue {
233 Value(Span, i32),
234 AutoIncr,
235}
236
237impl ToLitStr for TagValue {
238 fn to_lit_str(&self) -> LitStr {
239 if let Self::Value(span, value) = self {
240 LitStr::new(&format!("{}", value), *span)
241 } else {
242 unreachable!()
243 }
244 }
245}
246
247#[derive(Debug, Clone)]
249pub struct Field {
250 pub name: Ident,
252 pub field_name: Ident,
253 pub modifier: Option<Modifier>,
255 pub typ: FieldType,
257 pub tag: TagValue,
259 pub options: Vec<ProtobufOption>,
261 pub enum_field: bool,
262}
263
264#[derive(Debug, Clone)]
266pub enum MessageElement {
267 Field(Field),
268 OneOf(OneOf),
269}
270
271#[derive(Debug, Clone, Copy)]
272pub enum NestedTypeIndex {
273 Message(usize),
274 Enum(usize),
275 Oneof(usize),
276}
277
278#[derive(Debug, Clone)]
280pub struct Message {
281 pub name: Ident,
283 pub struct_name: Ident,
284 pub fields: Vec<MessageElement>,
286 pub reserved_nums: Vec<RangeInclusive<i32>>,
288 pub reserved_names: Vec<Ident>,
290 pub messages: Vec<Message>,
292 pub enums: Vec<Enumeration>,
294 pub options: Vec<ProtobufOption>,
296 pub extension_ranges: Vec<RangeInclusive<i32>>,
298 pub extensions: Vec<Extension>,
300 pub nested_types: Vec<NestedTypeIndex>,
301}
302
303#[derive(Debug, Clone)]
305pub struct EnumValue {
306 pub name: Ident,
308 pub variant_name: Ident,
310 pub proto_name: LitStr,
312 pub tag: Option<LitInt>,
314 pub tag_value: i32,
315 pub options: Option<Vec<ProtobufOption>>,
317}
318
319#[derive(Debug, Clone)]
321pub struct Enumeration {
322 pub name: Ident,
324 pub values: Vec<EnumValue>,
326 pub options: Vec<ProtobufOption>,
328 pub reserved_nums: Vec<RangeInclusive<i32>>,
330 pub reserved_names: Vec<Ident>,
332}
333
334#[derive(Debug, Clone)]
336pub struct OneOf {
337 pub name: Ident,
339 pub field_name: Ident,
340 pub field_lit: LitStr,
341 pub enum_name: Ident,
342 pub tags: LitStr,
343 pub fields: Vec<Field>,
345 pub options: Vec<ProtobufOption>,
347}
348
349#[derive(Debug, Clone)]
350pub struct Extension {
351 pub extendee: ProtobufPath,
353 pub field: Field,
355}
356
357#[derive(Debug, Clone)]
359pub struct Method {
360 pub name: Ident,
362 pub method_name: Ident,
364 pub input_message: Option<Message>,
366 pub input_type: Type,
368 pub output_message: Option<Message>,
370 pub output_type: Type,
372 #[allow(dead_code)] pub client_streaming: Option<Span>,
375 #[allow(dead_code)] pub server_streaming: Option<Span>,
378 pub options: Punctuated<ProtobufOption, Token![;]>,
380}
381
382#[derive(Debug, Clone)]
384pub struct Service {
385 pub name: Ident,
387 pub code_name: Ident,
388 pub methods: Vec<Method>,
389 pub options: Vec<ProtobufOption>,
390}
391
392#[derive(Debug, Clone, Hash, PartialEq, Eq)]
393pub struct AnyTypeUrl {
394 pub prefix: ProtobufPath,
395 pub full_type_name: ProtobufPath,
396}
397
398#[derive(Debug, Clone, Hash, PartialEq, Eq)]
399pub enum ProtobufConstantMessageFieldName {
400 Regular(Ident),
401 Extension(ProtobufPath),
402 AnyTypeUrl(AnyTypeUrl),
403}
404
405#[derive(Debug, Clone)]
406pub struct ProtobufConstantMessage {
407 pub fields: IndexMap<ProtobufConstantMessageFieldName, ProtobufConstant>,
408}
409
410#[derive(Debug, Clone)]
411#[allow(unused)]
412pub enum ProtobufConstant {
413 Int(LitInt),
414 Float(LitFloat),
415 Bool(LitBool),
416 Ident(ProtobufPath),
417 String(LitStr),
418 Message(ProtobufConstantMessage),
419}
420
421#[derive(Debug, Clone)]
423pub enum ProtobufOptionNamePart {
424 Direct(Ident),
425 Ext(ProtobufPath),
426}
427
428#[derive(Debug, Clone)]
429pub struct ProtobufOptionNameExt(pub Vec<ProtobufOptionNamePart>);
430
431#[derive(Debug, Clone)]
432pub enum ProtobufOptionName {
433 Builtin(Ident),
434 Ext(ProtobufOptionNameExt),
435}
436
437impl ProtobufOptionName {
438 pub fn is_option(&self, opt_name: &str) -> bool {
439 match self {
440 ProtobufOptionName::Builtin(name) => name.eq(opt_name),
441 ProtobufOptionName::Ext(ext) => {
442 let mut compared_index = 0;
443 for (index, n) in opt_name.split('.').enumerate() {
444 if let Some(seg) = ext.0.get(index) {
445 match seg {
446 ProtobufOptionNamePart::Direct(d) => {
447 if !d.eq(n) {
448 return false;
449 }
450 }
451 ProtobufOptionNamePart::Ext(_ext) => return false,
452 }
453 } else {
454 return false;
455 }
456 compared_index = index;
457 }
458 ext.0.len() == compared_index + 1
459 }
460 }
461 }
462}
463
464#[derive(Debug, Clone)]
465pub struct ProtobufOption {
466 pub name: ProtobufOptionName,
467 pub value: ProtobufConstant,
468}
469
470pub trait GetOption {
471 fn get_option<'a>(&'a self, name: &str) -> Option<&'a ProtobufOption>;
472 fn get_string_option<'a>(&'a self, name: &str) -> Option<&'a LitStr> {
473 if let Some(ProtobufOption {
474 value: ProtobufConstant::String(value),
475 ..
476 }) = self.get_option(name)
477 {
478 Some(value)
479 } else {
480 None
481 }
482 }
483 fn get_bool_option<'a>(&'a self, name: &str) -> Option<&'a LitBool> {
484 if let Some(ProtobufOption {
485 value: ProtobufConstant::Bool(value),
486 ..
487 }) = self.get_option(name)
488 {
489 Some(value)
490 } else {
491 None
492 }
493 }
494 fn get_int_option<'a>(&'a self, name: &str) -> Option<&'a LitInt> {
495 if let Some(ProtobufOption {
496 value: ProtobufConstant::Int(value),
497 ..
498 }) = self.get_option(name)
499 {
500 Some(value)
501 } else {
502 None
503 }
504 }
505 fn get_float_option<'a>(&'a self, name: &str) -> Option<&'a LitFloat> {
506 if let Some(ProtobufOption {
507 value: ProtobufConstant::Float(value),
508 ..
509 }) = self.get_option(name)
510 {
511 Some(value)
512 } else {
513 None
514 }
515 }
516 fn get_ident_option<'a>(&'a self, name: &str) -> Option<&'a ProtobufPath> {
517 if let Some(ProtobufOption {
518 value: ProtobufConstant::Ident(value),
519 ..
520 }) = self.get_option(name)
521 {
522 Some(value)
523 } else {
524 None
525 }
526 }
527 fn get_object_option<'a>(&'a self, name: &str) -> Option<&'a ProtobufConstantMessage> {
528 if let Some(ProtobufOption {
529 value: ProtobufConstant::Message(value),
530 ..
531 }) = self.get_option(name)
532 {
533 Some(value)
534 } else {
535 None
536 }
537 }
538}
539
540impl GetOption for Vec<ProtobufOption> {
541 fn get_option<'a>(&'a self, name: &str) -> Option<&'a ProtobufOption> {
542 self.iter().find(|opt| opt.name.is_option(name))
543 }
544}
545
546impl<P> GetOption for Punctuated<ProtobufOption, P> {
547 fn get_option<'a>(&'a self, name: &str) -> Option<&'a ProtobufOption> {
548 self.iter().find(|opt| opt.name.is_option(name))
549 }
550}
551
552#[derive(Debug, Clone)]
554pub enum ImportVis {
555 Default,
556 Public(Span),
557 Weak(Span),
558}
559
560impl Default for ImportVis {
561 fn default() -> Self {
562 ImportVis::Default
563 }
564}
565
566#[derive(Debug, Clone)]
568pub struct Import {
569 pub import_token: Span,
570 pub path: LitStr,
571 pub builtin: bool,
572 pub vis: ImportVis,
573 pub file_path: Option<FilePath>,
574}
575
576#[derive(Debug, Clone)]
577pub struct FilePath {
578 pub root: bool,
579 pub bin: bool,
580 pub example: bool,
581 pub is_mod: bool,
582 pub path: PathBuf,
583 pub mod_path: syn::Path,
584}
585
586#[derive(Debug, Clone)]
587pub struct Package {
588 pub package: Ident,
589}
590
591#[derive(Debug, Clone)]
592pub enum DeclIndex {
593 Message(usize),
594 Enum(usize),
595 Service(usize),
596}
597
598#[derive(Debug, Clone)]
600pub struct Protocol {
601 pub imports: Vec<Import>,
603 pub package: Option<Package>,
605 pub syntax: Syntax,
607 pub messages: Vec<Message>,
609 pub enums: Vec<Enumeration>,
611 pub extensions: Vec<Extension>,
613 pub services: Vec<Service>,
615 pub options: Vec<ProtobufOption>,
617 pub decls: Vec<DeclIndex>,
618 pub deps: Deps,
619}