Browse Source

Refactor some code and improve documentation

pull/162/head
Fenrir 10 months ago
parent
commit
559c757d35
  1. 55
      ctru-rs/src/applets/error.rs
  2. 4
      ctru-sys/src/lib.rs

55
ctru-rs/src/applets/error.rs

@ -1,4 +1,4 @@
//! Error applet //! Error applet.
//! //!
//! This applet displays error text as a pop-up message on the lower screen. //! This applet displays error text as a pop-up message on the lower screen.
@ -12,15 +12,15 @@ pub struct PopUp {
state: Box<errorConf>, state: Box<errorConf>,
} }
/// The kind of error applet to display. /// Determines whether the Error applet will use word wrapping when displaying a message.
#[doc(alias = "errorType")] #[doc(alias = "errorType")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
pub enum Kind { pub enum WordWrap {
/// Error text is centered in the error applet window. /// Error text is centered in the error applet window and does not use word wrapping.
Center = ctru_sys::ERROR_TEXT, Disabled = ctru_sys::ERROR_TEXT,
/// Error text starts at the top of the error applet window. /// Error text starts at the top of the error applet window and uses word wrapping.
Top = ctru_sys::ERROR_TEXT_WORD_WRAP, Enabled = ctru_sys::ERROR_TEXT_WORD_WRAP,
} }
/// Error returned by an unsuccessful [`PopUp::launch()`]. /// Error returned by an unsuccessful [`PopUp::launch()`].
@ -41,17 +41,22 @@ pub enum Error {
} }
impl PopUp { impl PopUp {
/// Initialize the error applet with the provided text kind. /// Initializes the error applet with the provided word wrap setting.
#[doc(alias = "errorInit")] #[doc(alias = "errorInit")]
pub fn new(kind: Kind) -> Self { pub fn new(word_wrap: WordWrap) -> Self {
let mut state = Box::<errorConf>::default(); let mut state = Box::<errorConf>::default();
unsafe { ctru_sys::errorInit(state.as_mut(), kind as _, 0) }; unsafe { ctru_sys::errorInit(state.as_mut(), word_wrap as _, 0) };
Self { state } Self { state }
} }
/// Sets the error text to display. /// Sets the error text to display.
///
/// # Notes
///
/// Messages that are too large will be truncated. The exact number of characters displayed can vary depending on factors such as
/// the length of individual words in the message and the chosen word wrap setting.
#[doc(alias = "errorText")] #[doc(alias = "errorText")]
pub fn set_text(&mut self, text: &str) { pub fn set_text(&mut self, text: &str) {
for (idx, code_unit) in text for (idx, code_unit) in text
@ -74,7 +79,7 @@ impl PopUp {
/// ///
/// # Safety /// # Safety
/// ///
/// Causes undefined behavior if the aforementioned services are not actually active when the applet launches. /// Potentially leads to undefined behavior if the aforementioned services are not actually active when the applet launches.
unsafe fn launch_unchecked(&mut self) -> Result<(), Error> { unsafe fn launch_unchecked(&mut self) -> Result<(), Error> {
unsafe { ctru_sys::errorDisp(self.state.as_mut()) }; unsafe { ctru_sys::errorDisp(self.state.as_mut()) };
@ -91,14 +96,18 @@ impl PopUp {
/// Sets a custom [panic hook](https://doc.rust-lang.org/std/panic/fn.set_hook.html) that uses the error applet to display panic messages. /// Sets a custom [panic hook](https://doc.rust-lang.org/std/panic/fn.set_hook.html) that uses the error applet to display panic messages.
/// ///
/// You can also choose to have the previously registered panic hook called along with the error applet message, which can be useful /// You can also choose to have the previously registered panic hook called along with the error applet popup, which can be useful
/// if you want to use output redirection to display panic messages over `3dslink` or `GDB`. /// if you want to use output redirection to display panic messages over `3dslink` or `GDB`.
/// ///
/// If the [`Gfx`] service is not initialized during a panic, the error applet will not be displayed and the old
/// panic hook will be called.
///
/// You can use [`std::panic::take_hook`](https://doc.rust-lang.org/std/panic/fn.take_hook.html) to unregister the panic hook /// You can use [`std::panic::take_hook`](https://doc.rust-lang.org/std/panic/fn.take_hook.html) to unregister the panic hook
/// set by this function. /// set by this function.
///
/// # Notes
///
/// * If the [`Gfx`] service is not initialized during a panic, the error applet will not be displayed and the old panic hook will be called.
///
/// * As mentioned in [`PopUp::set_text`], the error applet can only display a finite number of characters and so panic messages that are too long
/// can potentially end up being truncated. Consider using this hook along with the default hook so that you can capture full panic messages via stderr.
pub fn set_panic_hook(call_old_hook: bool) { pub fn set_panic_hook(call_old_hook: bool) {
use crate::services::gfx::GFX_ACTIVE; use crate::services::gfx::GFX_ACTIVE;
use std::sync::TryLockError; use std::sync::TryLockError;
@ -106,22 +115,22 @@ pub fn set_panic_hook(call_old_hook: bool) {
let old_hook = std::panic::take_hook(); let old_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| { std::panic::set_hook(Box::new(move |panic_info| {
let thread = std::thread::current();
let name = thread.name().unwrap_or("<unnamed>");
// If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized. // If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized.
// Otherwise fallback to printing over stderr. // Otherwise fallback to using the old panic hook.
if let (Err(TryLockError::WouldBlock), Ok(_apt)) = (GFX_ACTIVE.try_lock(), Apt::new()) { if let (Err(TryLockError::WouldBlock), Ok(_apt)) = (GFX_ACTIVE.try_lock(), Apt::new()) {
if call_old_hook { if call_old_hook {
old_hook(panic_info); old_hook(panic_info);
} }
let payload = format!("thread '{name}' {panic_info}"); let thread = std::thread::current();
let name = thread.name().unwrap_or("<unnamed>");
let message = format!("thread '{name}' {panic_info}");
let mut popup = PopUp::new(Kind::Top); let mut popup = PopUp::new(WordWrap::Enabled);
popup.set_text(&payload); popup.set_text(&message);
unsafe { unsafe {
let _ = popup.launch_unchecked(); let _ = popup.launch_unchecked();

4
ctru-sys/src/lib.rs

@ -21,6 +21,7 @@ pub use result::*;
// Libctru's `errorConf` struct contains two enums that depend on this narrowing property for size and alignment purposes, // Libctru's `errorConf` struct contains two enums that depend on this narrowing property for size and alignment purposes,
// and since `bindgen` generates all enums with `c_int` sizing, we have to blocklist those types and manually define them // and since `bindgen` generates all enums with `c_int` sizing, we have to blocklist those types and manually define them
// here with the proper size. // here with the proper size.
pub type errorReturnCode = libc::c_schar;
pub const ERROR_UNKNOWN: errorReturnCode = -1; pub const ERROR_UNKNOWN: errorReturnCode = -1;
pub const ERROR_NONE: errorReturnCode = 0; pub const ERROR_NONE: errorReturnCode = 0;
pub const ERROR_SUCCESS: errorReturnCode = 1; pub const ERROR_SUCCESS: errorReturnCode = 1;
@ -28,11 +29,10 @@ pub const ERROR_NOT_SUPPORTED: errorReturnCode = 2;
pub const ERROR_HOME_BUTTON: errorReturnCode = 10; pub const ERROR_HOME_BUTTON: errorReturnCode = 10;
pub const ERROR_SOFTWARE_RESET: errorReturnCode = 11; pub const ERROR_SOFTWARE_RESET: errorReturnCode = 11;
pub const ERROR_POWER_BUTTON: errorReturnCode = 12; pub const ERROR_POWER_BUTTON: errorReturnCode = 12;
pub type errorReturnCode = libc::c_schar;
pub type errorScreenFlag = libc::c_char;
pub const ERROR_NORMAL: errorScreenFlag = 0; pub const ERROR_NORMAL: errorScreenFlag = 0;
pub const ERROR_STEREO: errorScreenFlag = 1; pub const ERROR_STEREO: errorScreenFlag = 1;
pub type errorScreenFlag = libc::c_char;
include!(concat!(env!("OUT_DIR"), "/bindings.rs")); include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

Loading…
Cancel
Save