diff --git a/.ci/image/Dockerfile b/.ci/image/Dockerfile index f115929..b995065 100644 --- a/.ci/image/Dockerfile +++ b/.ci/image/Dockerfile @@ -1,6 +1,7 @@ # https://jake-shadle.github.io/xwin/ -FROM debian:bullseye-slim as xwin +FROM debian:bullseye-slim AS xwin +# renovate: datasource=github-releases depName=xwin packageName=Jake-Shadle/xwin ARG XWIN_VERSION=0.5.2 ARG XWIN_PREFIX="xwin-$XWIN_VERSION-x86_64-unknown-linux-musl" ADD https://github.com/Jake-Shadle/xwin/releases/download/$XWIN_VERSION/$XWIN_PREFIX.tar.gz /root/$XWIN_PREFIX.tar.gz @@ -31,7 +32,7 @@ RUN set -eux; \ # And to keep that to a minimum, we still delete the stuff we don't need. rm -rf /root/.xwin-cache; -FROM rust:slim-bullseye as linux +FROM rust:slim-bullseye AS linux RUN set -eux; \ apt-get update; \ @@ -58,8 +59,9 @@ WORKDIR /src/dtmt COPY lib/oodle/*.so lib/oodle/*.a /src/ -FROM linux as msvc +FROM linux AS msvc +# renovate: datasource=github-releases depName=llvm packageName=llvm/llvm-project ARG LLVM_VERSION=18 ENV KEYRINGS /usr/local/share/keyrings diff --git a/.gitmodules b/.gitmodules index e1964a8..558929a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,11 +1,11 @@ -[submodule "lib/luajit2-sys"] - path = lib/luajit2-sys - url = https://github.com/sclu1034/luajit2-sys.git [submodule "lib/color-eyre"] path = lib/color-eyre url = https://github.com/sclu1034/color-eyre.git - branch = "fork" + branch = "fork" [submodule "lib/ansi-parser"] path = lib/ansi-parser url = https://gitlab.com/lschwiderski/ansi-parser.git - branch = "issue/outdated-nom" + branch = "issue/outdated-nom" +[submodule "lib/luajit2-sys/luajit"] + path = lib/luajit2-sys/luajit + url = https://github.com/LuaJIT/LuaJIT.git diff --git a/.renovaterc b/.renovaterc index 7ad59cd..6d8dec6 100644 --- a/.renovaterc +++ b/.renovaterc @@ -10,5 +10,35 @@ "baseBranches": [ "$default", "/^release\\/.*/" + ], + "ignorePaths": [ + "lib/color_eyre/**", + "lib/ansi-parser/**", + "lib/luajit2-sys/**", + "**/target/**" + ], + "customManagers": [ + { + "customType": "regex", + "description": "Update _VERSION variables in Dockerfiles", + "fileMatch": [ + "(^|/|\\.)Dockerfile$", + "(^|/)Dockerfile\\.[^/]*$" + ], + "matchStrings": [ + "# renovate: datasource=(?[a-z-]+?)(?: depName=(?.+?))? packageName=(?.+?)(?: versioning=(?[a-z-]+?))?\\s(?:ENV|ARG) .+?_VERSION=(?.+?)\\s" + ] + } + ], + "packageRules": [ + { + "matchDatasources": [ + "github-releases" + ], + "matchPackageNames": [ + "llvm/llvm-project" + ], + "extractVersion": "^llvmorg-(?\\d+)\\.\\d+\\.\\d+$" + } ] } diff --git a/Cargo.lock b/Cargo.lock index b25b0b3..9fd5a96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.13" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -2173,9 +2173,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -2184,7 +2184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4581,7 +4581,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 99ce493..15e26c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,10 @@ ansi-parser = "0.9.1" ansi_term = "0.12.1" async-recursion = "1.0.5" bincode = "2.0.0" +bindgen = "0.70.1" bitflags = "2.5.0" byteorder = "1.4.3" +cc = "1.2.27" clap = { version = "4.0.15", features = ["color", "derive", "std", "cargo", "string", "unicode"] } cli-table = { version = "0.5.0", default-features = false, features = ["derive"] } color-eyre = { path = "lib/color-eyre" } @@ -28,11 +30,13 @@ druid = { version = "0.8", features = ["im", "serde", "image", "png", "jpeg", "b druid-widget-nursery = "0.1" dtmt-shared = { path = "lib/dtmt-shared" } fastrand = "2.1.0" +fs_extra = "1.1.0" futures = "0.3.25" futures-util = "0.3.24" glob = "0.3.0" interprocess = "2.1.0" lazy_static = "1.4.0" +libc = "0.2.174" luajit2-sys = { path = "lib/luajit2-sys" } minijinja = { version = "2.0.1", default-features = false, features = ["serde"] } nanorand = "0.8.0" diff --git a/crates/dtmm/src/controller/deploy.rs b/crates/dtmm/src/controller/deploy.rs index 481b07c..8b36ae2 100644 --- a/crates/dtmm/src/controller/deploy.rs +++ b/crates/dtmm/src/controller/deploy.rs @@ -469,7 +469,7 @@ async fn patch_boot_bundle(state: Arc, deployment_info: &str) -> Re } .instrument(tracing::trace_span!("read boot bundle")) .await - .wrap_err_with(|| format!("Failed to read bundle '{}'", BOOT_BUNDLE_NAME))?; + .wrap_err_with(|| format!("Failed to read bundle '{BOOT_BUNDLE_NAME}'"))?; { tracing::trace!("Adding mod package file to boot bundle"); diff --git a/crates/dtmm/src/controller/game.rs b/crates/dtmm/src/controller/game.rs index b93d985..a5853bb 100644 --- a/crates/dtmm/src/controller/game.rs +++ b/crates/dtmm/src/controller/game.rs @@ -208,7 +208,7 @@ pub(crate) async fn reset_mod_deployment(state: ActionState) -> Result<()> { for p in paths { let path = bundle_dir.join(p); - let backup = bundle_dir.join(format!("{}.bak", p)); + let backup = bundle_dir.join(format!("{p}.bak")); let res = async { tracing::debug!( diff --git a/crates/dtmm/src/controller/import.rs b/crates/dtmm/src/controller/import.rs index 6fc9693..36f3268 100644 --- a/crates/dtmm/src/controller/import.rs +++ b/crates/dtmm/src/controller/import.rs @@ -363,7 +363,7 @@ fn extract_legacy_mod( for i in 0..file_count { let mut f = archive .by_index(i) - .wrap_err_with(|| format!("Failed to get file at index {}", i))?; + .wrap_err_with(|| format!("Failed to get file at index {i}"))?; let Some(name) = f.enclosed_name().map(|p| p.to_path_buf()) else { let err = eyre::eyre!("File name in archive is not a safe path value.").suggestion( @@ -426,7 +426,7 @@ pub(crate) async fn import_from_file(state: ActionState, info: FileInfo) -> Resu let mod_info = api .mods_id(id) .await - .wrap_err_with(|| format!("Failed to query mod {} from Nexus", id))?; + .wrap_err_with(|| format!("Failed to query mod {id} from Nexus"))?; let version = match api.file_version(id, timestamp).await { Ok(version) => version, @@ -461,13 +461,13 @@ pub(crate) async fn import_from_file(state: ActionState, info: FileInfo) -> Resu pub(crate) async fn import_from_nxm(state: ActionState, uri: String) -> Result { let url = uri .parse() - .wrap_err_with(|| format!("Invalid Uri '{}'", uri))?; + .wrap_err_with(|| format!("Invalid Uri '{uri}'"))?; let api = NexusApi::new(state.nexus_api_key.to_string())?; let (mod_info, file_info, data) = api .handle_nxm(url) .await - .wrap_err_with(|| format!("Failed to download mod from NXM uri '{}'", uri))?; + .wrap_err_with(|| format!("Failed to download mod from NXM uri '{uri}'"))?; let nexus = NexusInfo::from(mod_info); import_mod(state, Some((nexus, file_info.version)), data).await @@ -524,7 +524,7 @@ pub(crate) async fn import_mod( let data = api .picture(url) .await - .wrap_err_with(|| format!("Failed to download Nexus image from '{}'", url))?; + .wrap_err_with(|| format!("Failed to download Nexus image from '{url}'"))?; let img = image_data_to_buffer(&data)?; diff --git a/crates/dtmm/src/main.rs b/crates/dtmm/src/main.rs index 54e101a..41a9253 100644 --- a/crates/dtmm/src/main.rs +++ b/crates/dtmm/src/main.rs @@ -47,7 +47,7 @@ fn notify_nxm_download( .to_ns_name::() .expect("Invalid socket name"), ) - .wrap_err_with(|| format!("Failed to connect to '{}'", IPC_ADDRESS)) + .wrap_err_with(|| format!("Failed to connect to '{IPC_ADDRESS}'")) .suggestion("Make sure the main window is open.")?; tracing::debug!("Connected to main process at '{}'", IPC_ADDRESS); @@ -159,7 +159,7 @@ fn main() -> Result<()> { loop { let res = server.accept().wrap_err_with(|| { - format!("IPC server failed to listen on '{}'", IPC_ADDRESS) + format!("IPC server failed to listen on '{IPC_ADDRESS}'") }); match res { diff --git a/crates/dtmm/src/state/delegate.rs b/crates/dtmm/src/state/delegate.rs index f3c4711..62fb319 100644 --- a/crates/dtmm/src/state/delegate.rs +++ b/crates/dtmm/src/state/delegate.rs @@ -108,20 +108,19 @@ impl std::fmt::Debug for AsyncAction { match self { AsyncAction::DeployMods(_) => write!(f, "AsyncAction::DeployMods(_state)"), AsyncAction::ResetDeployment(_) => write!(f, "AsyncAction::ResetDeployment(_state)"), - AsyncAction::AddMod(_, info) => write!(f, "AsyncAction::AddMod(_state, {:?})", info), + AsyncAction::AddMod(_, info) => write!(f, "AsyncAction::AddMod(_state, {info:?})"), AsyncAction::DeleteMod(_, info) => { - write!(f, "AsyncAction::DeleteMod(_state, {:?})", info) + write!(f, "AsyncAction::DeleteMod(_state, {info:?})") } AsyncAction::SaveSettings(_) => write!(f, "AsyncAction::SaveSettings(_state)"), AsyncAction::CheckUpdates(_) => write!(f, "AsyncAction::CheckUpdates(_state)"), AsyncAction::LoadInitial((path, is_default)) => write!( f, - "AsyncAction::LoadInitial(({:?}, {:?}))", - path, is_default + "AsyncAction::LoadInitial(({path:?}, {is_default:?}))" ), AsyncAction::Log(_) => write!(f, "AsyncAction::Log(_)"), AsyncAction::NxmDownload(_, uri) => { - write!(f, "AsyncAction::NxmDownload(_state, {})", uri) + write!(f, "AsyncAction::NxmDownload(_state, {uri})") } } } @@ -448,7 +447,7 @@ impl AppDelegate for Delegate { if let Err(err) = open::that_detached(Arc::as_ref(url)) { tracing::error!( "{:?}", - Report::new(err).wrap_err(format!("Failed to open url '{}'", url)) + Report::new(err).wrap_err(format!("Failed to open url '{url}'")) ); } diff --git a/crates/dtmm/src/ui/theme/colors.rs b/crates/dtmm/src/ui/theme/colors.rs index 1051539..c78644e 100644 --- a/crates/dtmm/src/ui/theme/colors.rs +++ b/crates/dtmm/src/ui/theme/colors.rs @@ -76,7 +76,7 @@ impl ColorExt for Color { fn darken(&self, fac: f32) -> Self { let (r, g, b, a) = self.as_rgba(); let rgb = Rgb::from(r as f32, g as f32, b as f32); - let rgb = rgb.lighten(-1. * fac); + let rgb = rgb.lighten(-fac); Self::rgba( rgb.get_red() as f64, rgb.get_green() as f64, diff --git a/crates/dtmm/src/ui/widget/controller.rs b/crates/dtmm/src/ui/widget/controller.rs index f789b5a..f3b8a2e 100644 --- a/crates/dtmm/src/ui/widget/controller.rs +++ b/crates/dtmm/src/ui/widget/controller.rs @@ -5,6 +5,7 @@ use druid::{ use crate::state::{State, ACTION_SET_DIRTY, ACTION_START_SAVE_SETTINGS}; +#[allow(dead_code)] pub struct DisabledButtonController; impl Controller> for DisabledButtonController { diff --git a/crates/dtmm/src/ui/window/dialog.rs b/crates/dtmm/src/ui/window/dialog.rs index 11df4d5..511d1de 100644 --- a/crates/dtmm/src/ui/window/dialog.rs +++ b/crates/dtmm/src/ui/window/dialog.rs @@ -34,9 +34,9 @@ pub fn error(err: Report, _parent: WindowHandle) -> WindowDesc { // The second to last one, the context to the root cause let context = err.chain().nth(count - 2).unwrap(); - (format!("{first}!"), format!("{}: {}", context, root)) + (format!("{first}!"), format!("{context}: {root}")) } else { - ("An error occurred!".to_string(), format!("{}: {}", first, root)) + ("An error occurred!".to_string(), format!("{first}: {root}")) } } }; diff --git a/crates/dtmm/src/ui/window/main.rs b/crates/dtmm/src/ui/window/main.rs index 022a780..3955bb1 100644 --- a/crates/dtmm/src/ui/window/main.rs +++ b/crates/dtmm/src/ui/window/main.rs @@ -348,7 +348,7 @@ fn build_mod_details_info() -> impl Widget { let nexus_link = Maybe::or_empty(|| { let link = Label::raw().lens(NexusInfo::id.map( |id| { - let url = format!("https://nexusmods.com/warhammer40kdarktide/mods/{}", id); + let url = format!("https://nexusmods.com/warhammer40kdarktide/mods/{id}"); let mut builder = RichTextBuilder::new(); builder .push("Open on Nexusmods") diff --git a/crates/dtmt/src/cmd/bundle/db.rs b/crates/dtmt/src/cmd/bundle/db.rs index b537991..2398573 100644 --- a/crates/dtmt/src/cmd/bundle/db.rs +++ b/crates/dtmt/src/cmd/bundle/db.rs @@ -94,10 +94,10 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { match bundle_name { IdString64::String(name) => { - println!("{:016x} {}", bundle_hash, name); + println!("{bundle_hash:016x} {name}"); } IdString64::Hash(hash) => { - println!("{:016x}", hash); + println!("{hash:016x}"); } } @@ -110,7 +110,7 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { println!("\t{:016x}.{:<12} {}", file.name, extension, name); } IdString64::Hash(hash) => { - println!("\t{:016x}.{}", hash, extension); + println!("\t{hash:016x}.{extension}"); } } } @@ -127,10 +127,10 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { match bundle_name { IdString64::String(name) => { - println!("{:016x} {}", bundle_hash, name); + println!("{bundle_hash:016x} {name}"); } IdString64::Hash(hash) => { - println!("{:016x}", hash); + println!("{hash:016x}"); } } } @@ -158,7 +158,7 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { for bundle in bundles { found = true; - println!("{:016x}", bundle); + println!("{bundle:016x}"); } if !found { diff --git a/crates/dtmt/src/cmd/bundle/extract.rs b/crates/dtmt/src/cmd/bundle/extract.rs index b595dba..f20733d 100644 --- a/crates/dtmt/src/cmd/bundle/extract.rs +++ b/crates/dtmt/src/cmd/bundle/extract.rs @@ -473,7 +473,7 @@ where } } Err(err) => { - let err = err.wrap_err(format!("Failed to decompile file {}", name)); + let err = err.wrap_err(format!("Failed to decompile file {name}")); tracing::error!("{:?}", err); } }; diff --git a/crates/dtmt/src/cmd/bundle/inject.rs b/crates/dtmt/src/cmd/bundle/inject.rs index 23e3f8b..1fba83d 100644 --- a/crates/dtmt/src/cmd/bundle/inject.rs +++ b/crates/dtmt/src/cmd/bundle/inject.rs @@ -147,7 +147,7 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { let patch_number = matches .get_one::("patch") - .map(|num| format!("{:03}", num)); + .map(|num| format!("{num:03}")); let output_path = matches .get_one::("output") @@ -156,7 +156,7 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { let mut output_path = bundle_path.clone(); if let Some(patch_number) = patch_number.as_ref() { - output_path.set_extension(format!("patch_{:03}", patch_number)); + output_path.set_extension(format!("patch_{patch_number:03}")); } output_path @@ -196,7 +196,7 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> { span.record("output_path", output_path.display().to_string()); span.record("raw", sub_matches.get_flag("raw")); span.record("target_name", target_name.display().to_string()); - span.record("file_type", format!("{:?}", file_type)); + span.record("file_type", format!("{file_type:?}")); } } diff --git a/crates/dtmt/src/cmd/bundle/list.rs b/crates/dtmt/src/cmd/bundle/list.rs index 558126b..d511f35 100644 --- a/crates/dtmt/src/cmd/bundle/list.rs +++ b/crates/dtmt/src/cmd/bundle/list.rs @@ -38,7 +38,7 @@ enum OutputFormat { fn format_byte_size(size: usize) -> String { if size < 1024 { - format!("{} Bytes", size) + format!("{size} Bytes") } else if size < 1024 * 1024 { format!("{} kB", size / 1024) } else if size < 1024 * 1024 * 1024 { diff --git a/crates/dtmt/src/cmd/new.rs b/crates/dtmt/src/cmd/new.rs index 571b0cb..9d69b74 100644 --- a/crates/dtmt/src/cmd/new.rs +++ b/crates/dtmt/src/cmd/new.rs @@ -164,7 +164,7 @@ pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> .iter() .map(|(path_tmpl, content_tmpl)| { env.render_str(path_tmpl, &render_ctx) - .wrap_err_with(|| format!("Failed to render template: {}", path_tmpl)) + .wrap_err_with(|| format!("Failed to render template: {path_tmpl}")) .and_then(|path| { env.render_named_str(&path, content_tmpl, &render_ctx) .wrap_err_with(|| format!("Failed to render template '{}'", &path)) diff --git a/crates/dtmt/src/main.rs b/crates/dtmt/src/main.rs index ef3d36b..e2cb718 100644 --- a/crates/dtmt/src/main.rs +++ b/crates/dtmt/src/main.rs @@ -1,6 +1,5 @@ #![feature(io_error_more)] #![feature(let_chains)] -#![feature(result_flattening)] #![feature(test)] #![windows_subsystem = "console"] diff --git a/lib/dtmt-shared/src/log.rs b/lib/dtmt-shared/src/log.rs index 9c95c63..e5afc6c 100644 --- a/lib/dtmt-shared/src/log.rs +++ b/lib/dtmt-shared/src/log.rs @@ -19,7 +19,7 @@ pub const TIME_FORMAT: &[FormatItem] = format_description!("[hour]:[minute]:[sec pub fn format_fields(w: &mut Writer<'_>, field: &Field, val: &dyn std::fmt::Debug) -> Result { if field.name() == "message" { - write!(w, "{:?}", val) + write!(w, "{val:?}") } else { Ok(()) } @@ -70,7 +70,7 @@ where writer, "[{}] [{:>5}] ", time, - color.bold().paint(format!("{}", level)) + color.bold().paint(format!("{level}")) )?; ctx.field_format().format_fields(writer.by_ref(), event)?; diff --git a/lib/luajit2-sys b/lib/luajit2-sys deleted file mode 160000 index 6d94a4d..0000000 --- a/lib/luajit2-sys +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6d94a4dd2c296bf1f044ee4c70fb10dca4c1c241 diff --git a/lib/luajit2-sys/Cargo.toml b/lib/luajit2-sys/Cargo.toml new file mode 100644 index 0000000..65dd61a --- /dev/null +++ b/lib/luajit2-sys/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "luajit2-sys" +version = "0.0.2" +description = "LuaJIT-2.1 FFI Bindings" +authors = ["Aaron Loucks "] +edition = "2021" +keywords = ["lua", "luajit", "script"] +license = "MIT OR Apache-2.0" +readme = "README.md" +repository = "https://github.com/aloucks/luajit2-sys" +documentation = "https://docs.rs/luajit2-sys" +links = "luajit" + +[dependencies] +libc = { workspace = true } + +[build-dependencies] +bindgen = { workspace = true } +cc = { workspace = true } +fs_extra = { workspace = true } diff --git a/lib/luajit2-sys/LICENSE-APACHE b/lib/luajit2-sys/LICENSE-APACHE new file mode 100644 index 0000000..f007b81 --- /dev/null +++ b/lib/luajit2-sys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/lib/luajit2-sys/LICENSE-MIT b/lib/luajit2-sys/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/lib/luajit2-sys/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/luajit2-sys/build.rs b/lib/luajit2-sys/build.rs new file mode 100644 index 0000000..fc564db --- /dev/null +++ b/lib/luajit2-sys/build.rs @@ -0,0 +1,216 @@ +use cc::Build; +use fs_extra::dir; +use fs_extra::dir::CopyOptions; +use std::env; +use std::path::PathBuf; +use std::process::{Command, Stdio}; + +const LIB_NAME: &str = "luajit"; +const LUAJIT_HEADERS: [&str; 4] = ["lua.h", "lualib.h", "lauxlib.h", "luajit.h"]; +const LUAJIT_SRC: [&str; 65] = [ + // LJCORE_O + // The MSVC toolchain cannot compile this assembler file, + // as it contains GNU-specific directives + // "lj_vm.S", + "lj_gc.c", + "lj_err.c", + "lj_char.c", + "lj_bc.c", + "lj_obj.c", + "lj_buf.c", + "lj_str.c", + "lj_tab.c", + "lj_func.c", + "lj_udata.c", + "lj_meta.c", + "lj_debug.c", + "lj_state.c", + "lj_dispatch.c", + "lj_vmevent.c", + "lj_vmmath.c", + "lj_strscan.c", + "lj_strfmt.c", + "lj_strfmt_num.c", + "lj_api.c", + "lj_profile.c", + "lj_lex.c", + "lj_parse.c", + "lj_bcread.c", + "lj_bcwrite.c", + "lj_load.c", + "lj_ir.c", + "lj_opt_mem.c", + "lj_opt_fold.c", + "lj_opt_narrow.c", + "lj_opt_dce.c", + "lj_opt_loop.c", + "lj_opt_split.c", + "lj_opt_sink.c", + "lj_mcode.c", + "lj_snap.c", + "lj_record.c", + "lj_crecord.c", + "lj_ffrecord.c", + "lj_asm.c", + "lj_trace.c", + "lj_gdbjit.c", + "lj_ctype.c", + "lj_cdata.c", + "lj_cconv.c", + "lj_ccall.c", + "lj_ccallback.c", + "lj_carith.c", + "lj_clib.c", + "lj_cparse.c", + "lj_lib.c", + "lj_alloc.c", + // LJLIB_O + "lib_aux.c", + "lib_base.c", + "lib_math.c", + "lib_bit.c", + "lib_string.c", + "lib_table.c", + "lib_io.c", + "lib_os.c", + "lib_package.c", + "lib_debug.c", + "lib_jit.c", + "lib_ffi.c", + "lib_init.c", +]; + +fn build_gcc(src_dir: &str) { + let mut buildcmd = Command::new("make"); + buildcmd.current_dir(src_dir); + buildcmd.stderr(Stdio::inherit()); + buildcmd.arg("--no-silent"); + + // We do need to cross-compile even here, so that `lj_vm.o` is created + // for the correct architecture. + if env::var("CARGO_CFG_WINDOWS").is_ok() { + buildcmd.arg("TARGET_SYS=Windows"); + buildcmd.arg("CROSS=x86_64-w64-mingw32-"); + } + + if cfg!(target_pointer_width = "32") { + buildcmd.arg("HOST_CC='gcc -m32'"); + buildcmd.arg("-e"); + } else { + buildcmd.arg("HOST_CC='gcc'"); + } + + let mut child = buildcmd.spawn().expect("failed to run make"); + + if !child + .wait() + .map(|status| status.success()) + .map_err(|_| false) + .unwrap_or(false) + { + panic!("Failed to build luajit"); + } +} + +fn build_msvc(src_dir: &str, out_dir: &str) { + let mut cc = Build::new(); + // cc can't handle many of the `clang-dl`-specific flags, so + // we need to port them manually from a `make -n` run. + cc.out_dir(out_dir) + // `llvm-as` (which the clang-based toolchain for MSVC would use to compile `lj_vm.S` + // assembler) doesn't support some of the GNU-specific directives. + // However, the previous host-targeted compilation already created the + // object, so we simply link that. + .object(format!("{src_dir}/lj_vm.o")) + .define("_FILE_OFFSET_BITS", "64") + .define("_LARGEFILE_SOURCE", None) + .define("LUA_MULTILIB", "\"lib\"") + .define("LUAJIT_UNWIND_EXTERNAL", None) + .flag("-fcolor-diagnostics") + // Disable warnings + .flag("/W0") + .flag("/U _FORTIFY_SOURCE") + // Link statically + .flag("/MT") + // Omit frame pointers + .flag("/Oy"); + + for f in LUAJIT_SRC { + cc.file(format!("{src_dir}/{f}")); + } + + cc.compile(LIB_NAME); +} + +fn main() { + let luajit_dir = format!("{}/luajit", env!("CARGO_MANIFEST_DIR")); + let out_dir = env::var("OUT_DIR").unwrap(); + let src_dir = format!("{out_dir}/luajit/src"); + + dbg!(&luajit_dir); + dbg!(&out_dir); + dbg!(&src_dir); + + let mut copy_options = CopyOptions::new(); + copy_options.overwrite = true; + + dir::copy(&luajit_dir, &out_dir, ©_options).expect("Failed to copy LuaJIT source"); + + // The first run builds with and for the host architecture. + // This also creates all the tools and generated sources that a compilation needs. + build_gcc(&src_dir); + + // Then, for cross-compilation, we can utilize those generated + // sources to re-compile just the library. + if env::var("CARGO_CFG_WINDOWS").is_ok() { + build_msvc(&src_dir, &out_dir); + println!("cargo:rustc-link-search={out_dir}"); + } else { + println!("cargo:rustc-link-search=native={src_dir}"); + } + + println!("cargo:lib-name={LIB_NAME}"); + println!("cargo:include={src_dir}"); + println!("cargo:rustc-link-lib=static={LIB_NAME}"); + + let mut bindings = bindgen::Builder::default(); + + for header in LUAJIT_HEADERS { + println!("cargo:rerun-if-changed={luajit_dir}/src/{header}"); + bindings = bindings.header(format!("{luajit_dir}/src/{header}")); + } + + let bindings = bindings + .allowlist_var("LUA.*") + .allowlist_var("LUAJIT.*") + .allowlist_type("lua_.*") + .allowlist_type("luaL_.*") + .allowlist_function("lua_.*") + .allowlist_function("luaL_.*") + .allowlist_function("luaJIT.*") + .ctypes_prefix("libc") + .impl_debug(true) + .use_core() + .detect_include_paths(true) + .formatter(bindgen::Formatter::Rustfmt) + .sort_semantically(true) + .merge_extern_blocks(true) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())); + + let bindings = if env::var("CARGO_CFG_WINDOWS").is_ok() { + bindings + .clang_arg("-I/xwin/sdk/include/ucrt") + .clang_arg("-I/xwin/sdk/include/um") + .clang_arg("-I/xwin/sdk/include/shared") + .clang_arg("-I/xwin/crt/include") + .generate() + .expect("Failed to generate bindings") + } else { + bindings.generate().expect("Failed to generate bindings") + }; + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Failed to write bindings"); +} diff --git a/lib/luajit2-sys/luajit b/lib/luajit2-sys/luajit new file mode 160000 index 0000000..70f4b15 --- /dev/null +++ b/lib/luajit2-sys/luajit @@ -0,0 +1 @@ +Subproject commit 70f4b15ee45a6137fe6b48b941faea79d72f7159 diff --git a/lib/luajit2-sys/src/lib.rs b/lib/luajit2-sys/src/lib.rs new file mode 100644 index 0000000..c48ca06 --- /dev/null +++ b/lib/luajit2-sys/src/lib.rs @@ -0,0 +1,167 @@ +#![no_std] +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(clippy::deprecated_semver)] +#![allow(clippy::missing_safety_doc)] + +//! # LuaJIT 2.1 +//! +//! +//! +//! +//! +//! ## Performance considerations +//! +//! The _Not Yet Implemented_ guide documents which language features will be JIT compiled +//! into native machine code. +//! +//! + +mod ffi { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} +pub use ffi::*; + +use core::ptr; + +// These are defined as macros + +/// +#[inline] +pub unsafe fn lua_pop(L: *mut lua_State, idx: libc::c_int) { + lua_settop(L, -(idx) - 1) +} + +/// +#[inline] +pub unsafe fn lua_newtable(L: *mut lua_State) { + lua_createtable(L, 0, 0) +} + +/// +#[inline] +pub unsafe fn lua_register(L: *mut lua_State, name: *const libc::c_char, f: lua_CFunction) { + lua_pushcfunction(L, f); + lua_setglobal(L, name); +} + +/// +#[inline] +pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) { + lua_pushcclosure(L, f, 0); +} + +/// +#[inline] +pub unsafe fn lua_strlen(L: *mut lua_State, idx: libc::c_int) -> usize { + lua_objlen(L, idx) +} + +/// +#[inline] +pub unsafe fn lua_isfunction(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TFUNCTION as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_istable(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TTABLE as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_islightuserdata(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TLIGHTUSERDATA as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_isnil(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TNIL as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_isboolean(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TBOOLEAN as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_isthread(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TTHREAD as i32) as i32 +} + +/// +#[inline] +pub unsafe fn lua_isnone(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) == LUA_TNONE) as i32 +} + +/// +#[inline] +pub unsafe fn lua_isnoneornil(L: *mut lua_State, idx: libc::c_int) -> libc::c_int { + (lua_type(L, idx) <= 0) as i32 +} + +/// +#[inline] +pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &str) { + lua_pushlstring(L, s.as_ptr() as _, s.len() as _); +} + +/// +#[inline] +pub unsafe fn lua_setglobal(L: *mut lua_State, k: *const libc::c_char) { + lua_setfield(L, LUA_GLOBALSINDEX, k); +} + +/// +#[inline] +pub unsafe fn lua_getglobal(L: *mut lua_State, k: *const libc::c_char) { + lua_getfield(L, LUA_GLOBALSINDEX, k) +} + +/// +#[inline] +pub unsafe fn lua_tostring(L: *mut lua_State, idx: libc::c_int) -> *const libc::c_char { + lua_tolstring(L, idx, ptr::null_mut()) +} + +// Additional compatibility items that are defined as macros + +/// `luaL_newstate()` +#[inline] +#[deprecated(since = "Lua 5.1", note = "replace with `luaL_newstate()`")] +pub unsafe fn lua_open() -> *mut lua_State { + luaL_newstate() +} + +/// `lua_pushvalue(L, LUA_REGISTRYINDEX)` +#[inline] +#[deprecated( + since = "Lua 5.1", + note = "replace with `lua_pushvalue(L, LUA_REGISTRYINDEX)`" +)] +pub unsafe fn lua_getregistry(L: *mut lua_State) { + lua_pushvalue(L, LUA_REGISTRYINDEX) +} + +/// `lua_gc(L, LUA_GCCOUNT as _, 0)` +#[inline] +#[deprecated( + since = "Lua 5.1", + note = "replace with `lua_gc(L, LUA_GCCOUNT as _, 0)`" +)] +pub unsafe fn lua_getgccount(L: *mut lua_State) -> libc::c_int { + lua_gc(L, LUA_GCCOUNT as _, 0) +} + +/// `lua_Reader` +#[deprecated(since = "Lua 5.1", note = "replace with `lua_Reader`")] +pub type lua_Chunkreader = lua_Reader; + +/// `lua_Writer` +#[deprecated(since = "Lua 5.1", note = "replace with `lua_Writer`")] +pub type lua_Chunkwriter = lua_Writer; diff --git a/lib/nexusmods/src/lib.rs b/lib/nexusmods/src/lib.rs index cddf6a0..5c243e6 100644 --- a/lib/nexusmods/src/lib.rs +++ b/lib/nexusmods/src/lib.rs @@ -99,7 +99,7 @@ impl Api { #[tracing::instrument(skip(self))] pub async fn mods_id(&self, id: u64) -> Result { - let url = BASE_URL_GAME.join(&format!("mods/{}.json", id))?; + let url = BASE_URL_GAME.join(&format!("mods/{id}.json"))?; let req = self.client.get(url); self.send(req).await } diff --git a/lib/oodle/build.rs b/lib/oodle/build.rs index 1a1d4e9..03b6463 100644 --- a/lib/oodle/build.rs +++ b/lib/oodle/build.rs @@ -11,7 +11,7 @@ fn main() { } else { "oo2core_win64" }; - println!("cargo:rustc-link-lib=static={}", lib_name); + println!("cargo:rustc-link-lib=static={lib_name}"); } else { println!("cargo:rustc-link-lib=static=oo2corelinux64"); println!("cargo:rustc-link-lib=stdc++"); diff --git a/lib/sdk/src/binary.rs b/lib/sdk/src/binary.rs index 9ce9d23..f96b3e0 100644 --- a/lib/sdk/src/binary.rs +++ b/lib/sdk/src/binary.rs @@ -247,7 +247,7 @@ pub mod sync { fn read_string_len(mut r: impl Read, len: usize) -> Result { let mut buf = vec![0; len]; r.read_exact(&mut buf) - .wrap_err_with(|| format!("Failed to read {} bytes", len))?; + .wrap_err_with(|| format!("Failed to read {len} bytes"))?; let res = match CStr::from_bytes_until_nul(&buf) { Ok(s) => { @@ -259,6 +259,6 @@ pub mod sync { res.wrap_err("Invalid binary for UTF8 string") .with_section(|| format!("{}", String::from_utf8_lossy(&buf)).header("ASCI:")) - .with_section(|| format!("{:x?}", buf).header("Bytes:")) + .with_section(|| format!("{buf:x?}").header("Bytes:")) } } diff --git a/lib/sdk/src/murmur/types.rs b/lib/sdk/src/murmur/types.rs index c66e2cf..4e6965b 100644 --- a/lib/sdk/src/murmur/types.rs +++ b/lib/sdk/src/murmur/types.rs @@ -50,7 +50,7 @@ impl fmt::LowerHex for Murmur64 { impl fmt::Display for Murmur64 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:016X}", self) + write!(f, "{self:016X}") } } @@ -158,7 +158,7 @@ impl fmt::LowerHex for Murmur32 { impl fmt::Display for Murmur32 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:08X}", self) + write!(f, "{self:08X}") } }