Skip to main content

yog_cli/project/
script_lib.rs

1//! The crate root `yog build` writes for a mod without Rust of its own
2//! (`src/lib.rs`): its code is Yog Script, and the native it still has
3//! registers what the content files say.
4
5use std::path::Path;
6
7use yog_codegen::{Header, Regenerate};
8use yog_codegen_rust::Rust;
9
10use crate::project::manifest::{RUST_LIB, SOURCES_DIR};
11
12/// The generated root's file, under `obj/generated/`.
13const FILE: &str = "mod.g.rs";
14
15/// The mod's crate root, as the generated `Cargo.toml` (in `obj/`) names
16/// it: its own `src/lib.rs`, or the generated one.
17pub fn lib_path(root: &Path) -> String {
18    if has_rust(root) {
19        format!("../{SOURCES_DIR}/{RUST_LIB}")
20    } else {
21        format!("{}/{FILE}", generated_dir())
22    }
23}
24
25/// Whether the mod at `root` has Rust of its own.
26pub fn has_rust(root: &Path) -> bool {
27    root.join(SOURCES_DIR).join(RUST_LIB).is_file()
28}
29
30/// The generated root's file in the mod at `root` (what cleaning up
31/// generated code leaves alone).
32pub fn root_file(root: &Path) -> std::path::PathBuf {
33    root.join(yog_ids::project::OBJ)
34        .join(generated_dir())
35        .join(FILE)
36}
37
38/// Writes the generated root when the mod has no `src/lib.rs` (only when
39/// it changed); `content`: whether the build generated content code.
40pub fn write(root: &Path, content: bool) -> Result<(), String> {
41    if has_rust(root) {
42        return Ok(());
43    }
44    let file = root_file(root);
45    if let Some(dir) = file.parent() {
46        std::fs::create_dir_all(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
47    }
48    crate::write_if_changed(&file, source(content))
49}
50
51/// `generated`: [`yog_ids::project::GENERATED`] under `obj/`.
52fn generated_dir() -> &'static str {
53    let obj = yog_ids::project::OBJ;
54    yog_ids::project::GENERATED
55        .strip_prefix(obj)
56        .map_or(yog_ids::project::GENERATED, |p| {
57            p.trim_start_matches(yog_ids::sep::PATH)
58        })
59}
60
61/// The root's code: the mod, registering nothing itself — its content
62/// (`yog_api::content!()`) registers when there is any.
63fn source(content: bool) -> String {
64    let mut code = HEADER.comment::<Rust>();
65    code.push_str("//! The mod's native: its code is Yog Script.\n\n");
66    if content {
67        code.push_str("yog_api::content!();\n\n");
68    }
69    code.push_str(
70        "/// The mod: what it registers is its content's.\npub struct ScriptMod;\n\nimpl yog_api::Mod for ScriptMod {\n    fn register(_registry: &mut yog_api::Registry) {}\n}\n\nyog_api::export_mod!(ScriptMod);\n",
71    );
72    code
73}
74
75const HEADER: Header = Header {
76    tool: "`yog build`",
77    source: "yog.toml",
78    regenerate: Regenerate::EveryBuild,
79};