Browse Source

Fixed duplicate services and constistency in naming

pull/50/head
Andrea Ciliberti 3 years ago
parent
commit
060b14f068
  1. 2
      ctru-rs/examples/buttons.rs
  2. 4
      ctru-rs/examples/file-explorer.rs
  3. 2
      ctru-rs/examples/futures-basic.rs
  4. 2
      ctru-rs/examples/futures-tokio.rs
  5. 2
      ctru-rs/examples/gfx-wide-mode.rs
  6. 2
      ctru-rs/examples/graphics-bitmap.rs
  7. 2
      ctru-rs/examples/hashmaps.rs
  8. 2
      ctru-rs/examples/hello-both-screens.rs
  9. 2
      ctru-rs/examples/hello-world.rs
  10. 2
      ctru-rs/examples/network-sockets.rs
  11. 4
      ctru-rs/examples/romfs.rs
  12. 2
      ctru-rs/examples/thread-basic.rs
  13. 2
      ctru-rs/examples/thread-locals.rs
  14. 2
      ctru-rs/examples/time-rtc.rs
  15. 3
      ctru-rs/src/error.rs
  16. 48
      ctru-rs/src/gfx.rs
  17. 25
      ctru-rs/src/lib.rs
  18. 26
      ctru-rs/src/romfs.rs
  19. 36
      ctru-rs/src/services/apt.rs
  20. 36
      ctru-rs/src/services/fs.rs
  21. 33
      ctru-rs/src/services/hid.rs
  22. 2
      ctru-rs/src/services/ps.rs
  23. 35
      ctru-rs/src/services/soc.rs
  24. 35
      ctru-rs/src/services/sslc.rs
  25. 32
      ctru-rs/src/srv.rs
  26. 7
      ctru-rs/src/test_runner.rs

2
ctru-rs/examples/buttons.rs

@ -8,7 +8,7 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let console = Console::init(gfx.top_screen.borrow_mut()); let console = Console::init(gfx.top_screen.borrow_mut());
println!("Hi there! Try pressing a button"); println!("Hi there! Try pressing a button");

4
ctru-rs/examples/file-explorer.rs

@ -14,10 +14,10 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
#[cfg(all(feature = "romfs", romfs_exists))] #[cfg(all(feature = "romfs", romfs_exists))]
let _romfs = ctru::romfs::RomFS::new().unwrap(); let _romfs = ctru::romfs::RomFS::init().unwrap();
FileExplorer::init(&apt, &hid, &gfx).run(); FileExplorer::init(&apt, &hid, &gfx).run();
} }

2
ctru-rs/examples/futures-basic.rs

@ -13,7 +13,7 @@ use futures::StreamExt;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/futures-tokio.rs

@ -6,7 +6,7 @@ use std::time::Duration;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/gfx-wide-mode.rs

@ -7,7 +7,7 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let mut console = Console::init(gfx.top_screen.borrow_mut()); let mut console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enable/disable wide screen mode."); println!("Press A to enable/disable wide screen mode.");

2
ctru-rs/examples/graphics-bitmap.rs

@ -19,7 +19,7 @@ static IMAGE: &[u8] = include_bytes!("assets/ferris.rgb");
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/hashmaps.rs

@ -12,7 +12,7 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
let mut map = std::collections::HashMap::new(); let mut map = std::collections::HashMap::new();

2
ctru-rs/examples/hello-both-screens.rs

@ -8,7 +8,7 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
// Start a console on the top screen // Start a console on the top screen
let top_screen = Console::init(gfx.top_screen.borrow_mut()); let top_screen = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/hello-world.rs

@ -7,7 +7,7 @@ use std::io::BufWriter;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/network-sockets.rs

@ -10,7 +10,7 @@ use std::time::Duration;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();

4
ctru-rs/examples/romfs.rs

