diff --git a/ctru-rs/src/gfx.rs b/ctru-rs/src/gfx.rs index 44104f8..f68f2bc 100644 --- a/ctru-rs/src/gfx.rs +++ b/ctru-rs/src/gfx.rs @@ -1,7 +1,7 @@ //! LCD screens manipulation helper -use std::cell::RefCell; use once_cell::sync::Lazy; +use std::cell::RefCell; use std::marker::PhantomData; use std::sync::Mutex; diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 40acf84..bf3d247 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -26,7 +26,7 @@ pub fn init() { libc::atexit(services_deinit); } - #[cfg(test)] + #[cfg(not(test))] panic_hook_setup(); } diff --git a/ctru-rs/src/romfs.rs b/ctru-rs/src/romfs.rs index c802706..dff45ca 100644 --- a/ctru-rs/src/romfs.rs +++ b/ctru-rs/src/romfs.rs @@ -10,8 +10,8 @@ //! romfs_dir = "romfs" //! ``` -use std::ffi::CStr; use once_cell::sync::Lazy; +use std::ffi::CStr; use std::sync::Mutex; use crate::services::ServiceReference; diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index eb53fe9..4662a4e 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -1,34 +1,15 @@ -use once_cell::sync::Lazy; -use std::sync::Mutex; - -use crate::services::ServiceReference; - -#[non_exhaustive] -pub struct Apt { - _service_handler: ServiceReference, -} - -static APT_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); +pub struct Apt(()); impl Apt { - pub fn init() -> crate::Result { - let _service_handler = ServiceReference::new( - &APT_ACTIVE, - true, - || { - let r = unsafe { ctru_sys::aptInit() }; - if r < 0 { - return Err(r.into()); - } - - Ok(()) - }, - || unsafe { - ctru_sys::aptExit(); - }, - )?; - - Ok(Self { _service_handler }) + pub fn init() -> crate::Result { + unsafe { + let r = ctru_sys::aptInit(); + if r < 0 { + Err(r.into()) + } else { + Ok(Apt(())) + } + } } pub fn main_loop(&self) -> bool { @@ -36,24 +17,19 @@ impl Apt { } pub fn set_app_cpu_time_limit(&self, percent: u32) -> crate::Result<()> { - let r = unsafe { ctru_sys::APT_SetAppCpuTimeLimit(percent) }; - if r < 0 { - Err(r.into()) - } else { - Ok(()) + unsafe { + let r = ctru_sys::APT_SetAppCpuTimeLimit(percent); + if r < 0 { + Err(r.into()) + } else { + Ok(()) + } } } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn apt_duplicate() { - // We don't need to build a `Apt` because the test runner has one already - let value = *APT_ACTIVE.lock().unwrap(); - - assert_eq!(value, 1); +impl Drop for Apt { + fn drop(&mut self) { + unsafe { ctru_sys::aptExit() }; } } diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 2c70195..9f3334a 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -9,17 +9,13 @@ 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 once_cell::sync::Lazy; use std::mem; use std::path::{Path, PathBuf}; use std::ptr; use std::slice; -use std::sync::{Arc, Mutex}; - +use std::sync::Arc; use widestring::{WideCStr, WideCString}; -use crate::services::ServiceReference; - bitflags! { #[derive(Default)] struct FsOpen: u32 { @@ -86,12 +82,7 @@ pub enum ArchiveID { /// until an instance of this struct is created. /// /// The service exits when all instances of this struct go out of scope. -#[non_exhaustive] -pub struct Fs { - _service_handler: ServiceReference, -} - -static FS_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); +pub struct Fs(()); /// Handle to an open filesystem archive. /// @@ -105,7 +96,6 @@ static FS_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); /// let fs = Fs::init().unwrap(); /// let sdmc_archive = fs.sdmc().unwrap(); /// ``` -#[non_exhaustive] pub struct Archive { id: ArchiveID, handle: u64, @@ -174,7 +164,6 @@ pub struct Archive { /// # Ok(()) /// # } /// ``` -#[non_exhaustive] pub struct File { handle: u32, offset: u64, @@ -186,7 +175,6 @@ pub struct File { /// represents known metadata about a file. /// /// [`metadata`]: fn.metadata.html -#[non_exhaustive] pub struct Metadata { attributes: u32, size: u64, @@ -269,7 +257,6 @@ pub struct OpenOptions { /// /// This Result will return Err if there's some sort of intermittent IO error /// during iteration. -#[non_exhaustive] pub struct ReadDir<'a> { handle: Dir, root: Arc, @@ -310,24 +297,15 @@ impl Fs { /// ctrulib services are reference counted, so this function may be called /// 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 = ServiceReference::new( - &FS_ACTIVE, - true, - || { - let r = unsafe { ctru_sys::fsInit() }; - if r < 0 { - return Err(r.into()); - } - - Ok(()) - }, - || unsafe { - ctru_sys::fsExit(); - }, - )?; - - Ok(Self { _service_handler }) + pub fn init() -> crate::Result { + unsafe { + let r = ctru_sys::fsInit(); + if r < 0 { + Err(r.into()) + } else { + Ok(Fs(())) + } + } } /// Returns a handle to the SDMC (memory card) Archive. @@ -1007,6 +985,14 @@ impl Seek for File { } } +impl Drop for Fs { + fn drop(&mut self) { + unsafe { + ctru_sys::fsExit(); + } + } +} + impl Drop for Archive { fn drop(&mut self) { unsafe { @@ -1073,23 +1059,3 @@ impl From for ctru_sys::FS_ArchiveID { } } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn fs_duplicate() { - let _fs = Fs::init().unwrap(); - - let value = *FS_ACTIVE.lock().unwrap(); - - assert_eq!(value, 1); - - drop(_fs); - - let value = *FS_ACTIVE.lock().unwrap(); - - assert_eq!(value, 0); - } -} diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index 53cdf97..18790f1 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -4,11 +4,6 @@ //! and circle pad information. It also provides information from the sound volume slider, //! the accelerometer, and the gyroscope. -use once_cell::sync::Lazy; -use std::sync::Mutex; - -use crate::services::ServiceReference; - bitflags::bitflags! { /// A set of flags corresponding to the button and directional pad /// inputs on the 3DS @@ -49,19 +44,12 @@ bitflags::bitflags! { /// when all instances of this struct fall out of scope. /// /// This service requires no special permissions to use. -#[non_exhaustive] -pub struct Hid { - _service_handler: ServiceReference, -} - -static HID_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); +pub struct Hid(()); /// Represents user input to the touchscreen. -#[non_exhaustive] pub struct TouchPosition(ctru_sys::touchPosition); /// Represents the current position of the 3DS circle pad. -#[non_exhaustive] pub struct CirclePosition(ctru_sys::circlePosition); /// Initializes the HID service. @@ -72,24 +60,15 @@ pub struct CirclePosition(ctru_sys::circlePosition); /// Since this service requires no special or elevated permissions, errors are /// rare in practice. impl Hid { - pub fn init() -> crate::Result { - let _service_handler = ServiceReference::new( - &HID_ACTIVE, - true, - || { - let r = unsafe { ctru_sys::hidInit() }; - if r < 0 { - return Err(r.into()); - } - - Ok(()) - }, - || unsafe { - ctru_sys::hidExit(); - }, - )?; - - Ok(Self { _service_handler }) + pub fn init() -> crate::Result { + unsafe { + let r = ctru_sys::hidInit(); + if r < 0 { + Err(r.into()) + } else { + Ok(Hid(())) + } + } } /// Scans the HID service for all user input occurring on the current @@ -169,15 +148,8 @@ impl CirclePosition { } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn hid_duplicate() { - // We don't need to build a `Hid` because the test runner has one already - let value = *HID_ACTIVE.lock().unwrap(); - - assert_eq!(value, 1); +impl Drop for Hid { + fn drop(&mut self) { + unsafe { ctru_sys::hidExit() }; } } diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index cc52685..0dc750c 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -3,12 +3,12 @@ pub mod fs; pub mod gspgpu; pub mod hid; pub mod ps; +mod reference; pub mod soc; pub mod sslc; -mod reference; pub use self::apt::Apt; pub use self::hid::Hid; pub use self::sslc::SslC; -pub (crate) use self::reference::ServiceReference; +pub(crate) use self::reference::ServiceReference; diff --git a/ctru-rs/src/services/reference.rs b/ctru-rs/src/services/reference.rs new file mode 100644 index 0000000..a2d1682 --- /dev/null +++ b/ctru-rs/src/services/reference.rs @@ -0,0 +1,44 @@ +use crate::Error; +use std::sync::Mutex; +pub(crate) struct ServiceReference { + counter: &'static Mutex, + close: Box, +} + +impl ServiceReference { + 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 ServiceReference { + 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)(); + } + } +} diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index 5c0d0e4..bdd5407 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -1,66 +1,35 @@ // TODO: Implement remaining functions -use once_cell::sync::Lazy; -use std::sync::Mutex; - -use crate::services::ServiceReference; - -#[non_exhaustive] -pub struct SslC { - _service_handler: ServiceReference, -} - -static SSLC_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); +pub struct SslC(()); impl SslC { /// Initialize sslc pub fn init() -> crate::Result { - let _service_handler = ServiceReference::new( - &SSLC_ACTIVE, - true, - || { - let r = unsafe { ctru_sys::sslcInit(0) }; - if r < 0 { - return Err(r.into()); - } - - Ok(()) - }, - || unsafe { - ctru_sys::sslcExit(); - }, - )?; - - Ok(Self { _service_handler }) + unsafe { + let r = ctru_sys::sslcInit(0); + if r < 0 { + Err(r.into()) + } else { + Ok(SslC(())) + } + } } /// Fill `buf` with `buf.len()` random bytes pub fn generate_random_data(&self, buf: &mut [u8]) -> crate::Result<()> { - let r = unsafe { ctru_sys::sslcGenerateRandomData(buf.as_ptr() as _, buf.len() as u32) }; - if r < 0 { - Err(r.into()) - } else { - Ok(()) + unsafe { + let r = ctru_sys::sslcGenerateRandomData(buf.as_ptr() as _, buf.len() as u32); + if r < 0 { + Err(r.into()) + } else { + Ok(()) + } } } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sslc_duplicate() { - let _sslc = SslC::init().unwrap(); - - let value = *SSLC_ACTIVE.lock().unwrap(); - - assert_eq!(value, 1); - - drop(_sslc); - - let value = *SSLC_ACTIVE.lock().unwrap(); - - assert_eq!(value, 0); +impl Drop for SslC { + fn drop(&mut self) { + unsafe { ctru_sys::sslcExit() }; } } diff --git a/ctru-rs/src/srv.rs b/ctru-rs/src/srv.rs index 5ab83b6..7d2ad21 100644 --- a/ctru-rs/src/srv.rs +++ b/ctru-rs/src/srv.rs @@ -1,53 +1,20 @@ -use once_cell::sync::Lazy; -use std::sync::Mutex; - -use crate::services::ServiceReference; - -#[non_exhaustive] -pub struct Srv { - _service_handler: ServiceReference, -} - -static SRV_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); +pub struct Srv(()); impl Srv { - pub fn init() -> crate::Result { - let _service_handler = ServiceReference::new( - &SRV_ACTIVE, - true, - || { - let r = unsafe { ctru_sys::srvInit() }; - if r < 0 { - return Err(r.into()); - } - - Ok(()) - }, - || unsafe { - ctru_sys::srvExit(); - }, - )?; - - Ok(Self { _service_handler }) + pub fn init() -> crate::Result { + unsafe { + let r = ctru_sys::srvInit(); + if r < 0 { + Err(r.into()) + } else { + Ok(Srv(())) + } + } } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn srv_duplicate() { - let _srv = Srv::init().unwrap(); - - let value = *SRV_ACTIVE.lock().unwrap(); - - assert_eq!(value, 1); - - drop(_srv); - - let value = *SRV_ACTIVE.lock().unwrap(); - - assert_eq!(value, 0); +impl Drop for Srv { + fn drop(&mut self) { + unsafe { ctru_sys::srvExit() }; } }