build.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. use proc_macro2::TokenStream;
  2. use protobuf::reflect::{FieldDescriptor, ReflectValueRef};
  3. use quote::quote;
  4. use serde_json::Map;
  5. use std::io::{BufWriter, Write};
  6. use std::{env, fs::File, path::Path};
  7. fn main() {
  8. // First we load up the descriptor using the protobuf crate
  9. // so that we can do reflection on it.
  10. let descriptors = protobuf_parse::Parser::new()
  11. .pure()
  12. .include(".")
  13. .input("Lib/gflanguages/languages_public.proto")
  14. .file_descriptor_set()
  15. .expect("Could not parse languages_public.proto");
  16. let protofile = descriptors.file.first().expect("No file in descriptor");
  17. let descriptor = protobuf::reflect::FileDescriptor::new_dynamic(protofile.clone(), &[])
  18. .expect("Could not create descriptor");
  19. // Now we use the prost crate to compile them, so that we can
  20. // generate Rust structs.
  21. let mut config = prost_build::Config::new();
  22. config.protoc_executable(protoc_bin_vendored::protoc_bin_path().unwrap());
  23. // config.boxed(".google.languages_public.LanguageProto.sample_text");
  24. // config.boxed(".google.languages_public.LanguageProto.exemplar_chars");
  25. // The reflection can tell us what messages we have, so we can configure
  26. // them to be deserializable with serde
  27. for message in descriptor.messages() {
  28. config.type_attribute(
  29. message.full_name(),
  30. "#[derive(serde::Serialize, serde::Deserialize)]",
  31. );
  32. }
  33. // Let's make our structs; this produces google.languages_public.rs
  34. config
  35. .compile_protos(
  36. &["Lib/gflanguages/languages_public.proto"],
  37. &["Lib/gflanguages/"],
  38. )
  39. .expect("Could not compile languages_public.proto");
  40. let path = Path::new(&env::var("OUT_DIR").unwrap()).join("data.rs");
  41. let mut file = BufWriter::new(File::create(path).unwrap());
  42. let mut output = quote! { use std::collections::BTreeMap; use std::sync::LazyLock; };
  43. output.extend(serialize_a_structure(
  44. ".google.languages_public.RegionProto",
  45. "Lib/gflanguages/data/regions/*.textproto",
  46. "REGIONS",
  47. &descriptor,
  48. ));
  49. output.extend(serialize_a_structure(
  50. ".google.languages_public.ScriptProto",
  51. "Lib/gflanguages/data/scripts/*.textproto",
  52. "SCRIPTS",
  53. &descriptor,
  54. ));
  55. output.extend(serialize_a_structure(
  56. ".google.languages_public.LanguageProto",
  57. "Lib/gflanguages/data/languages/*.textproto",
  58. "LANGUAGES",
  59. &descriptor,
  60. ));
  61. // file.write_all(output.to_string().as_bytes())
  62. // .expect("Could not write to file");
  63. let abstract_file: syn::File = syn::parse2(output).expect("Could not parse output");
  64. let formatted = prettyplease::unparse(&abstract_file);
  65. file.write_all(formatted.as_bytes())
  66. .expect("Could not write to file");
  67. }
  68. fn serialize_a_structure(
  69. proto_name: &str,
  70. pathglob: &str,
  71. output_variable: &str,
  72. descriptor: &protobuf::reflect::FileDescriptor,
  73. ) -> TokenStream {
  74. let proto = descriptor
  75. .message_by_full_name(proto_name)
  76. .unwrap_or_else(|| panic!("No {} message", proto_name));
  77. let files: Vec<std::path::PathBuf> = glob::glob(pathglob)
  78. .expect("Failed to read glob pattern")
  79. .flatten()
  80. .collect();
  81. let name: TokenStream = proto.name().parse().unwrap();
  82. let variable: TokenStream = output_variable.parse().unwrap();
  83. let mut map = Map::new();
  84. for file in files.into_iter() {
  85. serialize_file(file, &proto, &mut map);
  86. }
  87. let json_var: TokenStream = format!("__{}", output_variable).parse().unwrap();
  88. let docmsg = format!("A map of all the {} objects", name);
  89. let json_dump = serde_json::to_string(&map).expect("Could not serialize");
  90. quote! {
  91. static #json_var: &str = #json_dump;
  92. #[doc = #docmsg]
  93. pub static #variable: LazyLock<BTreeMap<String, Box<#name>>> = LazyLock::new(|| {
  94. serde_json::from_str(#json_var).expect("Could not deserialize")
  95. });
  96. }
  97. }
  98. fn serialize_file(
  99. path: std::path::PathBuf,
  100. descriptor: &protobuf::reflect::MessageDescriptor,
  101. value: &mut Map<String, serde_json::Value>,
  102. ) {
  103. let mut message = descriptor.new_instance();
  104. let message_mut = message.as_mut();
  105. let input = std::fs::read_to_string(&path).expect("Could not read file");
  106. protobuf::text_format::merge_from_str(message_mut, &input)
  107. .unwrap_or_else(|e| panic!("Could not parse file {:?}: {:?}", path, e));
  108. let id = path.file_stem().unwrap().to_str().unwrap();
  109. value.insert(id.to_string(), serialize_message(message_mut));
  110. }
  111. fn serialize_message(message: &dyn protobuf::MessageDyn) -> serde_json::Value {
  112. let descriptor = message.descriptor_dyn();
  113. // let descriptor_name: TokenStream = descriptor.name().parse().unwrap();
  114. let mut output = Map::new();
  115. for field in descriptor.fields() {
  116. let field_name: TokenStream = field.name().parse().unwrap();
  117. let field_contents = serialize_field(&field, message);
  118. output.insert(field_name.to_string(), field_contents);
  119. }
  120. output.into()
  121. }
  122. fn serialize_field(
  123. field: &FieldDescriptor,
  124. message: &dyn protobuf::MessageDyn,
  125. ) -> serde_json::Value {
  126. if field.is_repeated() {
  127. let v: Vec<serde_json::Value> = field
  128. .get_repeated(message)
  129. .into_iter()
  130. .map(|value| serialize_field_value(field, value))
  131. .collect();
  132. v.into()
  133. } else if field.is_required() {
  134. serialize_field_value(field, field.get_singular(message).unwrap())
  135. } else if field.has_field(message) {
  136. let value = serialize_field_value(field, field.get_singular(message).unwrap());
  137. value.into()
  138. } else {
  139. serde_json::Value::Null
  140. }
  141. }
  142. fn serialize_field_value(_field: &FieldDescriptor, value: ReflectValueRef) -> serde_json::Value {
  143. match value {
  144. ReflectValueRef::Bool(value) => value.into(),
  145. ReflectValueRef::I32(value) => value.into(),
  146. ReflectValueRef::I64(value) => value.into(),
  147. ReflectValueRef::U32(value) => value.into(),
  148. ReflectValueRef::U64(value) => value.into(),
  149. ReflectValueRef::F32(value) => value.into(),
  150. ReflectValueRef::F64(value) => value.into(),
  151. ReflectValueRef::String(value) => value.into(),
  152. ReflectValueRef::Bytes(value) => value.into(),
  153. ReflectValueRef::Enum(_value, _ix) => unimplemented!(),
  154. ReflectValueRef::Message(value) => serialize_message(&*value),
  155. }
  156. }