From 1f7e57e80cf2e48d0bcdf8736180fac59b83921b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Tue, 21 Feb 2023 18:12:11 +0000
Subject: [PATCH] feat: support for WASM engine version Uses built package to
 print dependencies.

---
 .gitignore             |  1 +
 CHANGELOG.md           |  2 +-
 Cargo.toml             |  1 +
 build.rs               | 72 ++++++++++++++++++++++++------------------
 frontends/web/ts/gb.ts |  5 +++
 src/gb.rs              | 16 +++++++++-
 src/gen/mock.rs        |  5 +++
 src/gen/mod.rs         | 10 ++++++
 8 files changed, 80 insertions(+), 32 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6c7bc2d1..98b51824 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ Cargo.lock
 /frontends/*/target
 
 /src/gen/build.rs
+/src/gen/_build.rs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbb835a6..7ee5b5a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
-*
+* Support for WASM engine version printing
 
 ### Changed
 
diff --git a/Cargo.toml b/Cargo.toml
index b8a44a36..65a09a89 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,7 @@ wasm-bindgen = { version = "0.2", optional = true }
 [build-dependencies]
 chrono = "0.4"
 regex = "1"
+built = "0.5"
 
 [profile.release]
 debug = false
diff --git a/build.rs b/build.rs
index 32323375..bf1b12ca 100644
--- a/build.rs
+++ b/build.rs
@@ -1,28 +1,30 @@
 #![allow(clippy::uninlined_format_args)]
 
-/// Build script (https://doc.rust-lang.org/cargo/reference/build-scripts.html)
-/// This script is executed as the first step in the compilation process.
-/// Here we export metadata constants to a `constants/generated.rs` file which is then
-/// imported and used by the remaining crate.
-///
-/// # Examples
-///
-/// In C you can use the preprocessor macro `__DATE__` to save the compilation date like:
-///
-/// ```c
-/// #define COMPILATION_DATE __DATE__
-/// ```
-///
-/// Rust does not have such preprocessor macros, so we use this script and do:
-///
-/// ```rust
-/// let now_utc = chrono::Utc::now();
-/// write_str_constant(
-///     &mut file,
-///     "COMPILATION_DATE",
-///     &format!("{}", now_utc.format("%b %d %Y")),
-/// );
-/// ```
+//! Build script (https://doc.rust-lang.org/cargo/reference/build-scripts.html)
+//! This script is executed as the first step in the compilation process.
+//! Here we export metadata constants to a `constants/generated.rs` file which is then
+//! imported and used by the remaining crate.
+//!
+//! # Examples
+//!
+//! In C you can use the preprocessor macro `__DATE__` to save the compilation date like:
+//!
+//! ```c
+//! #define COMPILATION_DATE __DATE__
+//! ```
+//!
+//! Rust does not have such preprocessor macros, so we use this script and do:
+//!
+//! ```rust
+//! let now_utc = chrono::Utc::now();
+//! write_str_constant(
+//!     &mut file,
+//!     "COMPILATION_DATE",
+//!     &format!("{}", now_utc.format("%b %d %Y")),
+//! );
+//! ```
+
+use built::{write_built_file_with_opts, Options};
 use chrono::Utc;
 use regex::Regex;
 use std::fs::{File, OpenOptions};
@@ -32,7 +34,7 @@ use std::process::Command;
 use std::{env, str};
 
 const BUILD_OUT_FILE: &str = "build.rs";
-const SOURCE_DIR: &str = "./src/gen";
+const GEN_DIR: &str = "./src/gen";
 
 fn main() {
     // in case we're running under docs.rs then we must return the control
@@ -44,7 +46,7 @@ fn main() {
 
     // opens the target destination file panicking with a proper message in
     // case it was not possible to open it (eg: directory inexistent)
-    let dest_path = Path::new(SOURCE_DIR).join(Path::new(BUILD_OUT_FILE));
+    let dest_path = Path::new(GEN_DIR).join(Path::new(BUILD_OUT_FILE));
     let mut file = OpenOptions::new()
         .truncate(true)
         .write(true)
@@ -52,11 +54,8 @@ fn main() {
         .open(dest_path)
         .unwrap_or_else(|_| panic!("Can't open '{}'", BUILD_OUT_FILE));
 
-    let module_doc_string = "//! Global constants, such as compiler version used, features, platform information and others.\n";
-    writeln!(file, "{}", module_doc_string).unwrap();
-
-    let generated_annotation = "// @generated\n";
-    writeln!(file, "{}", generated_annotation).unwrap();
+    writeln!(file, "{}", "//! Global constants, such as compiler version used, features, platform information and others.\n").unwrap();
+    writeln!(file, "{}", "// @generated\n").unwrap();
 
     let now_utc = Utc::now();
     write_str_constant(
@@ -152,6 +151,19 @@ fn main() {
         "PLATFORM_CPU_BITS_INT",
         std::mem::size_of::<usize>() * 8,
     );
+
+    let mut options = Options::default();
+    options.set_cfg(false);
+    options.set_ci(false);
+    options.set_compiler(false);
+    options.set_env(false);
+    options.set_dependencies(true);
+    options.set_features(true);
+
+    let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap();
+    let built_path = Path::new(GEN_DIR).join(Path::new("_build.rs"));
+
+    write_built_file_with_opts(&options, manifest_path.as_ref(), &built_path).unwrap();
 }
 
 fn write_constant<T>(file: &mut File, key: &str, val: T)
diff --git a/frontends/web/ts/gb.ts b/frontends/web/ts/gb.ts
index 02bb2589..4e82177b 100644
--- a/frontends/web/ts/gb.ts
+++ b/frontends/web/ts/gb.ts
@@ -547,6 +547,11 @@ export class GameboyEmulator extends EmulatorBase implements Emulator {
         };
     }
 
+    get wasmEngine(): string | null {
+        if (!this.gameBoy) return null;
+        return this.gameBoy.get_wasm_engine_ws();
+    }
+
     get framerate(): number {
         return this.fps;
     }
diff --git a/src/gb.rs b/src/gb.rs
index f78ff75f..b6394104 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -14,7 +14,10 @@ use crate::{
 use wasm_bindgen::prelude::*;
 
 #[cfg(feature = "wasm")]
-use crate::ppu::{Palette, Pixel};
+use crate::{
+    gen::dependencies_map,
+    ppu::{Palette, Pixel},
+};
 
 #[cfg(feature = "wasm")]
 use std::{
@@ -319,6 +322,17 @@ impl GameBoy {
         self.ppu().set_palette_colors(&palette);
     }
 
+    pub fn get_wasm_engine_ws(&self) -> String {
+        let dependencies = dependencies_map();
+        if !dependencies.contains_key("wasm-bindgen") {
+            return String::from("-");
+        }
+        String::from(format!(
+            "wasm-bindgen/{}",
+            *dependencies.get("wasm-bindgen").unwrap()
+        ))
+    }
+
     fn js_to_pixel(value: &JsValue) -> Pixel {
         value
             .as_string()
diff --git a/src/gen/mock.rs b/src/gen/mock.rs
index 5a9b8dde..4c9a6c39 100644
--- a/src/gen/mock.rs
+++ b/src/gen/mock.rs
@@ -14,3 +14,8 @@ pub const MAKEFLAGS: &str = "-";
 pub const FEATURES: [&str; 1] = ["cpu"];
 pub const PLATFORM_CPU_BITS: &str = "64";
 pub const PLATFORM_CPU_BITS_INT: usize = 64;
+
+pub const FEATURES: [&str; 0] = [];
+pub const FEATURES_STR: &str = r"";
+pub const DEPENDENCIES: [(&str, &str); 0] = [];
+pub const DEPENDENCIES_STR: &str = r"";
diff --git a/src/gen/mod.rs b/src/gen/mod.rs
index 427c7d62..f65c55ce 100644
--- a/src/gen/mod.rs
+++ b/src/gen/mod.rs
@@ -1,5 +1,7 @@
 //! Constants that define the current build and execution environment.
 
+use std::collections::HashMap;
+
 #[cfg(feature = "gen-mock")]
 pub mod mock;
 #[cfg(feature = "gen-mock")]
@@ -10,3 +12,11 @@ pub use self::mock::*;
 pub mod build;
 #[cfg(not(feature = "gen-mock"))]
 pub use self::build::*;
+#[cfg(not(feature = "gen-mock"))]
+pub mod _build;
+#[cfg(not(feature = "gen-mock"))]
+pub use self::_build::*;
+
+pub fn dependencies_map() -> HashMap<&'static str, &'static str> {
+    HashMap::from(DEPENDENCIES)
+}
-- 
GitLab