Skip to content

Commit 14ff594

Browse files
committed
Implement proper Debug for all foundation types
1 parent 893e04f commit 14ff594

17 files changed

+263
-69
lines changed

objc2-foundation/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
99
### Added
1010
* Implement `UnwindSafe` and `RefUnwindSafe` for all objects.
1111

12+
### Fixed
13+
* Made `Debug` impls for all objects print something useful.
14+
1215
### Removed
1316
* `NSObject::hash_code`, `NSObject::is_equal` and `NSObject::description` in
1417
favour of just having the trait implementations `Hash`, `PartiqalEq` and

objc2-foundation/src/array.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use alloc::vec::Vec;
2+
use core::fmt;
23
use core::marker::PhantomData;
34
use core::ops::{Index, Range};
45
use core::panic::{RefUnwindSafe, UnwindSafe};
@@ -26,7 +27,7 @@ __inner_extern_class! {
2627
/// What about `Id<NSArray<T, Shared>, Owned>`?
2728
// `T: PartialEq` bound correct because `NSArray` does deep (instead of
2829
// shallow) equality comparisons.
29-
#[derive(Debug, PartialEq, Eq, Hash)]
30+
#[derive(PartialEq, Eq, Hash)]
3031
unsafe pub struct NSArray<T, O: Ownership>: NSObject {
3132
item: PhantomData<Id<T, O>>,
3233
notunwindsafe: PhantomData<&'static mut ()>,
@@ -215,6 +216,13 @@ impl<T: Message> DefaultId for NSArray<T, Shared> {
215216
}
216217
}
217218

219+
impl<T: fmt::Debug + Message, O: Ownership> fmt::Debug for NSArray<T, O> {
220+
#[inline]
221+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222+
f.debug_list().entries(self.iter_fast()).finish()
223+
}
224+
}
225+
218226
#[cfg(test)]
219227
mod tests {
220228
use alloc::format;
@@ -276,15 +284,11 @@ mod tests {
276284
}
277285

278286
#[test]
279-
#[ignore = "Output is different depending on OS version and runtime"]
280287
fn test_debug() {
288+
let obj = sample_number_array(0);
289+
assert_eq!(format!("{:?}", obj), "[]");
281290
let obj = sample_number_array(3);
282-
let expected = r#"(
283-
"<00>",
284-
"<01>",
285-
"<02>"
286-
)"#;
287-
assert_eq!(format!("{:?}", obj), format!("{:?}", expected));
291+
assert_eq!(format!("{:?}", obj), "[0, 1, 2]");
288292
}
289293

290294
#[test]

objc2-foundation/src/attributed_string.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::fmt;
12
use core::panic::{RefUnwindSafe, UnwindSafe};
23

34
use objc2::rc::{DefaultId, Id, Shared};
@@ -22,7 +23,7 @@ extern_class! {
2223
/// framework contains most of the extension methods.
2324
///
2425
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsattributedstring?language=objc).
25-
#[derive(Debug, PartialEq, Eq, Hash)]
26+
#[derive(PartialEq, Eq, Hash)]
2627
unsafe pub struct NSAttributedString: NSObject;
2728
}
2829

@@ -132,10 +133,19 @@ impl alloc::borrow::ToOwned for NSAttributedString {
132133
}
133134
}
134135

136+
impl fmt::Debug for NSAttributedString {
137+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138+
// Use -[NSAttributedString description] since it is pretty good
139+
let obj: &NSObject = self;
140+
fmt::Debug::fmt(obj, f)
141+
}
142+
}
143+
135144
#[cfg(test)]
136145
mod tests {
137146
use alloc::string::ToString;
138-
use objc2::rc::autoreleasepool;
147+
use alloc::{format, vec};
148+
use objc2::rc::{autoreleasepool, Owned};
139149

140150
use super::*;
141151

@@ -174,4 +184,28 @@ mod tests {
174184
assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s3).cast());
175185
assert!(s3.is_kind_of(NSMutableAttributedString::class()));
176186
}
187+
188+
#[test]
189+
fn test_debug() {
190+
let s = NSAttributedString::from_nsstring(&NSString::from_str("abc"));
191+
let expected = if cfg!(feature = "gnustep-1-7") {
192+
"abc{}"
193+
} else {
194+
"abc{\n}"
195+
};
196+
assert_eq!(format!("{:?}", s), expected);
197+
198+
let obj: Id<Object, Owned> = unsafe { Id::cast(NSObject::new()) };
199+
let ptr: *const Object = &*obj;
200+
let s = NSAttributedString::new_with_attributes(
201+
&NSString::from_str("abc"),
202+
&NSDictionary::from_keys_and_objects(&[&*NSString::from_str("test")], vec![obj]),
203+
);
204+
let expected = if cfg!(feature = "gnustep-1-7") {
205+
format!("abc{{test = \"<NSObject: {:?}>\"; }}", ptr)
206+
} else {
207+
format!("abc{{\n test = \"<NSObject: {:?}>\";\n}}", ptr)
208+
};
209+
assert_eq!(format!("{:?}", s), expected);
210+
}
177211
}

