Fix BOOL return values from NSUserDefaults, improve documentation
This commit is contained in:
parent
8c39ea6f94
commit
db4da24268
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use cacao::macos::app::{App, AppDelegate};
|
||||
use cacao::macos::{App, AppDelegate};
|
||||
use cacao::defaults::{UserDefaults, Value};
|
||||
use cacao::foundation::NSData;
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl AppDelegate for DefaultsTest {
|
|||
//map.insert("LOL", Value::string("laugh"));
|
||||
//map.insert("X", Value::Integer(1));
|
||||
//map.insert("X2", Value::Float(1.0));
|
||||
map.insert("BOOL", Value::bool(true));
|
||||
map.insert("BOOL", Value::Bool(false));
|
||||
|
||||
println!("Test equivalency:");
|
||||
let s = "BYTES TEST".to_string().into_bytes();
|
||||
|
@ -34,7 +34,7 @@ impl AppDelegate for DefaultsTest {
|
|||
|
||||
//println!("Retrieved LOL: {:?}", defaults.get("LOL"));
|
||||
//println!("Retrieved LOL: {:?}", defaults.get("X"));
|
||||
//println!("Retrieved LOL: {:?}", defaults.get("X2"));
|
||||
println!("Retrieved LOL: {:?}", defaults.get("BOOL"));
|
||||
|
||||
let bytes = defaults.get("BYTES").unwrap();
|
||||
println!("Bytes: {:?}", bytes);
|
||||
|
|
|
@ -197,15 +197,24 @@ impl UserDefaults {
|
|||
// `NSNumber` returned and see what the wrapped encoding type is. `q` and `d` represent
|
||||
// `NSInteger` (platform specific) and `double` (f64) respectively, but conceivably we
|
||||
// might need others.
|
||||
//
|
||||
// BOOL returns as "c", which... something makes me feel weird there, but testing it seems
|
||||
// reliable.
|
||||
//
|
||||
// For context: https://nshipster.com/type-encodings/
|
||||
if NSNumber::is(result) {
|
||||
let number = NSNumber::wrap(result);
|
||||
|
||||
return match number.objc_type() {
|
||||
"q" => Some(Value::Integer(number.as_i64())),
|
||||
"c" => Some(Value::Bool(number.as_bool())),
|
||||
"d" => Some(Value::Float(number.as_f64())),
|
||||
"q" => Some(Value::Integer(number.as_i64())),
|
||||
|
||||
x => {
|
||||
// Debugging code that should be removed at some point.
|
||||
#[cfg(debug_assertions)]
|
||||
println!("Code: {}", x);
|
||||
|
||||
_ => {
|
||||
// @TODO: Verify this area.
|
||||
None
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
//! A wrapper for `NSDictionary`, which aims to make dealing with the class throughout this
|
||||
//! framework a tad bit simpler.
|
||||
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
use objc::runtime::Object;
|
||||
use objc_id::Id;
|
||||
|
@ -19,18 +16,28 @@ impl Default for NSDictionary {
|
|||
}
|
||||
|
||||
impl NSDictionary {
|
||||
/// Constructs an `NSMutableDictionary` and retains it.
|
||||
///
|
||||
/// Why mutable? It's just easier for working with it, as they're (mostly) interchangeable when
|
||||
/// passed around in Objective-C. We guard against mutation on our side using the standard Rust
|
||||
/// object model. You can, of course, bypass it and `msg_send![]` yourself, but it'd require an
|
||||
/// `unsafe {}` block... so you'll know you're in special territory then.
|
||||
pub fn new() -> Self {
|
||||
NSDictionary(unsafe {
|
||||
Id::from_ptr(msg_send![class!(NSMutableDictionary), new])
|
||||
})
|
||||
}
|
||||
|
||||
/// Inserts an object into the backing NSMutablyDictionary.
|
||||
///
|
||||
/// This intentionally requires `NSString` be allocated ahead of time.
|
||||
pub fn insert(&mut self, key: NSString, object: id) {
|
||||
unsafe {
|
||||
let _: () = msg_send![&*self.0, setObject:object forKey:key.into_inner()];
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes and returns the underlying `NSMutableDictionary`.
|
||||
pub fn into_inner(mut self) -> id {
|
||||
&mut *self.0
|
||||
}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
//! A wrapper for `NSNumber`.
|
||||
//!
|
||||
//! There are a few places where we have to interact with this type (e.g, `NSUserDefaults`) and so
|
||||
//! this type exists to wrap those unsafe operations.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
|
@ -13,10 +8,22 @@ use objc_id::Id;
|
|||
use crate::foundation::{id, BOOL, YES, NO, NSInteger};
|
||||
|
||||
/// Wrapper for a retained `NSNumber` object.
|
||||
///
|
||||
/// In general we strive to avoid using this in the codebase, but it's a requirement for moving
|
||||
/// objects in and out of certain situations (e.g, `UserDefaults`).
|
||||
#[derive(Debug)]
|
||||
pub struct NSNumber(pub Id<Object>);
|
||||
|
||||
impl NSNumber {
|
||||
/// If we're vended an NSNumber from a method (e.g, `NSUserDefaults` querying) we might want to
|
||||
/// wrap it while we figure out what to do with it. This does that.
|
||||
pub fn wrap(data: id) -> Self {
|
||||
NSNumber(unsafe {
|
||||
Id::from_ptr(data)
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs a `numberWithBool` instance of `NSNumber` and retains it.
|
||||
pub fn bool(value: bool) -> Self {
|
||||
NSNumber(unsafe {
|
||||
Id::from_ptr(msg_send![class!(NSNumber), numberWithBool:match value {
|
||||
|
@ -26,18 +33,25 @@ impl NSNumber {
|
|||
})
|
||||
}
|
||||
|
||||
/// Constructs a `numberWithInteger` instance of `NSNumber` and retains it.
|
||||
pub fn integer(value: i64) -> Self {
|
||||
NSNumber(unsafe {
|
||||
Id::from_ptr(msg_send![class!(NSNumber), numberWithInteger:value as NSInteger])
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs a `numberWithDouble` instance of `NSNumber` and retains it.
|
||||
pub fn float(value: f64) -> Self {
|
||||
NSNumber(unsafe {
|
||||
Id::from_ptr(msg_send![class!(NSNumber), numberWithDouble:value])
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the `objCType` of the underlying `NSNumber` as a Rust `&str`. This flag can be used
|
||||
/// to inform you how you should pull the underlying data out of the `NSNumber`.
|
||||
///
|
||||
/// For more information:
|
||||
/// [https://nshipster.com/type-encodings/](https://nshipster.com/type-encodings/)
|
||||
pub fn objc_type(&self) -> &str {
|
||||
unsafe {
|
||||
let t: *const c_char = msg_send![&*self.0, objCType];
|
||||
|
@ -46,6 +60,10 @@ impl NSNumber {
|
|||
}
|
||||
}
|
||||
|
||||
/// Pulls the underlying `NSInteger` value out and passes it back as an `i64`.
|
||||
///
|
||||
/// Note that this _does not check_ if the underlying type is actually this. You are
|
||||
/// responsible for doing so via the `objc_type()` method.
|
||||
pub fn as_i64(&self) -> i64 {
|
||||
unsafe {
|
||||
let i: NSInteger = msg_send![&*self.0, integerValue];
|
||||
|
@ -53,18 +71,30 @@ impl NSNumber {
|
|||
}
|
||||
}
|
||||
|
||||
/// Pulls the underlying `double` value out and passes it back as an `f64`.
|
||||
///
|
||||
/// Note that this _does not check_ if the underlying type is actually this. You are
|
||||
/// responsible for doing so via the `objc_type()` method.
|
||||
pub fn as_f64(&self) -> f64 {
|
||||
unsafe {
|
||||
msg_send![&*self.0, doubleValue]
|
||||
}
|
||||
}
|
||||
|
||||
/// If we're vended an NSNumber from a method (e.g, `NSUserDefaults` querying) we might want to
|
||||
/// wrap it while we figure out what to do with it. This does that.
|
||||
pub fn wrap(data: id) -> Self {
|
||||
NSNumber(unsafe {
|
||||
Id::from_ptr(data)
|
||||
})
|
||||
/// Pulls the underlying `BOOL` value out and passes it back as a `bool`.
|
||||
///
|
||||
/// Note that this _does not check_ if the underlying type is actually this. You are
|
||||
/// responsible for doing so via the `objc_type()` method.
|
||||
pub fn as_bool(&self) -> bool {
|
||||
let result: BOOL = unsafe {
|
||||
msg_send![&*self.0, boolValue]
|
||||
};
|
||||
|
||||
match result {
|
||||
YES => true,
|
||||
NO => false,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper method for determining if a given `NSObject` is an `NSNumber`.
|
||||
|
|
Loading…
Reference in a new issue