Skip to content

Commit c712e0c

Browse files
authored
Merge pull request #257 from madsmtm/foundation-for-winit
`objc2::foundation` additions for `winit`
2 parents 6caf8aa + 06f455c commit c712e0c

File tree

7 files changed

+165
-21
lines changed

7 files changed

+165
-21
lines changed

objc2/CHANGELOG_FOUNDATION.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

99
## Unreleased - YYYY-MM-DD
1010

11+
### Added
12+
* Added `NSSet`.
13+
* Added `NSMutableSet`.
14+
* Added `NSMutableDictionary`.
15+
* Added `NSNotFound`.
16+
* Added `NSBundle`.
17+
* Added `NSTimeInterval`.
18+
* Added `NSString::len_utf16` and `NSAttributedString::len_utf16`.
19+
* Added `NSString::concat` and `NSString::join_path`.
20+
21+
22+
## objc2 0.3.0-beta.2 - 2022-08-28
23+
1124
### Added
1225
* Added `NSNumber`.
1326
* Added `NSError`.

objc2/src/foundation/attributed_string.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,7 @@ extern_methods!(
8585
/// Alias for `self.string().len_utf16()`.
8686
#[doc(alias = "length")]
8787
#[sel(length)]
88-
#[allow(unused)]
89-
// TODO: Finish this
90-
fn len_utf16(&self) -> usize;
88+
pub fn len_utf16(&self) -> usize;
9189

9290
// /// TODO
9391
// ///

objc2/src/foundation/bundle.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use core::fmt;
2+
use core::panic::{RefUnwindSafe, UnwindSafe};
3+
4+
use super::{NSCopying, NSDictionary, NSObject, NSString};
5+
use crate::rc::{Id, Shared};
6+
use crate::{extern_class, extern_methods, msg_send_id, ns_string, ClassType};
7+
8+
extern_class!(
9+
/// A representation of the code and resources stored in a bundle
10+
/// directory on disk.
11+
///
12+
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsbundle?language=objc).
13+
#[derive(PartialEq, Eq, Hash)]
14+
pub struct NSBundle;
15+
16+
unsafe impl ClassType for NSBundle {
17+
type Super = NSObject;
18+
}
19+
);
20+
21+
// SAFETY: Bundles are documented as thread-safe.
22+
unsafe impl Sync for NSBundle {}
23+
unsafe impl Send for NSBundle {}
24+
25+
impl UnwindSafe for NSBundle {}
26+
impl RefUnwindSafe for NSBundle {}
27+
28+
extern_methods!(
29+
unsafe impl NSBundle {
30+
pub fn main() -> Id<Self, Shared> {
31+
unsafe { msg_send_id![Self::class(), mainBundle] }
32+
}
33+
34+
pub fn info(&self) -> Id<NSDictionary<NSString, NSObject>, Shared> {
35+
unsafe { msg_send_id![self, infoDictionary] }
36+
}
37+
38+
pub fn name(&self) -> Option<Id<NSString, Shared>> {
39+
self.info().get(ns_string!("CFBundleName")).map(|name| {
40+
let ptr: *const NSObject = name;
41+
let ptr: *const NSString = ptr.cast();
42+
// SAFETY: TODO
43+
let name = unsafe { ptr.as_ref().unwrap_unchecked() };
44+
name.copy()
45+
})
46+
}
47+
}
48+
);
49+
50+
impl fmt::Debug for NSBundle {
51+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52+
// Delegate to NSObject
53+
(**self).fmt(f)
54+
}
55+
}
56+
57+
#[cfg(test)]
58+
mod tests {
59+
use super::*;
60+
use alloc::format;
61+
use std::println;
62+
63+
#[test]
64+
#[cfg_attr(not(target_os = "macos"), ignore = "varies between platforms")]
65+
fn try_running_functions() {
66+
// This is mostly empty since cargo doesn't bundle the application
67+
// before executing.
68+
let bundle = NSBundle::main();
69+
println!("{:?}", bundle);
70+
assert_eq!(format!("{:?}", bundle.info()), "{}");
71+
assert_eq!(bundle.name(), None);
72+
}
73+
}

objc2/src/foundation/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@
5151
#![allow(missing_docs)]
5252
#![allow(clippy::missing_safety_doc)]
5353

