import("//build/rust/rust_static_library.gni")

# This is a fragment of the larger "mojom" template from "mojom.gni", split into
# a separate file for maintainability.
template("mojom_rust") {
  # Copy over all the variables from the primary mojom template. We can't use
  # "*" here, presumably because it only captures one scope up.
  forward_variables_from(invoker,
                         [
                           "output_target_name",
                           "all_deps",
                           "sources_list",
                           "mojom_generator_script",
                           "mojom_generator_sources",
                           "jinja2_sources",
                           "parser_target_name",
                           "common_generator_args",
                           "output_file_base_paths",
                           "variant_suffix",
                           "output_visibility",
                           "rust_typemaps",
                         ])

  base_name = target_name

  # Depends on all the mojom dependencies' metadata targets. A generated_file
  # rule will use this for GN metadata collection.
  group("${base_name}_deps_meta") {
    deps = []
    foreach(d, all_deps) {
      full_name = get_label_info(d, "label_no_toolchain")
      deps += [ "${full_name}_rust_meta" ]
    }
  }

  if (sources_list != []) {
    rust_generator_target_name = "${base_name}__generator"
    sources_for_rust_metadata = []
    foreach(s, sources_list) {
      sources_for_rust_metadata += [ rebase_path(s, "//") ]
    }

    # Contains metadata for this target's mojom dependencies.
    group("${base_name}_meta") {
      deps = [ ":${base_name}_deps_meta" ]
      metadata = {
        mojom_rust_target_map = [
          {
            target_name = get_label_info(":${base_name}", "label_no_toolchain")
            mojom_sources = sources_for_rust_metadata
          },
        ]
      }
    }

    # Outputs dependency info needed for Rust bindings generation.
    generated_file("${base_name}_dep_info") {
      outputs = [ "$target_gen_dir/${base_name}_dep_info.json" ]
      deps = [ ":${base_name}_meta" ]
      data_keys = [ "mojom_rust_target_map" ]

      output_conversion = "json"

      visibility = [ ":$rust_generator_target_name" ]
    }

    if (defined(rust_typemaps)) {
      _rust_typemaps = []
      foreach(typemap, rust_typemaps) {
        _typemap = {
        }
        _typemap = typemap
        if (defined(typemap.traits_file)) {
          _typemap.traits_file = rebase_path(typemap.traits_file, "//")
        }
        _rust_typemaps += [ _typemap ]
      }
      write_file("$target_gen_dir/${base_name}_typemap.json",
                 _rust_typemaps,
                 "json")
    }

    action(rust_generator_target_name) {
      script = mojom_generator_script
      inputs = mojom_generator_sources + jinja2_sources +
               get_target_outputs(":${base_name}_dep_info")
      if (defined(rust_typemaps)) {
        inputs += [ "$target_gen_dir/${base_name}_typemap.json" ]
      }
      sources = sources_list

      deps = [
        ":$parser_target_name",
        ":${base_name}_dep_info",
        "//mojo/public/tools/bindings:precompile_rust_templates",
      ]
      if (defined(invoker.parser_deps)) {
        deps += invoker.parser_deps
      }

      args = common_generator_args
      filelist = []
      outputs = []
      foreach(source, sources_list) {
        filelist += [ rebase_path("$source", root_build_dir) ]
      }
      foreach(base_path, output_file_base_paths) {
        outputs += [ "$root_gen_dir/${base_path}${variant_suffix}.rs" ]
      }

      response_file_contents = filelist
      dep_info_file = get_target_outputs(":${base_name}_dep_info")
      dep_info_file = rebase_path(dep_info_file[0], root_build_dir)

      args += [
        "--filelist={{response_file_name}}",
        "-g",
        "rust",
        "--rust_dep_info=$dep_info_file",
      ]
      if (defined(rust_typemaps)) {
        args += [ "--typemap=" +
                  rebase_path("$target_gen_dir/${base_name}_typemap.json",
                              root_build_dir) ]
      }
    }

    rust_crate_root_target_name = "${base_name}__crate_root"
    rust_crate_root_path = "$target_gen_dir/$output_target_name"
    rust_crate_root_librs = "$rust_crate_root_path/lib.rs"

    generated_file(rust_crate_root_target_name) {
      outputs = [ rust_crate_root_librs ]
      contents = [
        "// @generated by mojo/public/tools/bindings/mojom.gni for $output_target_name.",
        "",
      ]

      foreach(mojom_base, output_file_base_paths) {
        rs_rel_path =
            rebase_path(mojom_base, rust_crate_root_path, root_gen_dir)
        rs_rel_path += "${variant_suffix}.rs"
        rs_mod_name = get_path_info(mojom_base, "name")
        contents += [
          "#[path = \"$rs_rel_path\"]",
          "pub mod $rs_mod_name;",
        ]
      }

      visibility = [ ":${base_name}" ]
    }

    rust_static_library(target_name) {
      crate_root = rust_crate_root_librs
      sources = [ rust_crate_root_librs ] +
                get_target_outputs(":$rust_generator_target_name")
      if (defined(rust_typemaps)) {
        foreach(typemap, rust_typemaps) {
          if (defined(typemap.traits_file)) {
            sources += [ typemap.traits_file ]
          }
        }
      }
      deps = [
        ":$rust_crate_root_target_name",
        ":$rust_generator_target_name",
        "//mojo/public/rust/bindings",
        "//mojo/public/rust/mojom_value_parser",
        "//mojo/public/rust/system",
        "//third_party/rust/anyhow/v1:lib",
        "//third_party/rust/ordered_float/v5:lib",
      ]

      public_deps = []
      foreach(d, all_deps) {
        full_name = get_label_info(d, "label_no_toolchain")
        public_deps += [ "${full_name}_rust" ]
      }

      visibility = output_visibility

      # The generated crate doesn't need these dependencies.
      no_allocator_crate = true
      no_clippy = true
    }
  } else {
    group("${base_name}_meta") {
      deps = [ ":${base_name}_deps_meta" ]
    }

    group(target_name) {
      public_deps = []
      foreach(d, all_deps) {
        full_name = get_label_info(d, "label_no_toolchain")
        public_deps += [ "${full_name}_rust" ]
      }

      visibility = output_visibility
    }

    not_needed([
                 "output_target_name",
                 "mojom_generator_script",
                 "mojom_generator_sources",
                 "jinja2_sources",
                 "parser_target_name",
                 "common_generator_args",
                 "output_file_base_paths",
                 "variant_suffix",
               ])
  }
}
