daml_codegen/generator/
separate.rs1use crate::generator::module_matcher::ModuleMatcher;
2use crate::generator::RenderMethod;
3use crate::renderer::{quote_all_data, to_module_path, to_rust_identifier, RenderContext, RenderFilterMode};
4use daml_lf::element::{DamlArchive, DamlModule, DamlPackage};
5use itertools::Itertools;
6use std::fs::File;
7use std::io::{Error, Write};
8use std::path::Path;
9use std::path::PathBuf;
10use std::{fs, io};
11
12const DISABLE_WARNINGS: &str = "#![allow(clippy::all, warnings)]";
13const USE_DAML_PRELUDE: &str = "use ::daml::prelude::*;";
14
15pub fn generate_archive_separate(
16 archive: &DamlArchive<'_>,
17 output_path: &Path,
18 module_matcher: &ModuleMatcher,
19 render_method: &RenderMethod,
20) -> Result<(), Error> {
21 let ctx = RenderContext::with_archive(archive, RenderFilterMode::default());
22 for package in archive.packages() {
23 generate_package_source(&ctx, package, output_path, module_matcher, render_method)?;
24 }
25 Ok(())
26}
27
28fn generate_package_source(
29 ctx: &RenderContext<'_>,
30 package: &DamlPackage<'_>,
31 output_path: &Path,
32 module_matcher: &ModuleMatcher,
33 render_method: &RenderMethod,
34) -> Result<(), Error> {
35 let root_modules: Vec<_> =
36 package.root_module().child_modules().filter(|&m| is_interesting_module(m, module_matcher)).collect();
37 let module_decl = root_modules.iter().map(|m| make_pub_mod_declaration(m.local_name())).join("\n");
38 let package_body = format!("{}\n{}", DISABLE_WARNINGS, module_decl);
39 let mut package_file = create_file(&PathBuf::from(output_path), &make_package_filename(package.name()))?;
40 package_file.write_all(package_body.as_bytes())?;
41 let package_dir_path = PathBuf::from(output_path).join(&to_rust_identifier(package.name()));
42 for module in root_modules {
43 generate_module_source(ctx, module, &package_dir_path, module_matcher, render_method)?;
44 }
45 Ok(())
46}
47
48fn generate_module_source(
49 ctx: &RenderContext<'_>,
50 module: &DamlModule<'_>,
51 package_dir_path: &Path,
52 module_matcher: &ModuleMatcher,
53 render_method: &RenderMethod,
54) -> Result<(), Error> {
55 let sub_modules: Vec<_> = module.child_modules().filter(|&m| is_interesting_module(m, module_matcher)).collect();
56 let sub_module_decl: String = sub_modules.iter().map(|&m| make_pub_mod_declaration(m.local_name())).join("\n");
57 let module_types_text = quote_module_data_types(ctx, module, render_method);
58 let module_body = format!("{}\n{}{}", USE_DAML_PRELUDE, sub_module_decl, module_types_text);
59 let module_path: Vec<_> = module.path().collect();
60 let module_dir_path = module_path[..module_path.len() - 1].iter().map(to_rust_identifier).join("/");
61 let package_module_dir_path = PathBuf::from(package_dir_path).join(module_dir_path);
62 let mut module_file = create_file(&package_module_dir_path, &make_module_filename(module.local_name()))?;
63 module_file.write_all(module_body.as_bytes())?;
64 for child_module in sub_modules {
65 generate_module_source(ctx, child_module, package_dir_path, module_matcher, render_method)?;
66 }
67 Ok(())
68}
69
70fn is_interesting_module(module: &DamlModule<'_>, module_matcher: &ModuleMatcher) -> bool {
74 (module.data_types().next().is_some() && module_matcher.matches(&to_module_path(module.path())))
75 || module.child_modules().any(|m| is_interesting_module(m, module_matcher))
76}
77
78fn quote_module_data_types(ctx: &RenderContext<'_>, module: &DamlModule<'_>, render_method: &RenderMethod) -> String {
79 quote_all_data(ctx, module.data_types().collect::<Vec<_>>().as_slice(), render_method).to_string()
80}
81
82fn create_file(base_dir: &Path, filename: &str) -> io::Result<File> {
83 fs::create_dir_all(&base_dir)?;
84 File::create(base_dir.join(filename))
85}
86
87fn make_package_filename(name: &str) -> String {
88 format!("{}.rs", to_rust_identifier(name))
89}
90
91fn make_module_filename(name: &str) -> String {
92 format!("{}.rs", to_rust_identifier(name))
93}
94
95fn make_pub_mod_declaration(module_name: &str) -> String {
96 format!("pub mod {};", to_rust_identifier(module_name))
97}