54+
use std::os::raw::c_double;
55+
5456
pub use self::array::NSArray;
5557
pub use self::attributed_string::{NSAttributedString, NSAttributedStringKey};
58+
pub use self::bundle::NSBundle;
5659
pub use self::comparison_result::NSComparisonResult;
5760
pub use self::copying::{NSCopying, NSMutableCopying};
5861
pub use self::data::NSData;
@@ -84,6 +87,17 @@ pub use self::zone::NSZone;
8487
#[doc(no_inline)]
8588
pub use crate::ffi::{NSInteger, NSUInteger};
8689

90+
/// A value indicating that a requested item couldn’t be found or doesn’t exist.
91+
///
92+
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsnotfound?language=objc).
93+
#[allow(non_upper_case_globals)]
94+
pub const NSNotFound: NSInteger = crate::ffi::NSIntegerMax;
95+
96+
/// A number of seconds.
97+
///
98+
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nstimeinterval?language=objc).
99+
pub type NSTimeInterval = c_double;
100+
87101
#[cfg(feature = "apple")]
88102
#[link(name = "Foundation", kind = "framework")]
89103
extern "C" {}
@@ -96,6 +110,7 @@ extern "C" {}
96110
pub mod __ns_string;
97111
mod array;
98112
mod attributed_string;
113+
mod bundle;
99114
mod comparison_result;
100115
mod copying;
101116
mod data;

objc2/src/foundation/string.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use core::str;
1010
use std::os::raw::c_char;
1111

1212
use super::{NSComparisonResult, NSCopying, NSMutableCopying, NSMutableString, NSObject};
13-
use crate::ffi;
1413
use crate::rc::{autoreleasepool, AutoreleasePool, DefaultId, Id, Shared};
1514
use crate::runtime::{Class, Object};
1615
use crate::{extern_class, extern_methods, msg_send, msg_send_id, ClassType};
@@ -20,10 +19,6 @@ const UTF8_ENCODING: usize = 4;
2019
#[cfg(feature = "gnustep-1-7")]
2120
const UTF8_ENCODING: i32 = 4;
2221

