-
Notifications
You must be signed in to change notification settings - Fork 0
/
wip.rs
140 lines (125 loc) · 4.07 KB
/
wip.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#[objc_framework("Foundation")]
mod foundation {
#[objc_protocol]
pub trait NSObjectProtocol {
fn hash(&self) -> usize {
unsafe { objc!(self.hash) }
}
fn is_equal(&self, obj: Option<&impl ObjCPtr>) -> bool {
unsafe { objc!([self isEqual:obj]) }
}
fn description(&self) -> Option<NSString> {
unsafe { objc!([self.description]) }
}
}
#[objc_interface]
pub struct NSObject;
#[objc_interface]
impl NSObject {
pub fn new() -> Self {
objc!([Self new])
}
}
#[objc_enum]
pub struct NSStringEncoding;
#[objc_enum]
impl NSStringEncoding {
pub const ASCII: Self = NSASCIIStringEncoding;
pub const UTF8: Self = NSUTF8StringEncoding;
// Testing a strange use of some use of enums akin to categorys in Cocoa.
pub const PROPRIETARY: Self = NSProprietaryStringEncoding;
}
#[objc_interface]
pub trait NSStringInterface {
fn to_string(&self) -> Result<String, std::str::Utf8Error> {
let raw_self = self.as_raw().as_ptr();
let cstr = unsafe {
let bytes = objc!(self.UTF8String);
ffi::CStr::from_ptr(bytes)
};
Ok(cstr.to_str()?.to_string())
}
fn char_at(&self, index: usize) -> u16 {
objc!([self charAtIndex:index])
}
fn len(&self) -> usize {
objc!(self.length)
}
}
#[objc_interface]
impl NSString {
pub fn new_with_str(text: &str) -> Self {
let bytes = text.as_ptr();
let len = text.len();
let encoding = NSStringEncoding::UTF8;
unsafe {
Self::from_raw_unchecked(
objc!([[Self alloc] initWithBytes:bytes length:len encoding:encoding]),
)
}
}
}
#[objc_interface]
pub trait NSArrayInterface<T: ObjCPtr> {
fn first(&self) -> Option<T> {
unsafe { objc!(self.firstObject) }
}
fn last(&self) -> Option<T> {
unsafe { objc!(self.lastObject) }
}
fn object_at(&self, index: usize) -> T {
unsafe { objc![self objectAtIndex:index] }
}
fn count(&self) -> usize {
unsafe { objc![self count] }
}
fn adding_object<U: Into<T> + ObjCPtr>(&self, object: &U) -> NSArray<T> {
unsafe { objc![self arrayByAddingObject:object] }
}
fn enumerate_objects<F: FnMut(T, usize, &mut bool) + Clone>(&self, f: F) {
// TODO: thread check should maybe be done at the runtime level if block not Send + Sync?
#[cfg(debug_assertions)]
let thread_id = thread::current().id();
let wrapper = move |obj, idx, stop_ptr| {
debug_assert!(thread::current().id() == thread_id);
let mut stop: bool = false;
block(objc, idx, stop);
if stop {
*stop_ptr = 1;
}
};
unsafe { very_unsafe_objc![self enumerateObjectsUsingBlock:block] }
}
}
#[objc_interface]
pub struct NSArray<T: ObjCPtr> {
ptr: UntypedObjCPtr,
_marker: std::marker::PhantomData<T>,
}
#[objc_interface]
impl<T: ObjCPtr> NSArray<T> {
pub fn new() -> Self {
unsafe { objc![Self new] }
}
}
#[objc_interface]
pub trait NSMutableArrayInterface<T: ObjCPtr> {
fn add_object<U: Into<T> + ObjCPtr>(&self, object: &U) {
unsafe { objc![Self addObject:U] }
}
fn insert_object_at<U: Into<T> + ObjCPtr>(&self, object: &U, index: usize) {
unsafe { objc![Self insertObject:object atIndex:index] }
}
}
#[objc_interface]
pub struct NSMutableArray<T: ObjCPtr> {
ptr: UntypedObjCPtr,
_marker: std::marker::PhantomData<T>,
}
#[objc_interface]
impl<T: ObjCPtr> NSMutableArray<T> {
pub fn new() -> Self {
unsafe { objc!([Self new]) }
}
}
}