Browse Source

Merge pull request #50 from Meziu/fix/duplicate-services

Fixed duplicate services and constistency in naming
pull/54/head
Meziu 3 years ago committed by GitHub
parent
commit
cdc96d2eeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ctru-rs/Cargo.toml
  2. 2
      ctru-rs/examples/buttons.rs
  3. 4
      ctru-rs/examples/file-explorer.rs
  4. 2
      ctru-rs/examples/futures-basic.rs
  5. 2
      ctru-rs/examples/futures-tokio.rs
  6. 2
      ctru-rs/examples/gfx-wide-mode.rs
  7. 2
      ctru-rs/examples/graphics-bitmap.rs
  8. 2
      ctru-rs/examples/hashmaps.rs
  9. 2
      ctru-rs/examples/hello-both-screens.rs
  10. 2
      ctru-rs/examples/hello-world.rs
  11. 2
      ctru-rs/examples/network-sockets.rs
  12. 4
      ctru-rs/examples/romfs.rs
  13. 2
      ctru-rs/examples/software-keyboard.rs
  14. 2
      ctru-rs/examples/thread-basic.rs
  15. 2
      ctru-rs/examples/thread-locals.rs
  16. 2
      ctru-rs/examples/time-rtc.rs
  17. 3
      ctru-rs/src/error.rs
  18. 60
      ctru-rs/src/gfx.rs
  19. 22
      ctru-rs/src/lib.rs
  20. 59
      ctru-rs/src/romfs.rs
  21. 3
      ctru-rs/src/services/mod.rs
  22. 44
      ctru-rs/src/services/reference.rs
  23. 67
      ctru-rs/src/services/soc.rs
  24. 2
      ctru-rs/src/test_runner.rs

1
ctru-rs/Cargo.toml

@ -19,6 +19,7 @@ pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" }
libc = "0.2.116" libc = "0.2.116"
bitflags = "1.0.0" bitflags = "1.0.0"
widestring = "0.2.2" widestring = "0.2.2"
once_cell = "1.10.0"
[build-dependencies] [build-dependencies]
toml = "0.5" toml = "0.5"

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().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().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

@ -16,7 +16,7 @@ use std::os::horizon::thread::BuilderExt;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init().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/futures-tokio.rs

@ -9,7 +9,7 @@ use std::time::Duration;
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init().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/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().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().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/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().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().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().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().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().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());
@ -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/software-keyboard.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().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enter some text or press Start to quit"); println!("Press A to enter some text or press Start to quit");

2
ctru-rs/examples/thread-basic.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().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
let prio = std::os::horizon::thread::current_priority(); let prio = std::os::horizon::thread::current_priority();

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

@ -13,7 +13,7 @@ std::thread_local! {
fn main() { fn main() {
ctru::init(); ctru::init();
let gfx = Gfx::default(); let gfx = Gfx::init().expect("Couldn't obtain 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().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");

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,
} }
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 => f.debug_tuple("ServiceAlreadyActive").finish(),
} }
} }
} }
@ -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 => write!(f, "Service already active"),
} }
} }
} }

60
ctru-rs/src/gfx.rs

@ -1,11 +1,13 @@
//! LCD screens manipulation helper //! LCD screens manipulation helper
use once_cell::sync::Lazy;
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::sync::Mutex;
use crate::error::Result;
use crate::services::gspgpu::{self, FramebufferFormat}; use crate::services::gspgpu::{self, FramebufferFormat};
use crate::services::ServiceReference;
/// Trait implemented by TopScreen and BottomScreen for common methods /// Trait implemented by TopScreen and BottomScreen for common methods
pub trait Screen { pub trait Screen {
@ -71,25 +73,43 @@ pub enum Side {
pub struct Gfx { pub struct Gfx {
pub top_screen: RefCell<TopScreen>, pub top_screen: RefCell<TopScreen>,
pub bottom_screen: RefCell<BottomScreen>, pub bottom_screen: RefCell<BottomScreen>,
_service_handler: ServiceReference,
} }
static GFX_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
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()` instead of this function to initialize the module with default parameters
pub fn new( pub fn with_formats(
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> {
unsafe { let _service_handler = ServiceReference::new(
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); &GFX_ACTIVE,
} false,
Gfx { || unsafe {
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers);
Ok(())
},
|| unsafe { ctru_sys::gfxExit() },
)?;
Ok(Self {
top_screen: RefCell::new(TopScreen), top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen), bottom_screen: RefCell::new(BottomScreen),
} _service_handler,
})
}
/// Creates a new Gfx instance with default init values
/// It's the same as calling: `Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
pub fn init() -> Result<Self> {
Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
} }
/// Flushes the current framebuffers /// Flushes the current framebuffers
@ -197,18 +217,14 @@ impl From<Side> for ctru_sys::gfx3dSide_t {
} }
} }
impl Default for Gfx { #[cfg(test)]
fn default() -> Self { mod tests {
unsafe { ctru_sys::gfxInitDefault() }; use super::*;
Gfx { use crate::Error;
top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
}
}
}
impl Drop for Gfx { #[test]
fn drop(&mut self) { fn gfx_duplicate() {
unsafe { ctru_sys::gfxExit() }; // We don't need to build a `Gfx` because the test runner has one already
assert!(matches!(Gfx::init(), Err(Error::ServiceAlreadyActive)))
} }
} }

22
ctru-rs/src/lib.rs