23-
#[allow(unused)]
24-
#[allow(non_upper_case_globals)]
25-
const NSNotFound: ffi::NSInteger = ffi::NSIntegerMax;
26-
2722
extern_class!(
2823
/// An immutable, plain-text Unicode string object.
2924
///
@@ -61,20 +56,70 @@ extern_methods!(
6156
unsafe { msg_send_id![Self::class(), new] }
6257
}
6358

59+
/// Create a new string by appending the given string to self.
60+
///
61+
///
62+
/// # Example
63+
///
64+
/// ```
65+
/// # #[cfg(feature = "gnustep-1-7")]
66+
/// # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
67+
/// use objc2::ns_string;
68+
/// let error_tag = ns_string!("Error: ");
69+
/// let error_string = ns_string!("premature end of file.");
70+
/// let error_message = error_tag.concat(error_string);
71+
/// assert_eq!(&*error_message, ns_string!("Error: premature end of file."));
72+
/// ```
73+
#[doc(alias = "stringByAppendingString")]
74+
#[doc(alias = "stringByAppendingString:")]
75+
pub fn concat(&self, other: &Self) -> Id<Self, Shared> {
76+
// SAFETY: The other string is non-null, and won't be retained
77+
// by the function.
78+
unsafe { msg_send_id![self, stringByAppendingString: other] }
79+
}
80+
81+
/// Create a new string by appending the given string, separated by
82+
/// a path separator.
83+
///
84+
/// This is similar to [`Path::join`][std::path::Path::join].
85+
///
86+
/// Note that this method only works with file paths (not, for
87+
/// example, string representations of URLs).
88+
///
89+
///
90+
/// # Examples
91+
///
92+
/// ```
93+
/// # #[cfg(feature = "gnustep-1-7")]
94+
/// # unsafe { objc2::__gnustep_hack::get_class_to_force_linkage() };
95+
/// use objc2::ns_string;
96+
///
97+
/// let extension = ns_string!("scratch.tiff");
98+
/// assert_eq!(&*ns_string!("/tmp").join_path(extension), ns_string!("/tmp/scratch.tiff"));
99+
/// assert_eq!(&*ns_string!("/tmp/").join_path(extension), ns_string!("/tmp/scratch.tiff"));
100+
/// assert_eq!(&*ns_string!("/").join_path(extension), ns_string!("/scratch.tiff"));
101+
/// assert_eq!(&*ns_string!("").join_path(extension), ns_string!("scratch.tiff"));
102+
/// ```
103+
#[doc(alias = "stringByAppendingPathComponent")]
104+
#[doc(alias = "stringByAppendingPathComponent:")]
105+
pub fn join_path(&self, other: &Self) -> Id<Self, Shared> {
106+
// SAFETY: Same as `Self::concat`.
107+
unsafe { msg_send_id![self, stringByAppendingPathComponent: other] }
108+
}
109+
64110
/// The number of UTF-8 code units in `self`.
65111
#[doc(alias = "lengthOfBytesUsingEncoding")]
66112
#[doc(alias = "lengthOfBytesUsingEncoding:")]
67113
pub fn len(&self) -> usize {
68114
unsafe { msg_send![self, lengthOfBytesUsingEncoding: UTF8_ENCODING] }
69115
}
70116

71-
/// The number of UTF-16 code units in `self`.
117+
/// The number of UTF-16 code units in the string.
72118
///
73119
/// See also [`NSString::len`].
74120
#[doc(alias = "length")]
75-
// TODO: Finish this
76121
#[sel(length)]
77-
fn len_utf16(&self) -> usize;
122+
pub fn len_utf16(&self) -> usize;
78123

79124
pub fn is_empty(&self) -> bool {
80125
// TODO: lengthOfBytesUsingEncoding: might sometimes return 0 for

test-ui/ui/msg_send_id_invalid_return.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ error[E0277]: the trait bound `objc2::runtime::Class: Message` is not satisfied
2727
Exception
2828
NSArray<T, O>
2929
NSAttributedString
30+
NSBundle
3031
NSData
3132
NSDictionary<K, V>
3233
NSError
3334
NSException
34-
NSMutableArray<T, O>
35-
and 14 others
35+
and 15 others
3636
= note: required for `RetainSemantics<true, false, false, false>` to implement `MsgSendId<&objc2::runtime::Class, objc2::runtime::Class, Shared>`
3737

3838
error[E0277]: the trait bound `objc2::runtime::Class: Message` is not satisfied
@@ -48,12 +48,12 @@ error[E0277]: the trait bound `objc2::runtime::Class: Message` is not satisfied
4848
Exception
4949
NSArray<T, O>
5050
NSAttributedString
51+
NSBundle
5152
NSData
5253
NSDictionary<K, V>
5354
NSError
5455
NSException
55-
NSMutableArray<T, O>
56-
and 14 others
56+
and 15 others
5757
= note: required for `RetainSemantics<true, false, false, false>` to implement `MsgSendId<&objc2::runtime::Class, objc2::runtime::Class, Shared>`
5858

5959
error[E0277]: the trait bound `&objc2::runtime::Object: MaybeUnwrap<Allocated<_>, _>` is not satisfied
@@ -85,12 +85,12 @@ error[E0277]: the trait bound `objc2::runtime::Class: Message` is not satisfied
8585
Exception
8686
NSArray<T, O>
8787
NSAttributedString
88+
NSBundle
8889
NSData
8990
NSDictionary<K, V>
9091
NSError
9192
NSException
92-
NSMutableArray<T, O>
93-
and 14 others
93+
and 15 others
9494
= note: required for `RetainSemantics<false, true, false, false>` to implement `MsgSendId<&objc2::runtime::Class, Allocated<objc2::runtime::Class>, Shared>`
9595

9696
error[E0277]: the trait bound `Id<objc2::runtime::Object, Shared>: MaybeUnwrap<Allocated<_>, _>` is not satisfied

test-ui/ui/msg_send_super_not_classtype.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ error[E0277]: the trait bound `objc2::runtime::Object: ClassType` is not satisfi
1010
= help: the following other types implement trait `ClassType`:
1111
NSArray<T, O>
1212
NSAttributedString
13+
NSBundle
1314
NSData
1415
NSDictionary<K, V>
1516
NSError
1617
NSException
1718
NSMutableArray<T, O>
18-
NSMutableAttributedString
19-
and 12 others
19+
and 13 others
2020
note: required by a bound in `__send_super_message_static`
2121
--> $WORKSPACE/objc2/src/message/mod.rs
2222
|
@@ -35,13 +35,13 @@ error[E0277]: the trait bound `objc2::runtime::Object: ClassType` is not satisfi
3535
= help: the following other types implement trait `ClassType`:
3636
NSArray<T, O>
3737
NSAttributedString
38+
NSBundle
3839
NSData
3940
NSDictionary<K, V>
4041
NSError
4142
NSException
4243
NSMutableArray<T, O>
43-
NSMutableAttributedString
44-
and 12 others
44+
and 13 others
4545
note: required by a bound in `__send_super_message_static`
4646
--> $WORKSPACE/objc2/src/message/mod.rs
4747
|

0 commit comments

Comments
 (0)