#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::fmt;
use core::mem;
use core::ptr::NonNull;
use objc2::msg_send;
use objc2::rc::Retained;
#[cfg(feature = "NSObject")]
use objc2::runtime::ProtocolObject;
#[cfg(feature = "NSObject")]
use objc2::AllocAnyThread;
use objc2::Message;
#[cfg(feature = "NSEnumerator")]
use crate::iter;
#[cfg(feature = "NSObject")]
use crate::{util, CopyingHelper, NSCopying};
use crate::{NSDictionary, NSMutableDictionary};
#[cfg(feature = "NSObject")]
fn keys_to_ptr<CopiedKey>(keys: &[&CopiedKey]) -> *mut NonNull<ProtocolObject<dyn NSCopying>>
where
CopiedKey: Message + NSCopying,
{
let keys: *mut NonNull<CopiedKey> = util::ref_ptr_cast_const(keys.as_ptr());
let keys: *mut NonNull<ProtocolObject<dyn NSCopying>> = keys.cast();
keys
}
impl<KeyType: Message, ObjectType: Message> NSDictionary<KeyType, ObjectType> {
#[cfg(feature = "NSObject")]
pub fn from_slices<CopiedKey>(keys: &[&CopiedKey], objects: &[&ObjectType]) -> Retained<Self>
where
CopiedKey: Message + NSCopying + CopyingHelper<Result = KeyType>,
{
assert_eq!(
keys.len(),
objects.len(),
"key slice and object slice should have the same length",
);
let count = keys.len();
let keys = keys_to_ptr(keys);
let objects = util::ref_ptr_cast_const(objects.as_ptr());
unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) }
}
#[cfg(feature = "NSObject")]
pub fn from_retained_objects<CopiedKey>(
keys: &[&CopiedKey],
objects: &[Retained<ObjectType>],
) -> Retained<Self>
where
CopiedKey: Message + NSCopying + CopyingHelper<Result = KeyType>,
{
assert_eq!(
keys.len(),
objects.len(),
"key slice and object slice should have the same length",
);
let count = keys.len();
let keys = keys_to_ptr(keys);
let objects = util::retained_ptr_cast_const(objects.as_ptr());
unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) }
}
}
impl<KeyType: Message, ObjectType: Message> NSMutableDictionary<KeyType, ObjectType> {
#[cfg(feature = "NSObject")]
pub fn from_slices<CopiedKey>(keys: &[&CopiedKey], objects: &[&ObjectType]) -> Retained<Self>
where
CopiedKey: Message + NSCopying + CopyingHelper<Result = KeyType>,
{
assert_eq!(
keys.len(),
objects.len(),
"key slice and object slice should have the same length",
);
let count = keys.len();
let keys = keys_to_ptr(keys);
let objects = util::ref_ptr_cast_const(objects.as_ptr());
unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) }
}
#[cfg(feature = "NSObject")]
pub fn from_retained_objects<CopiedKey>(
keys: &[&CopiedKey],
objects: &[Retained<ObjectType>],
) -> Retained<Self>
where
CopiedKey: Message + NSCopying + CopyingHelper<Result = KeyType>,
{
assert_eq!(
keys.len(),
objects.len(),
"key slice and object slice should have the same length",
);
let count = keys.len();
let keys = keys_to_ptr(keys);
let objects = util::retained_ptr_cast_const(objects.as_ptr());
unsafe { Self::initWithObjects_forKeys_count(Self::alloc(), objects, keys, count) }
}
}
impl<KeyType: Message, ObjectType: Message> NSDictionary<KeyType, ObjectType> {
#[doc(alias = "objectForKey:")]
#[inline]
pub unsafe fn objectForKey_unchecked(&self, key: &KeyType) -> Option<&ObjectType> {
unsafe { msg_send![self, objectForKey: key] }
}
#[doc(alias = "getObjects:andKeys:")]
#[cfg(feature = "alloc")]
pub unsafe fn to_vecs_unchecked(&self) -> (Vec<&KeyType>, Vec<&ObjectType>) {
let len = self.len();
let mut keys = Vec::with_capacity(len);
let mut objs = Vec::with_capacity(len);
unsafe {
#[allow(deprecated)]
self.getObjects_andKeys(objs.as_mut_ptr(), keys.as_mut_ptr());
}
unsafe {
keys.set_len(len);
objs.set_len(len);
}
unsafe {
(
mem::transmute::<Vec<NonNull<KeyType>>, Vec<&KeyType>>(keys),
mem::transmute::<Vec<NonNull<ObjectType>>, Vec<&ObjectType>>(objs),
)
}
}
#[cfg(feature = "NSEnumerator")]
#[doc(alias = "keyEnumerator")]
#[inline]
pub unsafe fn keys_unchecked(&self) -> KeysUnchecked<'_, KeyType, ObjectType> {
KeysUnchecked(iter::IterUnchecked::new(self))
}
#[cfg(feature = "NSEnumerator")]
#[doc(alias = "objectEnumerator")]
#[inline]
pub unsafe fn objects_unchecked(&self) -> ObjectsUnchecked<'_, KeyType, ObjectType> {
let enumerator = unsafe { self.objectEnumerator() };
ObjectsUnchecked(unsafe { iter::IterUncheckedWithBackingEnum::new(self, enumerator) })
}
}
impl<KeyType: Message, ObjectType: Message> NSDictionary<KeyType, ObjectType> {
#[doc(alias = "count")]
#[inline]
pub fn len(&self) -> usize {
self.count()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(alias = "getObjects:")]
#[cfg(feature = "alloc")]
pub fn to_vecs(&self) -> (Vec<Retained<KeyType>>, Vec<Retained<ObjectType>>) {
let (keys, objects) = unsafe { self.to_vecs_unchecked() };
(
keys.into_iter().map(KeyType::retain).collect(),
objects.into_iter().map(ObjectType::retain).collect(),
)
}
#[cfg(feature = "NSEnumerator")]
#[doc(alias = "keyEnumerator")]
#[inline]
pub fn keys(&self) -> Keys<'_, KeyType, ObjectType> {
Keys(iter::Iter::new(self))
}
#[cfg_attr(feature = "NSString", doc = "```")]
#[cfg_attr(not(feature = "NSString"), doc = "```ignore")]
#[cfg(feature = "NSEnumerator")]
#[doc(alias = "objectEnumerator")]
#[inline]
pub fn objects(&self) -> Objects<'_, KeyType, ObjectType> {
let enumerator = unsafe { self.objectEnumerator() };
Objects(unsafe { iter::IterWithBackingEnum::new(self, enumerator) })
}
}
impl<KeyType: Message, ObjectType: Message> NSMutableDictionary<KeyType, ObjectType> {
#[cfg(feature = "NSObject")]
#[doc(alias = "setObject:forKey:")]
#[inline]
pub fn insert<CopiedKey>(&self, key: &CopiedKey, object: &ObjectType)
where
CopiedKey: Message + NSCopying + CopyingHelper<Result = KeyType>,
{
let key = ProtocolObject::from_ref(key);
unsafe { self.setObject_forKey(object, key) };
}
}
#[cfg(feature = "NSEnumerator")]
unsafe impl<KeyType: Message, ObjectType: Message> iter::FastEnumerationHelper
for NSDictionary<KeyType, ObjectType>
{
type Item = KeyType;
#[inline]
fn maybe_len(&self) -> Option<usize> {
Some(self.len())
}
}
#[cfg(feature = "NSEnumerator")]
unsafe impl<KeyType: Message, ObjectType: Message> iter::FastEnumerationHelper
for NSMutableDictionary<KeyType, ObjectType>
{
type Item = KeyType;
#[inline]
fn maybe_len(&self) -> Option<usize> {
Some(self.len())
}
}
#[derive(Debug)]
#[cfg(feature = "NSEnumerator")]
pub struct Keys<'a, KeyType: Message, ObjectType: Message>(
iter::Iter<'a, NSDictionary<KeyType, ObjectType>>,
);
#[cfg(feature = "NSEnumerator")]
__impl_iter! {
impl<'a, KeyType: Message, ObjectType: Message> Iterator<Item = Retained<KeyType>> for Keys<'a, KeyType, ObjectType> { ... }
}
#[derive(Debug)]
#[cfg(feature = "NSEnumerator")]
pub struct KeysUnchecked<'a, KeyType: Message, ObjectType: Message>(
iter::IterUnchecked<'a, NSDictionary<KeyType, ObjectType>>,
);
#[cfg(feature = "NSEnumerator")]
__impl_iter! {
impl<'a, KeyType: Message, ObjectType: Message> Iterator<Item = &'a KeyType> for KeysUnchecked<'a, KeyType, ObjectType> { ... }
}
#[derive(Debug)]
#[cfg(feature = "NSEnumerator")]
pub struct Objects<'a, KeyType: Message, ObjectType: Message>(
iter::IterWithBackingEnum<
'a,
NSDictionary<KeyType, ObjectType>,
crate::NSEnumerator<ObjectType>,
>,
);
#[cfg(feature = "NSEnumerator")]
__impl_iter! {
impl<'a, KeyType: Message, ObjectType: Message> Iterator<Item = Retained<ObjectType>> for Objects<'a, KeyType, ObjectType> { ... }
}
#[derive(Debug)]
#[cfg(feature = "NSEnumerator")]
pub struct ObjectsUnchecked<'a, KeyType: Message, ObjectType: Message + 'a>(
iter::IterUncheckedWithBackingEnum<
'a,
NSDictionary<KeyType, ObjectType>,
crate::NSEnumerator<ObjectType>,
>,
);
#[cfg(feature = "NSEnumerator")]
__impl_iter! {
impl<'a, KeyType: Message, ObjectType: Message> Iterator<Item = &'a ObjectType> for ObjectsUnchecked<'a, KeyType, ObjectType> { ... }
}
impl<KeyType: fmt::Debug + Message, ObjectType: fmt::Debug + Message> fmt::Debug
for NSDictionary<KeyType, ObjectType>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (keys, objects) = unsafe { self.to_vecs_unchecked() };
let iter = keys.into_iter().zip(objects);
f.debug_map().entries(iter).finish()
}
}
impl<KeyType: fmt::Debug + Message, ObjectType: fmt::Debug + Message> fmt::Debug
for NSMutableDictionary<KeyType, ObjectType>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}