1 use std::ops::Deref; 2 3 use protobuf::reflect::EnumDescriptor; 4 use protobuf::reflect::EnumValueDescriptor; 5 use protobuf::reflect::FieldDescriptor; 6 use protobuf::reflect::FileDescriptor; 7 use protobuf::reflect::MessageDescriptor; 8 use protobuf::reflect::OneofDescriptor; 9 use protobuf_parse::ProtobufAbsPath; 10 use protobuf_parse::ProtobufAbsPathRef; 11 use protobuf_parse::ProtobufIdentRef; 12 use protobuf_parse::ProtobufRelPath; 13 use protobuf_parse::ProtobufRelPathRef; 14 15 use crate::customize::Customize; 16 use crate::gen::field::rust_field_name_for_protobuf_field_name; 17 use crate::gen::file_and_mod::FileAndMod; 18 use crate::gen::map::map_entry; 19 use crate::gen::message::message_name_to_nested_mod_name; 20 use crate::gen::paths::proto_path_to_rust_mod; 21 use crate::gen::rust::ident::RustIdent; 22 use crate::gen::rust::ident_with_path::RustIdentWithPath; 23 use crate::gen::rust::rel_path::RustRelativePath; 24 use crate::gen::strx::capitalize; 25 26 pub(crate) struct RootScope<'a> { 27 pub file_descriptors: &'a [FileDescriptor], 28 } 29 30 impl<'a> RootScope<'a> { packages(&'a self) -> Vec<FileScope<'a>>31 fn packages(&'a self) -> Vec<FileScope<'a>> { 32 self.file_descriptors 33 .iter() 34 .map(|fd| FileScope { 35 file_descriptor: fd, 36 }) 37 .collect() 38 } 39 40 // find enum by fully qualified name _find_enum(&'a self, fqn: &ProtobufAbsPath) -> EnumWithScope<'a>41 pub fn _find_enum(&'a self, fqn: &ProtobufAbsPath) -> EnumWithScope<'a> { 42 match self.find_message_or_enum(fqn) { 43 MessageOrEnumWithScope::Enum(e) => e, 44 _ => panic!("not an enum: {}", fqn), 45 } 46 } 47 48 // find message by fully qualified name find_message(&'a self, fqn: &ProtobufAbsPath) -> MessageWithScope<'a>49 pub fn find_message(&'a self, fqn: &ProtobufAbsPath) -> MessageWithScope<'a> { 50 match self.find_message_or_enum(fqn) { 51 MessageOrEnumWithScope::Message(m) => m, 52 _ => panic!("not a message: {}", fqn), 53 } 54 } 55 56 // find message or enum by fully qualified name find_message_or_enum(&'a self, fqn: &ProtobufAbsPath) -> MessageOrEnumWithScope<'a>57 pub fn find_message_or_enum(&'a self, fqn: &ProtobufAbsPath) -> MessageOrEnumWithScope<'a> { 58 assert!(!fqn.is_root()); 59 self.packages() 60 .into_iter() 61 .flat_map(|p| p.find_message_or_enum_abs(fqn)) 62 .next() 63 .expect(&format!("enum not found by name: {}", fqn)) 64 } 65 } 66 67 #[derive(Clone, Debug)] 68 pub(crate) struct FileScope<'a> { 69 pub file_descriptor: &'a FileDescriptor, 70 } 71 72 impl<'a> Deref for FileScope<'a> { 73 type Target = FileDescriptor; 74 deref(&self) -> &Self::Target75 fn deref(&self) -> &Self::Target { 76 self.file_descriptor 77 } 78 } 79 80 impl<'a> FileScope<'a> { package(&self) -> ProtobufAbsPath81 fn package(&self) -> ProtobufAbsPath { 82 ProtobufAbsPath::package_from_file_descriptor(self.file_descriptor) 83 } 84 to_scope(&self) -> Scope<'a>85 pub fn to_scope(&self) -> Scope<'a> { 86 Scope { 87 file_scope: self.clone(), 88 path: Vec::new(), 89 } 90 } 91 find_message_or_enum( &self, name: &ProtobufRelPathRef, ) -> Option<MessageOrEnumWithScope<'a>>92 fn find_message_or_enum( 93 &self, 94 name: &ProtobufRelPathRef, 95 ) -> Option<MessageOrEnumWithScope<'a>> { 96 self.find_messages_and_enums() 97 .into_iter() 98 .filter(|e| e.protobuf_name_to_package().as_ref() == name) 99 .next() 100 } 101 find_message_or_enum_abs( &self, name: &ProtobufAbsPathRef, ) -> Option<MessageOrEnumWithScope<'a>>102 fn find_message_or_enum_abs( 103 &self, 104 name: &ProtobufAbsPathRef, 105 ) -> Option<MessageOrEnumWithScope<'a>> { 106 let name = name.to_owned(); 107 match name.remove_prefix(&self.package()) { 108 Some(rem) => self.find_message_or_enum(&rem), 109 None => None, 110 } 111 } 112 113 // find all enums in given file descriptor find_enums(&self) -> Vec<EnumWithScope<'a>>114 pub fn find_enums(&self) -> Vec<EnumWithScope<'a>> { 115 let mut r = Vec::new(); 116 117 self.to_scope().walk_scopes(|scope| { 118 r.extend(scope.enums()); 119 }); 120 121 r 122 } 123 124 /// Find all messages in given file descriptor find_messages(&self) -> Vec<MessageWithScope<'a>>125 pub fn find_messages(&self) -> Vec<MessageWithScope<'a>> { 126 let mut r = Vec::new(); 127 128 self.to_scope().walk_scopes(|scope| { 129 r.extend(scope.messages()); 130 }); 131 132 r 133 } 134 135 /// Find all messages in given file descriptor, except map messages find_messages_except_map(&self) -> Vec<MessageWithScope<'a>>136 pub fn find_messages_except_map(&self) -> Vec<MessageWithScope<'a>> { 137 self.find_messages() 138 .into_iter() 139 .filter(|m| !m.is_map()) 140 .collect() 141 } 142 143 /// find all messages and enums in given file descriptor find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>144 pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 145 let mut r = Vec::new(); 146 147 self.to_scope().walk_scopes(|scope| { 148 r.extend(scope.messages_and_enums()); 149 }); 150 151 r 152 } 153 } 154 155 #[derive(Clone, Debug)] 156 pub(crate) struct Scope<'a> { 157 pub file_scope: FileScope<'a>, 158 pub path: Vec<MessageDescriptor>, 159 } 160 161 impl<'a> Scope<'a> { file_descriptor(&self) -> FileDescriptor162 pub(crate) fn file_descriptor(&self) -> FileDescriptor { 163 self.file_scope.file_descriptor.clone() 164 } 165 166 // get message descriptors in this scope message_descriptors(&self) -> Vec<MessageDescriptor>167 fn message_descriptors(&self) -> Vec<MessageDescriptor> { 168 if self.path.is_empty() { 169 self.file_scope.file_descriptor.messages().collect() 170 } else { 171 self.path.last().unwrap().nested_messages().collect() 172 } 173 } 174 175 // get enum descriptors in this scope enum_descriptors(&self) -> Vec<EnumDescriptor>176 fn enum_descriptors(&self) -> Vec<EnumDescriptor> { 177 if self.path.is_empty() { 178 self.file_scope.file_descriptor.enums().collect() 179 } else { 180 self.path.last().unwrap().nested_enums().collect() 181 } 182 } 183 184 // get messages with attached scopes in this scope messages(&self) -> Vec<MessageWithScope<'a>>185 pub fn messages(&self) -> Vec<MessageWithScope<'a>> { 186 self.message_descriptors() 187 .into_iter() 188 .map(|message| MessageWithScope { 189 scope: self.clone(), 190 message, 191 }) 192 .collect() 193 } 194 195 // get enums with attached scopes in this scope enums(&self) -> Vec<EnumWithScope<'a>>196 pub fn enums(&self) -> Vec<EnumWithScope<'a>> { 197 self.enum_descriptors() 198 .into_iter() 199 .map(|en| EnumWithScope { 200 scope: self.clone(), 201 en, 202 }) 203 .collect() 204 } 205 206 // get messages and enums with attached scopes in this scope messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>207 pub fn messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> { 208 self.messages() 209 .into_iter() 210 .map(|m| MessageOrEnumWithScope::Message(m)) 211 .chain( 212 self.enums() 213 .into_iter() 214 .map(|m| MessageOrEnumWithScope::Enum(m)), 215 ) 216 .collect() 217 } 218 219 // nested scopes, i. e. scopes of nested messages nested_scopes(&self) -> Vec<Scope<'a>>220 fn nested_scopes(&self) -> Vec<Scope<'a>> { 221 self.message_descriptors() 222 .into_iter() 223 .map(|m| { 224 let mut nested = self.clone(); 225 nested.path.push(m); 226 nested 227 }) 228 .collect() 229 } 230 walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)231 fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) { 232 (*callback)(self); 233 234 for nested in self.nested_scopes() { 235 nested.walk_scopes_impl(callback); 236 } 237 } 238 239 // apply callback for this scope and all nested scopes walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),240 fn walk_scopes<F>(&self, mut callback: F) 241 where 242 F: FnMut(&Scope<'a>), 243 { 244 self.walk_scopes_impl(&mut callback); 245 } 246 rust_path_to_file(&self) -> RustRelativePath247 pub fn rust_path_to_file(&self) -> RustRelativePath { 248 RustRelativePath::from_idents( 249 self.path 250 .iter() 251 .map(|m| message_name_to_nested_mod_name(m.name())), 252 ) 253 } 254 path_str(&self) -> String255 pub fn path_str(&self) -> String { 256 let v: Vec<&str> = self.path.iter().map(|m| m.name()).collect(); 257 v.join(".") 258 } 259 prefix(&self) -> String260 pub fn prefix(&self) -> String { 261 let path_str = self.path_str(); 262 if path_str.is_empty() { 263 path_str 264 } else { 265 format!("{}.", path_str) 266 } 267 } 268 protobuf_path_to_file(&self) -> ProtobufRelPath269 pub fn protobuf_path_to_file(&self) -> ProtobufRelPath { 270 ProtobufRelPath::from_components(self.path.iter().map(|m| ProtobufIdentRef::new(m.name()))) 271 } 272 protobuf_absolute_path(&self) -> ProtobufAbsPath273 pub fn protobuf_absolute_path(&self) -> ProtobufAbsPath { 274 let mut r = self.file_scope.package(); 275 r.push_relative(&self.protobuf_path_to_file()); 276 r 277 } 278 file_and_mod(&self, customize: Customize) -> FileAndMod279 pub fn file_and_mod(&self, customize: Customize) -> FileAndMod { 280 FileAndMod { 281 file: self.file_scope.file_descriptor.proto().name().to_owned(), 282 relative_mod: self.rust_path_to_file(), 283 customize, 284 } 285 } 286 } 287 288 pub(crate) trait WithScope<'a> { scope(&self) -> &Scope<'a>289 fn scope(&self) -> &Scope<'a>; 290 file_descriptor(&self) -> FileDescriptor291 fn file_descriptor(&self) -> FileDescriptor { 292 self.scope().file_descriptor() 293 } 294 295 // message or enum name name(&self) -> &ProtobufIdentRef296 fn name(&self) -> &ProtobufIdentRef; 297 name_to_package(&self) -> String298 fn name_to_package(&self) -> String { 299 let mut r = self.scope().prefix(); 300 r.push_str(&self.name()); 301 r 302 } 303 protobuf_name_to_package(&self) -> ProtobufRelPath304 fn protobuf_name_to_package(&self) -> ProtobufRelPath { 305 let r = self.scope().protobuf_path_to_file(); 306 r.append_ident(ProtobufIdentRef::new(self.name())) 307 } 308 309 /// Return absolute name starting with dot name_absolute(&self) -> ProtobufAbsPath310 fn name_absolute(&self) -> ProtobufAbsPath { 311 let mut path = self.scope().protobuf_absolute_path(); 312 path.push_simple(self.name()); 313 path 314 } 315 316 // rust type name of this descriptor rust_name(&self) -> RustIdent317 fn rust_name(&self) -> RustIdent { 318 let rust_name = capitalize(&self.name()); 319 RustIdent::new(&rust_name) 320 } 321 rust_name_to_file(&self) -> RustIdentWithPath322 fn rust_name_to_file(&self) -> RustIdentWithPath { 323 self.scope() 324 .rust_path_to_file() 325 .into_path() 326 .with_ident(self.rust_name()) 327 } 328 329 // fully-qualified name of this type rust_name_with_file(&self) -> RustIdentWithPath330 fn rust_name_with_file(&self) -> RustIdentWithPath { 331 let mut r = self.rust_name_to_file(); 332 r.prepend_ident(proto_path_to_rust_mod( 333 self.scope().file_descriptor().name(), 334 )); 335 r 336 } 337 } 338 339 #[derive(Clone, Debug)] 340 pub(crate) struct MessageWithScope<'a> { 341 pub scope: Scope<'a>, 342 pub message: MessageDescriptor, 343 } 344 345 impl<'a> WithScope<'a> for MessageWithScope<'a> { scope(&self) -> &Scope<'a>346 fn scope(&self) -> &Scope<'a> { 347 &self.scope 348 } 349 name(&self) -> &ProtobufIdentRef350 fn name(&self) -> &ProtobufIdentRef { 351 ProtobufIdentRef::new(self.message.name()) 352 } 353 } 354 355 impl<'a> MessageWithScope<'a> { into_scope(mut self) -> Scope<'a>356 pub fn into_scope(mut self) -> Scope<'a> { 357 self.scope.path.push(self.message); 358 self.scope 359 } 360 to_scope(&self) -> Scope<'a>361 pub fn to_scope(&self) -> Scope<'a> { 362 self.clone().into_scope() 363 } 364 fields(&self) -> Vec<FieldWithContext<'a>>365 pub fn fields(&self) -> Vec<FieldWithContext<'a>> { 366 self.message 367 .fields() 368 .into_iter() 369 .map(|field| FieldWithContext { 370 field, 371 message: self.clone(), 372 }) 373 .collect() 374 } 375 oneofs(&self) -> Vec<OneofWithContext<'a>>376 pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> { 377 self.message 378 .oneofs() 379 .into_iter() 380 .map(|oneof| OneofWithContext { 381 message: self.clone(), 382 oneof, 383 }) 384 .collect() 385 } 386 mod_name(&self) -> RustIdent387 pub fn mod_name(&self) -> RustIdent { 388 message_name_to_nested_mod_name(self.message.name()) 389 } 390 391 /// This message is a special message which is a map. is_map(&self) -> bool392 pub fn is_map(&self) -> bool { 393 map_entry(self).is_some() 394 } 395 } 396 397 #[derive(Clone, Debug)] 398 pub(crate) struct EnumWithScope<'a> { 399 pub scope: Scope<'a>, 400 pub en: EnumDescriptor, 401 } 402 403 impl<'a> EnumWithScope<'a> { values(&self) -> Vec<EnumValueWithContext<'a>>404 pub fn values(&self) -> Vec<EnumValueWithContext<'a>> { 405 self.en 406 .values() 407 .into_iter() 408 .map(|v| EnumValueWithContext { 409 en: self.clone(), 410 proto: v, 411 }) 412 .collect() 413 } 414 415 // find enum value by protobuf name value_by_name(&self, name: &str) -> EnumValueWithContext<'a>416 pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> { 417 self.values() 418 .into_iter() 419 .find(|v| v.proto.proto().name() == name) 420 .unwrap() 421 } 422 } 423 424 #[derive(Clone, Debug)] 425 pub(crate) struct EnumValueWithContext<'a> { 426 pub en: EnumWithScope<'a>, 427 pub proto: EnumValueDescriptor, 428 } 429 430 impl<'a> EnumValueWithContext<'a> { rust_name(&self) -> RustIdent431 pub fn rust_name(&self) -> RustIdent { 432 // TODO: camel case or something. 433 RustIdent::new(self.proto.name()) 434 } 435 } 436 437 impl<'a> WithScope<'a> for EnumWithScope<'a> { scope(&self) -> &Scope<'a>438 fn scope(&self) -> &Scope<'a> { 439 &self.scope 440 } 441 name(&self) -> &ProtobufIdentRef442 fn name(&self) -> &ProtobufIdentRef { 443 ProtobufIdentRef::new(self.en.name()) 444 } 445 } 446 447 pub(crate) enum MessageOrEnumWithScope<'a> { 448 Message(MessageWithScope<'a>), 449 Enum(EnumWithScope<'a>), 450 } 451 452 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> { scope(&self) -> &Scope<'a>453 fn scope(&self) -> &Scope<'a> { 454 match self { 455 MessageOrEnumWithScope::Message(m) => m.scope(), 456 MessageOrEnumWithScope::Enum(e) => e.scope(), 457 } 458 } 459 name(&self) -> &ProtobufIdentRef460 fn name(&self) -> &ProtobufIdentRef { 461 match self { 462 MessageOrEnumWithScope::Message(m) => m.name(), 463 MessageOrEnumWithScope::Enum(e) => e.name(), 464 } 465 } 466 } 467 468 #[derive(Clone)] 469 pub(crate) struct FieldWithContext<'a> { 470 pub field: FieldDescriptor, 471 pub message: MessageWithScope<'a>, 472 } 473 474 impl<'a> Deref for FieldWithContext<'a> { 475 type Target = FieldDescriptor; 476 deref(&self) -> &Self::Target477 fn deref(&self) -> &Self::Target { 478 &self.field 479 } 480 } 481 482 impl<'a> FieldWithContext<'a> { is_oneof(&self) -> bool483 pub fn is_oneof(&self) -> bool { 484 self.field.containing_oneof().is_some() 485 } 486 oneof(&self) -> Option<OneofWithContext<'a>>487 pub fn oneof(&self) -> Option<OneofWithContext<'a>> { 488 match self.field.containing_oneof() { 489 Some(oneof) => Some(OneofWithContext { 490 message: self.message.clone(), 491 oneof, 492 }), 493 None => None, 494 } 495 } 496 } 497 498 #[derive(Clone)] 499 pub(crate) struct OneofVariantWithContext<'a> { 500 pub oneof: &'a OneofWithContext<'a>, 501 pub field: FieldDescriptor, 502 } 503 504 #[derive(Clone)] 505 pub(crate) struct OneofWithContext<'a> { 506 pub oneof: OneofDescriptor, 507 pub message: MessageWithScope<'a>, 508 } 509 510 impl<'a> OneofWithContext<'a> { field_name(&'a self) -> RustIdent511 pub fn field_name(&'a self) -> RustIdent { 512 return rust_field_name_for_protobuf_field_name(self.oneof.name()); 513 } 514 515 // rust type name of enum rust_name(&self) -> RustIdentWithPath516 pub fn rust_name(&self) -> RustIdentWithPath { 517 let type_name = RustIdent::from(capitalize(self.oneof.name())); 518 self.message 519 .to_scope() 520 .rust_path_to_file() 521 .into_path() 522 .with_ident(type_name) 523 } 524 variants(&'a self) -> Vec<OneofVariantWithContext<'a>>525 pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> { 526 self.message 527 .fields() 528 .into_iter() 529 .filter(|f| f.field.containing_oneof().as_ref() == Some(&self.oneof)) 530 .map(|f| OneofVariantWithContext { 531 oneof: self, 532 field: f.field, 533 }) 534 .collect() 535 } 536 } 537