1 use protobuf::descriptor::FileDescriptorProto; 2 use protobuf::descriptor::DescriptorProto; 3 use protobuf::descriptor::EnumDescriptorProto; 4 use protobuf::descriptor::EnumValueDescriptorProto; 5 use protobuf::descriptor::FieldDescriptorProto; 6 use protobuf::descriptor::OneofDescriptorProto; 7 use rust_name::RustIdent; 8 use rust_name::RustRelativePath; 9 use rust_name::RustIdentWithPath; 10 use strx::capitalize; 11 use rust::is_rust_keyword; 12 use file::proto_path_to_rust_mod; 13 use syntax::Syntax; 14 use ::{rust, Customize}; 15 use message::message_name_to_nested_mod_name; 16 use protobuf_name::ProtobufAbsolutePath; 17 use protobuf_name::ProtobufRelativePath; 18 use protobuf_name::ProtobufIdent; 19 use field::rust_field_name_for_protobuf_field_name; 20 use file_and_mod::FileAndMod; 21 22 23 pub(crate) struct RootScope<'a> { 24 pub file_descriptors: &'a [FileDescriptorProto], 25 } 26 27 impl<'a> RootScope<'a> { packages(&'a self) -> Vec<FileScope<'a>>28 fn packages(&'a self) -> Vec<FileScope<'a>> { 29 self.file_descriptors 30 .iter() 31 .map(|fd| FileScope { 32 file_descriptor: fd, 33 }).collect() 34 } 35 36 // find enum by fully qualified name _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a>37 pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> { 38 match self.find_message_or_enum(fqn) { 39 MessageOrEnumWithScope::Enum(e) => e, 40 _ => panic!("not an enum: {}", fqn), 41 } 42 } 43 44 // find message by fully qualified name find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a>45 pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> { 46 match self.find_message_or_enum(fqn) { 47 MessageOrEnumWithScope::Message(m) => m, 48 _ => panic!("not a message: {}", fqn), 49 } 50 } 51 52 // find message or enum by fully qualified name find_message_or_enum(&'a self, fqn: &ProtobufAbsolutePath) -> MessageOrEnumWithScope<'a>53 pub fn find_message_or_enum(&'a self, fqn: &ProtobufAbsolutePath) -> MessageOrEnumWithScope<'a> { 54 assert!(!fqn.is_empty()); 55 self.packages() 56 .into_iter() 57 .flat_map(|p| { 58 p.find_message_or_enum_abs(fqn) 59 }).next() 60 .expect(&format!("enum not found by name: {}", fqn)) 61 } 62 } 63 64 #[derive(Clone, Debug)] 65 pub(crate) struct FileScope<'a> { 66 pub file_descriptor: &'a FileDescriptorProto, 67 } 68 69 impl<'a> FileScope<'a> { get_package(&self) -> ProtobufAbsolutePath70 fn get_package(&self) -> ProtobufAbsolutePath { 71 ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute() 72 } 73 syntax(&self) -> Syntax74 pub fn syntax(&self) -> Syntax { 75 Syntax::parse(self.file_descriptor.get_syntax()) 76 } 77 to_scope(&self) -> Scope<'a>78 pub fn to_scope(&self) -> Scope<'a> { 79 Scope { 80 file_scope: self.clone(), 81 path: Vec::new(), 82 } 83 } 84 find_message_or_enum(&self, name: &ProtobufRelativePath) -> Option<MessageOrEnumWithScope<'a>>85 fn find_message_or_enum(&self, name: &ProtobufRelativePath) -> Option<MessageOrEnumWithScope<'a>> { 86 self.find_messages_and_enums() 87 .into_iter() 88 .filter(|e| e.protobuf_name_to_package() == *name) 89 .next() 90 } 91 find_message_or_enum_abs(&self, name: &ProtobufAbsolutePath) -> Option<MessageOrEnumWithScope<'a>>92 fn find_message_or_enum_abs(&self, name: &ProtobufAbsolutePath) -> Option<MessageOrEnumWithScope<'a>> { 93 match name.remove_prefix(&self.get_package()) { 94 Some(ref rem) => self.find_message_or_enum(rem), 95 None => None, 96 } 97 } 98 99 // find all enums in given file descriptor _find_enums(&self) -> Vec<EnumWithScope<'a>>100 pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> { 101 let mut r = Vec::new(); 102 103 self.to_scope().walk_scopes(|scope| { 104 r.extend(scope.get_enums()); 105 }); 106 107 r 108 } 109 110 // find all messages in given file descriptor _find_messages(&self) -> Vec<MessageWithScope<'a>>111 pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> { 112 let mut r = Vec::new(); 113 114 self.to_scope().walk_scopes(|scope| { 115 r.extend(scope.get_messages()); 116 }); 117 118 r 119 } 120 121 // find all messages and enums in given file descriptor find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>122 pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 123 let mut r = Vec::new(); 124 125 self.to_scope().walk_scopes(|scope| { 126 r.extend(scope.get_messages_and_enums()); 127 }); 128 129 r 130 } 131 } 132 133 #[derive(Clone, Debug)] 134 pub(crate) struct Scope<'a> { 135 pub file_scope: FileScope<'a>, 136 pub path: Vec<&'a DescriptorProto>, 137 } 138 139 impl<'a> Scope<'a> { get_file_descriptor(&self) -> &'a FileDescriptorProto140 pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto { 141 self.file_scope.file_descriptor 142 } 143 144 // get message descriptors in this scope get_message_descriptors(&self) -> &'a [DescriptorProto]145 fn get_message_descriptors(&self) -> &'a [DescriptorProto] { 146 if self.path.is_empty() { 147 &self.file_scope.file_descriptor.message_type 148 } else { 149 &self.path.last().unwrap().nested_type 150 } 151 } 152 153 // get enum descriptors in this scope get_enum_descriptors(&self) -> &'a [EnumDescriptorProto]154 fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] { 155 if self.path.is_empty() { 156 &self.file_scope.file_descriptor.enum_type 157 } else { 158 &self.path.last().unwrap().enum_type 159 } 160 } 161 162 // get messages with attached scopes in this scope get_messages(&self) -> Vec<MessageWithScope<'a>>163 pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> { 164 self.get_message_descriptors() 165 .iter() 166 .map(|m| MessageWithScope { 167 scope: self.clone(), 168 message: m, 169 }).collect() 170 } 171 172 // get enums with attached scopes in this scope get_enums(&self) -> Vec<EnumWithScope<'a>>173 pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> { 174 self.get_enum_descriptors() 175 .iter() 176 .map(|e| EnumWithScope { 177 scope: self.clone(), 178 en: e, 179 }).collect() 180 } 181 182 // get messages and enums with attached scopes in this scope get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>183 pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 184 self.get_messages() 185 .into_iter() 186 .map(|m| MessageOrEnumWithScope::Message(m)) 187 .chain( 188 self.get_enums() 189 .into_iter() 190 .map(|m| MessageOrEnumWithScope::Enum(m)), 191 ).collect() 192 } 193 194 // nested scopes, i. e. scopes of nested messages nested_scopes(&self) -> Vec<Scope<'a>>195 fn nested_scopes(&self) -> Vec<Scope<'a>> { 196 self.get_message_descriptors() 197 .iter() 198 .map(|m| { 199 let mut nested = self.clone(); 200 nested.path.push(m); 201 nested 202 }).collect() 203 } 204 walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)205 fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) { 206 (*callback)(self); 207 208 for nested in self.nested_scopes() { 209 nested.walk_scopes_impl(callback); 210 } 211 } 212 213 // apply callback for this scope and all nested scopes walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),214 fn walk_scopes<F>(&self, mut callback: F) 215 where 216 F: FnMut(&Scope<'a>), 217 { 218 self.walk_scopes_impl(&mut callback); 219 } 220 rust_path_to_file(&self) -> RustRelativePath221 pub fn rust_path_to_file(&self) -> RustRelativePath { 222 RustRelativePath::from_components( 223 self.path.iter().map(|m| message_name_to_nested_mod_name(m.get_name()))) 224 } 225 path_str(&self) -> String226 pub fn path_str(&self) -> String { 227 let v: Vec<&str> = self.path.iter().map(|m| m.get_name()).collect(); 228 v.join(".") 229 } 230 prefix(&self) -> String231 pub fn prefix(&self) -> String { 232 let path_str = self.path_str(); 233 if path_str.is_empty() { 234 path_str 235 } else { 236 format!("{}.", path_str) 237 } 238 } 239 protobuf_path_to_file(&self) -> ProtobufRelativePath240 pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath { 241 ProtobufRelativePath::from_components(self.path.iter().map(|m| ProtobufIdent::from(m.get_name()))) 242 } 243 protobuf_absolute_path(&self) -> ProtobufAbsolutePath244 pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath { 245 let mut r = self.file_scope.get_package(); 246 r.push_relative(&self.protobuf_path_to_file()); 247 r 248 } 249 get_file_and_mod(&self, customize: Customize) -> FileAndMod250 pub fn get_file_and_mod(&self, customize: Customize) -> FileAndMod { 251 FileAndMod { 252 file: self.file_scope.file_descriptor.get_name().to_owned(), 253 relative_mod: self.rust_path_to_file(), 254 customize, 255 } 256 } 257 } 258 259 pub(crate) trait WithScope<'a> { get_scope(&self) -> &Scope<'a>260 fn get_scope(&self) -> &Scope<'a>; 261 get_file_descriptor(&self) -> &'a FileDescriptorProto262 fn get_file_descriptor(&self) -> &'a FileDescriptorProto { 263 self.get_scope().get_file_descriptor() 264 } 265 266 // message or enum name get_name(&self) -> ProtobufIdent267 fn get_name(&self) -> ProtobufIdent; 268 escape_prefix(&self) -> &'static str269 fn escape_prefix(&self) -> &'static str; 270 name_to_package(&self) -> String271 fn name_to_package(&self) -> String { 272 let mut r = self.get_scope().prefix(); 273 r.push_str(self.get_name().get()); 274 r 275 } 276 protobuf_name_to_package(&self) -> ProtobufRelativePath277 fn protobuf_name_to_package(&self) -> ProtobufRelativePath { 278 let r = self.get_scope().protobuf_path_to_file(); 279 r.append_ident(&ProtobufIdent::from(self.get_name())) 280 } 281 282 /// Return absolute name starting with dot name_absolute(&self) -> ProtobufAbsolutePath283 fn name_absolute(&self) -> ProtobufAbsolutePath { 284 let mut path = self.get_scope().protobuf_absolute_path(); 285 path.push_simple(self.get_name()); 286 path 287 } 288 289 // rust type name of this descriptor rust_name(&self) -> RustIdent290 fn rust_name(&self) -> RustIdent { 291 let mut rust_name = capitalize(self.get_name().get()); 292 293 if is_rust_keyword(&rust_name) { 294 rust_name.insert_str(0, self.escape_prefix()); 295 } 296 297 RustIdent::new(&rust_name) 298 } 299 rust_name_to_file(&self) -> RustIdentWithPath300 fn rust_name_to_file(&self) -> RustIdentWithPath { 301 self.get_scope().rust_path_to_file().into_path().with_ident(self.rust_name()) 302 } 303 304 // fully-qualified name of this type rust_name_with_file(&self) -> RustIdentWithPath305 fn rust_name_with_file(&self) -> RustIdentWithPath { 306 let mut r = self.rust_name_to_file(); 307 r.prepend_ident(proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name())); 308 r 309 } 310 } 311 312 #[derive(Clone, Debug)] 313 pub(crate) struct MessageWithScope<'a> { 314 pub scope: Scope<'a>, 315 pub message: &'a DescriptorProto, 316 } 317 318 impl<'a> WithScope<'a> for MessageWithScope<'a> { get_scope(&self) -> &Scope<'a>319 fn get_scope(&self) -> &Scope<'a> { 320 &self.scope 321 } 322 escape_prefix(&self) -> &'static str323 fn escape_prefix(&self) -> &'static str { 324 "message_" 325 } 326 get_name(&self) -> ProtobufIdent327 fn get_name(&self) -> ProtobufIdent { 328 ProtobufIdent::from(self.message.get_name()) 329 } 330 } 331 332 impl<'a> MessageWithScope<'a> { into_scope(mut self) -> Scope<'a>333 pub fn into_scope(mut self) -> Scope<'a> { 334 self.scope.path.push(self.message); 335 self.scope 336 } 337 to_scope(&self) -> Scope<'a>338 pub fn to_scope(&self) -> Scope<'a> { 339 self.clone().into_scope() 340 } 341 fields(&self) -> Vec<FieldWithContext<'a>>342 pub fn fields(&self) -> Vec<FieldWithContext<'a>> { 343 self.message 344 .field 345 .iter() 346 .map(|f| FieldWithContext { 347 field: f, 348 message: self.clone(), 349 }).collect() 350 } 351 oneofs(&self) -> Vec<OneofWithContext<'a>>352 pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> { 353 self.message 354 .oneof_decl 355 .iter() 356 .enumerate() 357 .map(|(index, oneof)| OneofWithContext { 358 message: self.clone(), 359 oneof: oneof, 360 index: index as u32, 361 }).collect() 362 } 363 oneof_by_index(&self, index: u32) -> OneofWithContext<'a>364 pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> { 365 self.oneofs().swap_remove(index as usize) 366 } 367 mod_name(&self) -> RustIdent368 pub fn mod_name(&self) -> RustIdent { 369 message_name_to_nested_mod_name(self.message.get_name()) 370 } 371 } 372 373 #[derive(Clone, Debug)] 374 pub(crate) struct EnumWithScope<'a> { 375 pub scope: Scope<'a>, 376 pub en: &'a EnumDescriptorProto, 377 } 378 379 impl<'a> EnumWithScope<'a> { values(&self) -> Vec<EnumValueWithContext<'a>>380 pub fn values(&self) -> Vec<EnumValueWithContext<'a>> { 381 self.en.value.iter() 382 .map(|v| { 383 EnumValueWithContext { 384 en: self.clone(), 385 proto: v, 386 } 387 }) 388 .collect() 389 } 390 391 // find enum value by protobuf name value_by_name(&self, name: &str) -> EnumValueWithContext<'a>392 pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> { 393 self.values().into_iter().find(|v| v.proto.get_name() == name).unwrap() 394 } 395 } 396 397 #[derive(Clone, Debug)] 398 pub(crate) struct EnumValueWithContext<'a> { 399 pub en: EnumWithScope<'a>, 400 pub proto: &'a EnumValueDescriptorProto, 401 } 402 403 impl<'a> EnumValueWithContext<'a> { rust_name(&self) -> RustIdent404 pub fn rust_name(&self) -> RustIdent { 405 let mut r = String::new(); 406 if rust::is_rust_keyword(self.proto.get_name()) { 407 r.push_str("value_"); 408 } 409 r.push_str(self.proto.get_name()); 410 RustIdent::new(&r) 411 } 412 } 413 414 impl<'a> WithScope<'a> for EnumWithScope<'a> { get_scope(&self) -> &Scope<'a>415 fn get_scope(&self) -> &Scope<'a> { 416 &self.scope 417 } 418 get_name(&self) -> ProtobufIdent419 fn get_name(&self) -> ProtobufIdent { 420 ProtobufIdent::from(self.en.get_name()) 421 } 422 escape_prefix(&self) -> &'static str423 fn escape_prefix(&self) -> &'static str { 424 "enum_" 425 } 426 } 427 428 pub(crate) enum MessageOrEnumWithScope<'a> { 429 Message(MessageWithScope<'a>), 430 Enum(EnumWithScope<'a>), 431 } 432 433 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> { get_scope(&self) -> &Scope<'a>434 fn get_scope(&self) -> &Scope<'a> { 435 match self { 436 &MessageOrEnumWithScope::Message(ref m) => m.get_scope(), 437 &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(), 438 } 439 } 440 escape_prefix(&self) -> &'static str441 fn escape_prefix(&self) -> &'static str { 442 match self { 443 &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(), 444 &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(), 445 } 446 } 447 get_name(&self) -> ProtobufIdent448 fn get_name(&self) -> ProtobufIdent { 449 match self { 450 &MessageOrEnumWithScope::Message(ref m) => m.get_name(), 451 &MessageOrEnumWithScope::Enum(ref e) => e.get_name(), 452 } 453 } 454 } 455 456 #[derive(Clone)] 457 pub(crate) struct FieldWithContext<'a> { 458 pub field: &'a FieldDescriptorProto, 459 pub message: MessageWithScope<'a>, 460 } 461 462 impl<'a> FieldWithContext<'a> { is_oneof(&self) -> bool463 pub fn is_oneof(&self) -> bool { 464 self.field.has_oneof_index() 465 } 466 oneof(&self) -> Option<OneofWithContext<'a>>467 pub fn oneof(&self) -> Option<OneofWithContext<'a>> { 468 if self.is_oneof() { 469 Some( 470 self.message 471 .oneof_by_index(self.field.get_oneof_index() as u32), 472 ) 473 } else { 474 None 475 } 476 } 477 number(&self) -> u32478 pub fn number(&self) -> u32 { 479 self.field.get_number() as u32 480 } 481 rust_name(&self) -> RustIdent482 pub fn rust_name(&self) -> RustIdent { 483 rust_field_name_for_protobuf_field_name(self.name()) 484 } 485 486 /// Shortcut name(&self) -> &str487 pub fn name(&self) -> &str { 488 self.field.get_name() 489 } 490 491 // From field to file root _containing_messages(&self) -> Vec<&'a DescriptorProto>492 pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> { 493 let mut r = Vec::new(); 494 r.push(self.message.message); 495 r.extend(self.message.scope.path.iter().rev()); 496 r 497 } 498 } 499 500 #[derive(Clone)] 501 pub(crate) struct OneofVariantWithContext<'a> { 502 pub oneof: &'a OneofWithContext<'a>, 503 pub field: &'a FieldDescriptorProto, 504 } 505 506 #[derive(Clone)] 507 pub(crate) struct OneofWithContext<'a> { 508 pub oneof: &'a OneofDescriptorProto, 509 pub index: u32, 510 pub message: MessageWithScope<'a>, 511 } 512 513 impl<'a> OneofWithContext<'a> { field_name(&'a self) -> RustIdent514 pub fn field_name(&'a self) -> RustIdent { 515 return rust_field_name_for_protobuf_field_name(self.oneof.get_name()) 516 } 517 518 // rust type name of enum rust_name(&self) -> RustIdentWithPath519 pub fn rust_name(&self) -> RustIdentWithPath { 520 // TODO: escape name 521 let type_name = RustIdent::from(capitalize(self.oneof.get_name())); 522 self.message.to_scope().rust_path_to_file() 523 .into_path() 524 .with_ident(type_name) 525 } 526 variants(&'a self) -> Vec<OneofVariantWithContext<'a>>527 pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> { 528 self.message 529 .fields() 530 .iter() 531 .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32) 532 .map(|f| OneofVariantWithContext { 533 oneof: self, 534 field: &f.field, 535 }).collect() 536 } 537 } 538 539