@ -5,7 +5,7 @@ use ctru::services::hid::{Hid, KeyPad};
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
@ -15,7 +15,7 @@ fn main() {
// This never fails as `ctru-rs` examples inherit all of the `ctru` features, // This never fails as `ctru-rs` examples inherit all of the `ctru` features,
// but it might if a normal user application wasn't setup correctly // but it might if a normal user application wasn't setup correctly
if #[cfg(all(feature = "romfs", romfs_exists))] { if #[cfg(all(feature = "romfs", romfs_exists))] {
let _romfs = ctru::romfs::RomFS::new().unwrap(); let _romfs = ctru::romfs::RomFS::init().unwrap();
let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap(); let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap();
println!("Contents of test-file.txt: \n{f}\n"); println!("Contents of test-file.txt: \n{f}\n");

2
ctru-rs/examples/thread-basic.rs

@ -11,7 +11,7 @@ fn main() {
ctru::init(); ctru::init();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
let prio = thread::current().priority(); let prio = thread::current().priority();

2
ctru-rs/examples/thread-locals.rs

@ -10,7 +10,7 @@ std::thread_local! {
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
gfx.top_screen.borrow_mut().set_wide_mode(true); gfx.top_screen.borrow_mut().set_wide_mode(true);
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");

2
ctru-rs/examples/time-rtc.rs

@ -6,7 +6,7 @@ use ctru::services::hid::{Hid, KeyPad};
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().expect("Couldn't obtaint GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");

3
ctru-rs/src/error.rs

@ -9,6 +9,7 @@ pub type Result<T> = ::std::result::Result<T, Error>;
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
Os(ctru_sys::Result), Os(ctru_sys::Result),
ServiceAlreadyActive(&'static str),
} }
impl From<ctru_sys::Result> for Error { impl From<ctru_sys::Result> for Error {
@ -28,6 +29,7 @@ impl fmt::Debug for Error {
.field("summary", &R_SUMMARY(err)) .field("summary", &R_SUMMARY(err))
.field("level", &R_LEVEL(err)) .field("level", &R_LEVEL(err))
.finish(), .finish(),
Error::ServiceAlreadyActive(service) => write!(f, "Service {service} already active"),
} }
} }
} }
@ -39,6 +41,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Error::Os(err) => write!(f, "libctru result code: 0x{:08X}", err), Error::Os(err) => write!(f, "libctru result code: 0x{:08X}", err),
Error::ServiceAlreadyActive(service) => write!(f, "Service {service} already active"),
} }
} }
} }

48
ctru-rs/src/gfx.rs

@ -1,10 +1,11 @@
//! LCD screens manipulation helper //! LCD screens manipulation helper
use std::cell::RefCell; use std::cell::RefCell;
use std::default::Default;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Drop; use std::ops::Drop;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::{Error, Result};
use crate::services::gspgpu::{self, FramebufferFormat}; use crate::services::gspgpu::{self, FramebufferFormat};
/// Trait implemented by TopScreen and BottomScreen for common methods /// Trait implemented by TopScreen and BottomScreen for common methods
@ -73,23 +74,37 @@ pub struct Gfx {
pub bottom_screen: RefCell<BottomScreen>, pub bottom_screen: RefCell<BottomScreen>,
} }
static GFX_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Gfx { impl Gfx {
/// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
/// screens /// screens
/// ///
/// Use `Gfx::default()` instead of this function to initialize the module with default parameters /// Use `Gfx::init_default()` instead of this function to initialize the module with default parameters
pub fn new( pub fn init(
top_fb_fmt: FramebufferFormat, top_fb_fmt: FramebufferFormat,
bottom_fb_fmt: FramebufferFormat, bottom_fb_fmt: FramebufferFormat,
use_vram_buffers: bool, use_vram_buffers: bool,
) -> Self { ) -> Result<Self> {
match GFX_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => {
unsafe { unsafe {
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers);
} }
Gfx {
Ok(Gfx {
top_screen: RefCell::new(TopScreen), top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen), bottom_screen: RefCell::new(BottomScreen),
})
}
Err(_) => Err(Error::ServiceAlreadyActive("Gfx")),
}
} }
/// Creates a new Gfx instance with default init values
/// It's the same as calling: `Gfx::init(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
pub fn init_default() -> Result<Self> {
Gfx::init(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
} }
/// Flushes the current framebuffers /// Flushes the current framebuffers
@ -197,18 +212,21 @@ impl From<Side> for ctru_sys::gfx3dSide_t {
} }
} }
impl Default for Gfx {
fn default() -> Self {
unsafe { ctru_sys::gfxInitDefault() };
Gfx {
top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
}
}
}
impl Drop for Gfx { impl Drop for Gfx {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::gfxExit() }; unsafe { ctru_sys::gfxExit() };
GFX_ACTIVE.store(false, Ordering::Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gfx_duplicate() {
// We don't need to build a `Gfx` because the test runner has one already
assert!(Gfx::init_default().is_err());
} }
} }

