use std::collections::HashMap;
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use crate::foundation::{id, nil, to_bool, NSData, NSMutableDictionary, NSNumber, NSString, BOOL, NO, YES};
mod value;
pub use value::Value;
#[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 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])
})
}
pub fn register<K: AsRef<str>>(&mut self, values: HashMap<K, Value>) {
let dictionary = NSMutableDictionary::from(values);
unsafe {
let _: () = msg_send![&*self.0, registerDefaults:&*dictionary];
}
}
pub fn insert<K: AsRef<str>>(&mut self, key: K, value: Value) {
let key = NSString::new(key.as_ref());
let value: id = value.into();
unsafe {
let _: () = msg_send![&*self.0, setObject:value forKey:key];
}
}
pub fn remove<K: AsRef<str>>(&mut self, key: K) {
let key = NSString::new(key.as_ref());
unsafe {
let _: () = msg_send![&*self.0, removeObjectForKey:&*key];
}
}
pub fn get<K: AsRef<str>>(&self, key: K) -> Option<Value> {
let key = NSString::new(key.as_ref());
let result: id = unsafe { msg_send![&*self.0, objectForKey:&*key] };
if result == nil {
return None;
}
if NSData::is(result) {
let data = NSData::retain(result);
return Some(Value::Data(data.into_vec()));
}
if NSString::is(result) {
let s = NSString::retain(result).to_string();
return Some(Value::String(s));
}
if NSNumber::is(result) {
let number = NSNumber::wrap(result);
return match number.objc_type() {
"c" => Some(Value::Bool(number.as_bool())),
"d" => Some(Value::Float(number.as_f64())),
"q" => Some(Value::Integer(number.as_i64())),
_x => {
#[cfg(debug_assertions)]
println!("Unexpected code type found: {}", _x);
None
}
};
}
None
}
pub fn is_forced_for_key<K: AsRef<str>>(&self, key: K) -> bool {
let result: BOOL = unsafe {
let key = NSString::new(key.as_ref());
msg_send![&*self.0, objectIsForcedForKey:&*key]
};
to_bool(result)
}
pub fn synchronize(&self) {
unsafe {
let _: () = msg_send![&*self.0, synchronize];
}
}
}