diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5293618..8ccd74a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,13 @@ jobs: runs-on: ubuntu-latest container: devkitpro/devkitarm steps: + # https://github.com/nektos/act/issues/917#issuecomment-1074421318 + - if: ${{ env.ACT }} + name: Hack container for local development + run: | + curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - + sudo apt-get install -y nodejs + - name: Checkout branch uses: actions/checkout@v2 @@ -56,9 +63,10 @@ jobs: - name: Cargo check run: cargo 3ds clippy --color=always --workspace --verbose --all-targets - env: - RUSTFLAGS: - --deny=warnings + # --deny=warnings would be nice, but can easily break CI for new clippy + # lints getting added. I'd also like to use Github's "inline warnings" + # feature, but https://github.com/actions/runner/issues/2341 means we + # can't have both that *and* colored output. # TODO: it would be nice to actually build 3dsx for examples/tests, etc. # and run it somehow, but exactly how remains to be seen. diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index e1372e0..f824d6d 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -5,6 +5,7 @@ license = "https://en.wikipedia.org/wiki/Zlib_License" name = "ctru-rs" version = "0.7.1" edition = "2021" +rust-version = "1.64" [lib] crate-type = ["rlib"] diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 5054ada..18fd175 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::error; use std::ffi::CStr; use std::fmt; @@ -9,7 +10,7 @@ pub type Result = ::std::result::Result; #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] #[repr(transparent)] -pub(crate) struct ResultCode(pub ctru_sys::Result); +pub struct ResultCode(pub ctru_sys::Result); impl Try for ResultCode { type Output = (); @@ -88,10 +89,10 @@ impl fmt::Debug for Error { &Self::Os(err) => f .debug_struct("Error") .field("raw", &format_args!("{err:#08X}")) - .field("description", &R_DESCRIPTION(err)) - .field("module", &R_MODULE(err)) - .field("summary", &R_SUMMARY(err)) - .field("level", &R_LEVEL(err)) + .field("level", &result_code_level_str(err)) + .field("module", &result_code_module_str(err)) + .field("summary", &result_code_summary_str(err)) + .field("description", &result_code_description_str(err)) .finish(), Self::Libc(err) => f.debug_tuple("Libc").field(err).finish(), Self::ServiceAlreadyActive => f.debug_tuple("ServiceAlreadyActive").finish(), @@ -121,3 +122,205 @@ impl error::Error for Error { "error originating from a libctru function" } } + +fn result_code_level_str(result: ctru_sys::Result) -> Cow<'static, str> { + use ctru_sys::{ + RL_FATAL, RL_INFO, RL_PERMANENT, RL_REINITIALIZE, RL_RESET, RL_STATUS, RL_SUCCESS, + RL_TEMPORARY, RL_USAGE, + }; + + Cow::Borrowed(match R_LEVEL(result) as u32 { + RL_SUCCESS => "success", + RL_INFO => "info", + RL_FATAL => "fatal", + RL_RESET => "reset", + RL_REINITIALIZE => "reinitialize", + RL_USAGE => "usage", + RL_PERMANENT => "permanent", + RL_TEMPORARY => "temporary", + RL_STATUS => "status", + code => return Cow::Owned(format!("(unknown: {code:#x})")), + }) +} + +fn result_code_summary_str(result: ctru_sys::Result) -> Cow<'static, str> { + use ctru_sys::{ + RS_CANCELED, RS_INTERNAL, RS_INVALIDARG, RS_INVALIDRESVAL, RS_INVALIDSTATE, RS_NOP, + RS_NOTFOUND, RS_NOTSUPPORTED, RS_OUTOFRESOURCE, RS_STATUSCHANGED, RS_SUCCESS, + RS_WOULDBLOCK, RS_WRONGARG, + }; + + Cow::Borrowed(match R_SUMMARY(result) as u32 { + RS_SUCCESS => "success", + RS_NOP => "nop", + RS_WOULDBLOCK => "would_block", + RS_OUTOFRESOURCE => "out_of_resource", + RS_NOTFOUND => "not_found", + RS_INVALIDSTATE => "invalid_state", + RS_NOTSUPPORTED => "not_supported", + RS_INVALIDARG => "invalid_arg", + RS_WRONGARG => "wrong_arg", + RS_CANCELED => "canceled", + RS_STATUSCHANGED => "status_changed", + RS_INTERNAL => "internal", + RS_INVALIDRESVAL => "invalid_res_val", + code => return Cow::Owned(format!("(unknown: {code:#x})")), + }) +} + +fn result_code_description_str(result: ctru_sys::Result) -> Cow<'static, str> { + use ctru_sys::{ + RD_ALREADY_DONE, RD_ALREADY_EXISTS, RD_ALREADY_INITIALIZED, RD_BUSY, RD_CANCEL_REQUESTED, + RD_INVALID_ADDRESS, RD_INVALID_COMBINATION, RD_INVALID_ENUM_VALUE, RD_INVALID_HANDLE, + RD_INVALID_POINTER, RD_INVALID_RESULT_VALUE, RD_INVALID_SELECTION, RD_INVALID_SIZE, + RD_MISALIGNED_ADDRESS, RD_MISALIGNED_SIZE, RD_NOT_AUTHORIZED, RD_NOT_FOUND, + RD_NOT_IMPLEMENTED, RD_NOT_INITIALIZED, RD_NO_DATA, RD_OUT_OF_MEMORY, RD_OUT_OF_RANGE, + RD_SUCCESS, RD_TIMEOUT, RD_TOO_LARGE, + }; + + Cow::Borrowed(match R_DESCRIPTION(result) as u32 { + RD_SUCCESS => "success", + RD_INVALID_RESULT_VALUE => "invalid_result_value", + RD_TIMEOUT => "timeout", + RD_OUT_OF_RANGE => "out_of_range", + RD_ALREADY_EXISTS => "already_exists", + RD_CANCEL_REQUESTED => "cancel_requested", + RD_NOT_FOUND => "not_found", + RD_ALREADY_INITIALIZED => "already_initialized", + RD_NOT_INITIALIZED => "not_initialized", + RD_INVALID_HANDLE => "invalid_handle", + RD_INVALID_POINTER => "invalid_pointer", + RD_INVALID_ADDRESS => "invalid_address", + RD_NOT_IMPLEMENTED => "not_implemented", + RD_OUT_OF_MEMORY => "out_of_memory", + RD_MISALIGNED_SIZE => "misaligned_size", + RD_MISALIGNED_ADDRESS => "misaligned_address", + RD_BUSY => "busy", + RD_NO_DATA => "no_data", + RD_INVALID_COMBINATION => "invalid_combination", + RD_INVALID_ENUM_VALUE => "invalid_enum_value", + RD_INVALID_SIZE => "invalid_size", + RD_ALREADY_DONE => "already_done", + RD_NOT_AUTHORIZED => "not_authorized", + RD_TOO_LARGE => "too_large", + RD_INVALID_SELECTION => "invalid_selection", + code => return Cow::Owned(format!("(unknown: {code:#x})")), + }) +} + +fn result_code_module_str(result: ctru_sys::Result) -> Cow<'static, str> { + use ctru_sys::{ + RM_AC, RM_ACC, RM_ACT, RM_AM, RM_AM_LOW, RM_APPLET, RM_APPLICATION, RM_AVD, RM_BOSS, + RM_CAM, RM_CARD, RM_CARDNOR, RM_CARD_SPI, RM_CEC, RM_CODEC, RM_COMMON, RM_CONFIG, RM_CSND, + RM_CUP, RM_DBG, RM_DBM, RM_DD, RM_DI, RM_DLP, RM_DMNT, RM_DSP, RM_EC, RM_ENC, RM_FATFS, + RM_FILE_SERVER, RM_FND, RM_FRIENDS, RM_FS, RM_FSI, RM_GD, RM_GPIO, RM_GSP, RM_GYROSCOPE, + RM_HID, RM_HIO, RM_HIO_LOW, RM_HTTP, RM_I2C, RM_INVALIDRESVAL, RM_IR, RM_KERNEL, RM_L2B, + RM_LDR, RM_LOADER_SERVER, RM_MC, RM_MCU, RM_MIC, RM_MIDI, RM_MP, RM_MPWL, RM_MVD, RM_NDM, + RM_NEIA, RM_NEWS, RM_NEX, RM_NFC, RM_NFP, RM_NGC, RM_NIM, RM_NPNS, RM_NS, RM_NWM, RM_OLV, + RM_OS, RM_PDN, RM_PI, RM_PIA, RM_PL, RM_PM, RM_PM_LOW, RM_PS, RM_PTM, RM_PXI, RM_QTM, + RM_RDT, RM_RO, RM_ROMFS, RM_SDMC, RM_SND, RM_SOC, RM_SPI, RM_SPM, RM_SRV, RM_SSL, RM_SWC, + RM_TCB, RM_TEST, RM_UART, RM_UDS, RM_UPDATER, RM_UTIL, RM_VCTL, RM_WEB_BROWSER, + }; + + Cow::Borrowed(match R_MODULE(result) as u32 { + RM_COMMON => "common", + RM_KERNEL => "kernel", + RM_UTIL => "util", + RM_FILE_SERVER => "file_server", + RM_LOADER_SERVER => "loader_server", + RM_TCB => "tcb", + RM_OS => "os", + RM_DBG => "dbg", + RM_DMNT => "dmnt", + RM_PDN => "pdn", + RM_GSP => "gsp", + RM_I2C => "i2c", + RM_GPIO => "gpio", + RM_DD => "dd", + RM_CODEC => "codec", + RM_SPI => "spi", + RM_PXI => "pxi", + RM_FS => "fs", + RM_DI => "di", + RM_HID => "hid", + RM_CAM => "cam", + RM_PI => "pi", + RM_PM => "pm", + RM_PM_LOW => "pm_low", + RM_FSI => "fsi", + RM_SRV => "srv", + RM_NDM => "ndm", + RM_NWM => "nwm", + RM_SOC => "soc", + RM_LDR => "ldr", + RM_ACC => "acc", + RM_ROMFS => "romfs", + RM_AM => "am", + RM_HIO => "hio", + RM_UPDATER => "updater", + RM_MIC => "mic", + RM_FND => "fnd", + RM_MP => "mp", + RM_MPWL => "mpwl", + RM_AC => "ac", + RM_HTTP => "http", + RM_DSP => "dsp", + RM_SND => "snd", + RM_DLP => "dlp", + RM_HIO_LOW => "hio_low", + RM_CSND => "csnd", + RM_SSL => "ssl", + RM_AM_LOW => "am_low", + RM_NEX => "nex", + RM_FRIENDS => "friends", + RM_RDT => "rdt", + RM_APPLET => "applet", + RM_NIM => "nim", + RM_PTM => "ptm", + RM_MIDI => "midi", + RM_MC => "mc", + RM_SWC => "swc", + RM_FATFS => "fatfs", + RM_NGC => "ngc", + RM_CARD => "card", + RM_CARDNOR => "cardnor", + RM_SDMC => "sdmc", + RM_BOSS => "boss", + RM_DBM => "dbm", + RM_CONFIG => "config", + RM_PS => "ps", + RM_CEC => "cec", + RM_IR => "ir", + RM_UDS => "uds", + RM_PL => "pl", + RM_CUP => "cup", + RM_GYROSCOPE => "gyroscope", + RM_MCU => "mcu", + RM_NS => "ns", + RM_NEWS => "news", + RM_RO => "ro", + RM_GD => "gd", + RM_CARD_SPI => "card_spi", + RM_EC => "ec", + RM_WEB_BROWSER => "web_browser", + RM_TEST => "test", + RM_ENC => "enc", + RM_PIA => "pia", + RM_ACT => "act", + RM_VCTL => "vctl", + RM_OLV => "olv", + RM_NEIA => "neia", + RM_NPNS => "npns", + RM_AVD => "avd", + RM_L2B => "l2b", + RM_MVD => "mvd", + RM_NFC => "nfc", + RM_UART => "uart", + RM_SPM => "spm", + RM_QTM => "qtm", + RM_NFP => "nfp", + RM_APPLICATION => "application", + RM_INVALIDRESVAL => "invalid_res_val", + code => return Cow::Owned(format!("(unknown: {code:#x})")), + }) +} diff --git a/ctru-rs/src/test_runner.rs b/ctru-rs/src/test_runner.rs index ab4c60f..ebec899 100644 --- a/ctru-rs/src/test_runner.rs +++ b/ctru-rs/src/test_runner.rs @@ -4,7 +4,7 @@ extern crate test; use std::io; -use test::{ColorConfig, Options, OutputFormat, RunIgnored, TestDescAndFn, TestFn, TestOpts}; +use test::{ColorConfig, OutputFormat, TestDescAndFn, TestFn, TestOpts}; use crate::console::Console; use crate::gfx::Gfx; @@ -25,34 +25,18 @@ pub(crate) fn run(tests: &[&TestDescAndFn]) { top_screen.set_wide_mode(true); let _console = Console::init(top_screen); - // TODO: it would be nice to have a way of specifying argv to make these - // configurable at runtime, but I can't figure out how to do it easily, - // so for now, just hardcode everything. let opts = TestOpts { - list: false, - filters: Vec::new(), - filter_exact: false, - // Forking is not supported force_run_in_process: true, - exclude_should_panic: false, - run_ignored: RunIgnored::No, run_tests: true, - // Don't run benchmarks. We may want to create a separate runner for them in the future - bench_benchmarks: false, - logfile: None, - nocapture: false, // TODO: color doesn't work because of TERM/TERMINFO. // With RomFS we might be able to fake this out nicely... color: ColorConfig::AutoColor, format: OutputFormat::Pretty, - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: Vec::new(), - time_options: None, - options: Options::new(), + // Hopefully this interface is more stable vs specifying individual options, + // and parsing the empty list of args should always work, I think. + // TODO Ideally we could pass actual std::env::args() here too + ..test::test::parse_opts(&[]).unwrap().unwrap() }; - // Use the default test implementation with our hardcoded options let _success = run_static_tests(&opts, tests).unwrap(); diff --git a/ctru-sys/build.rs b/ctru-sys/build.rs index c31c56b..90d97e6 100644 --- a/ctru-sys/build.rs +++ b/ctru-sys/build.rs @@ -6,7 +6,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=DEVKITPRO"); - println!("cargo:rustc-link-search=native={}/libctru/lib", dkp_path); + println!("cargo:rustc-link-search=native={dkp_path}/libctru/lib"); println!( "cargo:rustc-link-lib=static={}", match profile.as_str() {