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}