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