diff --git a/examples/colored-tri/Cargo.lock b/examples/colored-tri/Cargo.lock index 2758818..848c89d 100644 --- a/examples/colored-tri/Cargo.lock +++ b/examples/colored-tri/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "bindgen" version = "0.69.4" @@ -78,22 +84,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -211,6 +201,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_enum" version = "0.5.11" @@ -238,9 +238,8 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "cfg-if", - "cstr_core", "libc", - "libm", + "num-traits", "num_enum", "ogc-sys", "voladdress", diff --git a/examples/colored-tri/src/main.rs b/examples/colored-tri/src/main.rs index 8afa45a..c47e8c5 100644 --- a/examples/colored-tri/src/main.rs +++ b/examples/colored-tri/src/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(start)] +#![no_mangle] use core::mem::ManuallyDrop; @@ -15,8 +15,8 @@ use ogc_rs::{ extern crate alloc; -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { let vi = Video::init(); let mut config = Video::get_preferred_mode(); diff --git a/examples/embedded-graphics-wii/Cargo.lock b/examples/embedded-graphics-wii/Cargo.lock index bd4e273..952e5cf 100644 --- a/examples/embedded-graphics-wii/Cargo.lock +++ b/examples/embedded-graphics-wii/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -96,22 +96,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -282,6 +266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -311,9 +296,8 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "cfg-if", - "cstr_core", "libc", - "libm", + "num-traits", "num_enum", "ogc-sys", "voladdress", diff --git a/examples/embedded-graphics-wii/src/main.rs b/examples/embedded-graphics-wii/src/main.rs index 82cd417..8dc9624 100644 --- a/examples/embedded-graphics-wii/src/main.rs +++ b/examples/embedded-graphics-wii/src/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(start)] +#![no_main] mod display; use crate::display::Display; @@ -15,8 +15,8 @@ use embedded_graphics::{ use ogc_rs::prelude::*; -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { let mut video = Video::init(); Input::init(ControllerType::Gamecube); Input::init(ControllerType::Wii); diff --git a/examples/obj-loading/src/main.rs b/examples/obj-loading/src/main.rs index 570f4df..f6c2a93 100644 --- a/examples/obj-loading/src/main.rs +++ b/examples/obj-loading/src/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(start)] +#![no_main] mod obj; use core::f32::consts::PI; @@ -28,8 +28,8 @@ const WHITE_BYTES: &[u8] = include_bytes!("../white.png"); #[derive(Clone, Copy)] pub struct Align32(pub T); -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { let Ok(obj) = obj::from_bytes(include_bytes!("./assets/untitled.obj")) else { panic!() }; diff --git a/examples/template/Cargo.lock b/examples/template/Cargo.lock index 2758818..848c89d 100644 --- a/examples/template/Cargo.lock +++ b/examples/template/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "bindgen" version = "0.69.4" @@ -78,22 +84,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -211,6 +201,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_enum" version = "0.5.11" @@ -238,9 +238,8 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "cfg-if", - "cstr_core", "libc", - "libm", + "num-traits", "num_enum", "ogc-sys", "voladdress", diff --git a/examples/template/src/main.rs b/examples/template/src/main.rs index d08ade8..093f1b0 100644 --- a/examples/template/src/main.rs +++ b/examples/template/src/main.rs @@ -1,13 +1,12 @@ #![no_std] -#![feature(start)] +#![no_main] extern crate alloc; -use core::mem::ManuallyDrop; use ogc_rs::{mp3player::MP3Player, prelude::*}; -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { let mp3 = include_bytes!("../mp3.mp3"); let video = Video::init(); diff --git a/examples/texture-tri/Cargo.lock b/examples/texture-tri/Cargo.lock index 8fb9602..c42d961 100644 --- a/examples/texture-tri/Cargo.lock +++ b/examples/texture-tri/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "bindgen" version = "0.69.4" @@ -84,22 +90,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -249,6 +239,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_enum" version = "0.5.11" @@ -276,9 +276,8 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "cfg-if", - "cstr_core", "libc", - "libm", + "num-traits", "num_enum", "ogc-sys", "voladdress", diff --git a/examples/texture-tri/src/main.rs b/examples/texture-tri/src/main.rs index 751a611..cbfb04f 100644 --- a/examples/texture-tri/src/main.rs +++ b/examples/texture-tri/src/main.rs @@ -1,7 +1,7 @@ #![no_std] -#![feature(start)] +#![no_main] -use core::{alloc::Layout, mem::ManuallyDrop}; +use core::mem::ManuallyDrop; use ogc_rs::{ ffi::{ @@ -22,8 +22,8 @@ extern crate alloc; use alloc::vec; const WHITE_BYTES: &[u8] = include_bytes!("../white.png"); -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { let vi = Video::init(); let mut config = Video::get_preferred_mode(); diff --git a/powerpc-unknown-eabi.json b/powerpc-unknown-eabi.json index 8255cfc..e28c9fd 100644 --- a/powerpc-unknown-eabi.json +++ b/powerpc-unknown-eabi.json @@ -27,7 +27,7 @@ "target-endian": "big", "target-family": "unix", "target-mcount": "_mcount", - "target-c-int-width": "32", + "target-c-int-width": 32, "target-pointer-width": "32", "vendor": "nintendo" } diff --git a/src/aesnd.rs b/src/aesnd.rs index 83c004f..c4b6fd5 100644 --- a/src/aesnd.rs +++ b/src/aesnd.rs @@ -59,9 +59,11 @@ impl Aesnd { unsafe { ffi::AESND_GetDSPProcessUsage() } } - pub fn register_audio_callback(callback: Option) { + pub fn register_audio_callback( + callback: Option, + ) { unsafe { - ffi::AESND_RegisterAudioCallbackWithArg(callback, core::ptr::null_mut()); + ffi::AESND_RegisterAudioCallbackWithArg(callback, core::ptr::null_mut()); } } @@ -119,7 +121,7 @@ impl Aesnd { pub fn set_voice_buffer(play_state: &mut AESNDPB, buffer: &[u8]) { //if already aligned just use the buffer. - if buffer.as_ptr().align_offset(32) == 0 && buffer.len() % 32 == 0 { + if buffer.as_ptr().align_offset(32) == 0 && buffer.len().is_multiple_of(32) { unsafe { ffi::AESND_SetVoiceBuffer( play_state, @@ -131,7 +133,7 @@ impl Aesnd { // othersize copy and allocate a buffer for AESND :) let align_buf = crate::utils::alloc_aligned_buffer(buffer); assert!( - align_buf.len() % 32 == 0, + align_buf.len().is_multiple_of(32), "Buffer is not padded to 32 bytes" ); unsafe { @@ -152,7 +154,7 @@ impl Aesnd { delay: u32, loop_: bool, ) { - if buffer.as_ptr().align_offset(32) == 0 && buffer.len() % 32 == 0 { + if buffer.as_ptr().align_offset(32) == 0 && buffer.len().is_multiple_of(32) { unsafe { ffi::AESND_PlayVoice( play_state, @@ -167,7 +169,7 @@ impl Aesnd { } else { let align_buf = crate::utils::alloc_aligned_buffer(buffer); assert!( - align_buf.len() % 32 == 0, + align_buf.len().is_multiple_of(32), "Buffer is not padded to 32 bytes" ); unsafe { diff --git a/src/asnd.rs b/src/asnd.rs index 2ec68b6..89ebc98 100644 --- a/src/asnd.rs +++ b/src/asnd.rs @@ -61,7 +61,7 @@ impl VoiceOptions { /// Voice slot to use for this sound. Valid values are `0..16` non-inclusive. #[must_use] pub fn voice(mut self, voice: u32) -> Self { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); self.voice = voice; self } @@ -259,7 +259,7 @@ impl Asnd { /// `Asnd::set_voice()`, which must return `Ok()`. /// The buffer MUST be aligned and padded to 32 bytes. fn add_voice(voice: u32, sound_buffer: &mut [u8]) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); Self::validate_buffer(sound_buffer); let err = unsafe { @@ -276,21 +276,21 @@ impl Asnd { /// Stops the selected voice. If the voice is used in song mode, you need to /// assign the samples with `Asnd::set_song_sample_voice()`. pub fn stop_voice(voice: u32) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); let err = unsafe { ffi::ASND_StopVoice(voice as i32) }; if_not!(SND_OK => "Asnd::stop_voice() failed with error {}", err) } /// Pauses the selected voice. Can also be used to resume voice. pub fn pause_voice(voice: u32, pause: bool) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); let err = unsafe { ffi::ASND_PauseVoice(voice as i32, pause as i32) }; if_not!(SND_OK => "Asnd::pause_voice() failed with error {}", err) } /// Returns the state of the selected voice. pub fn status_voice(voice: u32) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); let err = unsafe { ffi::ASND_StatusVoice(voice as i32) }; if_not!(SND_WORKING => "Asnd::status_voice() failed with error {}", err) } @@ -301,8 +301,7 @@ impl Asnd { match err { x if x < 16 => Ok(x as u32), _ => Err(OgcError::Audio(format!( - "Asnd::get_first_unused_voice() failed with error {}", - err + "Asnd::get_first_unused_voice() failed with error {err}", ))), } } @@ -310,7 +309,7 @@ impl Asnd { /// Changes the voice-pitch in real time. This function can be used to /// create audio effects such as Doppler effect simulation. pub fn change_pitch_voice(voice: u32, pitch: u32) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); let err = unsafe { ffi::ASND_ChangePitchVoice(voice as i32, pitch as i32) }; if_not!(SND_OK => "Asnd::change_pitch_voice() failed with error {}", err) } @@ -318,7 +317,7 @@ impl Asnd { /// Changes the voice volume in real time. This function can be used to create /// audio effects like distance attenuation. pub fn change_volume_voice(voice: u32, volume_left: u8, volume_right: u8) -> Result<()> { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); let err = unsafe { ffi::ASND_ChangeVolumeVoice(voice as i32, volume_left as i32, volume_right as i32) }; @@ -329,14 +328,14 @@ impl Asnd { /// since this voice started to play, sans delay time. If the lib is initialized with /// `INIT_RATE=48000`, a return value of 24000 is equal to 0.5 seconds. pub fn get_tick_counter_voice(voice: u32) -> u32 { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); unsafe { ffi::ASND_GetTickCounterVoice(voice as i32) } } /// Returns the voice playback time. This value represents the time in milliseconds /// since this voice started playing. pub fn get_timer_voice(voice: u32) -> u32 { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); unsafe { ffi::ASND_GetTimerVoice(voice as i32) } } @@ -346,14 +345,14 @@ impl Asnd { /// Returns 1 if the pointer is used as a buffer. /// Returns `ogc_sys::SND_INVALID` if invalid. pub fn test_pointer(voice: u32, pointer: *mut T) -> i32 { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); unsafe { ffi::ASND_TestPointer(voice as i32, pointer as *mut _) } } /// Tests to determine if the voice is ready to receive a new buffer sample /// with `Asnd::add_voice()`. Returns true if voice is ready. pub fn test_voice_buffer_ready(voice: u32) -> bool { - assert!(voice < 16, "Voice index {} is >= 16", voice); + assert!(voice < 16, "Voice index {voice} is >= 16"); unsafe { ffi::ASND_TestVoiceBufferReady(voice as i32) > 0 } } @@ -373,9 +372,8 @@ impl Asnd { sound_buffer.as_ptr().align_offset(32), "Data is not aligned correctly." ); - assert_eq!( - 0, - sound_buffer.len() % 32, + assert!( + sound_buffer.len().is_multiple_of(32), "Data length is not a multiple of 32." ); } diff --git a/src/error.rs b/src/error.rs index 0641d04..0eda5f0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,10 +17,10 @@ pub enum OgcError { impl fmt::Debug for OgcError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - OgcError::Network(err) => write!(f, "[ OGC - Network ]: {}", err), - OgcError::Audio(err) => write!(f, "[ OGC - Audio ]: {}", err), - OgcError::Console(err) => write!(f, "[ OGC - Console ]: {}", err), - OgcError::System(err) => write!(f, "[ OGC - System ]: {}", err), + OgcError::Network(err) => write!(f, "[ OGC - Network ]: {err}"), + OgcError::Audio(err) => write!(f, "[ OGC - Audio ]: {err}"), + OgcError::Console(err) => write!(f, "[ OGC - Console ]: {err}"), + OgcError::System(err) => write!(f, "[ OGC - System ]: {err}"), } } } @@ -28,10 +28,10 @@ impl fmt::Debug for OgcError { impl fmt::Display for OgcError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - OgcError::Network(err) => write!(f, "[ OGC - Network ]: {}", err), - OgcError::Audio(err) => write!(f, "[ OGC - Audio ]: {}", err), - OgcError::Console(err) => write!(f, "[ OGC - Console ]: {}", err), - OgcError::System(err) => write!(f, "[ OGC - System ]: {}", err), + OgcError::Network(err) => write!(f, "[ OGC - Network ]: {err}"), + OgcError::Audio(err) => write!(f, "[ OGC - Audio ]: {err}"), + OgcError::Console(err) => write!(f, "[ OGC - Console ]: {err}"), + OgcError::System(err) => write!(f, "[ OGC - System ]: {err}"), } } } diff --git a/src/gu.rs b/src/gu.rs index 29d3445..fe715c4 100644 --- a/src/gu.rs +++ b/src/gu.rs @@ -418,7 +418,7 @@ impl Mat4 { 0.0, -(top + bottom) * top_bottom_aspect, ], - [0.0, 0.0, -(1.0) * plane, -(z_far) * plane], + [0.0, 0.0, -plane, -(z_far) * plane], [0.0, 0.0, 0.0, 1.0], ]) } diff --git a/src/gx/mod.rs b/src/gx/mod.rs index fead90f..2e1541e 100644 --- a/src/gx/mod.rs +++ b/src/gx/mod.rs @@ -863,17 +863,17 @@ pub enum WrapMode { #[repr(transparent)] pub struct Texture<'img>(ffi::GXTexObj, PhantomData<&'img [u8]>); -impl Texture<'_> { +impl<'a> Texture<'a> { /// Used to initialize or change a texture object for non-color index textures. pub fn new( - img: &[u8], + img: &'a [u8], width: u16, height: u16, format: u8, wrap_s: WrapMode, wrap_t: WrapMode, mipmap: bool, - ) -> Texture { + ) -> Texture<'a> { let texture = core::mem::MaybeUninit::zeroed(); assert_eq!(0, img.as_ptr().align_offset(32)); assert!(width <= 1024, "max width for texture is 1024"); @@ -895,14 +895,14 @@ impl Texture<'_> { /// Used to initialize or change a texture object when the texture is color index format. pub fn with_color_idx( - img: &[u8], + img: &'a [u8], width: u16, height: u16, format: u8, wrap: (WrapMode, WrapMode), mipmap: bool, tlut_name: u32, - ) -> Texture { + ) -> Texture<'a> { let texture = core::mem::MaybeUninit::zeroed(); assert_eq!(0, img.as_ptr().align_offset(32)); assert!(width <= 1024, "max width for texture is 1024"); @@ -1984,8 +1984,8 @@ impl Gx { /// Allows the CPU to write color directly to the Embedded Frame Buffer (EFB) at position x, y. /// See [GX_PokeARGB](https://libogc.devkitpro.org/gx_8h.html#a5038d2f65e7959d64c68dcb1855353d8) for more. pub fn poke_argb(x: u16, y: u16, color: Color) { - assert!(x < 640, "x must be less than 640, currently {}", x); - assert!(y < 528, "y must be less than 527, currently {}", y); + assert!(x < 640, "x must be less than 640, currently {x}"); + assert!(y < 528, "y must be less than 527, currently {y}"); unsafe { ffi::GX_PokeARGB(x, y, color.0); } @@ -2359,7 +2359,7 @@ fn call_display_list(display_list: &[u8]) { "The display list is not correctly 32 byte aligned." ); assert!( - display_list.len() % 32 == 0, + display_list.len().is_multiple_of(32), "The display list is not correctly padded to 32 bytes. Please pad with GPCommand::Nop" ); @@ -2417,4 +2417,3 @@ pub enum ColorChannel { Color0 = ffi::GX_COLOR0, Color1 = ffi::GX_COLOR1, } - diff --git a/src/ios.rs b/src/ios.rs index 27882a9..4921688 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -1,5 +1,6 @@ #![warn(missing_docs)] #![warn(clippy::pedantic)] +//#![allow(clippy::missing_errors_doc)] use core::{ffi::CStr, fmt::Display}; diff --git a/src/ios/es.rs b/src/ios/es.rs index 3270a87..793b1a1 100644 --- a/src/ios/es.rs +++ b/src/ios/es.rs @@ -192,7 +192,7 @@ impl From for i32 { Ioctl::VerifySign => 49, Ioctl::GetStoredContentCount => 50, Ioctl::GetStoredContents => 51, - Ioctl::GetStoredTitleMetadataSize => 32, + Ioctl::GetStoredTitleMetadataSize => 52, Ioctl::GetStoredTitleMetadata => 53, Ioctl::GetSharedContentCount => 54, Ioctl::GetSharedContents => 55, @@ -222,6 +222,8 @@ use crate::ios::{self, FileDescriptor}; /// [`Ioctl::AddTicket`] /// /// Add ticket, certificates and certificate revoke list to system +/// # Errors +/// See [`ios::Error`] pub fn add_ticket( signed_ticket: &[u8], signed_certs: &[u8], @@ -245,6 +247,8 @@ pub fn add_ticket( /// /// Add title metadata, certificates and certifacte revoke list to system /// Needs to be canceled with the same file descriptor that this function is called with +/// # Errors +/// See [`ios::Error`] pub fn add_title_start( es: FileDescriptor, signed_title_meta: &[u8], @@ -270,6 +274,8 @@ pub fn add_title_start( /// /// Return content file descriptor for `title_id` and `content_id` /// Needs to be finished with the same file descriptor that this function is called with +/// # Errors +/// See [`ios::Error`] pub fn add_content_start( es: FileDescriptor, title_id: u64, @@ -288,6 +294,8 @@ pub fn add_content_start( /// [`Ioctl::AddContentData`] /// /// Add data to content file descriptor +/// # Errors +/// See [`ios::Error`] pub fn add_content_data( es: FileDescriptor, content_fd: i32, @@ -306,6 +314,8 @@ pub fn add_content_data( /// [`Ioctl::AddContentFinish`] /// /// Finish adding content data to content file descriptor +/// # Errors +/// See [`ios::Error`] pub fn add_content_finish(es: FileDescriptor, content_fd: u32) -> Result<(), ios::Error> { ios::ioctlv::<1, 0, 1>( es, @@ -320,6 +330,8 @@ pub fn add_content_finish(es: FileDescriptor, content_fd: u32) -> Result<(), ios /// [`Ioctl::AddTitleFinish`] /// /// Finish adding title to system +/// # Errors +/// See [`ios::Error`] pub fn add_title_finish(es: FileDescriptor) -> Result<(), ios::Error> { ios::ioctlv::<0, 0, 0>(es, Ioctl::AddTitleFinish, &[], &mut [])?; @@ -329,6 +341,8 @@ pub fn add_title_finish(es: FileDescriptor) -> Result<(), ios::Error> { /// [`Ioctl::GetDeviceId`] /// /// Get device id +/// # Errors +/// See [`ios::Error`] pub fn get_device_id() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -343,6 +357,8 @@ pub fn get_device_id() -> Result { /// [`Ioctl::Launch`] /// /// Launch system title +/// # Errors +/// See [`ios::Error`] pub fn launch_title(title_id: u64, ticket_view: &[u8]) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -359,6 +375,8 @@ pub fn launch_title(title_id: u64, ticket_view: &[u8]) -> Result /// [`Ioctl::OpenActiveTitleContent`] /// /// Open content from current title +/// # Errors +/// See [`ios::Error`] pub fn open_active_title_content(es: FileDescriptor, content_idx: u32) -> Result { let fd = ios::ioctlv::<1, 0, 1>( es, @@ -373,6 +391,8 @@ pub fn open_active_title_content(es: FileDescriptor, content_idx: u32) -> Result /// [`Ioctl::ReadContent`] /// /// Read data provided from `content_file_descriptor` into `out_buf` +/// # Errors +/// See [`ios::Error`] pub fn read_content( es: FileDescriptor, content_file_descriptor: i32, @@ -390,6 +410,8 @@ pub fn read_content( /// [`Ioctl::CloseContent`] /// /// Close content +/// # Errors +/// See [`ios::Error`] pub fn close_content(es: FileDescriptor, content_file_descriptor: i32) -> Result<(), ios::Error> { ios::ioctlv::<1, 0, 1>( es, @@ -404,6 +426,8 @@ pub fn close_content(es: FileDescriptor, content_file_descriptor: i32) -> Result /// [`Ioctl::GetOwnedTitleCount`] /// /// Get owned title count +/// # Errors +/// See [`ios::Error`] pub fn get_owned_title_count() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -417,6 +441,8 @@ pub fn get_owned_title_count() -> Result { /// [`Ioctl::GetOwnedTitles`] /// /// Get ids for owned titles +/// # Errors +/// See [`ios::Error`] pub fn get_owned_titles(title_count: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -430,14 +456,22 @@ pub fn get_owned_titles(title_count: u32) -> Result, ios::Error> { )?; // TODO: Avoid allocation - Ok(out_buf + out_buf .chunks_exact(core::mem::size_of::()) - .map(|bytes| u64::from_be_bytes(bytes.try_into().expect("should fit"))) - .collect()) + .map(|bytes| { + if let Ok(bytes) = bytes.try_into() { + Ok(u64::from_be_bytes(bytes)) + } else { + Err(ios::Error::Invalid) + } + }) + .collect::, ios::Error>>() } /// [`Ioctl::GetTitleCount`] /// /// Get title count +/// # Errors +/// See [`ios::Error`] pub fn get_title_count() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -452,6 +486,8 @@ pub fn get_title_count() -> Result { /// [`Ioctl::GetTitles`] /// /// Get ids for all titles +/// # Errors +/// See [`ios::Error`] pub fn get_titles(title_count: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -464,15 +500,23 @@ pub fn get_titles(title_count: u32) -> Result, ios::Error> { let _ = ios::close(es); // TODO: Avoid allocation - Ok(out_buf + out_buf .chunks_exact(core::mem::size_of::()) - .map(|bytes| u64::from_be_bytes(bytes.try_into().expect("should fit"))) - .collect()) + .map(|bytes| { + if let Ok(bytes) = bytes.try_into() { + Ok(u64::from_be_bytes(bytes)) + } else { + Err(ios::Error::Invalid) + } + }) + .collect::, ios::Error>>() } /// [`Ioctl::GetTitleContentsCount`] /// /// Get title contents count for `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_title_contents_count(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -491,6 +535,8 @@ pub fn get_title_contents_count(title_id: u64) -> Result { /// [`Ioctl::GetTitleContents`] /// /// Get content ids of title with `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_title_contents(title_id: u64, content_count: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -506,15 +552,23 @@ pub fn get_title_contents(title_id: u64, content_count: u32) -> Result, let _ = ios::close(es); //TODO: avoid allocation - Ok(out_buf + out_buf .chunks_exact(core::mem::size_of::()) - .map(|bytes| u32::from_be_bytes(bytes.try_into().expect("should fit"))) - .collect()) + .map(|bytes| { + if let Ok(bytes) = bytes.try_into() { + Ok(u32::from_be_bytes(bytes)) + } else { + Err(ios::Error::Invalid) + } + }) + .collect::, ios::Error>>() } /// [`Ioctl::GetTicketViewCount`] /// /// Get ticket view count of title with `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_ticket_view_count(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -537,10 +591,13 @@ pub fn get_ticket_view_count(title_id: u64) -> Result { /// [`Ioctl::GetTicketViews`] /// /// Get ticket views for title with `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_ticket_views(title_id: u64, view_count: u32) -> Result, ios::Error> { + const TICKET_VIEW_SIZE: usize = 216; // 0xD8 + let es = ios::open(DEV_ES, ios::Mode::None)?; - const TICKET_VIEW_SIZE: usize = 216; // 0xD8 let mut out_buf = alloc::vec![0u8; TICKET_VIEW_SIZE * view_count as usize]; ios::ioctlv::<2, 1, 3>( es, @@ -556,6 +613,8 @@ pub fn get_ticket_views(title_id: u64, view_count: u32) -> Result, ios:: /// [`Ioctl::GetTitleMetadataViewSize`] /// /// Get title metadata view size for title with `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_title_metadata_view_size(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -577,6 +636,8 @@ pub fn get_title_metadata_view_size(title_id: u64) -> Result { /// [`Ioctl::GetTitleMetadataView`] /// /// Get title metadata view for title with `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_title_metadata_view(title_id: u64, size: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -599,6 +660,8 @@ pub fn get_title_metadata_view(title_id: u64, size: u32) -> Result, ios: } /// Get tiklimit consumption count +/// # Errors +/// See [`ios::Error`] pub fn get_consumption_count(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -619,10 +682,13 @@ pub fn get_consumption_count(title_id: u64) -> Result { /// [`Ioctl::GetConsumption`] /// /// Get tiklimit consumption +/// # Errors +/// See [`ios::Error`] pub fn get_consumption(title_id: u64, limit_count: u32) -> Result, ios::Error> { + const TIKLIMIT_SIZE: usize = 8; + let es = ios::open(DEV_ES, ios::Mode::None)?; - const TIKLIMIT_SIZE: usize = 8; let limit_count = usize::try_from(limit_count).map_err(|_| ios::Error::Invalid)?; let title_id_in_buf = title_id.to_be_bytes(); @@ -642,6 +708,8 @@ pub fn get_consumption(title_id: u64, limit_count: u32) -> Result, ios:: /// [`Ioctl::DeleteTitle`] /// /// Delete title from system +/// # Errors +/// See [`ios::Error`] pub fn delete_title(title_id: u64) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -655,6 +723,8 @@ pub fn delete_title(title_id: u64) -> Result<(), ios::Error> { /// [`Ioctl:::DeleteTicket`] /// /// Delete ticket from system +/// # Errors +/// See [`ios::Error`] pub fn delete_ticket(ticket_view: &[u8]) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -668,6 +738,8 @@ pub fn delete_ticket(ticket_view: &[u8]) -> Result<(), ios::Error> { /// [`Ioctl::DiskInterfaceGetTitleMetadataViewSize`] /// /// Get current disk's title metadata view size +/// # Errors +/// See [`ios::Error`] pub fn disk_interface_get_title_metadata_view_size( signed_title_meta: &[u8], ) -> Result { @@ -690,6 +762,8 @@ pub fn disk_interface_get_title_metadata_view_size( /// [`Ioctl::DiskInterfaceGetTitleMetadataView`] /// /// Get current disk's title metadata view +/// # Errors +/// See [`ios::Error`] pub fn disk_interface_get_title_metadata_view( signed_title_meta: &[u8], tmd_view_size: u32, @@ -714,6 +788,8 @@ const TICKET_VIEW_SIZE: usize = 216; // 0xD8 /// [`Ioctl::DiskInterfaceGetTicketView`] /// /// Get current disk's ticket view +/// # Errors +/// See [`ios::Error`] pub fn disk_interface_get_ticket_view( signed_ticket: &[u8], ) -> Result<[u8; TICKET_VIEW_SIZE], ios::Error> { @@ -737,6 +813,8 @@ pub fn disk_interface_get_ticket_view( /// [`Ioctl::GetTitleDir`] /// /// Get title with `title_id`'s data directory +/// # Errors +/// See [`ios::Error`] pub fn get_data_directory(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -758,6 +836,8 @@ const DEVICE_CERT_SIZE: usize = 384; /// [`Ioctl::GetDeviceCertificate`] /// /// Get this device's certificate +/// # Errors +/// See [`ios::Error`] pub fn get_device_certificate() -> Result<[u8; DEVICE_CERT_SIZE], ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -773,7 +853,9 @@ pub fn get_device_certificate() -> Result<[u8; DEVICE_CERT_SIZE], ios::Error> { // pub fn import_boot /// [`Ioctl::GetTitleId`] /// -/// Get currently running title's title_id +/// Get currently running title's `title_id` +/// # Errors +/// See [`ios::Error`] pub fn get_title_id() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -788,6 +870,8 @@ pub fn get_title_id() -> Result { /// [`Ioctl::SetUid`] /// /// Set E-Ticket system user id +/// # Errors +/// See [`ios::Error`] pub fn set_uid(uid: u64) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -801,6 +885,8 @@ pub fn set_uid(uid: u64) -> Result<(), ios::Error> { /// [`Ioctl::DeleteTitleContent`] /// /// Delete title with `title_id` contents +/// # Errors +/// See [`ios::Error`] pub fn delete_title_content(title_id: u64) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -819,6 +905,8 @@ pub fn delete_title_content(title_id: u64) -> Result<(), ios::Error> { /// [`Ioctl::SeekContent`] /// /// Seek contents to `offset` using `seek_mode` +/// # Errors +/// See [`ios::Error`] pub fn seek_content( content_file_descriptor: i32, seek_mode: ios::SeekMode, @@ -845,6 +933,8 @@ pub fn seek_content( /// [`Ioctl::OpenContent`] /// /// Open title with `title_id` contents at `content_idx` using `ticket_views` +/// # Errors +/// See [`ios::Error`] pub fn open_title_content( title_id: u64, ticket_views: &[u8], @@ -873,6 +963,8 @@ pub fn open_title_content( /// [`Ioctl::ExportTitleInitalize`] /// /// Export title with `title_id` metadata into `export_tmd_buf` +/// # Errors +/// See [`ios::Error`] pub fn export_title_init(title_id: u64, exported_tmd_buf: &mut [u8]) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -890,6 +982,8 @@ pub fn export_title_init(title_id: u64, exported_tmd_buf: &mut [u8]) -> Result<( /// [`Ioctl::ExportContentBegin`] /// /// Open title with `title_id`'s content with `content_id` +/// # Errors +/// See [`ios::Error`] pub fn export_content_begin(title_id: u64, content_id: u32) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -909,6 +1003,8 @@ pub fn export_content_begin(title_id: u64, content_id: u32) -> Result Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -945,6 +1043,8 @@ pub fn export_content_end(content_file_descriptor: i32) -> Result<(), ios::Error } /// [`Ioctl::ExportTitleDone`] +/// # Errors +/// See [`ios::Error`] pub fn export_title_done() -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -958,6 +1058,8 @@ pub fn export_title_done() -> Result<(), ios::Error> { /// [`Ioctl::AddTitleMetadata`] /// /// Add title metadata to system +/// # Errors +/// See [`ios::Error`] pub fn add_tmd(title_meta: &[u8]) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -988,6 +1090,8 @@ pub enum Key { /// [`Ioctl::Encrypt`] /// /// Encrypt `source` with `iv` and `key` outputing to `destination` +/// # Errors +/// See [`ios::Error`] pub fn encrypt( keynum: Key, iv: &mut [u8; 16], @@ -995,7 +1099,7 @@ pub fn encrypt( destination: &mut [u8], ) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; - let iv_copy = iv.clone(); + let iv_copy = *iv; ios::ioctlv::<3, 2, 5>( es, @@ -1012,6 +1116,8 @@ pub fn encrypt( /// [`Ioctl::Decrypt`] /// /// Decrypt `source` with `iv` and `key` outputing to `destination` +/// # Errors +/// See [`ios::Error`] pub fn decrypt( keynum: Key, iv: &mut [u8; 16], @@ -1019,7 +1125,7 @@ pub fn decrypt( destination: &mut [u8], ) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; - let iv_copy = iv.clone(); + let iv_copy = *iv; ios::ioctlv::<3, 2, 5>( es, @@ -1036,6 +1142,8 @@ pub fn decrypt( /// [`Ioctl::GetBoot2Version`] /// /// Get boot 2 version +/// # Errors +/// See [`ios::Error`] pub fn get_boot_2_version() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1051,6 +1159,8 @@ pub fn get_boot_2_version() -> Result { /// [`Ioctl::AddTitleCancel`] /// /// Cancel add title to nand +/// # Errors +/// See [`ios::Error`] pub fn cancel_add_title() -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1064,6 +1174,8 @@ pub fn cancel_add_title() -> Result<(), ios::Error> { /// [`Ioctl::Sign`] /// /// Sign provided `data` returning a signature and certificate +/// # Errors +/// See [`ios::Error`] pub fn sign(data: &[u8]) -> Result<([u8; 60], [u8; 0x180]), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1078,6 +1190,8 @@ pub fn sign(data: &[u8]) -> Result<([u8; 60], [u8; 0x180]), ios::Error> { /// [`Ioctl::VerifySign`] /// /// Taking in `data_sha1`, `signature` and `certs` verify if properly signed +/// # Errors +/// See [`ios::Error`] pub fn verify_sign(data_sha1: &[u8], signature: &[u8], certs: &[u8]) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1095,6 +1209,8 @@ pub fn verify_sign(data_sha1: &[u8], signature: &[u8], certs: &[u8]) -> Result<( /// [`Ioctl::GetStoredContentCount`] /// /// Get count of contents stored on the NAND +/// # Errors +/// See [`ios::Error`] pub fn get_stored_contents_count(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1115,6 +1231,8 @@ pub fn get_stored_contents_count(title_id: u64) -> Result { /// [`Ioctl::GetStoredContents`] /// /// Get contents stored on the NAND +/// # Errors +/// See [`ios::Error`] pub fn get_stored_contents(title_id: u64, content_count: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1128,15 +1246,23 @@ pub fn get_stored_contents(title_id: u64, content_count: u32) -> Result let _ = ios::close(es); - Ok(content_ids + content_ids .chunks_exact(4) - .map(|bytes| u32::from_be_bytes(bytes.try_into().unwrap())) - .collect()) + .map(|bytes| { + if let Ok(bytes) = bytes.try_into() { + Ok(u32::from_be_bytes(bytes)) + } else { + Err(ios::Error::Invalid) + } + }) + .collect::, ios::Error>>() } /// [`Ioctl::GetStoredTitleMetadataSize`] /// /// Get stored title metadata size of `title_id` title +/// # Errors +/// See [`ios::Error`] pub fn get_stored_title_metadata_size(title_id: u64) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1151,9 +1277,7 @@ pub fn get_stored_title_metadata_size(title_id: u64) -> Result let _ = ios::close(es); - Ok(u32::from_be_bytes( - out_buf.try_into().map_err(|_| ios::Error::Invalid)?, - )) + Ok(u32::from_be_bytes(out_buf)) } // TODO: Proper enuming since there are different signature types and differing sizes for them @@ -1161,6 +1285,8 @@ pub fn get_stored_title_metadata_size(title_id: u64) -> Result /// [`Ioctl::GetStoredTitleMetadata`] /// /// Get stored title metadata of `title_id` title +/// # Errors +/// See [`ios::Error`] pub fn get_stored_title_metadata(title_id: u64, size: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1184,6 +1310,8 @@ pub fn get_stored_title_metadata(title_id: u64, size: u32) -> Result, io /// [`Ioctl::GetSharedContentCount`] /// /// Get shared contents count on NAND +/// # Errors +/// See [`ios::Error`] pub fn get_shared_contents_count() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1204,6 +1332,8 @@ pub fn get_shared_contents_count() -> Result { /// [`Ioctl::GetSharedContents`] /// /// Get shared contents sha1 hashes on NAND +/// # Errors +/// See [`ios::Error`] pub fn get_shared_contents(shared_contents_count: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1223,6 +1353,8 @@ pub fn get_shared_contents(shared_contents_count: u32) -> Result, ios::E /// [`Ioctl::DeleteSharedContents`] /// /// Delete shared content based on the provided `sha1_hash` +/// # Errors +/// See [`ios::Error`] pub fn delete_shared_content(sha1_hash: &[u8; 20]) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1233,6 +1365,8 @@ pub fn delete_shared_content(sha1_hash: &[u8; 20]) -> Result<(), ios::Error> { /// [`Ioctl::DiskInterfaceGetTitleMetadataSize`] /// /// Get disk title metadata size +/// # Errors +/// See [`ios::Error`] pub fn disk_interface_get_title_metadata_size() -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1253,6 +1387,8 @@ pub fn disk_interface_get_title_metadata_size() -> Result { /// [`Ioctl::DiskInterfaceGetTitleMetadata`] /// /// Get disk title metadata +/// # Errors +/// See [`ios::Error`] pub fn disk_interface_get_title_metadata(size: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1274,6 +1410,8 @@ pub fn disk_interface_get_title_metadata(size: u32) -> Result, ios::Erro /// [`Ioctl::SetupStreamKey`] /// /// Setup stream key +/// # Errors +/// See [`ios::Error`] pub fn setup_stream_key(tik_view: &[u8], tmd: &[u8]) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1281,7 +1419,7 @@ pub fn setup_stream_key(tik_view: &[u8], tmd: &[u8]) -> Result ios::ioctlv::<2, 1, 3>( es, Ioctl::SetupStreamKey, - &[&tik_view, &tmd], + &[tik_view, tmd], &mut [&mut handle], )?; @@ -1294,6 +1432,8 @@ pub fn setup_stream_key(tik_view: &[u8], tmd: &[u8]) -> Result /// [`Ioctl::DeleteStreamKey`] /// /// Delete stream key +/// # Errors +/// See [`ios::Error`] pub fn delete_stream_key(handle: u32) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1312,6 +1452,8 @@ pub fn delete_stream_key(handle: u32) -> Result<(), ios::Error> { /// [`Ioctl::DeleteContent`] /// /// Delete `title_id` title's content using `content_id` +/// # Errors +/// See [`ios::Error`] pub fn delete_content(title_id: u64, content_id: u32) -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1331,6 +1473,8 @@ const TICKET_SIZE: usize = 0x2A4; /// [`Ioctl::GetVersion0TicketFromView`] /// /// Get version ticket from provided `tik_view` +/// # Errors +/// See [`ios::Error`] pub fn get_version_0_ticket_from_view(tik_view: &[u8]) -> Result<[u8; TICKET_SIZE], ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1338,7 +1482,7 @@ pub fn get_version_0_ticket_from_view(tik_view: &[u8]) -> Result<[u8; TICKET_SIZ ios::ioctlv::<1, 1, 2>( es, Ioctl::GetVersion0TicketFromView, - &[&tik_view], + &[tik_view], &mut [&mut ticket], )?; @@ -1350,6 +1494,8 @@ pub fn get_version_0_ticket_from_view(tik_view: &[u8]) -> Result<[u8; TICKET_SIZ /// [`Ioctl::GetTicketFromView`] /// /// Get ticket size from provided `tik_view` +/// # Errors +/// See [`ios::Error`] pub fn get_ticket_size_from_view(tik_view: &[u8]) -> Result { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1357,7 +1503,7 @@ pub fn get_ticket_size_from_view(tik_view: &[u8]) -> Result { ios::ioctlv::<1, 1, 2>( es, Ioctl::GetTicketSizeFromView, - &[&tik_view], + &[tik_view], &mut [&mut size], )?; @@ -1370,6 +1516,8 @@ pub fn get_ticket_size_from_view(tik_view: &[u8]) -> Result { /// [`Ioctl::GetTicketFromView`] /// /// Get ticket from provided `tik_view` +/// # Errors +/// See [`ios::Error`] pub fn get_ticket_from_view(tik_view: &[u8], size: u32) -> Result, ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; @@ -1377,7 +1525,7 @@ pub fn get_ticket_from_view(tik_view: &[u8], size: u32) -> Result, ios:: ios::ioctlv::<2, 1, 3>( es, Ioctl::GetTicketFromView, - &[&tik_view, &size.to_be_bytes()], + &[tik_view, &size.to_be_bytes()], &mut [&mut ticket], )?; @@ -1389,6 +1537,8 @@ pub fn get_ticket_from_view(tik_view: &[u8], size: u32) -> Result, ios:: /// [`Ioctl::CheckKoreaRegion`] /// /// Check if the console's region is Korea +/// # Errors +/// See [`ios::Error`] pub fn check_korea_region() -> Result<(), ios::Error> { let es = ios::open(DEV_ES, ios::Mode::None)?; diff --git a/src/mmio/dsp.rs b/src/mmio/dsp.rs index ae41ce2..9f3b46e 100644 --- a/src/mmio/dsp.rs +++ b/src/mmio/dsp.rs @@ -15,7 +15,7 @@ pub const CPU_MAILBOX_LO: VolAddress = #[repr(transparent)] pub struct DSPControlStatus(u16); pub const DSP_CONTROL_STATUS_REGISTER: VolAddress = - unsafe { VolAddress::new(0xCC00_500a) }; + unsafe { VolAddress::new(0xCC00_500A) }; pub const AR_SIZE: VolAddress = unsafe { VolAddress::new(0xCC00_5012) }; pub const AR_MODE: VolAddress = unsafe { VolAddress::new(0xCC00_5016) }; diff --git a/src/mmio/vi.rs b/src/mmio/vi.rs index f0f556e..950479b 100644 --- a/src/mmio/vi.rs +++ b/src/mmio/vi.rs @@ -83,7 +83,7 @@ pub const SCALING_WIDTH_REGISTER: VolAddress = #[repr(transparent)] pub struct ScalingControl(u16); pub const HORIZONTAL_SCALING_REGISTER: VolAddress = - unsafe { VolAddress::new(0xCC00_204a) }; + unsafe { VolAddress::new(0xCC00_204A) }; #[repr(transparent)] pub struct FilterCoefficents(u32); diff --git a/src/network.rs b/src/network.rs index d75e482..20f80fa 100644 --- a/src/network.rs +++ b/src/network.rs @@ -239,7 +239,7 @@ pub fn dot_to_net_addr(dot: &str, addr: &mut IPV4Address) -> Result<()> { let r = unsafe { ffi::inet_aton(dot.as_ptr(), &mut addr.into()) }; if r < 0 { - Err(OgcError::Network(format!("network dot_to_net_addr: {}", r))) + Err(OgcError::Network(format!("network dot_to_net_addr: {r}"))) } else { Ok(()) } @@ -313,7 +313,7 @@ impl Network { let r = unsafe { ffi::net_init() }; if r < 0 { - Err(OgcError::Network(format!("network init: {}", r))) + Err(OgcError::Network(format!("network init: {r}"))) } else { Ok(Self) } @@ -324,7 +324,7 @@ impl Network { let r = unsafe { ffi::net_socket(domain.into(), socket_type.into(), 0) }; if r == INVALID_SOCKET { - Err(OgcError::Network(format!("network socket creation: {}", r))) + Err(OgcError::Network(format!("network socket creation: {r}"))) } else { Ok(Socket(r)) } @@ -343,7 +343,7 @@ impl Socket { let r = unsafe { ffi::net_connect(self.0, socket_addr.into(), address_length) }; if r < 0 { - Err(OgcError::Network(format!("network socket connect: {}", r))) + Err(OgcError::Network(format!("network socket connect: {r}"))) } else { Ok(()) } @@ -354,7 +354,7 @@ impl Socket { let r = unsafe { ffi::net_bind(self.0, socket_addr.into(), address_length) }; if r < 0 { - Err(OgcError::Network(format!("network socket bind: {}", r))) + Err(OgcError::Network(format!("network socket bind: {r}"))) } else { Ok(()) } @@ -365,7 +365,7 @@ impl Socket { let r = unsafe { ffi::net_listen(self.0, backlog) }; if r < 0 { - Err(OgcError::Network(format!("network socket listen: {}", r))) + Err(OgcError::Network(format!("network socket listen: {r}"))) } else { Ok(()) } @@ -377,7 +377,7 @@ impl Socket { let r = unsafe { ffi::net_accept(self.0, socket_addr.into(), address_length) }; if r < 0 { - Err(OgcError::Network(format!("network socket accept: {}", r))) + Err(OgcError::Network(format!("network socket accept: {r}"))) } else { Ok(r) } @@ -388,7 +388,7 @@ impl Socket { let r = unsafe { ffi::net_write(descriptor, buffer.as_ptr() as *const c_void, count) }; if r < 0 { - Err(OgcError::Network(format!("network writing failure: {}", r))) + Err(OgcError::Network(format!("network writing failure: {r}"))) } else { Ok(r) } @@ -400,7 +400,7 @@ impl Socket { unsafe { ffi::net_send(descriptor, buffer.as_ptr() as *const c_void, length, flags) }; if r < 0 { - Err(OgcError::Network(format!("network sending failure: {}", r))) + Err(OgcError::Network(format!("network sending failure: {r}"))) } else { Ok(r) } @@ -411,7 +411,7 @@ impl Socket { let r = unsafe { ffi::net_read(descriptor, buffer.as_ptr() as *mut c_void, count) }; if r < 0 { - Err(OgcError::Network(format!("network reading failure: {}", r))) + Err(OgcError::Network(format!("network reading failure: {r}"))) } else { Ok(r) } @@ -422,7 +422,7 @@ impl Socket { let r = unsafe { ffi::net_recv(descriptor, buffer.as_ptr() as *mut c_void, length, flags) }; if r < 0 { - Err(OgcError::Network(format!("network recieve failure: {}", r))) + Err(OgcError::Network(format!("network recieve failure: {r}"))) } else { Ok(r) } diff --git a/src/utils.rs b/src/utils.rs index 5081df6..7c1e10d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,13 +1,13 @@ //! Utility Functions to convert between types. use core::alloc::{Allocator, Layout}; -use core::{fmt, ops}; use core::ptr::NonNull; +use core::{fmt, ops}; use alloc::vec::Vec; /// OS memory pointer casting. -/// +/// /// For more information, refer to [Memory map](https://wiibrew.org/wiki/Memory_Map). pub mod mem { use crate::ffi; @@ -69,10 +69,10 @@ mod console_printing { } pub fn alloc_aligned_buffer(buffer: &[u8]) -> Vec { - let size = if buffer.len() % 32 == 0 { + let size = if buffer.len().is_multiple_of(32) { buffer.len() } else { - ((buffer.len() + 31) / 32) * 32 + buffer.len().next_multiple_of(32) }; let mut align_buf = unsafe { @@ -97,7 +97,6 @@ pub fn alloc_aligned_buffer(buffer: &[u8]) -> Vec { align_buf } - /// A heap-allocated buffer guaranteed to be aligned to a 32-byte boundary. /// /// This buffer does not grow or reallocate. It's meant as a simple way to @@ -107,86 +106,86 @@ pub fn alloc_aligned_buffer(buffer: &[u8]) -> Vec { pub struct Buf32(NonNull<[u8]>); impl Buf32 { - /// Allocates a new buffer at least `min_len` bytes long. Rounds up the size - /// to the next multiple of 32. - /// - /// # Panics - /// Panics if rounding up `min_len` to the next multiple of 32 would - /// overflow. - pub fn new(min_len: usize) -> Self { - // round len to lowest multiple of 32 - let padding = (32 - min_len % 32) % 32; - min_len.checked_add(padding).expect("length overflow"); - - // SAFETY: - // * align is non-zero and a power of two. - // * `min_len` is checked above to not overflow `usize::MAX` after rounding up - // for alignment. - let layout = unsafe { Layout::from_size_align_unchecked(min_len, 32) }; - - let block = match alloc::alloc::Global.allocate_zeroed(layout) { - Ok(block) => block, - Err(_) => alloc::alloc::handle_alloc_error(layout), - }; - - Buf32(block) - } + /// Allocates a new buffer at least `min_len` bytes long. Rounds up the size + /// to the next multiple of 32. + /// + /// # Panics + /// Panics if rounding up `min_len` to the next multiple of 32 would + /// overflow. + pub fn new(min_len: usize) -> Self { + // round len to lowest multiple of 32 + let padding = (32 - min_len % 32) % 32; + min_len.checked_add(padding).expect("length overflow"); + + // SAFETY: + // * align is non-zero and a power of two. + // * `min_len` is checked above to not overflow `usize::MAX` after rounding up + // for alignment. + let layout = unsafe { Layout::from_size_align_unchecked(min_len, 32) }; + + let block = match alloc::alloc::Global.allocate_zeroed(layout) { + Ok(block) => block, + Err(_) => alloc::alloc::handle_alloc_error(layout), + }; + + Buf32(block) + } - /// Extracts a slice of the entire buffer. - pub fn as_slice(&self) -> &[u8] { - // SAFETY: `self.0` is aligned, dereferenceable, initialized, and - // enforces aliasing rules by binding the reference's lifetime - // to that of `&self`. - unsafe { self.0.as_ref() } - } + /// Extracts a slice of the entire buffer. + pub fn as_slice(&self) -> &[u8] { + // SAFETY: `self.0` is aligned, dereferenceable, initialized, and + // enforces aliasing rules by binding the reference's lifetime + // to that of `&self`. + unsafe { self.0.as_ref() } + } - /// Extracts a mutable slice of the entire buffer. - pub fn as_mut_slice(&mut self) -> &mut [u8] { - // SAFETY: `self.0` is aligned, dereferenceable, initialized, and - // enforces aliasing rules by binding the reference's lifetime - // to that of `&mut self`. - unsafe { self.0.as_mut() } - } + /// Extracts a mutable slice of the entire buffer. + pub fn as_mut_slice(&mut self) -> &mut [u8] { + // SAFETY: `self.0` is aligned, dereferenceable, initialized, and + // enforces aliasing rules by binding the reference's lifetime + // to that of `&mut self`. + unsafe { self.0.as_mut() } + } } impl Clone for Buf32 { - fn clone(&self) -> Self { - let mut new_buf = Self::new(self.len()); - new_buf.clone_from(self); - new_buf - } - - fn clone_from(&mut self, source: &Self) { - self.as_mut_slice().copy_from_slice(source.as_slice()); - } + fn clone(&self) -> Self { + let mut new_buf = Self::new(self.len()); + new_buf.clone_from(self); + new_buf + } + + fn clone_from(&mut self, source: &Self) { + self.as_mut_slice().copy_from_slice(source.as_slice()); + } } impl core::ops::Deref for Buf32 { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.as_slice() - } + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } } impl core::ops::DerefMut for Buf32 { - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut_slice() - } + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } } impl ops::Index for Buf32 { - type Output = u8; - - fn index(&self, index: usize) -> &Self::Output { - &self.as_slice()[index] - } + type Output = u8; + + fn index(&self, index: usize) -> &Self::Output { + &self.as_slice()[index] + } } impl ops::IndexMut for Buf32 { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.as_mut_slice()[index] - } + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.as_mut_slice()[index] + } } macro_rules! impl_index_for_buf32 { @@ -194,12 +193,12 @@ macro_rules! impl_index_for_buf32 { $( impl ops::Index<$idx> for Buf32 { type Output = [u8]; - + fn index(&self, index: $idx) -> &Self::Output { &self.as_slice()[index] } } - + impl ops::IndexMut<$idx> for Buf32 { fn index_mut(&mut self, index: $idx) -> &mut Self::Output { &mut self.as_mut_slice()[index] @@ -210,50 +209,50 @@ macro_rules! impl_index_for_buf32 { } impl_index_for_buf32! { - ops::RangeFull, - ops::RangeFrom, - ops::RangeTo, - ops::Range, - ops::RangeInclusive, - ops::RangeToInclusive + ops::RangeFull, + ops::RangeFrom, + ops::RangeTo, + ops::Range, + ops::RangeInclusive, + ops::RangeToInclusive } impl fmt::Debug for Buf32 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.as_slice().fmt(f) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_slice().fmt(f) + } } impl core::cmp::Ord for Buf32 { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.as_slice().cmp(other.as_slice()) - } + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } } impl core::cmp::PartialOrd for Buf32 { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } impl core::cmp::PartialEq for Buf32 { - fn eq(&self, other: &Self) -> bool { - self.as_slice() == other.as_slice() - } + fn eq(&self, other: &Self) -> bool { + self.as_slice() == other.as_slice() + } } impl Drop for Buf32 { - fn drop(&mut self) { - // SAFETY: - // * from_size_align_unchecked(): - // * align is non-zero and a power of two. - // * `len` is already known to not overflow `usize::MAX`. - // * deallocate(): - // * `self.0` is currently allocated. - // * `layout` fits the block, using the size given to us. - unsafe { - let layout = Layout::from_size_align_unchecked(self.len(), 32); - alloc::alloc::Global.deallocate(self.0.as_non_null_ptr(), layout); - } - } + fn drop(&mut self) { + // SAFETY: + // * from_size_align_unchecked(): + // * align is non-zero and a power of two. + // * `len` is already known to not overflow `usize::MAX`. + // * deallocate(): + // * `self.0` is currently allocated. + // * `layout` fits the block, using the size given to us. + unsafe { + let layout = Layout::from_size_align_unchecked(self.len(), 32); + alloc::alloc::Global.deallocate(self.0.as_non_null_ptr(), layout); + } + } }