Browse Source

Am, Apt and refactoring to streamline the API and docs

pull/134/head
Andrea Ciliberti 1 year ago
parent
commit
39829e1820
  1. 13
      ctru-rs/examples/title-info.rs
  2. 5
      ctru-rs/src/lib.rs
  3. 64
      ctru-rs/src/services/am.rs
  4. 24
      ctru-rs/src/services/apt.rs
  5. 12
      ctru-rs/src/services/mod.rs

13
ctru-rs/examples/title-info.rs

@ -80,12 +80,13 @@ fn main() {
// Move cursor to top left // Move cursor to top left
println!("\x1b[1;1"); println!("\x1b[1;1");
match selected_title.title_info() { match selected_title.size() {
Ok(info) => { Ok(size) => println!("Size: {} kB", size / 1024),
println!("Size: {} KB", info.size_bytes() / 1024); Err(e) => println!("Failed to get title size: {}", e),
println!("Version: 0x{:x}", info.version()); }
} match selected_title.version() {
Err(e) => println!("Failed to get title info: {}", e), Ok(version) => println!("Version: 0x{:x}", version),
Err(e) => println!("Failed to get title version: {}", e),
} }
match selected_title.product_code() { match selected_title.product_code() {
Ok(code) => println!("Product code: \"{code}\""), Ok(code) => println!("Product code: \"{code}\""),

5
ctru-rs/src/lib.rs

@ -24,6 +24,7 @@
#![feature(test)] #![feature(test)]
#![feature(custom_test_frameworks)] #![feature(custom_test_frameworks)]
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
#![feature(once_cell_try)]
#![feature(allocator_api)] #![feature(allocator_api)]
#![test_runner(test_runner::run)] #![test_runner(test_runner::run)]
#![doc( #![doc(
@ -39,7 +40,9 @@ extern crate shim_3ds;
/// Expanded stack size used to spawn the main thread by `libctru`. /// Expanded stack size used to spawn the main thread by `libctru`.
/// ///
/// This value was chosen to support crate dependencies which expected more stack than provided, without compromising performance. /// It takes effect only if the `big-stack` feature is active. Otherwise, the default stack size should be ~32kB.
///
/// This value was chosen to support crate dependencies which expected more stack than provided. It's suggested to use less stack if possible.
#[no_mangle] #[no_mangle]
#[cfg(feature = "big-stack")] #[cfg(feature = "big-stack")]
static __stacksize__: usize = 2 * 1024 * 1024; // 2MB static __stacksize__: usize = 2 * 1024 * 1024; // 2MB

64
ctru-rs/src/services/am.rs

@ -1,35 +1,34 @@
//! Application Manager service.
//!
//! As the name implies, the AM service manages installed applications. It can:
//! - Read the installed applications on the console and their information (depending on the install location).
//! - Install compatible applications to the console.
//!
//! `ctru` doesn't support installing titles (yet).
use crate::error::ResultCode; use crate::error::ResultCode;
use crate::services::fs::FsMediaType; use crate::services::fs::FsMediaType;
use std::cell::OnceCell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
#[derive(Copy, Clone, Debug)] /// Struct holding general information about a specific title.
#[repr(transparent)] #[doc(alias = "AM_TitleEntry")]
pub struct TitleInfo(ctru_sys::AM_TitleEntry);
impl TitleInfo {
pub fn id(&self) -> u64 {
self.0.titleID
}
pub fn size_bytes(&self) -> u64 {
self.0.size
}
pub fn version(&self) -> u16 {
self.0.version
}
}
pub struct Title<'a> { pub struct Title<'a> {
id: u64, id: u64,
mediatype: FsMediaType, mediatype: FsMediaType,
entry: OnceCell<ctru_sys::AM_TitleEntry>,
_am: PhantomData<&'a Am>, _am: PhantomData<&'a Am>,
} }
impl<'a> Title<'a> { impl<'a> Title<'a> {
/// Returns this title's ID.
pub fn id(&self) -> u64 { pub fn id(&self) -> u64 {
self.id self.id
} }
/// Returns this title's unique product code.
#[doc(alias = "AM_GetTitleProductCode")]
pub fn product_code(&self) -> crate::Result<String> { pub fn product_code(&self) -> crate::Result<String> {
let mut buf: [u8; 16] = [0; 16]; let mut buf: [u8; 16] = [0; 16];
@ -43,7 +42,9 @@ impl<'a> Title<'a> {
Ok(String::from_utf8_lossy(&buf).to_string()) Ok(String::from_utf8_lossy(&buf).to_string())
} }
pub fn title_info(&self) -> crate::Result<TitleInfo> { /// Retrieves additional information on the title.
#[doc(alias = "AM_GetTitleInfo")]
fn title_info(&self) -> crate::Result<ctru_sys::AM_TitleEntry> {
let mut info = MaybeUninit::zeroed(); let mut info = MaybeUninit::zeroed();
unsafe { unsafe {
@ -57,11 +58,34 @@ impl<'a> Title<'a> {
Ok(info.assume_init()) Ok(info.assume_init())
} }
} }
/// Returns the size of this title in bytes.
pub fn size(&self) -> crate::Result<u64> {
// Get the internal entry, or fill it if empty.
let entry = self.entry.get_or_try_init(|| -> crate::Result<ctru_sys::AM_TitleEntry> {
self.title_info()
})?;
Ok(entry.size)
}
/// Returns the installed version of this title.
pub fn version(&self) -> crate::Result<u16> {
// Get the internal entry, or fill it if empty.
let entry = self.entry.get_or_try_init(|| -> crate::Result<ctru_sys::AM_TitleEntry> {
self.title_info()
})?;
Ok(entry.version)
}
} }
/// Handle to the Application Manager service.
pub struct Am(()); pub struct Am(());
impl Am { impl Am {
/// Initialize a new handle.
#[doc(alias = "amInit")]
pub fn new() -> crate::Result<Am> { pub fn new() -> crate::Result<Am> {
unsafe { unsafe {
ResultCode(ctru_sys::amInit())?; ResultCode(ctru_sys::amInit())?;
@ -69,6 +93,8 @@ impl Am {
} }
} }
/// Returns the amount of titles currently installed in a specific install location.
#[doc(alias = "AM_GetTitleCount")]
pub fn title_count(&self, mediatype: FsMediaType) -> crate::Result<u32> { pub fn title_count(&self, mediatype: FsMediaType) -> crate::Result<u32> {
unsafe { unsafe {
let mut count = 0; let mut count = 0;
@ -77,6 +103,8 @@ impl Am {
} }
} }
/// Returns the list of titles installed in a specific install location.
#[doc(alias = "AM_GetTitleList")]
pub fn title_list(&self, mediatype: FsMediaType) -> crate::Result<Vec<Title>> { pub fn title_list(&self, mediatype: FsMediaType) -> crate::Result<Vec<Title>> {
let count = self.title_count(mediatype)?; let count = self.title_count(mediatype)?;
let mut buf = vec![0; count as usize]; let mut buf = vec![0; count as usize];
@ -94,6 +122,7 @@ impl Am {
.map(|id| Title { .map(|id| Title {
id, id,
mediatype, mediatype,
entry: OnceCell::new(),
_am: PhantomData, _am: PhantomData,
}) })
.collect()) .collect())
@ -101,6 +130,7 @@ impl Am {
} }
impl Drop for Am { impl Drop for Am {
#[doc(alias = "amExit")]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::amExit() }; unsafe { ctru_sys::amExit() };
} }

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

@ -1,8 +1,17 @@
//! Applet service.
//!
//! The APT service handles integration with some higher level OS features such as Sleep mode, the Home Menu and application switching.
//!
//! It also handles running applets, small programs made available by the OS to streamline specific functionality. Those are implemented in the [`applets`](crate::applets) module.
use crate::error::ResultCode; use crate::error::ResultCode;
/// Handle to the Applet service.
pub struct Apt(()); pub struct Apt(());
impl Apt { impl Apt {
/// Initialize a new handle.
#[doc(alias = "aptInit")]
pub fn new() -> crate::Result<Apt> { pub fn new() -> crate::Result<Apt> {
unsafe { unsafe {
ResultCode(ctru_sys::aptInit())?; ResultCode(ctru_sys::aptInit())?;
@ -10,10 +19,24 @@ impl Apt {
} }
} }
/// Returns `true` if the application is running in the foreground as normal.
///
/// # Notes
///
/// This function is called as such since it automatically handles all checks for Home Menu switching, Sleep mode and other events that could take away control from the application.
/// For this reason, its main use is as the condition of a while loop that controls the main logic for your program.
#[doc(alias = "aptMainLoop")]
pub fn main_loop(&self) -> bool { pub fn main_loop(&self) -> bool {
unsafe { ctru_sys::aptMainLoop() } unsafe { ctru_sys::aptMainLoop() }
} }
/// Sets (in percentage) the amount of time to lend to the application thread spawned on the syscore (core #1).
///
/// # Notes
///
/// It is necessary to set a time limit before spawning threads on the syscore.
/// The percentage value must be withing 5% and 89%, though it is suggested to use lower values (around 30-45%) to avoid slowing down the OS processes.
#[doc(alias = "APT_SetAppCpuTimeLimit")]
pub fn set_app_cpu_time_limit(&mut self, percent: u32) -> crate::Result<()> { pub fn set_app_cpu_time_limit(&mut self, percent: u32) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::APT_SetAppCpuTimeLimit(percent))?; ResultCode(ctru_sys::APT_SetAppCpuTimeLimit(percent))?;
@ -23,6 +46,7 @@ impl Apt {
} }
impl Drop for Apt { impl Drop for Apt {
#[doc(alias = "aptExit")]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { ctru_sys::aptExit() }; unsafe { ctru_sys::aptExit() };
} }

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

@ -1,9 +1,15 @@
//! System services used to handle system-specific functionalities. //! OS services used to handle system-specific functionality.
//! //!
//! Most of the 3DS console's functionalities (when writing homebrew) are locked behind services, //! Most of the 3DS console's functionalities (when writing user-land homebrew) are accessible via services,
//! which need to be initialized before accessing any particular feature. //! which need to be initialized before accessing any particular feature.
//! //!
//! Some include: button input, audio playback, graphics rendering, built-in cameras, etc. //! To ensure safety measures when using the underlying services, `ctru` leverages Rust's lifetime model.
//! After initializing the handle for a specific service (e.g. [`Apt`](apt::Apt)) the service will be accessible as long as there is at least one handle "alive".
//! As such, handles should be dropped *after* the use of a specific service. This is particularly important for services which are necessary for functionality
//! "outside" their associated methods, such as [`RomFS`](romfs::RomFS), which creates an accessible virtual filesystem, or [`Soc`](soc::Soc),
//! which enables all network communications via sockets.
//!
//! In `ctru` some services only allow a single handle to be created at a time, to ensure a safe and controlled environment.
pub mod am; pub mod am;
pub mod apt; pub mod apt;

Loading…
Cancel
Save