gammaloop_api/
templates.rs1use color_eyre::Result;
2use rust_embed::RustEmbed;
3use std::fs;
4use std::path::Path;
5
6const LINNEST_PACKAGE_DIR: &str = "crates/linnest/typst";
7const KURVST_PACKAGE_DIR: &str = "crates/kurvst/typst";
8
9#[derive(RustEmbed)]
10#[folder = "../../assets/embedded"]
11pub struct Assets;
12
13#[derive(RustEmbed)]
14#[folder = "$CARGO_MANIFEST_DIR/../../assets/embedded/drawing/templates"]
15#[include = "*.typ"]
16struct GammaLoopTemplateAssets;
17
18#[derive(RustEmbed)]
19#[folder = "$CARGO_MANIFEST_DIR/../linnest/typst"]
20#[include = "src/*.typ"]
21#[include = "src/**/*.typ"]
22#[include = "typst.toml"]
23#[include = "linnest.wasm"]
24struct LinnestPackageAssets;
25
26#[derive(RustEmbed)]
27#[folder = "$CARGO_MANIFEST_DIR/../kurvst/typst"]
28#[include = "src/*.typ"]
29#[include = "src/**/*.typ"]
30#[include = "typst.toml"]
31#[include = "kurvst.wasm"]
32struct KurvstPackageAssets;
33
34impl Assets {
35 pub fn template_paths() -> impl Iterator<Item = String> {
37 GammaLoopTemplateAssets::iter().map(|path| path.to_string())
38 }
39
40 pub fn extract_templates<P: AsRef<Path>>(target_dir: P) -> Result<()> {
42 let target = target_dir.as_ref().join("drawings/templates");
43
44 fs::create_dir_all(&target)?;
45
46 extract_package::<GammaLoopTemplateAssets>(&target)?;
47 extract_package::<LinnestPackageAssets>(&target.join(LINNEST_PACKAGE_DIR))?;
48 extract_package::<KurvstPackageAssets>(&target.join(KURVST_PACKAGE_DIR))?;
49
50 Ok(())
51 }
52
53 pub fn extract_justfile<P: AsRef<Path>>(target_dir: P) -> Result<()> {
55 let justfile_path = target_dir.as_ref().join("justfile");
56
57 if let Some(file) = Self::get("drawing/justfile") {
58 fs::write(&justfile_path, file.data)?;
59 }
60
61 Ok(())
62 }
63}
64
65fn extract_package<E: RustEmbed>(target: &Path) -> Result<()> {
66 fs::create_dir_all(target)?;
67 for package_path in E::iter() {
68 if let Some(file) = E::get(package_path.as_ref()) {
69 let target_path = target.join(package_path.as_ref());
70
71 if let Some(parent) = target_path.parent() {
72 fs::create_dir_all(parent)?;
73 }
74
75 fs::write(&target_path, file.data)?;
76 }
77 }
78
79 Ok(())
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn extract_templates_uses_canonical_package_layout() -> Result<()> {
88 let tempdir = tempfile::tempdir()?;
89
90 Assets::extract_templates(tempdir.path())?;
91
92 let templates = tempdir.path().join("drawings/templates");
93 assert!(templates.join("figure.typ").is_file());
94 assert!(templates.join("grid.typ").is_file());
95 assert!(templates.join("layout.typ").is_file());
96 assert!(templates.join("layout-core.typ").is_file());
97 assert!(fs::read_to_string(templates.join("grid.typ"))?.contains("page_format"));
98 let figure = fs::read_to_string(templates.join("figure.typ"))?;
99 assert!(figure.contains("amplitude-mode"));
100 assert!(figure.contains("cross-section-mode"));
101 assert!(figure.contains("show-node-index"));
102 assert!(figure.contains("unit: 1.5"));
103 let layout = fs::read_to_string(templates.join("layout.typ"))?;
104 assert!(layout.contains("#import \"layout-core.typ\": bind-layout"));
105 assert!(layout.contains("#let layout = bind-layout("));
106 assert!(!layout.contains("graph.parse(input)"));
107 let layout_core = fs::read_to_string(templates.join("layout-core.typ"))?;
108 assert!(layout_core.contains("autogen-external-edge-fields"));
109 assert!(layout_core.contains("momentum-index"));
110 assert!(layout_core.contains("$(p_#index)$"));
111 assert!(layout_core.contains("$n_#index$"));
112 assert!(layout_core.contains("graph.style("));
113 assert!(layout_core.contains("length-scale: 0.4"));
114 assert!(layout_core.contains("z-spring-growth: 1.01"));
115
116 assert!(templates
117 .join("crates/linnest/typst/linnest.wasm")
118 .is_file());
119 assert!(templates
120 .join("crates/linnest/typst/src/curve.typ")
121 .is_file());
122 assert!(templates
123 .join("crates/linnest/typst/src/impl/graph.typ")
124 .is_file());
125 assert!(templates.join("crates/kurvst/typst/kurvst.wasm").is_file());
126 assert!(templates.join("crates/kurvst/typst/src/lib.typ").is_file());
127 assert!(templates.join("crates/kurvst/typst/src/impl.typ").is_file());
128
129 assert!(!templates.join("linnest.wasm").exists());
130 assert!(!templates.join("kurvst.wasm").exists());
131 assert!(!templates.join("curve.typ").exists());
132
133 Assets::extract_justfile(tempdir.path())?;
134 let justfile = fs::read_to_string(tempdir.path().join("justfile"))?;
135 assert!(justfile.contains("--style drawings/templates/layout-core.typ"));
136 assert!(justfile.contains("momentum_line_mark := \"auto\""));
137 assert!(justfile.contains("show_node_index := \"true\""));
138 assert!(justfile.contains("show_particle := \"false\""));
139
140 Ok(())
141 }
142}