From 95abc73beb5fe4dba599773038cc15157daf736b Mon Sep 17 00:00:00 2001
From: Rachel Powers <508861+Ryex@users.noreply.github.com>
Date: Tue, 8 Oct 2024 12:06:21 -0700
Subject: [PATCH] setup rust side of hematite lib scafold
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
---
.gitignore | 3 +
CMakeLists.txt | 11 +-
launcher/CMakeLists.txt | 51 +-
launcher/hematite/.cargo/config.toml | 2 +
launcher/hematite/CMakeLists.txt | 69 ++
launcher/hematite/Cargo.lock | 1091 ++++++++++++++++++++++++++
launcher/hematite/Cargo.toml | 35 +
launcher/hematite/Readme.md | 17 +
launcher/hematite/xtask/Cargo.toml | 24 +
launcher/hematite/xtask/src/main.rs | 282 +++++++
10 files changed, 1576 insertions(+), 9 deletions(-)
create mode 100644 launcher/hematite/.cargo/config.toml
create mode 100644 launcher/hematite/CMakeLists.txt
create mode 100644 launcher/hematite/Cargo.lock
create mode 100644 launcher/hematite/Cargo.toml
create mode 100644 launcher/hematite/Readme.md
create mode 100644 launcher/hematite/xtask/Cargo.toml
create mode 100644 launcher/hematite/xtask/src/main.rs
diff --git a/.gitignore b/.gitignore
index b5523f6857..182b02d38c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,6 @@ flatbuild
# Snap
*.snap
+
+# Rust
+launcher/hematite/target
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cec384b33d..686899e56d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
+cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip & Corrosion
project(Launcher)
@@ -328,13 +328,17 @@ endif()
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
include(ECMQueryQt)
+ # ecm_query_qt(QT_BINS_DIR QT_INSTALL_BINS)
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
+ # ecm_query_qt(QT_QML_DIR QT_INSTALL_QML)
else()
+ # set(QT_BINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_BINS})
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
+ # set(QT_QML_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_QML})
endif()
# NOTE: Qt 6 already sets this by default
@@ -380,6 +384,7 @@ if(UNIX AND APPLE)
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
set(FRAMEWORK_DEST_DIR "${Launcher_Name}.app/Contents/Frameworks")
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
+ # set(QML_DEST_DIR "${RESOURCES_DEST_DIR}/qml")
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
# Apps to bundle
@@ -438,7 +443,8 @@ elseif(UNIX)
set(PLUGIN_DEST_DIR "plugins")
set(BUNDLE_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
-
+ # set(QML_DEST_DIR "qml")
+
# Apps to bundle
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}")
@@ -459,6 +465,7 @@ elseif(WIN32)
set(LIBRARY_DEST_DIR ".")
set(PLUGIN_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
+ # set(QML_DEST_DIR "qml")
set(JARS_DEST_DIR "jars")
# Apps to bundle
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 486aaff3ee..005cd68f74 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -97,7 +97,7 @@ set(CORE_SOURCES
MTPixmapCache.h
)
if (UNIX AND NOT CYGWIN AND NOT APPLE)
-set(CORE_SOURCES
+ set(CORE_SOURCES
${CORE_SOURCES}
# MangoHud
@@ -1144,7 +1144,7 @@ SET(LAUNCHER_SOURCES
)
if (NOT Apple)
-set(LAUNCHER_SOURCES
+ set(LAUNCHER_SOURCES
${LAUNCHER_SOURCES}
ui/dialogs/UpdateAvailableDialog.h
@@ -1265,6 +1265,9 @@ include(CompilerWarnings)
# Add executable
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
+if(BUILD_TESTING)
+ target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_TEST)
+endif()
set_project_warnings(Launcher_logic
"${Launcher_MSVC_WARNINGS}"
"${Launcher_CLANG_WARNINGS}"
@@ -1310,11 +1313,11 @@ if(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
if(Launcher_ENABLE_UPDATER)
- file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
- file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
+ file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
+ file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
- find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
- add_compile_definitions(SPARKLE_ENABLED)
+ find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
+ add_compile_definitions(SPARKLE_ENABLED)
endif()
target_link_libraries(Launcher_logic
@@ -1324,7 +1327,7 @@ if(APPLE)
"-framework ApplicationServices"
)
if(Launcher_ENABLE_UPDATER)
- target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
+ target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
endif()
endif()
@@ -1345,6 +1348,8 @@ if(DEFINED Launcher_APP_BINARY_DEFS)
target_compile_definitions(Launcher_logic PRIVATE ${Launcher_APP_BINARY_DEFS})
endif()
+add_subdirectory(hematite)
+
install(TARGETS ${Launcher_Name}
BUNDLE DESTINATION "." COMPONENT Runtime
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
@@ -1544,6 +1549,38 @@ if(INSTALL_BUNDLE STREQUAL "full")
PATTERN "*qcertonlybackend*" EXCLUDE
)
endif()
+ # # QML plugins
+ # install(
+ # DIRECTORY "${QT_QML_DIR}/QtQml"
+ # CONFIGURATIONS Debug RelWithDebInfo ""
+ # DESTINATION ${QML_DEST_DIR}
+ # COMPONENT Runtime
+ # )
+ # install(
+ # DIRECTORY "${QT_QML_DIR}/QtQml"
+ # CONFIGURATIONS Release MinSizeRel
+ # DESTINATION ${QML_DEST_DIR}
+ # COMPONENT Runtime
+ # REGEX "d\\." EXCLUDE
+ # REGEX "_debug\\." EXCLUDE
+ # REGEX "\\.dSYM" EXCLUDE
+ # )
+ # # QtQuick plugins
+ # install(
+ # DIRECTORY "${QT_QML_DIR}/QtQuick"
+ # CONFIGURATIONS Debug RelWithDebInfo ""
+ # DESTINATION ${QML_DEST_DIR}
+ # COMPONENT Runtime
+ # )
+ # install(
+ # DIRECTORY "${QT_QML_DIR}/QtQuick"
+ # CONFIGURATIONS Release MinSizeRel
+ # DESTINATION ${QML_DEST_DIR}
+ # COMPONENT Runtime
+ # REGEX "d\\." EXCLUDE
+ # REGEX "_debug\\." EXCLUDE
+ # REGEX "\\.dSYM" EXCLUDE
+ # )
# Wayland support
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-client")
install(
diff --git a/launcher/hematite/.cargo/config.toml b/launcher/hematite/.cargo/config.toml
new file mode 100644
index 0000000000..39fbaa5435
--- /dev/null
+++ b/launcher/hematite/.cargo/config.toml
@@ -0,0 +1,2 @@
+[alias]
+xtask = "run --package xtask --"
diff --git a/launcher/hematite/CMakeLists.txt b/launcher/hematite/CMakeLists.txt
new file mode 100644
index 0000000000..12b711539e
--- /dev/null
+++ b/launcher/hematite/CMakeLists.txt
@@ -0,0 +1,69 @@
+
+# SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+# Prism Launcher - Minecraft Launcher
+# Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# Rust always links against non-debug Windows runtime on *-msvc targets
+# Note it is best to set this on the command line to ensure all targets are consistent
+# https://github.com/corrosion-rs/corrosion/blob/master/doc/src/common_issues.md#linking-debug-cc-libraries-into-rust-fails-on-windows-msvc-targets
+# https://github.com/rust-lang/rust/issues/39016
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+endif()
+
+find_package(CxxQt QUIET)
+if(NOT CxxQt_FOUND)
+ include(FetchContent)
+ FetchContent_Declare(
+ CxxQt
+ GIT_REPOSITORY https://github.com/kdab/cxx-qt-cmake.git
+ GIT_TAG main
+ )
+
+ FetchContent_MakeAvailable(CxxQt)
+endif()
+
+function(LinkCxxQtCrate CRATE_DIR CRATE)
+ cxx_qt_import_crate(MANIFEST_PATH "${CRATE_DIR}/Cargo.toml" CRATES ${CRATE})
+
+
+ target_link_libraries(${CRATE} INTERFACE Qt::Core)
+
+ # if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${CRATE}/qml" AND IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${CRATE}/qml")
+ #
+ # file(GLOB build_cxx_qt_qml_files_list "${CMAKE_CURRENT_SOURCE_DIR}/${CRATE}/qml/*")
+ # list(LENGTH build_cxx_qt_qml_files_list build_cxx_qt_qml_files_list_count)
+ # if(build_cxx_qt_qml_files_list_count GREATER 0)
+ #
+ # target_link_libraries(${CRATE} INTERFACE Qt::Gui Qt::Qml Qt::QuickControls2)
+ #
+ # cxx_qt_import_qml_module(${CRATE}_qml
+ # URI "org.prismlauncher.hematite.${CRATE}"
+ # SOURCE_CRATE ${CRATE}
+ # )
+ #
+ # target_link_libraries(Launcher_logic PRIVATE ${CRATE}_qml)
+ # endif()
+ # endif()
+
+ target_link_libraries(Launcher_logic INTERFACE ${CRATE})
+endfunction()
+
+# Automated instertion marker for `cargo xtask new`
+# BEGIN CRATES_TO_BUILD
+# END CRATES_TO BUILD
diff --git a/launcher/hematite/Cargo.lock b/launcher/hematite/Cargo.lock
new file mode 100644
index 0000000000..6a49fae627
--- /dev/null
+++ b/launcher/hematite/Cargo.lock
@@ -0,0 +1,1091 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "backtrace"
+version = "0.3.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "cargo_toml"
+version = "0.20.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88da5a13c620b4ca0078845707ea9c3faf11edbc3ffd8497d11d686211cd1ac0"
+dependencies = [
+ "serde",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "serde",
+ "windows-targets",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+
+[[package]]
+name = "color-eyre"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5"
+dependencies = [
+ "backtrace",
+ "color-spantrace",
+ "eyre",
+ "indenter",
+ "once_cell",
+ "owo-colors",
+ "tracing-error",
+]
+
+[[package]]
+name = "color-spantrace"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
+dependencies = [
+ "once_cell",
+ "owo-colors",
+ "tracing-core",
+ "tracing-error",
+]
+
+[[package]]
+name = "colorchoice"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+ "serde",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "eyre"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.0",
+ "serde",
+]
+
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.159"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "num"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
+dependencies = [
+ "num-bigint",
+ "num-complex",
+ "num-integer",
+ "num-iter",
+ "num-rational",
+ "num-traits",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "object"
+version = "0.32.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "owo-colors"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "portable-atomic"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_ignored"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8e319a36d1b52126a0d608f24e93b2d81297091818cd70625fcf50a15d84ddf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.128"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "3.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.6.0",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "time"
+version = "0.3.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "time-macros"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap 2.6.0",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-error"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
+dependencies = [
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "sharded-slab",
+ "thread_local",
+ "tracing-core",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "cargo_toml",
+ "clap",
+ "color-eyre",
+ "indexmap 2.6.0",
+ "indoc",
+ "num",
+ "num-integer",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_ignored",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_with",
+ "thiserror",
+ "tracing",
+]
diff --git a/launcher/hematite/Cargo.toml b/launcher/hematite/Cargo.toml
new file mode 100644
index 0000000000..37a7bfac3e
--- /dev/null
+++ b/launcher/hematite/Cargo.toml
@@ -0,0 +1,35 @@
+
+[workspace]
+members = [ "xtask" ]
+resolver = "2"
+
+[workspace.package]
+version = "0.1.0"
+edition = "2021"
+authors = [
+ "Prism Launcher Contributors",
+ "Rachel Powers <508861+Ryex@users.noreply.github.com>",
+]
+description = "A rust extension crate for Prism Launcher"
+readme = "Readme.md"
+homepage = "https://prismlauncher.org/"
+repository = "https://github.com/PrismLauncher/PrismLauncher"
+license = "GPL-3.0"
+license-file = "../LICENSE"
+
+
+[workspace.dependencies]
+cxx = {version = "1.0.128", features = ["c++17"]}
+cxx-qt = "0.6"
+cxx-qt-lib = { version = "0.6", default-features = false, features = [
+ "qt_gui",
+] }
+cxx-qt-build = "0.6"
+
+
+[profile.release]
+# Tell `rustc` to optimize for small code size.
+opt-level = "s"
+lto = true
+[profile.dev]
+opt-level = 1
diff --git a/launcher/hematite/Readme.md b/launcher/hematite/Readme.md
new file mode 100644
index 0000000000..0a41af4c08
--- /dev/null
+++ b/launcher/hematite/Readme.md
@@ -0,0 +1,17 @@
+
+
+
Prism Launcher - Hematite
+
+
+ A (experimental) rust cxx-qt based extension for Prism launcher
+
+
+
+
+
+## About
+
+Hematite, ~~is an iron oxide crystal which~~ -- is an atempt to allow Prismluancher to be extended and contributed to via rust.
+It is not an attempt to rewrite the whole of Prism with rust. Currently an expariment to see if the process feels comfortable.
+
+Some of the initial decision will be wrong, some will feel like the "hard way" these are all nessacery to feel out the right and wrong way to go about it.
diff --git a/launcher/hematite/xtask/Cargo.toml b/launcher/hematite/xtask/Cargo.toml
new file mode 100644
index 0000000000..ec7ae01363
--- /dev/null
+++ b/launcher/hematite/xtask/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "xtask"
+version.workspace = true
+edition.workspace = true
+
+[dependencies]
+clap = { version = "4.5.4", features = ["derive", "env"] }
+indexmap = { version = "2.2.6", features = ["serde"] }
+# onig = "6.4.0"
+serde = "1.0.202"
+serde_derive = "1.0.202"
+serde_ignored = "0.1.10"
+serde_json = "1.0.117"
+serde_path_to_error = "0.1.16"
+serde_with = "3.8.1"
+thiserror = "1.0.61"
+
+tracing = "0.1.40"
+num-integer = "0.1.46"
+num = "0.4.3"
+color-eyre = "0.6.3"
+cargo_toml = "0.20.5"
+regex = "1.11.0"
+indoc = "2.0.5"
diff --git a/launcher/hematite/xtask/src/main.rs b/launcher/hematite/xtask/src/main.rs
new file mode 100644
index 0000000000..a3d8e1a60e
--- /dev/null
+++ b/launcher/hematite/xtask/src/main.rs
@@ -0,0 +1,282 @@
+use std::{
+ io::{BufRead, Seek, Write},
+ process::{Command, ExitStatus},
+};
+
+use clap::{Parser, Subcommand};
+use indoc::indoc;
+
+/// Helper program to manage hematite crates
+///
+/// Can be invoked as `cargo xtask `
+#[derive(Debug, Parser)]
+#[command(bin_name = "cargo xtask")]
+struct Args {
+ #[command(subcommand)]
+ task: Task,
+}
+
+#[derive(Debug, Subcommand)]
+enum Task {
+ /// Add a new sub crate
+ New {
+ /// Name of the crate to add
+ name: String,
+ },
+}
+
+#[derive(thiserror::Error)]
+enum Error {
+ #[error("failed to run command `{0}`")]
+ Command(String, #[source] std::io::Error),
+}
+
+impl std::fmt::Debug for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use std::error::Error;
+ use std::fmt::*;
+ write!(f, "Error: {}", self)?;
+ let mut err: &dyn Error = self;
+ while let Some(cause) = err.source() {
+ write!(f, "\nCaused by: ")?;
+ Display::fmt(&cause, f)?;
+ err = cause;
+ }
+ Ok(())
+ }
+}
+
+// const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
+
+fn main() -> color_eyre::Result<()> {
+ color_eyre::install()?;
+ let args = Args::parse();
+ let workspace = {
+ let out = Command::new("cargo")
+ .arg("metadata")
+ .arg("--no-deps")
+ .arg("--format-version=1")
+ .output()
+ .map_err(|e| Error::Command("cargo metadata".to_string(), e))?;
+ let s = std::str::from_utf8(&out.stdout).unwrap();
+ let Some((_, s)) = s.split_once(r#"workspace_root":""#) else {
+ panic!("couldn't find workspace root");
+ };
+ let Some((path, _)) = s.split_once("\",") else {
+ panic!("couldn't find workspace root");
+ };
+ std::path::PathBuf::from(path)
+ };
+ match &args.task {
+ Task::New { name } => {
+ new_crate(&workspace, name)?;
+ }
+ }
+ Ok(())
+}
+
+fn new_crate(workspace: &std::path::Path, name: &str) -> color_eyre::Result<()> {
+ let crate_name = format!("hematite_{}", name);
+ run_command(
+ "cargo",
+ ["new", "--name", &crate_name, "--lib", name],
+ workspace,
+ )?;
+ {
+ let mut file = std::fs::File::options()
+ .append(true)
+ .open(workspace.join(name).join("Cargo.toml"))?;
+ write!(
+ &mut file,
+ indoc!(
+ r#"
+
+ [lib]
+ crate-type = ["staticlib"]
+
+ "#
+ )
+ )?;
+ }
+ run_command(
+ "cargo",
+ ["add", "cxx", "cxx-qt", "cxx-qt-lib"],
+ workspace.join(name),
+ )?;
+ run_command(
+ "cargo",
+ ["add", "--build", "cxx-qt-build"],
+ workspace.join(name),
+ )?;
+
+ {
+ let mut build_rs = std::fs::File::create(workspace.join(name).join("build.rs"))?;
+ write!(
+ &mut build_rs,
+ indoc!(
+ r#"
+ //Generated build.rs, modify as needed
+
+ use cxx_qt_build::{{CxxQtBuilder, QmlModule}};
+
+ fn main() {{
+ CxxQtBuilder::new()
+ // Link Qt's Network library
+ // - Qt Core is always linked
+ // - Qt Gui is linked by enabling the qt_gui Cargo feature (default).
+ // - Qt Qml is linked by enabling the qt_qml Cargo feature (default).
+ // - Qt Qml requires linking Qt Network on macOS
+ // - use .qt_module("Network") qt link a Qt library e.g. Link Qt's Network library
+ // .qml_module(QmlModule {{
+ // uri: "org.prismlauncher.hematite.{}",
+ // rust_files: &["src/cxxqt_object.rs"],
+ // qml_files: &["../qml/main.qml"],
+ // ..Default::default()
+ // }})
+ .file("src/lib.rs")
+ .cc_builder(|cc| {{
+ cc.include("../../")
+ }})
+ .build();
+ }}
+ "#,
+ ),
+ crate_name
+ )?;
+ }
+ {
+ std::fs::create_dir_all(workspace.join(name).join("src"))?;
+ let mut lib_rs = std::fs::File::create(workspace.join(name).join("src").join("lib.rs"))?;
+ write!(
+ &mut lib_rs,
+ indoc!(
+ r#"
+ /// The bridge definition for our QObject
+ #[cxx_qt::bridge]
+ pub mod qobject {{
+
+ unsafe extern "C++" {{
+ include!("cxx-qt-lib/qstring.h");
+ /// An alias to the QString type
+ type QString = cxx_qt_lib::QString;
+ }}
+
+ unsafe extern "RustQt" {{
+ // The QObject definition
+ // We tell CXX-Qt that we want a QObject class with the name MyObject
+ // based on the Rust struct MyObjectRust.
+ #[qobject]
+ type MyObject = super::MyObjectRust;
+ }}
+
+ unsafe extern "RustQt" {{
+ // Declare the invocable methods we want to expose on the QObject
+ }}
+ }}
+
+ use core::pin::Pin;
+ use cxx_qt_lib::QString;
+
+ /// The Rust struct for the QObject
+ #[derive(Default)]
+ pub struct MyObjectRust {{
+ }}
+
+ impl qobject::MyObject {{
+ }}
+
+ "#
+ )
+ )?;
+ }
+ {
+ let mut file = std::fs::File::options()
+ .read(true)
+ .write(true)
+ .open(workspace.join("CMakeLists.txt"))?;
+ let reader = std::io::BufReader::new(&file);
+ let mut before: Vec = Vec::new();
+ let mut build_lines: Vec = Vec::new();
+ let mut after: Vec = Vec::new();
+
+ enum AppendMode {
+ Before,
+ Build,
+ After,
+ }
+
+ let mut mode = AppendMode::Before;
+
+ let begin_re = regex::Regex::new(r"^# BEGIN CRATES_TO_BUILD").unwrap();
+ let end_re = regex::Regex::new(r"^# END CRATES_TO_BUILD").unwrap();
+ let build_line_re = regex::Regex::new(r"^LinkCxxQtCrate\((.*)\)$").unwrap();
+
+ for line in reader.lines() {
+ let line = line?;
+ match mode {
+ AppendMode::Before => {
+ if begin_re.is_match(&line) {
+ mode = AppendMode::Build;
+ }
+ before.push(line);
+ }
+ AppendMode::Build => {
+ if end_re.is_match(&line) {
+ mode = AppendMode::After;
+ build_lines.push(line);
+ } else if build_line_re.is_match(&line) {
+ if !build_lines.contains(&line) {
+ build_lines.push(line);
+ }
+ } else {
+ after.push(line);
+ }
+ }
+ AppendMode::After => {
+ after.push(line);
+ }
+ }
+ }
+
+ build_lines.push(format!("LinkCxxQtCrate({name} {crate_name})"));
+
+ build_lines.sort();
+
+ file.seek(std::io::SeekFrom::Start(0))?;
+ file.write_all((before.join("\n") + "\n").as_bytes())?;
+ file.write_all((build_lines.join("\n") + "\n").as_bytes())?;
+ file.write_all(after.join("\n").as_bytes())?;
+ }
+ Ok(())
+}
+
+fn build_command(program: S, args: I, working_dir: P) -> Command
+where
+ S: AsRef,
+ A: AsRef,
+ I: IntoIterator- ,
+ P: AsRef,
+{
+ let mut cmd = Command::new(program);
+ cmd.current_dir(working_dir);
+ cmd.args(args);
+ cmd
+}
+
+fn run_command
(
+ program: S,
+ args: I,
+ working_dir: P,
+) -> Result<(ExitStatus, Command), Error>
+where
+ S: AsRef,
+ A: AsRef,
+ I: IntoIterator- ,
+ P: AsRef,
+{
+ let mut cmd = build_command(program, args, working_dir);
+ let status = cmd
+ .status()
+ .map_err(|e| Error::Command(format!("{}", cmd.get_program().to_string_lossy()), e))?;
+ Ok((status, cmd))
+}