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