diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml
index 16f4a3d..027a3cb 100644
--- a/ctru-rs/Cargo.toml
+++ b/ctru-rs/Cargo.toml
@@ -22,7 +22,7 @@ const-zero = "0.1.0"
shim-3ds = { git = "https://github.com/rust3ds/shim-3ds.git" }
pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" }
libc = "0.2.121"
-bitflags = "1.0.0"
+bitflags = "2.3.3"
widestring = "0.2.2"
[build-dependencies]
diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs
index 7cd0f81..fa69034 100644
--- a/ctru-rs/src/applets/mii_selector.rs
+++ b/ctru-rs/src/applets/mii_selector.rs
@@ -1,11 +1,11 @@
//! Mii Selector applet.
//!
//! This applet opens a window on the console's bottom screen which lets the player/user choose a Mii from the ones present on their console.
-//! The application can access the selected Mii's data via the use of the [`mii`](crate::mii) module.
+//! The selected Mii is readable as a [`MiiData`](crate::mii::MiiData).
use crate::mii::MiiData;
use bitflags::bitflags;
-use std::ffi::CString;
+use std::{ffi::CString, error::Error, fmt};
/// Index of a Mii used to configure some parameters of the Mii Selector.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -16,7 +16,7 @@ pub enum Index {
All,
}
-/// The type of a Mii with their respective data
+/// The type of a Mii.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum MiiType {
/// Guest Mii.
@@ -31,29 +31,56 @@ pub enum MiiType {
}
bitflags! {
- /// Options for the Mii Selector
+ /// Options to configure the [MiiSelector].
+ ///
+ ///
Example
+ ///
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # fn main() -> Result<(), Box> {
+ /// #
+ /// use ctru::applets::mii_selector::{MiiSelector, Options};
+ ///
+ /// // Setup a `MiiSelector` that can be cancelled and that makes Guest Miis available to select.
+ /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS;
+ ///
+ /// let mut mii_selector = MiiSelector::new();
+ /// mii_selector.set_options(opts);
+ ///
+ /// let result = mii_selector.launch()?;
+ /// #
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct Options: u32 {
- /// Show the cancel button
- const MII_SELECTOR_CANCEL = ctru_sys::MIISELECTOR_CANCEL;
- /// Make guest Miis selectable
- const MII_SELECTOR_GUESTS = ctru_sys::MIISELECTOR_GUESTS;
- /// Show on the top screen
- const MII_SELECTOR_TOP = ctru_sys::MIISELECTOR_TOP;
- /// Start on the guest's page
- const MII_SELECTOR_GUEST_START = ctru_sys::MIISELECTOR_GUESTSTART;
+ /// Show the cancel button.
+ const ENABLE_CANCEL = ctru_sys::MIISELECTOR_CANCEL;
+ /// Make guest Miis available to select.
+ const ENABLE_GUESTS = ctru_sys::MIISELECTOR_GUESTS;
+ /// Show on the top screen.
+ const USE_TOP_SCREEN = ctru_sys::MIISELECTOR_TOP;
+ /// Start on the guests' page. Requires [Options::ENABLE_GUESTS].
+ const START_WITH_GUESTS = ctru_sys::MIISELECTOR_GUESTSTART;
}
}
-/// An instance of the Mii Selector
+/// Configuration object to setup the Mii Selector applet.
///
/// # Example
-/// ```
+/// ```no_run
+/// # use std::error::Error;
+/// # fn main() -> Result<(), Box> {
+/// #
/// use ctru::applets::mii_selector::MiiSelector;
///
/// let mut mii_selector = MiiSelector::new();
-/// mii_selector.set_title("Example Mii selector");
+/// mii_selector.set_title("Example Mii Selector");
///
-/// let result = mii_selector.launch().unwrap();
+/// let result = mii_selector.launch()?;
+/// #
+/// # Ok(())
+/// # }
/// ```
#[doc(alias = "MiiSelectorConf")]
#[derive(Clone, Debug)]
@@ -61,27 +88,27 @@ pub struct MiiSelector {
config: Box,
}
-/// Return value from a MiiSelector's launch
+/// Return value of a successful [MiiSelector::launch()].
#[non_exhaustive]
#[derive(Clone, Debug)]
-pub struct SelectionResult {
- /// Data regarding the selected Mii.
+pub struct Selection {
+ /// Data of the selected Mii.
pub mii_data: MiiData,
/// Type of the selected Mii.
pub mii_type: MiiType,
}
-/// Error type for the Mii selector
+/// Error returned by an unsuccessful [MiiSelector::launch()].
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LaunchError {
- /// The selected Mii's data is corrupt in some way
+ /// The selected Mii's data is corrupt in some way.
InvalidChecksum,
- /// Either the user cancelled the selection (see [Options::MII_SELECTOR_CANCEL]), or no valid Miis were available to select
+ /// Either the user cancelled the selection (see [Options::ENABLE_CANCEL]), or no valid Miis were available to select.
NoMiiSelected,
}
impl MiiSelector {
- /// Initializes a Mii Selector
+ /// Initialize a new configuration for the Mii Selector applet.
#[doc(alias = "miiSelectorInit")]
pub fn new() -> Self {
let mut config = Box::::default();
@@ -91,9 +118,9 @@ impl MiiSelector {
Self { config }
}
- /// Set the title of the Mii Selector.
+ /// Set the title of the Mii Selector window.
///
- /// This function would panic if the given ``&str`` contains NUL bytes.
+ /// This function will panic if the given `&str` contains NUL bytes.
#[doc(alias = "miiSelectorSetTitle")]
pub fn set_title(&mut self, text: &str) {
// This can only fail if the text contains NUL bytes in the string... which seems
@@ -104,13 +131,15 @@ impl MiiSelector {
}
}
- /// Set the options of the Mii Selector
+ /// Set the options of the Mii Selector.
+ ///
+ /// This will overwrite any previously saved options.
#[doc(alias = "miiSelectorSetOptions")]
pub fn set_options(&mut self, options: Options) {
- unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits) }
+ unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits()) }
}
- /// Whitelist a guest Mii
+ /// Whitelist a guest Mii based on its index.
#[doc(alias = "miiSelectorWhitelistGuestMii")]
pub fn whitelist_guest_mii(&mut self, mii_index: Index) {
let index = match mii_index {
@@ -121,7 +150,7 @@ impl MiiSelector {
unsafe { ctru_sys::miiSelectorWhitelistGuestMii(self.config.as_mut(), index) }
}
- /// Blacklist a guest Mii
+ /// Blacklist a guest Mii based on its index.
#[doc(alias = "miiSelectorBlacklistGuestMii")]
pub fn blacklist_guest_mii(&mut self, mii_index: Index) {
let index = match mii_index {
@@ -132,7 +161,7 @@ impl MiiSelector {
unsafe { ctru_sys::miiSelectorBlacklistGuestMii(self.config.as_mut(), index) }
}
- /// Whitelist a user Mii
+ /// Whitelist a user Mii based on its index.
#[doc(alias = "miiSelectorWhitelistUserMii")]
pub fn whitelist_user_mii(&mut self, mii_index: Index) {
let index = match mii_index {
@@ -143,7 +172,7 @@ impl MiiSelector {
unsafe { ctru_sys::miiSelectorWhitelistUserMii(self.config.as_mut(), index) }
}
- /// Blacklist a user Mii
+ /// Blacklist a user Mii based on its index.
#[doc(alias = "miiSelectorBlacklistUserMii")]
pub fn blacklist_user_mii(&mut self, mii_index: Index) {
let index = match mii_index {
@@ -154,8 +183,9 @@ impl MiiSelector {
unsafe { ctru_sys::miiSelectorBlacklistUserMii(self.config.as_mut(), index) }
}
- /// Set where the cursor will be.
- /// If there's no Mii at that index, the cursor will start at the Mii with the index 0
+ /// Set where the cursor will start at.
+ ///
+ /// If there's no Mii at that index, the cursor will start at the Mii with the index 0.
pub fn set_initial_index(&mut self, index: usize) {
// This function is static inline in libctru
// https://github.com/devkitPro/libctru/blob/af5321c78ee5c72a55b526fd2ed0d95ca1c05af9/libctru/include/3ds/applets/miiselector.h#L155
@@ -163,9 +193,10 @@ impl MiiSelector {
}
/// Launch the Mii Selector.
- /// Returns an error when the checksum of the Mii is invalid.
+ ///
+ /// Depending on the configuration, the Mii Selector window will appear either on the bottom screen (default behaviour) or the top screen (see [Options::USE_TOP_SCREEN]).
#[doc(alias = "miiSelectorLaunch")]
- pub fn launch(&mut self) -> Result {
+ pub fn launch(&mut self) -> Result {
let mut return_val = Box::::default();
unsafe { ctru_sys::miiSelectorLaunch(self.config.as_mut(), return_val.as_mut()) }
@@ -187,12 +218,23 @@ impl Default for MiiSelector {
}
}
-impl From for SelectionResult {
+impl fmt::Display for LaunchError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::InvalidChecksum => write!(f, "selected mii has invalid checksum"),
+ Self::NoMiiSelected => write!(f, "no mii was selected"),
+ }
+ }
+}
+
+impl Error for LaunchError {}
+
+impl From for Selection {
fn from(ret: ctru_sys::MiiSelectorReturn) -> Self {
let raw_mii_data = ret.mii;
let mut guest_mii_name = ret.guest_mii_name;
- SelectionResult {
+ Selection {
mii_data: raw_mii_data.into(),
mii_type: if ret.guest_mii_index != 0xFFFFFFFF {
MiiType::Guest {
diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs
index e8af7ca..15216fa 100644
--- a/ctru-rs/src/applets/mod.rs
+++ b/ctru-rs/src/applets/mod.rs
@@ -2,6 +2,9 @@
//!
//! Applets are small integrated programs that the OS makes available to the developer to streamline commonly needed functionality.
//! Thanks to these integrations the developer can avoid wasting time re-implementing common features and instead use a more reliable base for their application.
+//!
+//! Unlike [services](crate::services), applets aren't accessed via a system subprocess (which would require obtaining a special handle at runtime).
+//! Instead, the user builds a configuration storing the various parameters which is then used to "launch" the applet.
pub mod mii_selector;
pub mod swkbd;
diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs
index 59c658d..86f6357 100644
--- a/ctru-rs/src/applets/swkbd.rs
+++ b/ctru-rs/src/applets/swkbd.rs
@@ -89,6 +89,7 @@ pub enum ValidInput {
bitflags! {
/// Keyboard feature flags.
+ #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct Features: u32 {
/// Parental PIN mode.
const PARENTAL_PIN = ctru_sys::SWKBD_PARENTAL;
@@ -111,6 +112,7 @@ bitflags! {
}
/// Keyboard input filtering flags
+ #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct Filters: u32 {
/// Disallows the usage of numerical digits.
const DIGITS = ctru_sys::SWKBD_FILTER_DIGITS;
@@ -183,13 +185,13 @@ impl Swkbd {
/// Sets special features for this keyboard
#[doc(alias = "swkbdSetFeatures")]
pub fn set_features(&mut self, features: Features) {
- unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits) }
+ unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits()) }
}
/// Configures input validation for this keyboard
pub fn set_validation(&mut self, validation: ValidInput, filters: Filters) {
self.state.valid_input = validation.into();
- self.state.filter_flags = filters.bits;
+ self.state.filter_flags = filters.bits();
}
/// Configures the maximum number of digits that can be entered in the keyboard when the
diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs
index 71c0f46..895bed1 100644
--- a/ctru-rs/src/error.rs
+++ b/ctru-rs/src/error.rs
@@ -21,7 +21,9 @@ pub type Result = ::std::result::Result;
/// # Example
///
/// ```no_run
-/// pub fn hid_init() -> crate::Result<()> {
+/// use ctru::error::{Result, ResultCode};
+///
+/// pub fn hid_init() -> Result<()> {
/// // We run an unsafe function which returns a `ctru_sys::Result`.
/// let result: ctru_sys::Result = unsafe { ctru_sys::hidInit() };
///
diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs
index 7e29748..64ef0fa 100644
--- a/ctru-rs/src/lib.rs
+++ b/ctru-rs/src/lib.rs
@@ -14,10 +14,6 @@
//! Read thoroughly the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools.
//! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency
//! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds).
-//!
-//! # Examples
-//!
-//! You can check out the examples provided with this crate which dive into most of the implemented functionality.
#![crate_type = "rlib"]
#![crate_name = "ctru"]
diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs
index f008954..1f0fed7 100644
--- a/ctru-rs/src/services/fs.rs
+++ b/ctru-rs/src/services/fs.rs
@@ -17,20 +17,20 @@ use std::sync::Arc;
use widestring::{WideCStr, WideCString};
bitflags! {
- #[derive(Default)]
+ #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsOpen: u32 {
const FS_OPEN_READ = 1;
const FS_OPEN_WRITE = 2;
const FS_OPEN_CREATE = 4;
}
- #[derive(Default)]
+ #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsWrite: u32 {
const FS_WRITE_FLUSH = 1;
const FS_WRITE_UPDATE_TIME = 256;
}
- #[derive(Default)]
+ #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
struct FsAttribute: u32 {
const FS_ATTRIBUTE_DIRECTORY = 1;
const FS_ATTRIBUTE_HIDDEN = 256;
diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs
index 54ec061..b1432f2 100644
--- a/ctru-rs/src/services/gfx.rs
+++ b/ctru-rs/src/services/gfx.rs
@@ -222,8 +222,17 @@ impl Gfx {
/// Creates a new [`Gfx`] instance with default init values
/// It's the same as calling:
///
- /// ```
- /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
+ /// ```no_run
+ /// # use std::error::Error;
+ /// # fn main() -> Result<(), Box> {
+ /// #
+ /// # use ctru::services::gfx::Gfx;
+ /// use ctru::services::gspgpu::FramebufferFormat;
+ ///
+ /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false);
+ /// #
+ /// # Ok(())
+ /// # }
/// ```
#[doc(alias = "gfxInit")]
pub fn new() -> Result {
diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs
index cb2550f..b592f6a 100644
--- a/ctru-rs/src/services/hid.rs
+++ b/ctru-rs/src/services/hid.rs
@@ -5,9 +5,12 @@
//! the accelerometer, and the gyroscope.
use crate::error::ResultCode;
-bitflags::bitflags! {
+use bitflags::bitflags;
+
+bitflags! {
/// A set of flags corresponding to the button and directional pad
/// inputs on the 3DS
+ #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct KeyPad: u32 {
/// A button.
const A = ctru_sys::KEY_A;