@ -26,6 +26,13 @@ pub fn init() {
libc::atexit(services_deinit); libc::atexit(services_deinit);
} }
#[cfg(not(test))]
panic_hook_setup();
}
#[cfg(not(test))]
fn panic_hook_setup() {
use crate::services::hid::{Hid, KeyPad};
use std::panic::PanicInfo; use std::panic::PanicInfo;
let main_thread = std::thread::current().id(); let main_thread = std::thread::current().id();
@ -38,13 +45,16 @@ pub fn init() {
// Only for panics in the main thread // Only for panics in the main thread
if main_thread == std::thread::current().id() && console::Console::exists() { if main_thread == std::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();
loop { match Hid::init() {
hid.scan_input(); Ok(hid) => loop {
if hid.keys_down().contains(services::hid::KeyPad::KEY_SELECT) { hid.scan_input();
break; let keys = hid.keys_down();
} if keys.contains(KeyPad::KEY_SELECT) {
break;
}
},
Err(e) => println!("Error while intializing Hid controller during panic: {e}"),
} }
} }
}); });

59
ctru-rs/src/romfs.rs

@ -10,27 +10,58 @@
//! romfs_dir = "romfs" //! romfs_dir = "romfs"
//! ``` //! ```
use once_cell::sync::Lazy;
use std::ffi::CStr; use std::ffi::CStr;
use std::sync::Mutex;
use crate::services::ServiceReference;
#[non_exhaustive] #[non_exhaustive]
pub struct RomFS; pub struct RomFS {
_service_handler: ServiceReference,
}
static ROMFS_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
impl RomFS { impl RomFS {
pub fn new() -> crate::Result<Self> { pub fn init() -> crate::Result<Self> {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap(); let _service_handler = ServiceReference::new(
let result = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) }; &ROMFS_ACTIVE,
true,
if result < 0 { || {
Err(result.into()) let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
} else { let r = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) };
Ok(Self) if r < 0 {
} return Err(r.into());
}
Ok(())
},
|| {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) };
},
)?;
Ok(Self { _service_handler })
} }
} }
impl Drop for RomFS { #[cfg(test)]
fn drop(&mut self) { mod tests {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap(); use super::*;
unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) };
#[test]
fn romfs_counter() {
let _romfs = RomFS::init().unwrap();
let value = *ROMFS_ACTIVE.lock().unwrap();
assert_eq!(value, 1);
drop(_romfs);
let value = *ROMFS_ACTIVE.lock().unwrap();
assert_eq!(value, 0);
} }
} }

3
ctru-rs/src/services/mod.rs

@ -3,9 +3,12 @@ pub mod fs;
pub mod gspgpu; pub mod gspgpu;
pub mod hid; pub mod hid;
pub mod ps; pub mod ps;
mod reference;
pub mod soc; pub mod soc;
pub mod sslc; pub mod sslc;
pub use self::apt::Apt; pub use self::apt::Apt;
pub use self::hid::Hid; pub use self::hid::Hid;
pub use self::sslc::SslC; pub use self::sslc::SslC;
pub(crate) use self::reference::ServiceReference;

44
ctru-rs/src/services/reference.rs

@ -0,0 +1,44 @@
use crate::Error;
use std::sync::Mutex;
pub(crate) struct ServiceReference {
counter: &'static Mutex<usize>,
close: Box<dyn Fn() + Send + Sync>,
}
impl ServiceReference {
pub fn new<S, E>(
counter: &'static Mutex<usize>,
allow_multiple: bool,
start: S,
close: E,
) -> crate::Result<Self>
where
S: FnOnce() -> crate::Result<()>,
E: Fn() + Send + Sync + 'static,
{
let mut value = counter.lock().expect("Mutex Counter for ServiceReference is poisoned"); // 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().expect("Mutex Counter for ServiceReference is poisoned"); // todo: handle poisoning
*value -= 1;
if *value == 0 {
(self.close)();
}
}
}

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

@ -1,21 +1,27 @@
use ctru_sys::{socExit, socInit}; use libc::memalign;
use libc::{free, memalign}; use once_cell::sync::Lazy;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::sync::Mutex;
use crate::services::ServiceReference;
/// 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, _service_handler: ServiceReference,
} }
static SOC_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
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,18 +30,29 @@ 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 { let _service_handler = ServiceReference::new(
let soc_mem = memalign(0x1000, num_bytes) as *mut u32; &SOC_ACTIVE,
false,
let r = socInit(soc_mem, num_bytes as u32); || {
if r < 0 { let soc_mem = unsafe { memalign(0x1000, num_bytes) } as *mut u32;
free(soc_mem as *mut _); let r = unsafe { ctru_sys::socInit(soc_mem, num_bytes as u32) };
Err(r.into()) if r < 0 {
} else { return Err(r.into());
Ok(Soc { soc_mem }) }
}
} 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::socExit();
},
)?;
Ok(Self { _service_handler })
} }
/// IP Address of the Nintendo 3DS system. /// IP Address of the Nintendo 3DS system.
@ -45,11 +62,15 @@ impl Soc {
} }
} }
impl Drop for Soc { #[cfg(test)]
fn drop(&mut self) { mod tests {
unsafe { use super::*;
socExit(); use crate::Error;
free(self.soc_mem as *mut _);
} #[test]
fn soc_duplicate() {
let _soc = Soc::init().unwrap();
assert!(matches!(Soc::init(), Err(Error::ServiceAlreadyActive)))
} }
} }

2
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().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();

Loading…
Cancel
Save