25
ctru-rs/src/lib.rs

@ -38,15 +38,34 @@ pub fn init() {
// Only for panics in the main thread // Only for panics in the main thread
if main_thread == thread::current().id() && console::Console::exists() { if main_thread == thread::current().id() && console::Console::exists() {
println!("\nPress SELECT to exit the software"); println!("\nPress SELECT to exit the software");
let hid = services::hid::Hid::init().unwrap();
// The use of unsafe functions here is basically obligatory.
// To have memory safety when using the `Hid` struct, we must not make more
// than one available at the same time, so no drop/service ownership issues arise.
// The problem here is that the `panic_hook` is run _before_ the app cleanup,
// so an `Hid` stuct may still be alive and thus make the `panic_hook` panic.
// If that were to happen, the system would have to reboot to properly close the app.
//
// Using `hidInit` is safe when another instance is open, and we can do safe operations afterwards.
// The only (probably) unsafe part of this system is the `hidExit`, since in a multithreaded
// environment some other threads may still be doing operations on the service
// before the cleanup, though the time window would be almost nonexistent, and it would only
// really be a problem in preemptive threads.
//
// TL;DR : This code is bad.
unsafe {
ctru_sys::hidInit();
loop { loop {
hid.scan_input(); ctru_sys::hidScanInput();
if hid.keys_down().contains(services::hid::KeyPad::KEY_SELECT) { let keys = services::hid::KeyPad::from_bits_truncate(ctru_sys::hidKeysDown());
if keys.contains(services::hid::KeyPad::KEY_SELECT) {
ctru_sys::hidExit();
break; break;
} }
} }
} }
}
}); });
std::panic::set_hook(new_hook); std::panic::set_hook(new_hook);
} }

26
ctru-rs/src/romfs.rs

@ -11,12 +11,19 @@
//! ``` //! ```
use std::ffi::CStr; use std::ffi::CStr;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
#[non_exhaustive] #[non_exhaustive]
pub struct RomFS; pub struct RomFS;
static ROMFS_ACTIVE: AtomicBool = AtomicBool::new(false);
impl RomFS { impl RomFS {
pub fn new() -> crate::Result<Self> { pub fn init() -> crate::Result<Self> {
match ROMFS_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap(); let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
let result = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) }; let result = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) };
@ -26,11 +33,28 @@ impl RomFS {
Ok(Self) Ok(Self)
} }
} }
Err(_) => Err(Error::ServiceAlreadyActive("RomFS")),
}
}
} }
impl Drop for RomFS { impl Drop for RomFS {
fn drop(&mut self) { fn drop(&mut self) {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap(); let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) }; unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) };
ROMFS_ACTIVE.store(false, Ordering::Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn romfs_duplicate() {
let _romfs = RomFS::init().unwrap();
assert!(RomFS::init().is_err());
} }
} }

36
ctru-rs/src/services/apt.rs

@ -1,15 +1,25 @@
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
#[non_exhaustive]
pub struct Apt(()); pub struct Apt(());
static APT_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Apt { impl Apt {
pub fn init() -> crate::Result<Apt> { pub fn init() -> crate::Result<Self> {
unsafe { match APT_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
let r = ctru_sys::aptInit(); Ok(_) => {
let r = unsafe { ctru_sys::aptInit() };
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(Apt(())) Ok(Self(()))
} }
} }
Err(_) => Err(Error::ServiceAlreadyActive("Apt")),
}
} }
pub fn main_loop(&self) -> bool { pub fn main_loop(&self) -> bool {
@ -17,19 +27,31 @@ impl Apt {
} }
pub fn set_app_cpu_time_limit(&self, percent: u32) -> crate::Result<()> { pub fn set_app_cpu_time_limit(&self, percent: u32) -> crate::Result<()> {
unsafe { let r = unsafe { ctru_sys::APT_SetAppCpuTimeLimit(percent) };
let r = ctru_sys::APT_SetAppCpuTimeLimit(percent);
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(()) Ok(())
} }
} }
}
} }
impl Drop for Apt { impl Drop for Apt {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::aptExit() }; unsafe { ctru_sys::aptExit() };
APT_ACTIVE.store(false, Ordering::Release);
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gfx_duplicate() {
// We don't need to build a `Apt` because the test runner has one already
assert!(Apt::init().is_err());
}
}

