Browse Source

Merge branch 'master' into feature/std-threads

# Conflicts:
#	ctru-rs/src/services/ps.rs
pull/46/head
Mark Drobnak 3 years ago
parent
commit
8113950f4b
No known key found for this signature in database
GPG Key ID: 47A133F3BF9D03D3
  1. 1
      ctru-rs/Cargo.toml
  2. 2
      ctru-rs/examples/futures-tokio.rs
  3. 12
      ctru-rs/examples/hashmaps.rs
  4. 48
      ctru-rs/examples/romfs.rs
  5. 1
      ctru-rs/examples/romfs/ファイル.txt
  6. 14
      ctru-rs/src/lib.rs
  7. 100
      ctru-rs/src/services/ps.rs

1
ctru-rs/Cargo.toml

@ -28,6 +28,7 @@ ferris-says = "0.2.1" @@ -28,6 +28,7 @@ ferris-says = "0.2.1"
futures = "0.3"
time = "0.3.7"
tokio = { version = "1.16", features = ["rt", "time", "sync", "macros"] }
cfg-if = "1.0.0"
[features]
default = ["romfs"]

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

@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
use ctru::console::Console;
use ctru::services::hid::KeyPad;
use ctru::services::ps::Ps;
use ctru::services::{Apt, Hid};
use ctru::Gfx;
use std::os::horizon::thread::BuilderExt;
@ -13,7 +12,6 @@ fn main() { @@ -13,7 +12,6 @@ fn main() {
let gfx = Gfx::default();
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _ps = Ps::init().expect("Couldn't initialize PS service");
let _console = Console::init(gfx.top_screen.borrow_mut());
// Give ourselves up to 30% of the system core's time

12
ctru-rs/examples/hashmaps.rs

@ -2,23 +2,19 @@ use ctru::console::Console; @@ -2,23 +2,19 @@ use ctru::console::Console;
use ctru::gfx::Gfx;
use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad};
use ctru::services::ps::Ps;
fn main() {
// Initialize services
//
// HashMaps generate hashes thanks to the 3DS' cryptografically secure generator.
// This generator is only active when activating the `PS` service.
// This service is automatically initialized in `ctru::init`
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let _console = Console::init(gfx.top_screen.borrow_mut());
// HashMaps generate hashes thanks to the 3DS' criptografically secure generator.
// Sadly, this generator is only active when activating the `Ps` service.
// To do this, we have to make sure the `Ps` service handle is alive for the whole
// run time (or at least, when `HashMaps` are used).
// Not having a living `Ps` instance when using `HashMap`s results in a panic
let _ps = Ps::init().unwrap();
let mut map = std::collections::HashMap::new();
map.insert("A Key!", 102);
map.insert("Another key?", 543);

48
ctru-rs/examples/romfs.rs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
use ctru::console::Console;
use ctru::gfx::Gfx;
use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad};
fn main() {
ctru::init();
let gfx = Gfx::default();
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());
cfg_if::cfg_if! {
// Run this code if RomFS are wanted and available
// 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
if #[cfg(all(feature = "romfs", romfs_exists))] {
let _romfs = ctru::romfs::RomFS::new().unwrap();
let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap();
println!("Contents of test-file.txt: \n{f}\n");
let f = std::fs::read_to_string("romfs:/ファイル.txt").unwrap();
// While RomFS supports UTF-16 file paths, `Console` doesn't...
println!("Contents of [UTF-16 File]: \n{f}\n");
} else {
println!("No RomFS was found, are you sure you included it?")
}
}
println!("\nPress START to exit");
// Main loop
while apt.main_loop() {
//Scan all the inputs. This should be done once for each frame
hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) {
break;
}
// Flush and swap framebuffers
gfx.flush_buffers();
gfx.swap_buffers();
//Wait for VBlank
gfx.wait_for_vblank();
}
}

1
ctru-rs/examples/romfs/ファイル.txt

@ -0,0 +1 @@ @@ -0,0 +1 @@
This filename has UTF-16 exclusive characters!

14
ctru-rs/src/lib.rs

