protobuf_parser/
lib.rs

1//! A nom-based protobuf file parser
2//!
3//! This crate can be seen as a rust transcription of the
4//! [descriptor.proto](https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto) file
5
6#[macro_use]
7extern crate nom;
8
9mod parser;
10
11use std::ops::Range;
12use parser::file_descriptor;
13
14/// Protobox syntax
15#[derive(Debug, Clone, Copy)]
16pub enum Syntax {
17    /// Protobuf syntax [2](https://developers.google.com/protocol-buffers/docs/proto) (default)
18    Proto2,
19    /// Protobuf syntax [3](https://developers.google.com/protocol-buffers/docs/proto3)
20    Proto3,
21}
22
23impl Default for Syntax {
24    fn default() -> Syntax {
25        Syntax::Proto2
26    }
27}
28
29/// A field rule
30#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
31pub enum Rule {
32    /// A well-formed message can have zero or one of this field (but not more than one).
33    Optional,
34    /// This field can be repeated any number of times (including zero) in a well-formed message.
35    /// The order of the repeated values will be preserved.
36    Repeated,
37    /// A well-formed message must have exactly one of this field.
38    Required,
39}
40
41/// Protobuf supported field types
42///
43/// TODO: Groups (even if deprecated)
44#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45pub enum FieldType {
46    /// Protobuf int32
47    ///
48    /// # Remarks
49    ///
50    /// Uses variable-length encoding. Inefficient for encoding negative numbers – if
51    /// your field is likely to have negative values, use sint32 instead.
52    Int32,
53    /// Protobuf int64
54    ///
55    /// # Remarks
56    ///
57    /// Uses variable-length encoding. Inefficient for encoding negative numbers – if
58    /// your field is likely to have negative values, use sint64 instead.
59    Int64,
60    /// Protobuf uint32
61    ///
62    /// # Remarks
63    ///
64    /// Uses variable-length encoding.
65    Uint32,
66    /// Protobuf uint64
67    ///
68    /// # Remarks
69    ///
70    /// Uses variable-length encoding.
71    Uint64,
72    /// Protobuf sint32
73    ///
74    /// # Remarks
75    ///
76    /// Uses ZigZag variable-length encoding. Signed int value. These more efficiently
77    /// encode negative numbers than regular int32s.
78    Sint32,
79    /// Protobuf sint64
80    ///
81    /// # Remarks
82    ///
83    /// Uses ZigZag variable-length encoding. Signed int value. These more efficiently
84    /// encode negative numbers than regular int32s.
85    Sint64,
86    /// Protobuf bool
87    Bool,
88    /// Protobuf fixed64
89    ///
90    /// # Remarks
91    ///
92    /// Always eight bytes. More efficient than uint64 if values are often greater than 2^56.
93    Fixed64,
94    /// Protobuf sfixed64
95    ///
96    /// # Remarks
97    ///
98    /// Always eight bytes.
99    Sfixed64,
100    /// Protobuf double
101    Double,
102    /// Protobuf string
103    ///
104    /// # Remarks
105    ///
106    /// A string must always contain UTF-8 encoded or 7-bit ASCII text.
107    String,
108    /// Protobuf bytes
109    ///
110    /// # Remarks
111    ///
112    /// May contain any arbitrary sequence of bytes.
113    Bytes,
114    /// Protobut fixed32
115    ///
116    /// # Remarks
117    ///
118    /// Always four bytes. More efficient than uint32 if values are often greater than 2^28.
119    Fixed32,
120    /// Protobut sfixed32
121    ///
122    /// # Remarks
123    ///
124    /// Always four bytes.
125    Sfixed32,
126    /// Protobut float
127    Float,
128    /// Protobuf message or enum (holds the name)
129    MessageOrEnum(String),
130    /// Protobut map
131    Map(Box<(FieldType, FieldType)>),
132    /// Protobuf group (deprecated)
133    Group(Vec<Field>),
134}
135
136/// A Protobuf Field
137#[derive(Debug, Clone, Hash, Eq, PartialEq)]
138pub struct Field {
139    /// Field name
140    pub name: String,
141    /// Field `Rule`
142    pub rule: Rule,
143    /// Field type
144    pub typ: FieldType,
145    /// Tag number
146    pub number: i32,
147    /// Default value for the field
148    pub default: Option<String>,
149    /// Packed property for repeated fields
150    pub packed: Option<bool>,
151    /// Is the field deprecated
152    pub deprecated: bool,
153}
154
155/// A protobuf message
156#[derive(Debug, Clone, Default)]
157pub struct Message {
158    /// Message name
159    pub name: String,
160    /// Message `Field`s
161    pub fields: Vec<Field>,
162    /// Message `OneOf`s
163    pub oneofs: Vec<OneOf>,
164    /// Message reserved numbers
165    ///
166    /// TODO: use RangeInclusive once stable
167    pub reserved_nums: Vec<Range<i32>>,
168    /// Message reserved names
169    pub reserved_names: Vec<String>,
170    /// Nested messages
171    pub messages: Vec<Message>,
172    /// Nested enums
173    pub enums: Vec<Enumeration>,
174}
175
176/// A protobuf enumeration field
177#[derive(Debug, Clone)]
178pub struct EnumValue {
179    /// enum value name
180    pub name: String,
181    /// enum value number
182    pub number: i32,
183}
184
185/// A protobuf enumerator
186#[derive(Debug, Clone)]
187pub struct Enumeration {
188    /// enum name
189    pub name: String,
190    /// enum values
191    pub values: Vec<EnumValue>,
192}
193
194/// A OneOf
195#[derive(Debug, Clone, Default)]
196pub struct OneOf {
197    /// OneOf name
198    pub name: String,
199    /// OneOf fields
200    pub fields: Vec<Field>,
201}
202
203#[derive(Debug, Clone)]
204pub struct Extension {
205    /// Extend this type with field
206    pub extendee: String,
207    /// Extension field
208    pub field: Field,
209}
210
211/// A File descriptor representing a whole .proto file
212#[derive(Debug, Default, Clone)]
213pub struct FileDescriptor {
214    /// Imports
215    pub import_paths: Vec<String>,
216    /// Package
217    pub package: String,
218    /// Protobuf Syntax
219    pub syntax: Syntax,
220    /// Top level messages
221    pub messages: Vec<Message>,
222    /// Enums
223    pub enums: Vec<Enumeration>,
224    /// Extensions
225    pub extensions: Vec<Extension>,
226}
227
228impl FileDescriptor {
229    /// Parses a .proto file content into a `FileDescriptor`
230    pub fn parse<S: AsRef<[u8]>>(file: S) -> Result<Self, ::nom::IError> {
231        let file = file.as_ref();
232        match file_descriptor(file) {
233            ::nom::IResult::Done(unparsed, r) => {
234                if !unparsed.is_empty() {
235                    // TODO: make error detection part of parser and report position
236                    Err(::nom::IError::Error(::nom::ErrorKind::NoneOf))
237                } else {
238                    Ok(r)
239                }
240            }
241            o => o.to_full_result(),
242        }
243    }
244}