Further work on wrapping NSUserDefaults
This commit is contained in:
parent
ccaf61f56f
commit
e4ddfb975a
30
examples/defaults.rs
Normal file
30
examples/defaults.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//! This tests the `defaults` module to ensure things behave as they should.
|
||||||
|
|
||||||
|
use cacao::macos::app::{App, AppDelegate};
|
||||||
|
use cacao::defaults::UserDefaults;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DefaultsTest;
|
||||||
|
|
||||||
|
impl AppDelegate for DefaultsTest {
|
||||||
|
fn did_finish_launching(&self) {
|
||||||
|
let mut defaults = UserDefaults::standard();
|
||||||
|
|
||||||
|
match defaults.get_string("LOL") {
|
||||||
|
Some(s) => {
|
||||||
|
println!("Retrieved {}", s);
|
||||||
|
},
|
||||||
|
|
||||||
|
None => {
|
||||||
|
defaults.set_string("LOL", "laugh");
|
||||||
|
println!("Run this again to get a laugh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new("com.cacao.defaults-test", DefaultsTest::default()).run();
|
||||||
|
}
|
123
src/defaults.rs
Normal file
123
src/defaults.rs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
//! Wraps `NSUserDefaults`, providing an interface to store and query small amounts of data.
|
||||||
|
//!
|
||||||
|
//! It may seem a bit verbose at points, but it aims to implement everything on the Objective-C
|
||||||
|
//! side as closely as possible.
|
||||||
|
|
||||||
|
use std::unreachable;
|
||||||
|
|
||||||
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, YES, NO, BOOL, NSString};
|
||||||
|
|
||||||
|
/// Wraps and provides methods for interacting with `NSUserDefaults`, which can be used for storing
|
||||||
|
/// pieces of information (preferences, or _defaults_) to persist across application restores.
|
||||||
|
///
|
||||||
|
/// This should not be used for sensitive data - use the Keychain for that.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UserDefaults(pub Id<Object>);
|
||||||
|
|
||||||
|
impl Default for UserDefaults {
|
||||||
|
/// Equivalent to calling `UserDefaults::standard()`.
|
||||||
|
fn default() -> Self {
|
||||||
|
UserDefaults::standard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserDefaults {
|
||||||
|
/// Returns the `standardUserDefaults`, which is... exactly what it sounds like.
|
||||||
|
pub fn standard() -> Self {
|
||||||
|
UserDefaults(unsafe {
|
||||||
|
Id::from_ptr(msg_send![class!(NSUserDefaults), standardUserDefaults])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new user defaults to work with. You probably don't want this, and either want
|
||||||
|
/// `suite()` or `standard()`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
UserDefaults(unsafe {
|
||||||
|
let alloc: id = msg_send![class!(NSUserDefaults), alloc];
|
||||||
|
Id::from_ptr(msg_send![alloc, init])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a user defaults instance for the given suite name. You typically use this to share
|
||||||
|
/// preferences across apps and extensions.
|
||||||
|
pub fn suite(named: &str) -> Self {
|
||||||
|
let name = NSString::new(named);
|
||||||
|
|
||||||
|
UserDefaults(unsafe {
|
||||||
|
let alloc: id = msg_send![class!(NSUserDefaults), alloc];
|
||||||
|
Id::from_ptr(msg_send![alloc, initWithSuiteName:name.into_inner()])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the default associated with the key. If the key doesn't exist, this is a noop.
|
||||||
|
pub fn remove(&mut self, key: &str) {
|
||||||
|
let key = NSString::new(key);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![&*self.0, removeObjectForKey:key.into_inner()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a bool for the given key. If the key doesn't exist, it returns `false`.
|
||||||
|
///
|
||||||
|
/// Note that behind the scenes, this will coerce certain "truthy" and "falsy" values - this is
|
||||||
|
/// done on the system side, and is not something that can be changed.
|
||||||
|
///
|
||||||
|
/// e.g:
|
||||||
|
/// `"true"`, `"YES"`, `"1"`, `1`, `1.0` will become `true`
|
||||||
|
/// `"false"`, `"NO"`, `"0"`, `0`, `0.0` will become `false`
|
||||||
|
pub fn get_bool(&self, key: &str) -> bool {
|
||||||
|
let key = NSString::new(key);
|
||||||
|
|
||||||
|
let result: BOOL = unsafe {
|
||||||
|
msg_send![&*self.0, boolForKey:key.into_inner()]
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
YES => true,
|
||||||
|
NO => false,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the bool for the given key to the specified value.
|
||||||
|
pub fn set_bool(&mut self, key: &str, value: bool) {
|
||||||
|
let key = NSString::new(key);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![&*self.0, setBool:match value {
|
||||||
|
true => YES,
|
||||||
|
false => NO
|
||||||
|
} forKey:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the given String if it exists, mapping Objective-C's `nil` to `None`.
|
||||||
|
pub fn get_string(&self, key: &str) -> Option<String> {
|
||||||
|
let key = NSString::new(key);
|
||||||
|
|
||||||
|
let result: id = unsafe {
|
||||||
|
msg_send![&*self.0, stringForKey:key.into_inner()]
|
||||||
|
};
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(NSString::wrap(result).to_str().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the string for the given key to the specified value.
|
||||||
|
pub fn set_string(&mut self, key: &str, value: &str) {
|
||||||
|
let key = NSString::new(key);
|
||||||
|
let value = NSString::new(value);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![&*self.0, setObject:value.into_inner() forKey:key.into_inner()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,6 +85,7 @@ pub mod color;
|
||||||
pub mod dragdrop;
|
pub mod dragdrop;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
pub mod defaults;
|
||||||
pub mod filesystem;
|
pub mod filesystem;
|
||||||
pub mod foundation;
|
pub mod foundation;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
@ -98,7 +99,6 @@ pub mod user_notifications;
|
||||||
|
|
||||||
pub mod user_activity;
|
pub mod user_activity;
|
||||||
pub(crate) mod utils;
|
pub(crate) mod utils;
|
||||||
pub mod user_defaults;
|
|
||||||
|
|
||||||
pub mod view;
|
pub mod view;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::foundation::{id, YES, NO, NSUInteger, AutoReleasePool};
|
use crate::foundation::{id, nil, YES, NO, NSUInteger, AutoReleasePool};
|
||||||
use crate::macos::menu::Menu;
|
use crate::macos::menu::Menu;
|
||||||
use crate::notification_center::Dispatcher;
|
use crate::notification_center::Dispatcher;
|
||||||
|
|
||||||
|
@ -236,4 +236,13 @@ impl App {
|
||||||
let _: () = msg_send![app, setMainMenu:main_menu];
|
let _: () = msg_send![app, setMainMenu:main_menu];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Terminates the application, firing the requisite cleanup delegate methods in the process.
|
||||||
|
///
|
||||||
|
/// This is typically called when the user chooses to quit via the App menu.
|
||||||
|
pub fn terminate() {
|
||||||
|
shared_application(|app| unsafe {
|
||||||
|
let _: () = msg_send![app, terminate:nil];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
//! Wraps `NSUserDefaults`, providing an interface to store and query small amounts of data.
|
|
||||||
//!
|
|
||||||
//! It mirrors much of the API of the standard Rust `HashMap`, but uses `NSUserDefaults` as a
|
|
||||||
//! backing store.
|
|
||||||
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
|
||||||
use objc::runtime::Object;
|
|
||||||
use objc_id::Id;
|
|
||||||
|
|
||||||
use crate::foundation::{id, NSString};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UserDefaults(pub Id<Object>);
|
|
||||||
|
|
||||||
impl Default for UserDefaults {
|
|
||||||
fn default() -> Self {
|
|
||||||
UserDefaults::standard()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserDefaults {
|
|
||||||
pub fn standard() -> Self {
|
|
||||||
UserDefaults(unsafe {
|
|
||||||
Id::from_ptr(msg_send![class!(NSUserDefaults), standardUserDefaults])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new() -> Self {
|
|
||||||
UserDefaults(unsafe {
|
|
||||||
let alloc: id = msg_send![class!(NSUserDefaults), alloc];
|
|
||||||
Id::from_ptr(msg_send![alloc, init])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn suite(named: &str) -> Self {
|
|
||||||
let name = NSString::new(named);
|
|
||||||
|
|
||||||
UserDefaults(unsafe {
|
|
||||||
let alloc: id = msg_send![class!(NSUserDefaults), alloc];
|
|
||||||
Id::from_ptr(msg_send![alloc, initWithSuiteName:name.into_inner()])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove the default associated with the key. If the key doesn't exist, this is a noop.
|
|
||||||
pub fn remove(&self, key: &str) {
|
|
||||||
let key = NSString::new(key);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let _: () = msg_send![&*self.0, removeObjectForKey:key.into_inner()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue