protobuf_ast_parser/
ast.rs

1//! AST definitions for parsed Protocol Buffers files.
2//!
3//! # Examples
4//! ```rust
5//! use protobuf_ast_parser::ast::{Field, FieldModifier, Message, MessageEntry, RootEntry};
6//!
7//! let field = Field::new(Some(FieldModifier::Optional), "string", "name", 1, vec![]);
8//! let message = Message::new("User", vec![MessageEntry::Field(field)]);
9//! let file = vec![RootEntry::from(message)];
10//! assert_eq!(file.len(), 1);
11//! ```
12
13use ownable::traits::IntoOwned;
14use ownable::IntoOwned;
15use std::borrow::Cow;
16use std::collections::HashMap;
17use std::ops::{Deref, DerefMut};
18
19/// Represents a reserved or extensions range in `.proto` syntax.
20///
21/// # Examples
22/// ```rust
23/// use protobuf_ast_parser::ast::Range;
24///
25/// let finite = Range::from(1..5);
26/// let open_ended = Range::from(10..);
27/// ```
28#[derive(Debug, Clone, PartialEq)]
29pub enum Range {
30    Default(std::ops::Range<i64>),
31    From(std::ops::RangeFrom<i64>),
32}
33
34impl IntoOwned for Range {
35    type Owned = Self;
36
37    fn into_owned(self) -> Self::Owned {
38        self
39    }
40}
41
42impl From<std::ops::Range<i64>> for Range {
43    fn from(range: std::ops::Range<i64>) -> Self {
44        Self::Default(range)
45    }
46}
47
48impl From<std::ops::RangeFrom<i64>> for Range {
49    fn from(range: std::ops::RangeFrom<i64>) -> Self {
50        Self::From(range)
51    }
52}
53
54/// Option values and literal constants that can appear in `.proto` files.
55///
56/// # Examples
57/// ```rust
58/// use protobuf_ast_parser::ast::{Map, MapValue};
59/// use std::borrow::Cow;
60///
61/// let map: Map = [(Cow::from("enabled"), MapValue::from(true))].into();
62/// let value = MapValue::from(map);
63/// ```
64#[derive(Debug, Clone, PartialEq, IntoOwned)]
65pub enum MapValue<'a> {
66    Boolean(bool),
67    Integer(i64),
68    Ident(Cow<'a, str>),
69    String(Cow<'a, str>),
70    Map(Map<'a>),
71}
72
73impl<'a> From<bool> for MapValue<'a> {
74    fn from(value: bool) -> Self {
75        Self::Boolean(value)
76    }
77}
78
79impl<'a> From<i64> for MapValue<'a> {
80    fn from(value: i64) -> Self {
81        Self::Integer(value)
82    }
83}
84
85impl<'a> From<Map<'a>> for MapValue<'a> {
86    fn from(value: Map<'a>) -> Self {
87        Self::Map(value)
88    }
89}
90
91/// Map literal used by options and aggregate constants.
92pub type Map<'a> = HashMap<Cow<'a, str>, MapValue<'a>>;
93
94/// Helper for building a [`Map`] from borrowed keys.
95pub trait FromBorrowedIter<'a> {
96    type Item;
97
98    fn from_borrowed_iter<T: IntoIterator<Item = Self::Item>>(iter: T) -> Self;
99}
100
101impl<'a> FromBorrowedIter<'a> for Map<'a> {
102    type Item = (&'a str, MapValue<'a>);
103
104    fn from_borrowed_iter<T: IntoIterator<Item = (&'a str, MapValue<'a>)>>(iter: T) -> Self {
105        let iter = iter.into_iter().map(|(key, value)| (Cow::from(key), value));
106        Self::from_iter(iter)
107    }
108}
109
110/// Represents an `option` statement or an inline option list entry.
111///
112/// # Examples
113/// ```rust
114/// use protobuf_ast_parser::ast::{MapValue, Option};
115///
116/// let option = Option::new("deprecated", MapValue::from(true));
117/// assert_eq!(option.key, "deprecated");
118/// ```
119#[derive(Debug, Clone, PartialEq, IntoOwned)]
120pub struct Option<'a> {
121    pub key: Cow<'a, str>,
122    pub value: MapValue<'a>,
123}
124
125impl<'a> Option<'a> {
126    pub fn new(key: &'a str, value: MapValue<'a>) -> Self {
127        Self {
128            key: Cow::from(key),
129            value,
130        }
131    }
132}
133
134/// A parsed comment with both raw source and trimmed text.
135#[derive(Debug, Clone, PartialEq, IntoOwned)]
136pub struct Comment<'a> {
137    pub r#type: CommentType,
138    pub source: Cow<'a, str>,
139    pub text: Cow<'a, str>,
140}
141
142impl<'a> Comment<'a> {
143    pub fn new(r#type: CommentType, source: &'a str, text: &'a str) -> Self {
144        Self {
145            r#type,
146            text: Cow::from(text),
147            source: Cow::from(source),
148        }
149    }
150
151    pub fn single_line(source: &'a str) -> Self {
152        Self {
153            r#type: CommentType::SingleLine,
154            text: Cow::from(source[2..].trim()),
155            source: Cow::from(source),
156        }
157    }
158
159    pub fn multi_line(source: &'a str) -> Self {
160        Self {
161            r#type: CommentType::MultiLine,
162            text: Cow::from(source[2..source.len() - 2].trim()),
163            source: Cow::from(source),
164        }
165    }
166}
167
168/// Comment type markers for single-line (`//`) and multi-line (`/* */`) comments.
169#[derive(Debug, Clone, PartialEq, IntoOwned)]
170pub enum CommentType {
171    SingleLine,
172    MultiLine,
173}
174
175/// Top-level entries in a `.proto` file.
176///
177/// # Examples
178/// ```rust
179/// use protobuf_ast_parser::ast::{RootEntry, Comment};
180///
181/// let entry = RootEntry::from(Comment::single_line("// hi"));
182/// ```
183#[derive(Debug, Clone, PartialEq, IntoOwned)]
184pub enum RootEntry<'a> {
185    Comment(Comment<'a>),
186    Syntax(Cow<'a, str>),
187    Package(Cow<'a, str>),
188    Import(Cow<'a, str>),
189    Option(Option<'a>),
190    Service(Service<'a>),
191    Message(Message<'a>),
192    Extend(Extend<'a>),
193    Enum(Enum<'a>),
194}
195
196impl<'a> From<Comment<'a>> for RootEntry<'a> {
197    fn from(comment: Comment<'a>) -> Self {
198        Self::Comment(comment)
199    }
200}
201
202impl<'a> From<Option<'a>> for RootEntry<'a> {
203    fn from(option: Option<'a>) -> Self {
204        Self::Option(option)
205    }
206}
207
208impl<'a> From<Service<'a>> for RootEntry<'a> {
209    fn from(service: Service<'a>) -> Self {
210        Self::Service(service)
211    }
212}
213
214impl<'a> From<Message<'a>> for RootEntry<'a> {
215    fn from(message: Message<'a>) -> Self {
216        Self::Message(message)
217    }
218}
219
220impl<'a> From<Extend<'a>> for RootEntry<'a> {
221    fn from(extend: Extend<'a>) -> Self {
222        Self::Extend(extend)
223    }
224}
225
226impl<'a> From<Enum<'a>> for RootEntry<'a> {
227    fn from(r#enum: Enum<'a>) -> Self {
228        Self::Enum(r#enum)
229    }
230}
231
232/// Alias for a full `.proto` file AST.
233pub type Root<'a> = Vec<RootEntry<'a>>;
234
235/// Service definition with its RPC entries.
236#[derive(Debug, Clone, PartialEq, IntoOwned)]
237pub struct Service<'a> {
238    pub ident: Cow<'a, str>,
239    pub entries: Vec<ServiceEntry<'a>>,
240}
241
242impl<'a> Service<'a> {
243    pub fn new(ident: &'a str, entries: Vec<ServiceEntry<'a>>) -> Self {
244        Self {
245            ident: Cow::from(ident),
246            entries,
247        }
248    }
249}
250
251/// Entries that can appear inside a `service` block.
252#[derive(Debug, Clone, PartialEq, IntoOwned)]
253pub enum ServiceEntry<'a> {
254    Comment(Comment<'a>),
255    Option(Option<'a>),
256
257    Rpc(Rpc<'a>),
258}
259
260impl<'a> From<Comment<'a>> for ServiceEntry<'a> {
261    fn from(comment: Comment<'a>) -> Self {
262        ServiceEntry::Comment(comment)
263    }
264}
265
266impl<'a> From<Option<'a>> for ServiceEntry<'a> {
267    fn from(option: Option<'a>) -> Self {
268        ServiceEntry::Option(option)
269    }
270}
271
272impl<'a> From<Rpc<'a>> for ServiceEntry<'a> {
273    fn from(rpc: Rpc<'a>) -> Self {
274        ServiceEntry::Rpc(rpc)
275    }
276}
277
278/// RPC definition inside a `service`.
279#[derive(Debug, Clone, PartialEq, IntoOwned)]
280pub struct Rpc<'a> {
281    pub ident: Cow<'a, str>,
282
283    pub request: Cow<'a, str>,
284    pub reply: Cow<'a, str>,
285
286    pub stream: RpcStream,
287}
288
289impl<'a> Rpc<'a> {
290    pub fn new(ident: &'a str, request: &'a str, reply: &'a str, stream: RpcStream) -> Self {
291        Self {
292            ident: Cow::from(ident),
293            request: Cow::from(request),
294            reply: Cow::from(reply),
295            stream,
296        }
297    }
298}
299
300/// Streaming mode for an RPC definition.
301#[derive(Debug, Clone, PartialEq, IntoOwned)]
302pub enum RpcStream {
303    None,
304    ClientBound,
305    ServerBound,
306    Bidirectional,
307}
308
309impl RpcStream {
310    pub fn new(server_bound: bool, client_bound: bool) -> Self {
311        match (server_bound, client_bound) {
312            (true, true) => Self::Bidirectional,
313            (true, false) => Self::ServerBound,
314            (false, true) => Self::ClientBound,
315            _ => Self::None,
316        }
317    }
318}
319
320/// Message definition with nested entries.
321#[derive(Debug, Clone, PartialEq, IntoOwned)]
322pub struct Message<'a> {
323    pub ident: Cow<'a, str>,
324    pub entries: Vec<MessageEntry<'a>>,
325}
326
327impl<'a> Message<'a> {
328    pub fn new(ident: &'a str, entries: Vec<MessageEntry<'a>>) -> Self {
329        Self {
330            ident: Cow::from(ident),
331            entries,
332        }
333    }
334
335    pub fn empty(ident: &'a str) -> Self {
336        Self {
337            ident: Cow::from(ident),
338            entries: vec![],
339        }
340    }
341}
342
343#[derive(Debug, Clone, PartialEq, IntoOwned)]
344pub struct ReservedIndices(Vec<Range>);
345
346impl From<Vec<Range>> for ReservedIndices {
347    fn from(value: Vec<Range>) -> Self {
348        ReservedIndices(value)
349    }
350}
351
352impl Into<Vec<Range>> for ReservedIndices {
353    fn into(self) -> Vec<Range> {
354        self.0
355    }
356}
357
358impl Deref for ReservedIndices {
359    type Target = Vec<Range>;
360
361    fn deref(&self) -> &Self::Target {
362        &self.0
363    }
364}
365
366impl DerefMut for ReservedIndices {
367    fn deref_mut(&mut self) -> &mut Self::Target {
368        &mut self.0
369    }
370}
371
372#[derive(Debug, Clone, PartialEq, IntoOwned)]
373pub struct ReservedIdents<'a>(Vec<Cow<'a, str>>);
374
375impl<'a> From<Vec<&'a str>> for ReservedIdents<'a> {
376    fn from(value: Vec<&'a str>) -> Self {
377        ReservedIdents(value.iter().map(|s| Cow::from(*s)).collect())
378    }
379}
380
381impl<'a> From<Vec<Cow<'a, str>>> for ReservedIdents<'a> {
382    fn from(value: Vec<Cow<'a, str>>) -> Self {
383        ReservedIdents(value)
384    }
385}
386
387impl<'a> Into<Vec<Cow<'a, str>>> for ReservedIdents<'a> {
388    fn into(self) -> Vec<Cow<'a, str>> {
389        self.0
390    }
391}
392
393impl<'a> Deref for ReservedIdents<'a> {
394    type Target = Vec<Cow<'a, str>>;
395
396    fn deref(&self) -> &Self::Target {
397        &self.0
398    }
399}
400
401impl<'a> DerefMut for ReservedIdents<'a> {
402    fn deref_mut(&mut self) -> &mut Self::Target {
403        &mut self.0
404    }
405}
406
407#[derive(Debug, Clone, PartialEq, IntoOwned)]
408pub struct Extensions(Vec<Range>);
409
410impl From<Vec<Range>> for Extensions {
411    fn from(value: Vec<Range>) -> Self {
412        Extensions(value)
413    }
414}
415
416impl Into<Vec<Range>> for Extensions {
417    fn into(self) -> Vec<Range> {
418        self.0
419    }
420}
421
422impl Deref for Extensions {
423    type Target = Vec<Range>;
424
425    fn deref(&self) -> &Self::Target {
426        &self.0
427    }
428}
429
430impl DerefMut for Extensions {
431    fn deref_mut(&mut self) -> &mut Self::Target {
432        &mut self.0
433    }
434}
435
436/// Entries that can appear inside a `message` block.
437#[derive(Debug, Clone, PartialEq, IntoOwned)]
438pub enum MessageEntry<'a> {
439    Comment(Comment<'a>),
440    Option(Option<'a>),
441
442    Field(Field<'a>),
443    OneOf(OneOf<'a>),
444    Message(Message<'a>),
445    Extend(Extend<'a>),
446    Enum(Enum<'a>),
447
448    ReservedIndices(ReservedIndices),
449    ReservedIdents(ReservedIdents<'a>),
450
451    Extensions(Extensions),
452}
453
454impl<'a> From<Comment<'a>> for MessageEntry<'a> {
455    fn from(comment: Comment<'a>) -> Self {
456        Self::Comment(comment)
457    }
458}
459
460impl<'a> From<Option<'a>> for MessageEntry<'a> {
461    fn from(option: Option<'a>) -> Self {
462        Self::Option(option)
463    }
464}
465
466impl<'a> From<Field<'a>> for MessageEntry<'a> {
467    fn from(field: Field<'a>) -> Self {
468        Self::Field(field)
469    }
470}
471
472impl<'a> From<OneOf<'a>> for MessageEntry<'a> {
473    fn from(one_of: OneOf<'a>) -> Self {
474        Self::OneOf(one_of)
475    }
476}
477
478impl<'a> From<Message<'a>> for MessageEntry<'a> {
479    fn from(message: Message<'a>) -> Self {
480        Self::Message(message)
481    }
482}
483
484impl<'a> From<Extend<'a>> for MessageEntry<'a> {
485    fn from(extend: Extend<'a>) -> Self {
486        Self::Extend(extend)
487    }
488}
489
490impl<'a> From<Enum<'a>> for MessageEntry<'a> {
491    fn from(r#enum: Enum<'a>) -> Self {
492        Self::Enum(r#enum)
493    }
494}
495
496impl<'a> From<ReservedIndices> for MessageEntry<'a> {
497    fn from(reserved_indices: ReservedIndices) -> Self {
498        Self::ReservedIndices(reserved_indices)
499    }
500}
501
502impl<'a> From<ReservedIdents<'a>> for MessageEntry<'a> {
503    fn from(reserved_idents: ReservedIdents<'a>) -> Self {
504        Self::ReservedIdents(reserved_idents)
505    }
506}
507
508impl<'a> From<Extensions> for MessageEntry<'a> {
509    fn from(extensions: Extensions) -> Self {
510        Self::Extensions(extensions)
511    }
512}
513
514/// Field definition inside a message, oneof, or extend block.
515///
516/// # Examples
517/// ```rust
518/// use protobuf_ast_parser::ast::{Field, FieldModifier};
519///
520/// let field = Field::new(Some(FieldModifier::Optional), "string", "name", 1, vec![]);
521/// assert_eq!(field.index, 1);
522/// ```
523#[derive(Debug, Clone, PartialEq, IntoOwned)]
524pub struct Field<'a> {
525    pub modifier: std::option::Option<FieldModifier>,
526    pub r#type: Cow<'a, str>,
527    pub ident: Cow<'a, str>,
528    pub index: i64,
529    pub options: Vec<Option<'a>>,
530}
531
532impl<'a> Field<'a> {
533    pub fn new(
534        modifier: std::option::Option<FieldModifier>,
535        r#type: &'a str,
536        ident: &'a str,
537        index: i64,
538        options: Vec<Option<'a>>,
539    ) -> Self {
540        Self {
541            modifier,
542            r#type: Cow::from(r#type),
543            ident: Cow::from(ident),
544            index,
545            options,
546        }
547    }
548}
549
550/// `oneof` definition inside a message.
551#[derive(Debug, Clone, PartialEq, IntoOwned)]
552pub struct OneOf<'a> {
553    pub ident: Cow<'a, str>,
554    pub entries: Vec<OneOfEntry<'a>>,
555}
556
557impl<'a> OneOf<'a> {
558    pub fn new(ident: &'a str, entries: Vec<OneOfEntry<'a>>) -> Self {
559        Self {
560            ident: Cow::from(ident),
561            entries,
562        }
563    }
564}
565
566/// Entries that can appear inside a `oneof` block.
567#[derive(Debug, Clone, PartialEq, IntoOwned)]
568pub enum OneOfEntry<'a> {
569    Comment(Comment<'a>),
570    Option(Option<'a>),
571
572    Field(Field<'a>),
573}
574
575impl<'a> From<Comment<'a>> for OneOfEntry<'a> {
576    fn from(comment: Comment<'a>) -> Self {
577        Self::Comment(comment)
578    }
579}
580
581impl<'a> From<Option<'a>> for OneOfEntry<'a> {
582    fn from(option: Option<'a>) -> Self {
583        Self::Option(option)
584    }
585}
586
587impl<'a> From<Field<'a>> for OneOfEntry<'a> {
588    fn from(field: Field<'a>) -> Self {
589        Self::Field(field)
590    }
591}
592
593/// Field modifier keywords.
594#[derive(Debug, Clone, PartialEq, IntoOwned)]
595pub enum FieldModifier {
596    Optional,
597    Required,
598    Repeated,
599}
600
601/// Extend block definition.
602#[derive(Debug, Clone, PartialEq, IntoOwned)]
603pub struct Extend<'a> {
604    pub r#type: Cow<'a, str>,
605    pub entries: Vec<ExtendEntry<'a>>,
606}
607
608impl<'a> Extend<'a> {
609    pub fn new(r#type: &'a str, entries: Vec<ExtendEntry<'a>>) -> Self {
610        Self {
611            r#type: Cow::from(r#type),
612            entries,
613        }
614    }
615}
616
617/// Entries that can appear inside an `extend` block.
618#[derive(Debug, Clone, PartialEq, IntoOwned)]
619pub enum ExtendEntry<'a> {
620    Comment(Comment<'a>),
621    Field(Field<'a>),
622}
623
624impl<'a> From<Comment<'a>> for ExtendEntry<'a> {
625    fn from(comment: Comment<'a>) -> Self {
626        Self::Comment(comment)
627    }
628}
629
630impl<'a> From<Field<'a>> for ExtendEntry<'a> {
631    fn from(field: Field<'a>) -> Self {
632        Self::Field(field)
633    }
634}
635
636/// Enum definition.
637#[derive(Debug, Clone, PartialEq, IntoOwned)]
638pub struct Enum<'a> {
639    pub ident: Cow<'a, str>,
640    pub entries: Vec<EnumEntry<'a>>,
641}
642
643impl<'a> Enum<'a> {
644    pub fn new(ident: &'a str, entries: Vec<EnumEntry<'a>>) -> Self {
645        Self {
646            ident: Cow::from(ident),
647            entries,
648        }
649    }
650}
651
652/// Entries that can appear inside an `enum` block.
653#[derive(Debug, Clone, PartialEq, IntoOwned)]
654pub enum EnumEntry<'a> {
655    Comment(Comment<'a>),
656    Option(Option<'a>),
657    Variant(EnumVariant<'a>),
658}
659
660impl<'a> From<Comment<'a>> for EnumEntry<'a> {
661    fn from(comment: Comment<'a>) -> Self {
662        Self::Comment(comment)
663    }
664}
665
666impl<'a> From<Option<'a>> for EnumEntry<'a> {
667    fn from(option: Option<'a>) -> Self {
668        Self::Option(option)
669    }
670}
671
672impl<'a> From<EnumVariant<'a>> for EnumEntry<'a> {
673    fn from(value: EnumVariant<'a>) -> Self {
674        Self::Variant(value)
675    }
676}
677
678/// Enum variant definition inside an enum block.
679///
680/// # Examples
681/// ```rust
682/// use protobuf_ast_parser::ast::EnumVariant;
683///
684/// let variant = EnumVariant::new("FIRST", 1, vec![]);
685/// assert_eq!(variant.value, 1);
686/// ```
687#[derive(Debug, Clone, PartialEq, IntoOwned)]
688pub struct EnumVariant<'a> {
689    pub ident: Cow<'a, str>,
690    pub value: i64,
691    pub options: Vec<Option<'a>>,
692}
693
694impl<'a> EnumVariant<'a> {
695    pub fn new(ident: &'a str, value: i64, options: Vec<Option<'a>>) -> Self {
696        Self {
697            ident: Cow::from(ident),
698            value,
699            options,
700        }
701    }
702}