@ -4,6 +4,12 @@ @@ -4,6 +4,12 @@
#![feature(custom_test_frameworks)]
#![test_runner(test_runner::run)]
extern "C" fn services_deinit() {
unsafe {
ctru_sys::psExit();
}
}
/// Call this somewhere to force Rust to link some required crates
/// This is also a setup for some crate integration only available at runtime
///
@ -12,6 +18,14 @@ pub fn init() { @@ -12,6 +18,14 @@ pub fn init() {
linker_fix_3ds::init();
pthread_3ds::init();
// Initialize the PS service for random data generation
unsafe {
ctru_sys::psInit();
// Setup the deconstruction at the program's end
libc::atexit(services_deinit);
}
use std::panic::PanicInfo;
let main_thread = std::thread::current().id();

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

@ -1,13 +1,9 @@ @@ -1,13 +1,9 @@
//! Process Services (PS) module. This is used for miscellaneous utility tasks, but
//! is particularly important because it is used to generate random data, which
//! is required for common things like [`HashMap`](std::collections::HashMap).
//! As such, it is initialized by default in `ctru::init` instead of having a safety handler
//! See also <https://www.3dbrew.org/wiki/Process_Services>
/// PS handle. This must not be dropped in order for random generation
/// to work (in most cases, the lifetime of an application).
#[non_exhaustive]
pub struct Ps;
#[repr(u32)]
pub enum AESAlgorithm {
CbcEnc,
@ -32,55 +28,34 @@ pub enum AESKeyType { @@ -32,55 +28,34 @@ pub enum AESKeyType {
Keyslot39Nfc,
}
impl Ps {
/// Initialize the PS module.
pub fn init() -> crate::Result<Self> {
let r = unsafe { ctru_sys::psInit() };
if r < 0 {
Err(r.into())
} else {
Ok(Self)
}
}
pub fn local_friend_code_seed(&self) -> crate::Result<u64> {
let mut seed: u64 = 0;
pub fn local_friend_code_seed() -> crate::Result<u64> {
let mut seed: u64 = 0;
let r = unsafe { ctru_sys::PS_GetLocalFriendCodeSeed(&mut seed) };
if r < 0 {
Err(r.into())
} else {
Ok(seed)
}
let r = unsafe { ctru_sys::PS_GetLocalFriendCodeSeed(&mut seed) };
if r < 0 {
Err(r.into())
} else {
Ok(seed)
}
}
pub fn device_id(&self) -> crate::Result<u32> {
let mut id: u32 = 0;
let r = unsafe { ctru_sys::PS_GetDeviceId(&mut id) };
if r < 0 {
Err(r.into())
} else {
Ok(id)
}
}
pub fn device_id() -> crate::Result<u32> {
let mut id: u32 = 0;
pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> {
let r =
unsafe { ctru_sys::PS_GenerateRandomBytes(out as *mut _ as *mut _, out.len() as u32) };
if r < 0 {
Err(r.into())
} else {
Ok(())
}
let r = unsafe { ctru_sys::PS_GetDeviceId(&mut id) };
if r < 0 {
Err(r.into())
} else {
Ok(id)
}
}
impl Drop for Ps {
fn drop(&mut self) {
unsafe {
ctru_sys::psExit();
}
pub fn generate_random_bytes(out: &mut [u8]) -> crate::Result<()> {
let r = unsafe { ctru_sys::PS_GenerateRandomBytes(out as *mut _ as *mut _, out.len() as u32) };
if r < 0 {
Err(r.into())
} else {
Ok(())
}
}
@ -92,8 +67,6 @@ mod tests { @@ -92,8 +67,6 @@ mod tests {
#[test]
fn construct_hash_map() {
let _ps = Ps::init().unwrap();
let mut input = vec![
(1_i32, String::from("123")),
(2, String::from("2")),
@ -108,33 +81,4 @@ mod tests { @@ -108,33 +81,4 @@ mod tests {
assert_eq!(input, actual);
}
#[test]
fn construct_hash_map_no_rand() {
// Without initializing PS, we can't use `libc::getrandom` and constructing
// a HashMap panics at runtime.
//
// If any test case successfully creates a HashMap before this test,
// the thread-local RandomState in std will be initialized. We spawn
// a new thread to actually create the hash map, since even in multi-threaded
// test environment there's a chance this test wouldn't panic because
// some other test case ran before it.
//
// One downside of this approach is that the panic handler for the panicking
// thread prints to the console, which is not captured by the default test
// harness and prints even when the test passes.
std::thread::Builder::new()
.spawn(|| {
let map: HashMap<i32, String> = HashMap::from_iter([
(1_i32, String::from("123")),
(2, String::from("2")),
(6, String::from("six")),
]);
dbg!(map);
})
.unwrap()
.join()
.expect_err("should have panicked");
}
}

Loading…
Cancel
Save