diff --git a/Cargo.lock b/Cargo.lock index 329df37..df65043 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,25 @@ dependencies = [ "nix", ] +[[package]] +name = "cbindgen" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e3973b165dc0f435831a9e426de67e894de532754ff7a3f307c03ee5dec7dc" +dependencies = [ + "clap 2.34.0", + "heck 0.3.3", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml", +] + [[package]] name = "cc" version = "1.0.72" @@ -241,7 +260,7 @@ version = "3.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fd2078197a22f338bd4fbf7d6387eb6f0d6a3c69e6cbc09f5c93e97321fd92a" dependencies = [ - "heck", + "heck 0.4.0", "proc-macro-error", "proc-macro2", "quote", @@ -578,6 +597,15 @@ dependencies = [ "serde", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "fnv" version = "1.0.7" @@ -603,6 +631,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" name = "generate_headers" version = "0.1.0" dependencies = [ + "cbindgen", "mist", ] @@ -724,6 +753,15 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.0" @@ -773,6 +811,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "jni-sys" version = "0.3.0" @@ -1242,6 +1286,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "ron" version = "0.7.0" @@ -1259,6 +1312,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + [[package]] name = "scoped-tls" version = "1.0.0" @@ -1314,6 +1373,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "shared_library" version = "0.1.9" @@ -1404,6 +1474,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -1463,6 +1547,12 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281" +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + [[package]] name = "unicode-width" version = "0.1.9" diff --git a/cbindgen.toml b/cbindgen.toml index 74c9965..67c76b9 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -9,8 +9,14 @@ after_includes = """ #define MIST_IS_SUCCESS(result) (MIST_RESULT_CODE(result) == MistResult_Success) #define MIST_IS_ERROR(result) (!MIST_IS_SUCCESS(result))""" +header = """/* Autogenerated file, do not edit by hand. */ +#ifndef mist_h +#define mist_h""" -include_guard = "mist_h" +trailer = """ +#include "mist_callbacks.h" + +#endif /* mist_h */ +""" includes = ["mist_results.h"] - diff --git a/include/mist.h b/include/mist.h index e1bb9a2..6384671 100644 --- a/include/mist.h +++ b/include/mist.h @@ -1,3 +1,4 @@ +/* Autogenerated file, do not edit by hand. */ #ifndef mist_h #define mist_h @@ -250,4 +251,6 @@ MistResult mist_remote_storage_end_file_write_batch(void); */ MistResult mist_utils_get_appid(AppId *app_id); +#include "mist_callbacks.h" + #endif /* mist_h */ diff --git a/include/mist_callbacks.h b/include/mist_callbacks.h new file mode 100644 index 0000000..1a14b1e --- /dev/null +++ b/include/mist_callbacks.h @@ -0,0 +1,12 @@ +typedef struct MistCallbackDlcInstalled { + AppId app_id; +} MistCallbackDlcInstalled; + +typedef struct MistCallbackRemoteStorageLocalFileChange { + +} MistCallbackRemoteStorageLocalFileChange; + +enum { + MistCallback_DlcInstalled = 1005, + MistCallback_RemoteStorageLocalFileChange = 1333, +}; diff --git a/mist/Cargo.toml b/mist/Cargo.toml index 8158e8b..316a30e 100644 --- a/mist/Cargo.toml +++ b/mist/Cargo.toml @@ -12,6 +12,7 @@ serde_derive = "1.0" steamworks-sys = { path = "../steamworks-sys", optional = true } # Only include steamworks for the binary [features] +codegen = ["steamworks"] steamworks = ["steamworks-sys"] [lib] diff --git a/mist/src/codegen.rs b/mist/src/codegen.rs index 3717f82..9e87067 100644 --- a/mist/src/codegen.rs +++ b/mist/src/codegen.rs @@ -365,6 +365,7 @@ macro_rules! mist_errors { // This will get LTO'd on normal builds so it should be fine // Called from generate headers tool #[allow(dead_code)] + #[cfg(feature = "codegen")] pub fn generate_header() -> String { let mut out: String = "enum {\n\tMistResult_Success = 0".into(); @@ -413,12 +414,16 @@ macro_rules! mist_callbacks { $( #[derive(Serialize, Deserialize, PartialEq)] #[repr(C)] - pub struct [] { + pub struct [] { $($callback_field_ident: $callback_var_ty),* } )* )* + pub mod callbacks { + pub use super::{$($([]),*),*}; + } + #[derive(Serialize, Deserialize, PartialEq)] pub struct MistCallback { pub user: SteamUser, @@ -429,7 +434,7 @@ macro_rules! mist_callbacks { #[derive(Serialize, Deserialize, PartialEq)] pub enum MistCallbacks { $($( - [<$module $callback_ident>] ([]) + [<$module $callback_ident>] ([]) ),*),* } @@ -449,7 +454,7 @@ macro_rules! mist_callbacks { Some(MistCallback { user, callback: callback_id, - data: MistCallbacks::[<$module $callback_ident>] ([] { + data: MistCallbacks::[<$module $callback_ident>] ([] { $($callback_field_ident: data.$callback_var_ident),* }) }) @@ -459,6 +464,27 @@ macro_rules! mist_callbacks { _ => None } } + + #[allow(dead_code)] + #[cfg(feature = "codegen")] + pub fn get_struct_callback(s: &str) -> u32 { + match s { + $($(stringify!([]) => steamworks_sys::[<$callback_ident _t_k_iCallback>],)*)* + _ => unreachable!() + } + } + + #[allow(dead_code)] + #[cfg(feature = "codegen")] + pub fn get_struct_idents() -> Vec { + let mut out = Vec::new(); + + $($( + out.push(stringify!([]).into()); + )*)* + + out + } } } } diff --git a/mist/src/lib.rs b/mist/src/lib.rs index 8da0860..733e302 100644 --- a/mist/src/lib.rs +++ b/mist/src/lib.rs @@ -1,6 +1,6 @@ #[macro_use] mod codegen; -mod callbacks; +pub mod callbacks; mod consts; pub mod result; mod service; @@ -8,7 +8,7 @@ mod service; mod lib_subprocess; mod types; -pub use callbacks::MistCallbackMsg; +use callbacks::MistCallbackMsg; use result::{Error, MistError, MistResult, Success}; macro_rules! unwrap_client_result { diff --git a/tools/generate_headers.sh b/tools/generate_headers.sh index 997d1c8..12cda20 100755 --- a/tools/generate_headers.sh +++ b/tools/generate_headers.sh @@ -1,4 +1,4 @@ #!/bin/bash -cargo run --bin generate_headers -- "$(dirname $0)/../include/" +cargo run --bin generate_headers -- "$(dirname $0)/../" (cd $(dirname $0)/../ && cbindgen --config cbindgen.toml --crate mist --output "$(dirname $0)/../include/mist.h") diff --git a/tools/generate_headers/Cargo.toml b/tools/generate_headers/Cargo.toml index b7c6102..fbe4dc7 100644 --- a/tools/generate_headers/Cargo.toml +++ b/tools/generate_headers/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -mist = { path = "../../mist" } \ No newline at end of file +cbindgen = "0.20" +mist = { path = "../../mist", features = ["codegen"] } diff --git a/tools/generate_headers/src/main.rs b/tools/generate_headers/src/main.rs index bdaa80f..a8eb567 100644 --- a/tools/generate_headers/src/main.rs +++ b/tools/generate_headers/src/main.rs @@ -1,4 +1,90 @@ fn main() { let path = std::path::PathBuf::from(std::env::args().nth(1).expect("include path")); - std::fs::write(path.join("mist_results.h"), mist::result::generate_header()).unwrap(); + let include_path = path.join("include"); + std::fs::write( + include_path.join("mist_results.h"), + mist::result::generate_header(), + ) + .unwrap(); + + // Callback codegen requires macro expansion + std::env::set_var("RUSTC_BOOTSTRAP", "1"); + let bindings = cbindgen::Builder::new() + .with_config(cbindgen::Config { + no_includes: true, + language: cbindgen::Language::C, + export: cbindgen::ExportConfig { + include: mist::callbacks::MistCallback::get_struct_idents(), + item_types: vec![cbindgen::ItemType::Structs], + ..Default::default() + }, + parse: cbindgen::ParseConfig { + expand: cbindgen::ParseExpandConfig { + crates: vec!["mist".into()], + all_features: true, + ..Default::default() + }, + ..Default::default() + }, + ..Default::default() + }) + .with_crate_and_name(&path, "mist") + .generate() + .unwrap(); + + let mut out = Vec::new(); + bindings.write(&mut out); + let header = String::from_utf8_lossy(&out).to_string(); + + let mut callback_struct_idents = std::collections::HashSet::new(); + + for i in mist::callbacks::MistCallback::get_struct_idents() { + callback_struct_idents.insert(i); + } + + let mut callbacks_out = String::new(); + + let mut pos = 0; + let mut start = None; + let mut callbacks = Vec::new(); + // Filter out headers we do not want + for line in header.lines() { + if line.starts_with("typedef struct ") { + let end = line.find("{").unwrap() - 1; + let ident: &str = &line["typedef struct ".len()..end]; + if callback_struct_idents.contains(ident) { + start = Some(pos); + } + } + + pos += line.len() + 1; + + if line.starts_with("} ") { + let end = line.find(";").unwrap(); + let ident = &line[2..end]; + + if callback_struct_idents.contains(ident) { + let text = header[start.unwrap()..pos].to_string(); + let callback_id = mist::callbacks::MistCallback::get_struct_callback(ident); + callbacks.push((ident, callback_id)); + + callbacks_out.push_str(&text); + callbacks_out.push_str("\n"); + + start = None; + } + } + } + + callbacks_out.push_str("enum {\n"); + + for (ident, value) in callbacks { + let mut ident = ident.to_string(); + ident.insert("MistCallback".len(), '_'); + callbacks_out.push_str(&format!(" {} = {},\n", ident, value)); + } + + callbacks_out.push_str("};\n"); + + std::fs::write(include_path.join("mist_callbacks.h"), callbacks_out).unwrap(); }