1 use protobuf::descriptor::DescriptorProto; 2 use protobuf::descriptor::EnumDescriptorProto; 3 use protobuf::descriptor::EnumValueDescriptorProto; 4 use protobuf::descriptor::FieldDescriptorProto; 5 use protobuf::descriptor::FileDescriptorProto; 6 use protobuf::descriptor::OneofDescriptorProto; 7 8 use crate::field::rust_field_name_for_protobuf_field_name; 9 use crate::file::proto_path_to_rust_mod; 10 use crate::protobuf_name::ProtobufAbsolutePath; 11 use crate::protobuf_name::ProtobufIdent; 12 use crate::protobuf_name::ProtobufRelativePath; 13 use crate::rust; 14 use crate::rust_name::RustIdent; 15 use crate::rust_name::RustIdentWithPath; 16 use crate::syntax::Syntax; 17 18 pub(crate) struct RootScope<'a> { 19 pub file_descriptors: &'a [FileDescriptorProto], 20 } 21 22 impl<'a> RootScope<'a> { packages(&'a self) -> Vec<FileScope<'a>>23 fn packages(&'a self) -> Vec<FileScope<'a>> { 24 self.file_descriptors 25 .iter() 26 .map(|fd| FileScope { 27 file_descriptor: fd, 28 }) 29 .collect() 30 } 31 32 // find enum by fully qualified name _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a>33 pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> { 34 match self.find_message_or_enum(fqn) { 35 MessageOrEnumWithScope::Enum(e) => e, 36 _ => panic!("not an enum: {}", fqn), 37 } 38 } 39 40 // find message by fully qualified name find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a>41 pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> { 42 match self.find_message_or_enum(fqn) { 43 MessageOrEnumWithScope::Message(m) => m, 44 _ => panic!("not a message: {}", fqn), 45 } 46 } 47 48 // find message or enum by fully qualified name find_message_or_enum( &'a self, fqn: &ProtobufAbsolutePath, ) -> MessageOrEnumWithScope<'a>49 pub fn find_message_or_enum( 50 &'a self, 51 fqn: &ProtobufAbsolutePath, 52 ) -> MessageOrEnumWithScope<'a> { 53 assert!(!fqn.is_empty()); 54 self.packages() 55 .into_iter() 56 .flat_map(|p| p.find_message_or_enum_abs(fqn)) 57 .next() 58 .expect(&format!("enum not found by name: {}", fqn)) 59 } 60 } 61 62 #[derive(Clone, Debug)] 63 pub(crate) struct FileScope<'a> { 64 pub file_descriptor: &'a FileDescriptorProto, 65 } 66 67 impl<'a> FileScope<'a> { get_package(&self) -> ProtobufAbsolutePath68 fn get_package(&self) -> ProtobufAbsolutePath { 69 ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute() 70 } 71 syntax(&self) -> Syntax72 pub fn syntax(&self) -> Syntax { 73 Syntax::parse(self.file_descriptor.get_syntax()) 74 } 75 to_scope(&self) -> Scope<'a>76 pub fn to_scope(&self) -> Scope<'a> { 77 Scope { 78 file_scope: self.clone(), 79 path: Vec::new(), 80 } 81 } 82 find_message_or_enum( &self, name: &ProtobufRelativePath, ) -> Option<MessageOrEnumWithScope<'a>>83 fn find_message_or_enum( 84 &self, 85 name: &ProtobufRelativePath, 86 ) -> Option<MessageOrEnumWithScope<'a>> { 87 self.find_messages_and_enums() 88 .into_iter() 89 .filter(|e| e.protobuf_name_to_package() == *name) 90 .next() 91 } 92 find_message_or_enum_abs( &self, name: &ProtobufAbsolutePath, ) -> Option<MessageOrEnumWithScope<'a>>93 fn find_message_or_enum_abs( 94 &self, 95 name: &ProtobufAbsolutePath, 96 ) -> Option<MessageOrEnumWithScope<'a>> { 97 match name.remove_prefix(&self.get_package()) { 98 Some(ref rem) => self.find_message_or_enum(rem), 99 None => None, 100 } 101 } 102 103 // find all enums in given file descriptor _find_enums(&self) -> Vec<EnumWithScope<'a>>104 pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> { 105 let mut r = Vec::new(); 106 107 self.to_scope().walk_scopes(|scope| { 108 r.extend(scope.get_enums()); 109 }); 110 111 r 112 } 113 114 // find all messages in given file descriptor _find_messages(&self) -> Vec<MessageWithScope<'a>>115 pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> { 116 let mut r = Vec::new(); 117 118 self.to_scope().walk_scopes(|scope| { 119 r.extend(scope.get_messages()); 120 }); 121 122 r 123 } 124 125 // find all messages and enums in given file descriptor find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>126 pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 127 let mut r = Vec::new(); 128 129 self.to_scope().walk_scopes(|scope| { 130 r.extend(scope.get_messages_and_enums()); 131 }); 132 133 r 134 } 135 } 136 137 #[derive(Clone, Debug)] 138 pub(crate) struct Scope<'a> { 139 pub file_scope: FileScope<'a>, 140 pub path: Vec<&'a DescriptorProto>, 141 } 142 143 impl<'a> Scope<'a> { get_file_descriptor(&self) -> &'a FileDescriptorProto144 pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto { 145 self.file_scope.file_descriptor 146 } 147 148 // get message descriptors in this scope get_message_descriptors(&self) -> &'a [DescriptorProto]149 fn get_message_descriptors(&self) -> &'a [DescriptorProto] { 150 if self.path.is_empty() { 151 &self.file_scope.file_descriptor.get_message_type() 152 } else { 153 &self.path.last().unwrap().get_nested_type() 154 } 155 } 156 157 // get enum descriptors in this scope get_enum_descriptors(&self) -> &'a [EnumDescriptorProto]158 fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] { 159 if self.path.is_empty() { 160 &self.file_scope.file_descriptor.get_enum_type() 161 } else { 162 &self.path.last().unwrap().get_enum_type() 163 } 164 } 165 166 // get messages with attached scopes in this scope get_messages(&self) -> Vec<MessageWithScope<'a>>167 pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> { 168 self.get_message_descriptors() 169 .iter() 170 .map(|m| MessageWithScope { 171 scope: self.clone(), 172 message: m, 173 }) 174 .collect() 175 } 176 177 // get enums with attached scopes in this scope get_enums(&self) -> Vec<EnumWithScope<'a>>178 pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> { 179 self.get_enum_descriptors() 180 .iter() 181 .map(|e| EnumWithScope { 182 scope: self.clone(), 183 en: e, 184 }) 185 .collect() 186 } 187 188 // get messages and enums with attached scopes in this scope get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>189 pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 190 self.get_messages() 191 .into_iter() 192 .map(|m| MessageOrEnumWithScope::Message(m)) 193 .chain( 194 self.get_enums() 195 .into_iter() 196 .map(|m| MessageOrEnumWithScope::Enum(m)), 197 ) 198 .collect() 199 } 200 201 // nested scopes, i. e. scopes of nested messages nested_scopes(&self) -> Vec<Scope<'a>>202 fn nested_scopes(&self) -> Vec<Scope<'a>> { 203 self.get_message_descriptors() 204 .iter() 205 .map(|m| { 206 let mut nested = self.clone(); 207 nested.path.push(m); 208 nested 209 }) 210 .collect() 211 } 212 walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)213 fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) { 214 (*callback)(self); 215 216 for nested in self.nested_scopes() { 217 nested.walk_scopes_impl(callback); 218 } 219 } 220 221 // apply callback for this scope and all nested scopes walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),222 fn walk_scopes<F>(&self, mut callback: F) 223 where 224 F: FnMut(&Scope<'a>), 225 { 226 self.walk_scopes_impl(&mut callback); 227 } 228 prefix(&self) -> String229 pub fn prefix(&self) -> String { 230 if self.path.is_empty() { 231 "".to_string() 232 } else { 233 let v: Vec<&'a str> = self.path.iter().map(|m| m.get_name()).collect(); 234 let mut r = v.join("."); 235 r.push_str("."); 236 r 237 } 238 } 239 protobuf_path_to_file(&self) -> ProtobufRelativePath240 pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath { 241 ProtobufRelativePath::from_components( 242 self.path.iter().map(|m| ProtobufIdent::from(m.get_name())), 243 ) 244 } 245 protobuf_absolute_path(&self) -> ProtobufAbsolutePath246 pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath { 247 let mut r = self.file_scope.get_package(); 248 r.push_relative(&self.protobuf_path_to_file()); 249 r 250 } 251 252 // rust type name prefix for this scope rust_prefix(&self) -> String253 pub fn rust_prefix(&self) -> String { 254 self.prefix().replace(".", "_") 255 } 256 } 257 258 pub(crate) trait WithScope<'a> { get_scope(&self) -> &Scope<'a>259 fn get_scope(&self) -> &Scope<'a>; 260 get_file_descriptor(&self) -> &'a FileDescriptorProto261 fn get_file_descriptor(&self) -> &'a FileDescriptorProto { 262 self.get_scope().get_file_descriptor() 263 } 264 265 // message or enum name get_name(&self) -> ProtobufIdent266 fn get_name(&self) -> ProtobufIdent; 267 escape_prefix(&self) -> &'static str268 fn escape_prefix(&self) -> &'static str; 269 name_to_package(&self) -> String270 fn name_to_package(&self) -> String { 271 let mut r = self.get_scope().prefix(); 272 r.push_str(self.get_name().get()); 273 r 274 } 275 protobuf_name_to_package(&self) -> ProtobufRelativePath276 fn protobuf_name_to_package(&self) -> ProtobufRelativePath { 277 let r = self.get_scope().protobuf_path_to_file(); 278 r.append_ident(&ProtobufIdent::from(self.get_name())) 279 } 280 281 /// Return absolute name starting with dot name_absolute(&self) -> ProtobufAbsolutePath282 fn name_absolute(&self) -> ProtobufAbsolutePath { 283 let mut path = self.get_scope().protobuf_absolute_path(); 284 path.push_simple(self.get_name()); 285 path 286 } 287 288 // rust type name of this descriptor rust_name(&self) -> RustIdent289 fn rust_name(&self) -> RustIdent { 290 let mut r = self.get_scope().rust_prefix(); 291 // Only escape if prefix is not empty 292 if r.is_empty() && rust::is_rust_keyword(self.get_name().get()) { 293 r.push_str(self.escape_prefix()); 294 } 295 r.push_str(self.get_name().get()); 296 RustIdent::from(r) 297 } 298 299 // fully-qualified name of this type rust_fq_name(&self) -> String300 fn rust_fq_name(&self) -> String { 301 format!( 302 "{}::{}", 303 proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()), 304 self.rust_name() 305 ) 306 } 307 } 308 309 #[derive(Clone, Debug)] 310 pub(crate) struct MessageWithScope<'a> { 311 pub scope: Scope<'a>, 312 pub message: &'a DescriptorProto, 313 } 314 315 impl<'a> WithScope<'a> for MessageWithScope<'a> { get_scope(&self) -> &Scope<'a>316 fn get_scope(&self) -> &Scope<'a> { 317 &self.scope 318 } 319 escape_prefix(&self) -> &'static str320 fn escape_prefix(&self) -> &'static str { 321 "message_" 322 } 323 get_name(&self) -> ProtobufIdent324 fn get_name(&self) -> ProtobufIdent { 325 ProtobufIdent::from(self.message.get_name()) 326 } 327 } 328 329 impl<'a> MessageWithScope<'a> { into_scope(mut self) -> Scope<'a>330 pub fn into_scope(mut self) -> Scope<'a> { 331 self.scope.path.push(self.message); 332 self.scope 333 } 334 to_scope(&self) -> Scope<'a>335 pub fn to_scope(&self) -> Scope<'a> { 336 self.clone().into_scope() 337 } 338 fields(&self) -> Vec<FieldWithContext<'a>>339 pub fn fields(&self) -> Vec<FieldWithContext<'a>> { 340 self.message 341 .get_field() 342 .iter() 343 .map(|f| FieldWithContext { 344 field: f, 345 message: self.clone(), 346 }) 347 .collect() 348 } 349 oneofs(&self) -> Vec<OneofWithContext<'a>>350 pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> { 351 self.message 352 .get_oneof_decl() 353 .iter() 354 .enumerate() 355 .map(|(index, oneof)| OneofWithContext { 356 message: self.clone(), 357 oneof: oneof, 358 index: index as u32, 359 }) 360 .collect() 361 } 362 oneof_by_index(&self, index: u32) -> OneofWithContext<'a>363 pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> { 364 self.oneofs().swap_remove(index as usize) 365 } 366 367 /// Pair of (key, value) if this message is map entry map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)>368 pub fn map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)> { 369 if self.message.get_options().get_map_entry() { 370 let key = self 371 .fields() 372 .into_iter() 373 .find(|f| f.field.get_number() == 1) 374 .unwrap(); 375 let value = self 376 .fields() 377 .into_iter() 378 .find(|f| f.field.get_number() == 2) 379 .unwrap(); 380 Some((key, value)) 381 } else { 382 None 383 } 384 } 385 } 386 387 #[derive(Clone, Debug)] 388 pub(crate) struct EnumWithScope<'a> { 389 pub scope: Scope<'a>, 390 pub en: &'a EnumDescriptorProto, 391 } 392 393 impl<'a> EnumWithScope<'a> { values(&self) -> Vec<EnumValueWithContext<'a>>394 pub fn values(&self) -> Vec<EnumValueWithContext<'a>> { 395 self.en 396 .get_value() 397 .iter() 398 .map(|v| EnumValueWithContext { 399 _en: self.clone(), 400 proto: v, 401 }) 402 .collect() 403 } 404 405 // find enum value by protobuf name value_by_name(&self, name: &str) -> EnumValueWithContext<'a>406 pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> { 407 self.values() 408 .into_iter() 409 .find(|v| v.proto.get_name() == name) 410 .unwrap() 411 } 412 } 413 414 #[derive(Clone, Debug)] 415 pub(crate) struct EnumValueWithContext<'a> { 416 _en: EnumWithScope<'a>, 417 pub proto: &'a EnumValueDescriptorProto, 418 } 419 420 impl<'a> EnumValueWithContext<'a> { rust_name(&self) -> RustIdent421 pub fn rust_name(&self) -> RustIdent { 422 let mut r = String::new(); 423 if rust::is_rust_keyword(self.proto.get_name()) { 424 r.push_str("value_"); 425 } 426 r.push_str(self.proto.get_name()); 427 RustIdent::new(&r) 428 } 429 } 430 431 impl<'a> WithScope<'a> for EnumWithScope<'a> { get_scope(&self) -> &Scope<'a>432 fn get_scope(&self) -> &Scope<'a> { 433 &self.scope 434 } 435 escape_prefix(&self) -> &'static str436 fn escape_prefix(&self) -> &'static str { 437 "enum_" 438 } 439 get_name(&self) -> ProtobufIdent440 fn get_name(&self) -> ProtobufIdent { 441 ProtobufIdent::from(self.en.get_name()) 442 } 443 } 444 445 pub(crate) enum MessageOrEnumWithScope<'a> { 446 Message(MessageWithScope<'a>), 447 Enum(EnumWithScope<'a>), 448 } 449 450 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> { get_scope(&self) -> &Scope<'a>451 fn get_scope(&self) -> &Scope<'a> { 452 match self { 453 &MessageOrEnumWithScope::Message(ref m) => m.get_scope(), 454 &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(), 455 } 456 } 457 escape_prefix(&self) -> &'static str458 fn escape_prefix(&self) -> &'static str { 459 match self { 460 &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(), 461 &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(), 462 } 463 } 464 get_name(&self) -> ProtobufIdent465 fn get_name(&self) -> ProtobufIdent { 466 match self { 467 &MessageOrEnumWithScope::Message(ref m) => m.get_name(), 468 &MessageOrEnumWithScope::Enum(ref e) => e.get_name(), 469 } 470 } 471 } 472 473 #[derive(Clone)] 474 pub(crate) struct FieldWithContext<'a> { 475 pub field: &'a FieldDescriptorProto, 476 pub message: MessageWithScope<'a>, 477 } 478 479 impl<'a> FieldWithContext<'a> { is_oneof(&self) -> bool480 pub fn is_oneof(&self) -> bool { 481 self.field.has_oneof_index() 482 } 483 oneof(&self) -> Option<OneofWithContext<'a>>484 pub fn oneof(&self) -> Option<OneofWithContext<'a>> { 485 if self.is_oneof() { 486 Some( 487 self.message 488 .oneof_by_index(self.field.get_oneof_index() as u32), 489 ) 490 } else { 491 None 492 } 493 } 494 number(&self) -> u32495 pub fn number(&self) -> u32 { 496 self.field.get_number() as u32 497 } 498 499 /// Shortcut name(&self) -> &str500 pub fn name(&self) -> &str { 501 self.field.get_name() 502 } 503 rust_name(&self) -> RustIdent504 pub fn rust_name(&self) -> RustIdent { 505 rust_field_name_for_protobuf_field_name(self.name()) 506 } 507 508 // From field to file root _containing_messages(&self) -> Vec<&'a DescriptorProto>509 pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> { 510 let mut r = Vec::new(); 511 r.push(self.message.message); 512 r.extend(self.message.scope.path.iter().rev()); 513 r 514 } 515 } 516 517 #[derive(Clone)] 518 pub(crate) struct OneofVariantWithContext<'a> { 519 pub oneof: &'a OneofWithContext<'a>, 520 pub field: &'a FieldDescriptorProto, 521 } 522 523 #[derive(Clone)] 524 pub(crate) struct OneofWithContext<'a> { 525 pub oneof: &'a OneofDescriptorProto, 526 pub index: u32, 527 pub message: MessageWithScope<'a>, 528 } 529 530 impl<'a> OneofWithContext<'a> { field_name(&'a self) -> RustIdent531 pub fn field_name(&'a self) -> RustIdent { 532 return rust_field_name_for_protobuf_field_name(self.oneof.get_name()); 533 } 534 535 // rust type name of enum rust_name(&self) -> RustIdentWithPath536 pub fn rust_name(&self) -> RustIdentWithPath { 537 RustIdentWithPath::from(format!( 538 "{}_oneof_{}", 539 self.message.rust_name(), 540 self.oneof.get_name() 541 )) 542 } 543 variants(&'a self) -> Vec<OneofVariantWithContext<'a>>544 pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> { 545 self.message 546 .fields() 547 .iter() 548 .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32) 549 .map(|f| OneofVariantWithContext { 550 oneof: self, 551 field: &f.field, 552 }) 553 .collect() 554 } 555 } 556