36
ctru-rs/src/services/fs.rs

@ -13,9 +13,12 @@ use std::mem;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use widestring::{WideCStr, WideCString}; use widestring::{WideCStr, WideCString};
use crate::error::Error;
bitflags! { bitflags! {
#[derive(Default)] #[derive(Default)]
struct FsOpen: u32 { struct FsOpen: u32 {
@ -82,8 +85,11 @@ pub enum ArchiveID {
/// until an instance of this struct is created. /// until an instance of this struct is created.
/// ///
/// The service exits when all instances of this struct go out of scope. /// The service exits when all instances of this struct go out of scope.
#[non_exhaustive]
pub struct Fs(()); pub struct Fs(());
static FS_ACTIVE: AtomicBool = AtomicBool::new(false);
/// Handle to an open filesystem archive. /// Handle to an open filesystem archive.
/// ///
/// Archives are automatically closed when they go out of scope. /// Archives are automatically closed when they go out of scope.
@ -96,6 +102,7 @@ pub struct Fs(());
/// let fs = Fs::init().unwrap(); /// let fs = Fs::init().unwrap();
/// let sdmc_archive = fs.sdmc().unwrap(); /// let sdmc_archive = fs.sdmc().unwrap();
/// ``` /// ```
#[non_exhaustive]
pub struct Archive { pub struct Archive {
id: ArchiveID, id: ArchiveID,
handle: u64, handle: u64,
@ -164,6 +171,7 @@ pub struct Archive {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[non_exhaustive]
pub struct File { pub struct File {
handle: u32, handle: u32,
offset: u64, offset: u64,
@ -175,6 +183,7 @@ pub struct File {
/// represents known metadata about a file. /// represents known metadata about a file.
/// ///
/// [`metadata`]: fn.metadata.html /// [`metadata`]: fn.metadata.html
#[non_exhaustive]
pub struct Metadata { pub struct Metadata {
attributes: u32, attributes: u32,
size: u64, size: u64,
@ -257,6 +266,7 @@ pub struct OpenOptions {
/// ///
/// This Result will return Err if there's some sort of intermittent IO error /// This Result will return Err if there's some sort of intermittent IO error
/// during iteration. /// during iteration.
#[non_exhaustive]
pub struct ReadDir<'a> { pub struct ReadDir<'a> {
handle: Dir, handle: Dir,
root: Arc<PathBuf>, root: Arc<PathBuf>,
@ -297,15 +307,18 @@ impl Fs {
/// ctrulib services are reference counted, so this function may be called /// ctrulib services are reference counted, so this function may be called
/// as many times as desired and the service will not exit until all /// as many times as desired and the service will not exit until all
/// instances of Fs drop out of scope. /// instances of Fs drop out of scope.
pub fn init() -> crate::Result<Fs> { pub fn init() -> crate::Result<Self> {
unsafe { match FS_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
let r = ctru_sys::fsInit(); Ok(_) => {
let r = unsafe { ctru_sys::fsInit() };
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(Fs(())) Ok(Self(()))
} }
} }
Err(_) => Err(Error::ServiceAlreadyActive("Fs")),
}
} }
/// Returns a handle to the SDMC (memory card) Archive. /// Returns a handle to the SDMC (memory card) Archive.
@ -990,6 +1003,8 @@ impl Drop for Fs {
unsafe { unsafe {
ctru_sys::fsExit(); ctru_sys::fsExit();
} }
FS_ACTIVE.store(false, Ordering::Release);
} }
} }
@ -1059,3 +1074,16 @@ impl From<ArchiveID> for ctru_sys::FS_ArchiveID {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fs_duplicate() {
let _fs = Fs::init().unwrap();
assert!(Fs::init().is_err());
}
}

33
ctru-rs/src/services/hid.rs

@ -4,6 +4,10 @@
//! and circle pad information. It also provides information from the sound volume slider, //! and circle pad information. It also provides information from the sound volume slider,
//! the accelerometer, and the gyroscope. //! the accelerometer, and the gyroscope.
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
bitflags::bitflags! { bitflags::bitflags! {
/// A set of flags corresponding to the button and directional pad /// A set of flags corresponding to the button and directional pad
/// inputs on the 3DS /// inputs on the 3DS
@ -44,12 +48,17 @@ bitflags::bitflags! {
/// when all instances of this struct fall out of scope. /// when all instances of this struct fall out of scope.
/// ///
/// This service requires no special permissions to use. /// This service requires no special permissions to use.
#[non_exhaustive]
pub struct Hid(()); pub struct Hid(());
static HID_ACTIVE: AtomicBool = AtomicBool::new(false);
/// Represents user input to the touchscreen. /// Represents user input to the touchscreen.
#[non_exhaustive]
pub struct TouchPosition(ctru_sys::touchPosition); pub struct TouchPosition(ctru_sys::touchPosition);
/// Represents the current position of the 3DS circle pad. /// Represents the current position of the 3DS circle pad.
#[non_exhaustive]
pub struct CirclePosition(ctru_sys::circlePosition); pub struct CirclePosition(ctru_sys::circlePosition);
/// Initializes the HID service. /// Initializes the HID service.
@ -60,14 +69,17 @@ pub struct CirclePosition(ctru_sys::circlePosition);
/// Since this service requires no special or elevated permissions, errors are /// Since this service requires no special or elevated permissions, errors are
/// rare in practice. /// rare in practice.
impl Hid { impl Hid {
pub fn init() -> crate::Result<Hid> { pub fn init() -> crate::Result<Self> {
unsafe { match HID_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
let r = ctru_sys::hidInit(); Ok(_) => {
let r = unsafe { ctru_sys::hidInit() };
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(Hid(())) Ok(Self(()))
}
} }
Err(_) => Err(Error::ServiceAlreadyActive("Hid")),
} }
} }
@ -151,5 +163,18 @@ impl CirclePosition {
impl Drop for Hid { impl Drop for Hid {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::hidExit() }; unsafe { ctru_sys::hidExit() };
HID_ACTIVE.store(false, Ordering::Release);
}
}
#[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
assert!(Hid::init().is_err());
} }
} }

2
ctru-rs/src/services/ps.rs

@ -63,8 +63,6 @@ pub fn generate_random_bytes(out: &mut [u8]) -> crate::Result<()> {
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use super::*;
#[test] #[test]
fn construct_hash_map() { fn construct_hash_map() {
let mut input = vec![ let mut input = vec![

35
ctru-rs/src/services/soc.rs

@ -1,21 +1,27 @@
use ctru_sys::{socExit, socInit};
use libc::{free, memalign}; use libc::{free, memalign};
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
use ctru_sys::{socExit, socInit};
/// Soc service. Initializing this service will enable the use of network sockets and utilities /// 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. /// such as those found in `std::net`. The service will be closed when this struct is is dropped.
#[non_exhaustive]
pub struct Soc { pub struct Soc {
soc_mem: *mut u32, soc_mem: *mut u32,
} }
static SOC_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Soc { impl Soc {
/// Initialize the Soc service with a default buffer size of 0x100000 bytes /// Initialize the Soc service with a default buffer size of 0x100000 bytes
/// ///
/// # Errors /// # Errors
/// ///
/// This function will return an error if the `Soc` service is already initialized /// This function will return an error if the `Soc` service is already initialized
pub fn init() -> crate::Result<Soc> { pub fn init() -> crate::Result<Self> {
Soc::init_with_buffer_size(0x100000) Self::init_with_buffer_size(0x100000)
} }
/// Initialize the Soc service with a custom buffer size in bytes. The size should be /// Initialize the Soc service with a custom buffer size in bytes. The size should be
@ -24,8 +30,9 @@ impl Soc {
/// # Errors /// # Errors
/// ///
/// This function will return an error if the `Soc` service is already initialized /// This function will return an error if the `Soc` service is already initialized
pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result<Soc> { pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result<Self> {
unsafe { match SOC_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => unsafe {
let soc_mem = memalign(0x1000, num_bytes) as *mut u32; let soc_mem = memalign(0x1000, num_bytes) as *mut u32;
let r = socInit(soc_mem, num_bytes as u32); let r = socInit(soc_mem, num_bytes as u32);
@ -33,8 +40,10 @@ impl Soc {
free(soc_mem as *mut _); free(soc_mem as *mut _);
Err(r.into()) Err(r.into())
} else { } else {
Ok(Soc { soc_mem }) Ok(Self { soc_mem })
} }
},
Err(_) => Err(Error::ServiceAlreadyActive("Soc")),
} }
} }
@ -51,5 +60,19 @@ impl Drop for Soc {
socExit(); socExit();
free(self.soc_mem as *mut _); free(self.soc_mem as *mut _);
} }
SOC_ACTIVE.store(false, Ordering::Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn soc_duplicate() {
let _soc = Soc::init().unwrap();
assert!(Soc::init().is_err());
} }
} }

35
ctru-rs/src/services/sslc.rs

@ -1,35 +1,58 @@
// TODO: Implement remaining functions // TODO: Implement remaining functions
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
#[non_exhaustive]
pub struct SslC(()); pub struct SslC(());
static SSLC_ACTIVE: AtomicBool = AtomicBool::new(false);
impl SslC { impl SslC {
/// Initialize sslc /// Initialize sslc
pub fn init() -> crate::Result<Self> { pub fn init() -> crate::Result<Self> {
unsafe { match SSLC_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
let r = ctru_sys::sslcInit(0); Ok(_) => {
let r = unsafe { ctru_sys::sslcInit(0) };
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(SslC(())) Ok(Self(()))
} }
} }
Err(_) => Err(Error::ServiceAlreadyActive("SslC")),
}
} }
/// Fill `buf` with `buf.len()` random bytes /// Fill `buf` with `buf.len()` random bytes
pub fn generate_random_data(&self, buf: &mut [u8]) -> crate::Result<()> { pub fn generate_random_data(&self, buf: &mut [u8]) -> crate::Result<()> {
unsafe { let r = unsafe { ctru_sys::sslcGenerateRandomData(buf.as_ptr() as _, buf.len() as u32) };
let r = ctru_sys::sslcGenerateRandomData(buf.as_ptr() as _, buf.len() as u32);
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(()) Ok(())
} }
} }
}
} }
impl Drop for SslC { impl Drop for SslC {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::sslcExit() }; unsafe { ctru_sys::sslcExit() };
SSLC_ACTIVE.store(false, Ordering::Release);
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sslc_duplicate() {
let _sslc = SslC::init().unwrap();
assert!(SslC::init().is_err());
}
}

32
ctru-rs/src/srv.rs

@ -1,20 +1,44 @@
use std::sync::atomic::{AtomicBool, Ordering};
use crate::error::Error;
#[non_exhaustive]
pub struct Srv(()); pub struct Srv(());
static SRV_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Srv { impl Srv {
pub fn init() -> crate::Result<Srv> { pub fn init() -> crate::Result<Self> {
unsafe { match SRV_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
let r = ctru_sys::srvInit(); Ok(_) => {
let r = unsafe { ctru_sys::srvInit() };
if r < 0 { if r < 0 {
Err(r.into()) Err(r.into())
} else { } else {
Ok(Srv(())) Ok(Self(()))
} }
} }
Err(_) => Err(Error::ServiceAlreadyActive("Srv")),
}
} }
} }
impl Drop for Srv { impl Drop for Srv {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::srvExit() }; unsafe { ctru_sys::srvExit() };
SRV_ACTIVE.store(false, Ordering::Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn srv_duplicate() {
let _srv = Srv::init().unwrap();
assert!(Srv::init().is_err());
} }
} }

7
ctru-rs/src/test_runner.rs

@ -17,7 +17,7 @@ use crate::services::Apt;
pub(crate) fn run(tests: &[&TestDescAndFn]) { pub(crate) fn run(tests: &[&TestDescAndFn]) {
crate::init(); crate::init();
let gfx = Gfx::default(); let gfx = Gfx::init_default().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
@ -115,9 +115,4 @@ mod link_fix {
extern "C" fn sigemptyset(_arg1: *mut libc::sigset_t) -> ::libc::c_int { extern "C" fn sigemptyset(_arg1: *mut libc::sigset_t) -> ::libc::c_int {
-1 -1
} }
#[no_mangle]
extern "C" fn sysconf(_name: libc::c_int) -> libc::c_long {
-1
}
} }

Loading…
Cancel
Save