build.rs 6.3 KB

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