diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index abc6f79..53d39d3 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -29,6 +29,7 @@ futures = "0.3" time = "0.3.7" tokio = { version = "1.16", features = ["rt", "time", "sync", "macros"] } cfg-if = "1.0.0" +once_cell = "1.10.0" [features] default = ["romfs"] diff --git a/ctru-rs/src/gfx.rs b/ctru-rs/src/gfx.rs index 4016a91..44104f8 100644 --- a/ctru-rs/src/gfx.rs +++ b/ctru-rs/src/gfx.rs @@ -1,13 +1,13 @@ //! LCD screens manipulation helper use std::cell::RefCell; -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::marker::PhantomData; use std::sync::Mutex; use crate::error::{Error, Result}; use crate::services::gspgpu::{self, FramebufferFormat}; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; /// Trait implemented by TopScreen and BottomScreen for common methods pub trait Screen { @@ -73,10 +73,10 @@ pub enum Side { pub struct Gfx { pub top_screen: RefCell, pub bottom_screen: RefCell, - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static GFX_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static GFX_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl Gfx { /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom @@ -88,7 +88,7 @@ impl Gfx { bottom_fb_fmt: FramebufferFormat, use_vram_buffers: bool, ) -> Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &GFX_ACTIVE, false, || unsafe { diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 559f2db..40acf84 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -3,7 +3,6 @@ #![feature(test)] #![feature(custom_test_frameworks)] #![test_runner(test_runner::run)] -#![feature(once_cell)] extern "C" fn services_deinit() { unsafe { @@ -27,9 +26,13 @@ pub fn init() { libc::atexit(services_deinit); } + #[cfg(test)] + panic_hook_setup(); +} + +fn panic_hook_setup() { use std::panic::PanicInfo; - #[cfg(not(test))] let main_thread = thread::current().id(); // Panic Hook setup @@ -38,7 +41,6 @@ pub fn init() { default_hook(info); // Only for panics in the main thread - #[cfg(not(test))] if main_thread == thread::current().id() && console::Console::exists() { println!("\nPress SELECT to exit the software"); diff --git a/ctru-rs/src/romfs.rs b/ctru-rs/src/romfs.rs index 0d366c8..c802706 100644 --- a/ctru-rs/src/romfs.rs +++ b/ctru-rs/src/romfs.rs @@ -11,21 +11,21 @@ //! ``` use std::ffi::CStr; -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; #[non_exhaustive] pub struct RomFS { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static ROMFS_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static ROMFS_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl RomFS { pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &ROMFS_ACTIVE, true, || { @@ -54,14 +54,14 @@ mod tests { #[test] fn romfs_duplicate() { let _romfs = RomFS::init().unwrap(); - let lock = *ROMFS_ACTIVE.lock().unwrap(); + let value = *ROMFS_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); drop(_romfs); - let lock = *ROMFS_ACTIVE.lock().unwrap(); + let value = *ROMFS_ACTIVE.lock().unwrap(); - assert_eq!(lock, 0); + assert_eq!(value, 0); } } diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index 089b896..eb53fe9 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -1,18 +1,18 @@ -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; #[non_exhaustive] pub struct Apt { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static APT_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static APT_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl Apt { pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &APT_ACTIVE, true, || { @@ -23,11 +23,7 @@ impl Apt { Ok(()) }, - // `socExit` returns an error code. There is no documentantion of when errors could happen, - // but we wouldn't be able to handle them in the `Drop` implementation anyways. - // Surely nothing bad will happens :D || unsafe { - // The socket buffer is freed automatically by `socExit` ctru_sys::aptExit(); }, )?; @@ -56,8 +52,8 @@ mod tests { #[test] fn apt_duplicate() { // We don't need to build a `Apt` because the test runner has one already - let lock = *APT_ACTIVE.lock().unwrap(); + let value = *APT_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); } } diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 731e1e0..2c70195 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -9,7 +9,7 @@ use std::io::Error as IoError; use std::io::ErrorKind as IoErrorKind; use std::io::Result as IoResult; use std::io::{Read, Seek, SeekFrom, Write}; -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::mem; use std::path::{Path, PathBuf}; use std::ptr; @@ -18,7 +18,7 @@ use std::sync::{Arc, Mutex}; use widestring::{WideCStr, WideCString}; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; bitflags! { #[derive(Default)] @@ -88,10 +88,10 @@ pub enum ArchiveID { /// The service exits when all instances of this struct go out of scope. #[non_exhaustive] pub struct Fs { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static FS_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static FS_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); /// Handle to an open filesystem archive. /// @@ -311,7 +311,7 @@ impl Fs { /// as many times as desired and the service will not exit until all /// instances of Fs drop out of scope. pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &FS_ACTIVE, true, || { @@ -322,11 +322,7 @@ impl Fs { Ok(()) }, - // `socExit` returns an error code. There is no documentantion of when errors could happen, - // but we wouldn't be able to handle them in the `Drop` implementation anyways. - // Surely nothing bad will happens :D || unsafe { - // The socket buffer is freed automatically by `socExit` ctru_sys::fsExit(); }, )?; @@ -1086,14 +1082,14 @@ mod tests { fn fs_duplicate() { let _fs = Fs::init().unwrap(); - let lock = *FS_ACTIVE.lock().unwrap(); + let value = *FS_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); drop(_fs); - let lock = *FS_ACTIVE.lock().unwrap(); + let value = *FS_ACTIVE.lock().unwrap(); - assert_eq!(lock, 0); + assert_eq!(value, 0); } } diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index c26e96a..53cdf97 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -4,10 +4,10 @@ //! and circle pad information. It also provides information from the sound volume slider, //! the accelerometer, and the gyroscope. -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; bitflags::bitflags! { /// A set of flags corresponding to the button and directional pad @@ -51,10 +51,10 @@ bitflags::bitflags! { /// This service requires no special permissions to use. #[non_exhaustive] pub struct Hid { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static HID_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static HID_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); /// Represents user input to the touchscreen. #[non_exhaustive] @@ -73,7 +73,7 @@ pub struct CirclePosition(ctru_sys::circlePosition); /// rare in practice. impl Hid { pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &HID_ACTIVE, true, || { @@ -176,8 +176,8 @@ mod tests { #[test] fn hid_duplicate() { // We don't need to build a `Hid` because the test runner has one already - let lock = *HID_ACTIVE.lock().unwrap(); + let value = *HID_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); } } diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index 67418de..cc52685 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -5,52 +5,10 @@ pub mod hid; pub mod ps; pub mod soc; pub mod sslc; +mod reference; pub use self::apt::Apt; pub use self::hid::Hid; pub use self::sslc::SslC; -use crate::Error; -use std::sync::Mutex; -pub(crate) struct ServiceHandler { - counter: &'static Mutex, - close: Box, -} - -impl ServiceHandler { - pub fn new( - counter: &'static Mutex, - allow_multiple: bool, - start: S, - close: E, - ) -> crate::Result - where - S: FnOnce() -> crate::Result<()>, - E: Fn() + 'static, - { - let mut value = counter.lock().unwrap(); // todo: handle poisoning - - if *value == 0 { - start()?; - } else if !allow_multiple { - return Err(Error::ServiceAlreadyActive); - } - - *value += 1; - - Ok(Self { - counter, - close: Box::new(close), - }) - } -} - -impl Drop for ServiceHandler { - fn drop(&mut self) { - let mut value = self.counter.lock().unwrap(); // should probably handle poisoning - could just map_err to ignore it. - *value -= 1; - if *value == 0 { - (self.close)(); - } - } -} +pub (crate) use self::reference::ServiceReference; diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index 44041f4..5514adf 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -1,18 +1,18 @@ use libc::memalign; -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::net::Ipv4Addr; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; /// Soc service. Initializing this service will enable the use of network sockets and utilities /// such as those found in `std::net`. The service will be closed when this struct is is dropped. #[non_exhaustive] pub struct Soc { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static SOC_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static SOC_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl Soc { /// Initialize the Soc service with a default buffer size of 0x100000 bytes @@ -31,7 +31,7 @@ impl Soc { /// /// This function will return an error if the `Soc` service is already initialized pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &SOC_ACTIVE, true, || { @@ -69,14 +69,14 @@ mod tests { #[test] fn soc_duplicate() { let _soc = Soc::init().unwrap(); - let lock = *SOC_ACTIVE.lock().unwrap(); + let value = *SOC_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); drop(_soc); - let lock = *SOC_ACTIVE.lock().unwrap(); + let value = *SOC_ACTIVE.lock().unwrap(); - assert_eq!(lock, 0); + assert_eq!(value, 0); } } diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index ba8d41f..5c0d0e4 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -1,21 +1,21 @@ // TODO: Implement remaining functions -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; #[non_exhaustive] pub struct SslC { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static SSLC_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static SSLC_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl SslC { /// Initialize sslc pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &SSLC_ACTIVE, true, || { @@ -26,11 +26,7 @@ impl SslC { Ok(()) }, - // `socExit` returns an error code. There is no documentantion of when errors could happen, - // but we wouldn't be able to handle them in the `Drop` implementation anyways. - // Surely nothing bad will happens :D || unsafe { - // The socket buffer is freed automatically by `socExit` ctru_sys::sslcExit(); }, )?; @@ -57,14 +53,14 @@ mod tests { fn sslc_duplicate() { let _sslc = SslC::init().unwrap(); - let lock = *SSLC_ACTIVE.lock().unwrap(); + let value = *SSLC_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); drop(_sslc); - let lock = *SSLC_ACTIVE.lock().unwrap(); + let value = *SSLC_ACTIVE.lock().unwrap(); - assert_eq!(lock, 0); + assert_eq!(value, 0); } } diff --git a/ctru-rs/src/srv.rs b/ctru-rs/src/srv.rs index fa0f353..5ab83b6 100644 --- a/ctru-rs/src/srv.rs +++ b/ctru-rs/src/srv.rs @@ -1,18 +1,18 @@ -use std::lazy::SyncLazy; +use once_cell::sync::Lazy; use std::sync::Mutex; -use crate::services::ServiceHandler; +use crate::services::ServiceReference; #[non_exhaustive] pub struct Srv { - _service_handler: ServiceHandler, + _service_handler: ServiceReference, } -static SRV_ACTIVE: SyncLazy> = SyncLazy::new(|| Mutex::new(0)); +static SRV_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); impl Srv { pub fn init() -> crate::Result { - let _service_handler = ServiceHandler::new( + let _service_handler = ServiceReference::new( &SRV_ACTIVE, true, || { @@ -40,14 +40,14 @@ mod tests { fn srv_duplicate() { let _srv = Srv::init().unwrap(); - let lock = *SRV_ACTIVE.lock().unwrap(); + let value = *SRV_ACTIVE.lock().unwrap(); - assert_eq!(lock, 1); + assert_eq!(value, 1); drop(_srv); - let lock = *SRV_ACTIVE.lock().unwrap(); + let value = *SRV_ACTIVE.lock().unwrap(); - assert_eq!(lock, 0); + assert_eq!(value, 0); } }