1use std::fmt;
7use std::fmt::Write;
8use std::ops::Deref;
9use std::ops::RangeInclusive;
10
11use indexmap::IndexMap;
12use protobuf::reflect::ReflectValueBox;
13use protobuf::reflect::RuntimeType;
14use protobuf_support::lexer::float::format_protobuf_float;
15use protobuf_support::lexer::loc::Loc;
16use protobuf_support::lexer::str_lit::StrLit;
17
18use crate::model;
19use crate::proto_path::ProtoPathBuf;
20use crate::protobuf_abs_path::ProtobufAbsPath;
21use crate::protobuf_ident::ProtobufIdent;
22use crate::protobuf_path::ProtobufPath;
23use crate::pure::parser::Parser;
24pub use crate::pure::parser::ParserErrorWithLocation;
25
26#[derive(thiserror::Error, Debug)]
27enum ModelError {
28 #[error("cannot convert value `{1}` to type `{0}`")]
29 InconvertibleValue(RuntimeType, model::ProtobufConstant),
30}
31
32#[derive(Debug, Clone, PartialEq)]
33pub(crate) struct WithLoc<T> {
34 pub loc: Loc,
35 pub t: T,
36}
37
38impl<T> Deref for WithLoc<T> {
39 type Target = T;
40
41 fn deref(&self) -> &Self::Target {
42 &self.t
43 }
44}
45
46impl<T> WithLoc<T> {
47 pub fn with_loc(loc: Loc) -> impl FnOnce(T) -> WithLoc<T> {
48 move |t| WithLoc {
49 t,
50 loc: loc.clone(),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, Eq, PartialEq)]
57pub(crate) enum Syntax {
58 Proto2,
60 Proto3,
62}
63
64impl Default for Syntax {
65 fn default() -> Syntax {
66 Syntax::Proto2
67 }
68}
69
70#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
72pub(crate) enum Rule {
73 Optional,
75 Repeated,
78 Required,
80}
81
82impl Rule {
83 pub(crate) const ALL: [Rule; 3] = [Rule::Optional, Rule::Repeated, Rule::Required];
84
85 pub(crate) const fn as_str(&self) -> &'static str {
86 match self {
87 Rule::Optional => "optional",
88 Rule::Repeated => "repeated",
89 Rule::Required => "required",
90 }
91 }
92}
93
94#[derive(Debug, Clone, PartialEq)]
96pub(crate) struct Group {
97 pub name: String,
99 pub fields: Vec<WithLoc<Field>>,
100}
101
102#[derive(Debug, Clone, PartialEq)]
104pub(crate) enum FieldType {
105 Int32,
112 Int64,
119 Uint32,
125 Uint64,
131 Sint32,
138 Sint64,
145 Bool,
147 Fixed64,
153 Sfixed64,
159 Double,
161 String,
167 Bytes,
173 Fixed32,
179 Sfixed32,
185 Float,
187 MessageOrEnum(ProtobufPath),
189 Map(Box<(FieldType, FieldType)>),
191 Group(Group),
193}
194
195#[derive(Debug, Clone, PartialEq)]
197pub(crate) struct Field {
198 pub name: String,
200 pub rule: Option<Rule>,
202 pub typ: FieldType,
204 pub number: i32,
206 pub options: Vec<ProtobufOption>,
208}
209
210#[derive(Debug, Clone, PartialEq)]
212pub(crate) enum FieldOrOneOf {
213 Field(WithLoc<Field>),
214 OneOf(OneOf),
215}
216
217#[derive(Debug, Clone, Default)]
219pub(crate) struct Message {
220 pub name: String,
222 pub fields: Vec<WithLoc<FieldOrOneOf>>,
224 pub reserved_nums: Vec<RangeInclusive<i32>>,
226 pub reserved_names: Vec<String>,
228 pub messages: Vec<WithLoc<Message>>,
230 pub enums: Vec<WithLoc<Enumeration>>,
232 pub options: Vec<ProtobufOption>,
234 pub extension_ranges: Vec<RangeInclusive<i32>>,
236 pub extensions: Vec<WithLoc<Extension>>,
238}
239
240impl Message {
241 pub fn regular_fields_including_in_oneofs(&self) -> Vec<&WithLoc<Field>> {
242 self.fields
243 .iter()
244 .flat_map(|fo| match &fo.t {
245 FieldOrOneOf::Field(f) => vec![f],
246 FieldOrOneOf::OneOf(o) => o.fields.iter().collect(),
247 })
248 .collect()
249 }
250
251 pub fn field_by_name(&self, name: &str) -> Option<&Field> {
253 self.regular_fields_including_in_oneofs()
254 .iter()
255 .find(|f| f.t.name == name)
256 .map(|f| &f.t)
257 }
258
259 pub fn _nested_extensions(&self) -> Vec<&Group> {
260 self.regular_fields_including_in_oneofs()
261 .into_iter()
262 .flat_map(|f| match &f.t.typ {
263 FieldType::Group(g) => Some(g),
264 _ => None,
265 })
266 .collect()
267 }
268
269 #[cfg(test)]
270 pub fn regular_fields_for_test(&self) -> Vec<&Field> {
271 self.fields
272 .iter()
273 .flat_map(|fo| match &fo.t {
274 FieldOrOneOf::Field(f) => Some(&f.t),
275 FieldOrOneOf::OneOf(_) => None,
276 })
277 .collect()
278 }
279
280 pub(crate) fn oneofs(&self) -> Vec<&OneOf> {
281 self.fields
282 .iter()
283 .flat_map(|fo| match &fo.t {
284 FieldOrOneOf::Field(_) => None,
285 FieldOrOneOf::OneOf(o) => Some(o),
286 })
287 .collect()
288 }
289}
290
291#[derive(Debug, Clone)]
293pub(crate) struct EnumValue {
294 pub name: String,
296 pub number: i32,
298 pub options: Vec<ProtobufOption>,
300}
301
302#[derive(Debug, Clone)]
304pub(crate) struct Enumeration {
305 pub name: String,
307 pub values: Vec<EnumValue>,
309 pub options: Vec<ProtobufOption>,
311 pub reserved_nums: Vec<RangeInclusive<i32>>,
313 pub reserved_names: Vec<String>,
315}
316
317#[derive(Debug, Clone, Default, PartialEq)]
319pub(crate) struct OneOf {
320 pub name: String,
322 pub fields: Vec<WithLoc<Field>>,
324 pub options: Vec<ProtobufOption>,
326}
327
328#[derive(Debug, Clone)]
329pub(crate) struct Extension {
330 pub extendee: ProtobufPath,
332 pub field: WithLoc<Field>,
334}
335
336#[derive(Debug, Clone)]
338pub(crate) struct Method {
339 pub name: String,
341 pub input_type: ProtobufPath,
343 pub output_type: ProtobufPath,
345 #[allow(dead_code)] pub client_streaming: bool,
348 #[allow(dead_code)] pub server_streaming: bool,
351 pub options: Vec<ProtobufOption>,
353}
354
355#[derive(Debug, Clone)]
357pub(crate) struct Service {
358 pub name: String,
360 pub methods: Vec<Method>,
361 pub options: Vec<ProtobufOption>,
362}
363
364#[derive(Debug, Clone, PartialEq, Eq, Hash)]
365pub(crate) struct AnyTypeUrl {
366 pub(crate) prefix: String,
367 pub(crate) full_type_name: ProtobufPath,
368}
369
370impl fmt::Display for AnyTypeUrl {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 write!(f, "{}/{}", self.prefix, self.full_type_name)
373 }
374}
375
376#[derive(Debug, Clone, PartialEq, Eq, Hash)]
377pub(crate) enum ProtobufConstantMessageFieldName {
378 Regular(String),
379 Extension(ProtobufPath),
380 AnyTypeUrl(AnyTypeUrl),
381}
382
383impl fmt::Display for ProtobufConstantMessageFieldName {
384 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385 match self {
386 ProtobufConstantMessageFieldName::Regular(s) => write!(f, "{}", s),
387 ProtobufConstantMessageFieldName::Extension(p) => write!(f, "[{}]", p),
388 ProtobufConstantMessageFieldName::AnyTypeUrl(a) => write!(f, "[{}]", a),
389 }
390 }
391}
392
393#[derive(Debug, Clone, PartialEq, Default)]
394pub(crate) struct ProtobufConstantMessage {
395 pub(crate) fields: IndexMap<ProtobufConstantMessageFieldName, ProtobufConstant>,
396}
397
398#[derive(Debug, Clone, PartialEq)]
409pub(crate) enum ProtobufConstant {
410 U64(u64),
411 I64(i64),
412 F64(f64), Bool(bool),
414 Ident(ProtobufPath),
415 String(StrLit),
416 Message(ProtobufConstantMessage),
417 Repeated(Vec<ProtobufConstant>),
418}
419
420impl fmt::Display for ProtobufConstant {
421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422 match self {
423 ProtobufConstant::U64(v) => write!(f, "{}", v),
424 ProtobufConstant::I64(v) => write!(f, "{}", v),
425 ProtobufConstant::F64(v) => write!(f, "{}", format_protobuf_float(*v)),
426 ProtobufConstant::Bool(v) => write!(f, "{}", v),
427 ProtobufConstant::Ident(v) => write!(f, "{}", v),
428 ProtobufConstant::String(v) => write!(f, "{}", v),
429 ProtobufConstant::Message(v) => write!(f, "{:?}", v),
431 ProtobufConstant::Repeated(v) => write!(f, "{:?}", v),
432 }
433 }
434}
435
436impl ProtobufConstantMessage {
437 pub fn format(&self) -> String {
438 let mut s = String::new();
439 write!(s, "{{ ").unwrap();
440 for (n, v) in &self.fields {
441 match v {
442 ProtobufConstant::Message(m) => write!(s, "{} {}", n, m.format()).unwrap(),
443 v => write!(s, "{}: {} ", n, v.format()).unwrap(),
444 }
445 }
446 write!(s, "}}").unwrap();
447 s
448 }
449}
450
451impl ProtobufConstant {
452 pub fn format(&self) -> String {
453 match *self {
454 ProtobufConstant::U64(u) => u.to_string(),
455 ProtobufConstant::I64(i) => i.to_string(),
456 ProtobufConstant::F64(f) => format_protobuf_float(f),
457 ProtobufConstant::Bool(b) => b.to_string(),
458 ProtobufConstant::Ident(ref i) => format!("{}", i),
459 ProtobufConstant::String(ref s) => s.quoted(),
460 ProtobufConstant::Message(ref s) => s.format(),
461 ProtobufConstant::Repeated(ref l) => {
462 let mut s = String::from("[");
463 let mut it = l.iter().peekable();
464 while let Some(constant) = it.next() {
465 s.push_str(&constant.format());
466 if it.peek().is_some() {
467 s.push(',');
468 }
469 }
470 s.push(']');
471 s
472 }
473 }
474 }
475
476 pub fn as_type(&self, ty: RuntimeType) -> anyhow::Result<ReflectValueBox> {
478 match (self, &ty) {
479 (ProtobufConstant::Ident(ident), RuntimeType::Enum(e)) => {
480 if let Some(v) = e.value_by_name(&ident.to_string()) {
481 return Ok(ReflectValueBox::Enum(e.clone(), v.value()));
482 }
483 }
484 (ProtobufConstant::Bool(b), RuntimeType::Bool) => return Ok(ReflectValueBox::Bool(*b)),
485 (ProtobufConstant::String(lit), RuntimeType::String) => {
486 return Ok(ReflectValueBox::String(lit.decode_utf8()?))
487 }
488 _ => {}
489 }
490 Err(ModelError::InconvertibleValue(ty.clone(), self.clone()).into())
491 }
492}
493
494#[derive(Debug, Clone, PartialEq)]
496pub(crate) enum ProtobufOptionNamePart {
497 Direct(ProtobufIdent),
498 Ext(ProtobufPath),
499}
500
501impl fmt::Display for ProtobufOptionNamePart {
502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 match self {
504 ProtobufOptionNamePart::Direct(n) => write!(f, "{}", n),
505 ProtobufOptionNamePart::Ext(n) => write!(f, "({})", n),
506 }
507 }
508}
509
510#[derive(Debug, Clone, PartialEq)]
511pub(crate) struct ProtobufOptionNameExt(pub Vec<ProtobufOptionNamePart>);
512
513#[derive(Debug, Clone, PartialEq)]
514pub(crate) enum ProtobufOptionName {
515 Builtin(ProtobufIdent),
516 Ext(ProtobufOptionNameExt),
517}
518
519impl ProtobufOptionName {
520 pub fn simple(name: &str) -> ProtobufOptionName {
521 ProtobufOptionName::Builtin(ProtobufIdent::new(name))
522 }
523}
524
525impl fmt::Display for ProtobufOptionNameExt {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 for (index, comp) in self.0.iter().enumerate() {
528 if index != 0 {
529 write!(f, ".")?;
530 }
531 write!(f, "{}", comp)?;
532 }
533 Ok(())
534 }
535}
536
537impl fmt::Display for ProtobufOptionName {
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 match self {
540 ProtobufOptionName::Builtin(n) => write!(f, "{}", n),
541 ProtobufOptionName::Ext(n) => write!(f, "{}", n),
542 }
543 }
544}
545
546#[derive(Debug, Clone, PartialEq)]
547pub(crate) struct ProtobufOption {
548 pub name: ProtobufOptionName,
549 pub value: ProtobufConstant,
550}
551
552#[derive(Debug, Clone, Eq, PartialEq)]
554pub(crate) enum ImportVis {
555 Default,
556 Public,
557 Weak,
558}
559
560impl Default for ImportVis {
561 fn default() -> Self {
562 ImportVis::Default
563 }
564}
565
566#[derive(Debug, Default, Clone)]
568pub(crate) struct Import {
569 pub path: ProtoPathBuf,
570 pub vis: ImportVis,
571}
572
573#[derive(Debug, Default, Clone)]
575pub(crate) struct FileDescriptor {
576 pub imports: Vec<Import>,
578 pub package: ProtobufAbsPath,
580 pub syntax: Syntax,
582 pub messages: Vec<WithLoc<Message>>,
584 pub enums: Vec<WithLoc<Enumeration>>,
586 pub extensions: Vec<WithLoc<Extension>>,
588 pub services: Vec<WithLoc<Service>>,
590 pub options: Vec<ProtobufOption>,
592}
593
594impl FileDescriptor {
595 pub fn parse<S: AsRef<str>>(file: S) -> Result<Self, ParserErrorWithLocation> {
597 let mut parser = Parser::new(file.as_ref());
598 match parser.next_proto() {
599 Ok(r) => Ok(r),
600 Err(error) => {
601 let Loc { line, col } = parser.tokenizer.loc();
602 Err(ParserErrorWithLocation { error, line, col })
603 }
604 }
605 }
606}