objc2-foundation/src/data.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(feature = "block")]
22
use alloc::vec::Vec;
33
use core::ffi::c_void;
4+
use core::fmt;
45
use core::ops::Index;
56
use core::panic::{RefUnwindSafe, UnwindSafe};
67
use core::slice::{self, SliceIndex};
@@ -17,7 +18,7 @@ extern_class! {
1718
/// This is similar to a [`slice`][`prim@slice`] of [`u8`].
1819
///
1920
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsdata?language=objc).
20-
#[derive(Debug, PartialEq, Eq, Hash)]
21+
#[derive(PartialEq, Eq, Hash)]
2122
unsafe pub struct NSData: NSObject;
2223
}
2324

@@ -120,6 +121,14 @@ impl DefaultId for NSData {
120121
}
121122
}
122123

124+
impl fmt::Debug for NSData {
125+
#[inline]
126+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127+
// -[NSData description] is quite unreadable
128+
fmt::Debug::fmt(self.bytes(), f)
129+
}
130+
}
131+
123132
pub(crate) unsafe fn data_with_bytes(cls: &Class, bytes: &[u8]) -> *mut Object {
124133
let bytes_ptr: *const c_void = bytes.as_ptr().cast();
125134
unsafe {
@@ -164,6 +173,7 @@ pub(crate) unsafe fn data_from_vec(cls: &Class, bytes: Vec<u8>) -> *mut Object {
164173
#[cfg(test)]
165174
mod tests {
166175
use super::*;
176+
use alloc::format;
167177
#[cfg(feature = "block")]
168178
use alloc::vec;
169179

@@ -190,4 +200,11 @@ mod tests {
190200
let data = NSData::from_vec(bytes);
191201
assert_eq!(data.bytes().as_ptr(), bytes_ptr);
192202
}
203+
204+
#[test]
205+
fn test_debug() {
206+
let bytes = [3, 7, 16, 52, 112, 19];
207+
let data = NSData::with_bytes(&bytes);
208+
assert_eq!(format!("{:?}", data), "[3, 7, 16, 52, 112, 19]");
209+
}
193210
}

objc2-foundation/src/dictionary.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use alloc::vec::Vec;
22
use core::cmp::min;
3+
use core::fmt;
34
use core::marker::PhantomData;
45
use core::ops::Index;
56
use core::panic::{RefUnwindSafe, UnwindSafe};
@@ -11,7 +12,7 @@ use objc2::{msg_send, msg_send_id, Message};
1112
use super::{NSArray, NSCopying, NSEnumerator, NSFastEnumeration, NSObject, __inner_extern_class};
1213

1314
__inner_extern_class! {
14-
#[derive(Debug, PartialEq, Eq, Hash)]
15+
#[derive(PartialEq, Eq, Hash)]
1516
unsafe pub struct NSDictionary<K, V>: NSObject {
1617
key: PhantomData<Id<K, Shared>>,
1718
obj: PhantomData<Id<V, Owned>>,
@@ -159,8 +160,17 @@ impl<'a, K: Message, V: Message> Index<&'a K> for NSDictionary<K, V> {
159160
}
160161
}
161162

163+
impl<K: fmt::Debug + Message, V: fmt::Debug + Message> fmt::Debug for NSDictionary<K, V> {
164+
#[inline]
165+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166+
let iter = self.iter_keys().zip(self.iter_values());
167+
f.debug_map().entries(iter).finish()
168+
}
169+
}
170+
162171
#[cfg(test)]
163172
mod tests {
173+
use alloc::format;
164174
use alloc::vec;
165175
use objc2::rc::{autoreleasepool, Id, Shared};
166176

@@ -250,4 +260,13 @@ mod tests {
250260
// let objs = NSDictionary::into_values_array(dict);
251261
// assert_eq!(objs.len(), 1);
252262
}
263+
264+
#[test]
265+
fn test_debug() {
266+
let key = NSString::from_str("a");
267+
// TODO: Fix this
268+
let val = unsafe { Id::from_shared(NSString::from_str("b")) };
269+
let dict = NSDictionary::from_keys_and_objects(&[&*key], vec![val]);
270+
assert_eq!(format!("{:?}", dict), r#"{"a": "b"}"#);
271+
}
253272
}

objc2-foundation/src/exception.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ mod tests {
158158
assert_eq!(format!("{:?}", exc), debug);
159159

160160
let description = if cfg!(feature = "gnustep-1-7") {
161-
format!("\"<NSException: {:p}> NAME:abc REASON:def\"", exc)
161+
format!("<NSException: {:p}> NAME:abc REASON:def", exc)
162162
} else {
163-
"\"def\"".into()
163+
"def".into()
164164
};
165165

166166
let exc: &NSObject = &exc;

objc2-foundation/src/mutable_array.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use alloc::vec::Vec;
22
use core::cmp::Ordering;
33
use core::ffi::c_void;
4+
use core::fmt;
45
use core::marker::PhantomData;
56
use core::ops::{Index, IndexMut};
67

@@ -17,7 +18,7 @@ use crate::{
1718
__inner_extern_class! {
1819
// TODO: Ensure that this deref to NSArray is safe!
1920
// This "inherits" NSArray, and has the same `Send`/`Sync` impls as that.
20-
#[derive(Debug, PartialEq, Eq, Hash)]
21+
#[derive(PartialEq, Eq, Hash)]
2122
unsafe pub struct NSMutableArray<T, O: Ownership>: NSArray<T, O>, NSObject {
2223
p: PhantomData<*mut ()>,
2324
}
@@ -197,6 +198,13 @@ impl<T: Message, O: Ownership> DefaultId for NSMutableArray<T, O> {
197198
}
198199
}
199200

201+
impl<T: fmt::Debug + Message, O: Ownership> fmt::Debug for NSMutableArray<T, O> {
202+
#[inline]
203+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204+
fmt::Debug::fmt(&**self, f)
205+
}
206+
}
207+
200208
#[cfg(test)]
201209
mod tests {
202210
use alloc::vec;

objc2-foundation/src/mutable_attributed_string.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::fmt;
2+
13
use objc2::rc::{DefaultId, Id, Owned, Shared};
24
use objc2::{msg_send, msg_send_id};
35

@@ -7,7 +9,7 @@ extern_class! {
79
/// A mutable string that has associated attributes.
810
///
911
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsmutableattributedstring?language=objc).
10-
#[derive(Debug, PartialEq, Eq, Hash)]
12+
#[derive(PartialEq, Eq, Hash)]
1113
unsafe pub struct NSMutableAttributedString: NSAttributedString, NSObject;
1214
}
1315

@@ -76,6 +78,12 @@ impl alloc::borrow::ToOwned for NSMutableAttributedString {
7678
}
7779
}
7880

81+
impl fmt::Debug for NSMutableAttributedString {
82+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83+
fmt::Debug::fmt(&**self, f)
84+
}
85+
}
86+
7987
#[cfg(test)]
8088
mod tests {
8189
use alloc::string::ToString;

objc2-foundation/src/mutable_data.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(feature = "block")]
22
use alloc::vec::Vec;
33
use core::ffi::c_void;
4+
use core::fmt;
45
use core::ops::{Index, IndexMut, Range};
56
use core::slice::{self, SliceIndex};
67
use std::io;
@@ -19,7 +20,7 @@ extern_class! {
1920
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsmutabledata?language=objc).
2021
///
2122
/// [`Vec`]: std::vec::Vec
22-
#[derive(Debug, PartialEq, Eq, Hash)]
23+
#[derive(PartialEq, Eq, Hash)]
2324
unsafe pub struct NSMutableData: NSData, NSObject;
2425
}
2526

@@ -208,6 +209,13 @@ impl DefaultId for NSMutableData {
208209
}
209210
}
210211

212+
impl fmt::Debug for NSMutableData {
213+
#[inline]
214+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215+
fmt::Debug::fmt(&**self, f)
216+
}
217+
}
218+
211219
#[cfg(test)]
212220
mod tests {
213221
use objc2::runtime::Object;

objc2-foundation/src/mutable_string.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,26 @@ impl fmt::Display for NSMutableString {
164164
}
165165

166166
impl fmt::Debug for NSMutableString {
167+
#[inline]
167168
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168-
fmt::Display::fmt(&**self, f)
169+
fmt::Debug::fmt(&**self, f)
169170
}
170171
}
171172

172173
#[cfg(test)]
173174
mod tests {
175+
use alloc::format;
174176
use alloc::string::ToString;
175177

176178
use super::*;
177179

180+
#[test]
181+
fn display_debug() {
182+
let s = NSMutableString::from_str("test\"123");
183+
assert_eq!(format!("{}", s), "test\"123");
184+
assert_eq!(format!("{:?}", s), r#""test\"123""#);
185+
}
186+
178187
#[test]
179188
fn test_from_nsstring() {
180189
let s = NSString::from_str("abc");

0 commit comments

Comments
 (0)