1#![allow(deprecated)]
21#![allow(non_snake_case)]
22#![allow(non_upper_case_globals)]
23#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
24
25#[macro_use]
26pub extern crate objc;
27#[macro_use]
28pub extern crate foreign_types;
29#[macro_use]
30pub extern crate paste;
31
32use std::{
33 borrow::Borrow,
34 ffi::{c_char, c_void},
35 marker::PhantomData,
36 mem,
37 ops::Deref,
38};
39
40use core_graphics_types::{base::CGFloat, geometry::CGSize};
41use foreign_types::ForeignType;
42use objc::runtime::{Object, NO, YES};
43
44#[cfg(target_pointer_width = "64")]
46pub type NSInteger = i64;
47
48#[cfg(not(target_pointer_width = "64"))]
50pub type NSInteger = i32;
51
52#[cfg(target_pointer_width = "64")]
54pub type NSUInteger = u64;
55
56#[cfg(target_pointer_width = "32")]
58pub type NSUInteger = u32;
59
60#[repr(C)]
62#[derive(Copy, Clone)]
63pub struct NSRange {
64 pub location: NSUInteger,
65 pub length: NSUInteger,
66}
67
68impl NSRange {
69 #[inline]
70 pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange {
71 NSRange { location, length }
72 }
73}
74
75fn nsstring_as_str(nsstr: &objc::runtime::Object) -> &str {
76 let bytes = unsafe {
77 let bytes: *const c_char = msg_send![nsstr, UTF8String];
78 bytes.cast()
79 };
80 let len: NSUInteger = unsafe { msg_send![nsstr, length] };
81 unsafe {
82 let bytes = std::slice::from_raw_parts(bytes, len as usize);
83 std::str::from_utf8(bytes).unwrap()
84 }
85}
86
87fn nsstring_from_str(string: &str) -> *mut objc::runtime::Object {
88 const UTF8_ENCODING: usize = 4;
89
90 let cls = class!(NSString);
91 let bytes = string.as_ptr().cast::<c_void>();
92 unsafe {
93 let obj: *mut objc::runtime::Object = msg_send![cls, alloc];
94 let obj: *mut objc::runtime::Object = msg_send![
95 obj,
96 initWithBytes:bytes
97 length:string.len()
98 encoding:UTF8_ENCODING
99 ];
100 let _: *mut c_void = msg_send![obj, autorelease];
101 obj
102 }
103}
104
105macro_rules! foreign_obj_type {
149 {
150 type CType = $raw_ident:ident;
151 pub struct $owned_ident:ident;
152 type ParentType = $parent_ident:ident;
153 } => {
154 foreign_obj_type! {
155 type CType = $raw_ident;
156 pub struct $owned_ident;
157 }
158
159 impl ::std::ops::Deref for paste!{[<$owned_ident Ref>]} {
160 type Target = paste!{[<$parent_ident Ref>]};
161
162 #[inline]
163 fn deref(&self) -> &Self::Target {
164 unsafe { std::mem::transmute(self) }
165 }
166 }
167
168 impl ::std::convert::From<$owned_ident> for $parent_ident {
169 fn from(item: $owned_ident) -> Self {
170 unsafe { Self::from_ptr(item.into_ptr().cast()) }
171 }
172 }
173 };
174 {
175 type CType = $raw_ident:ident;
176 pub struct $owned_ident:ident;
177 } => {
178 foreign_type! {
179 pub unsafe type $owned_ident: Sync + Send {
180 type CType = $raw_ident;
181 fn drop = crate::obj_drop;
182 fn clone = crate::obj_clone;
183 }
184 }
185
186 unsafe impl ::objc::Message for $raw_ident {
187 }
188 unsafe impl ::objc::Message for paste!{[<$owned_ident Ref>]} {
189 }
190
191 impl ::std::fmt::Debug for paste!{[<$owned_ident Ref>]} {
192 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
193 unsafe {
194 let string: *mut ::objc::runtime::Object = msg_send![self, debugDescription];
195 write!(f, "{}", crate::nsstring_as_str(&*string))
196 }
197 }
198 }
199
200 impl ::std::fmt::Debug for $owned_ident {
201 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
202 ::std::ops::Deref::deref(self).fmt(f)
203 }
204 }
205 };
206}
207
208macro_rules! try_objc {
209 {
210 $err_name: ident => $body:expr
211 } => {
212 {
213 let mut $err_name: *mut Object = ::std::ptr::null_mut();
214 let value = $body;
215 if !$err_name.is_null() {
216 let desc: *mut Object = msg_send![$err_name, localizedDescription];
217 let compile_error: *const c_char = msg_send![desc, UTF8String];
218 let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
219 return Err(message);
220 }
221 value
222 }
223 };
224}
225
226macro_rules! msg_send_bool {
227 ($obj:expr, $name:ident) => {{
228 match msg_send![$obj, $name] {
229 YES => true,
230 NO => false,
231 #[cfg(not(target_arch = "aarch64"))]
232 _ => unreachable!(),
233 }
234 }};
235 ($obj:expr, $name:ident : $arg:expr) => {{
236 match msg_send![$obj, $name: $arg] {
237 YES => true,
238 NO => false,
239 #[cfg(not(target_arch = "aarch64"))]
240 _ => unreachable!(),
241 }
242 }};
243}
244
245macro_rules! msg_send_bool_error_check {
246 ($obj:expr, $name:ident: $arg:expr) => {{
247 let mut err: *mut Object = ptr::null_mut();
248 let result: BOOL = msg_send![$obj, $name:$arg
249 error:&mut err];
250 if !err.is_null() {
251 let desc: *mut Object = msg_send![err, localizedDescription];
252 let c_msg: *const c_char = msg_send![desc, UTF8String];
253 let message = CStr::from_ptr(c_msg).to_string_lossy().into_owned();
254 Err(message)
255 } else {
256 match result {
257 YES => Ok(true),
258 NO => Ok(false),
259 #[cfg(not(target_arch = "aarch64"))]
260 _ => unreachable!(),
261 }
262 }
263 }};
264}
265
266pub struct NSArray<T> {
268 _phantom: PhantomData<T>,
269}
270
271pub struct Array<T>(*mut NSArray<T>)
272where
273 T: ForeignType + 'static,
274 T::Ref: objc::Message + 'static;
275
276pub struct ArrayRef<T>(foreign_types::Opaque, PhantomData<T>)
277where
278 T: ForeignType + 'static,
279 T::Ref: objc::Message + 'static;
280
281impl<T> Drop for Array<T>
282where
283 T: ForeignType + 'static,
284 T::Ref: objc::Message + 'static,
285{
286 fn drop(&mut self) {
287 unsafe {
288 let () = msg_send![self.0, release];
289 }
290 }
291}
292
293impl<T> Clone for Array<T>
294where
295 T: ForeignType + 'static,
296 T::Ref: objc::Message + 'static,
297{
298 fn clone(&self) -> Self {
299 unsafe { Array(msg_send![self.0, retain]) }
300 }
301}
302
303unsafe impl<T> objc::Message for NSArray<T>
304where
305 T: ForeignType + 'static,
306 T::Ref: objc::Message + 'static,
307{
308}
309
310unsafe impl<T> objc::Message for ArrayRef<T>
311where
312 T: ForeignType + 'static,
313 T::Ref: objc::Message + 'static,
314{
315}
316
317impl<T> Array<T>
318where
319 T: ForeignType + 'static,
320 T::Ref: objc::Message + 'static,
321{
322 pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef<T> {
323 unsafe {
324 let class = class!(NSArray);
325 msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
326 }
327 }
328
329 pub fn from_owned_slice<'a>(s: &[T]) -> &'a ArrayRef<T> {
330 unsafe {
331 let class = class!(NSArray);
332 msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
333 }
334 }
335}
336
337unsafe impl<T> foreign_types::ForeignType for Array<T>
338where
339 T: ForeignType + 'static,
340 T::Ref: objc::Message + 'static,
341{
342 type CType = NSArray<T>;
343 type Ref = ArrayRef<T>;
344
345 unsafe fn from_ptr(p: *mut NSArray<T>) -> Self {
346 Array(p)
347 }
348
349 fn as_ptr(&self) -> *mut NSArray<T> {
350 self.0
351 }
352}
353
354unsafe impl<T> foreign_types::ForeignTypeRef for ArrayRef<T>
355where
356 T: ForeignType + 'static,
357 T::Ref: objc::Message + 'static,
358{
359 type CType = NSArray<T>;
360}
361
362impl<T> Deref for Array<T>
363where
364 T: ForeignType + 'static,
365 T::Ref: objc::Message + 'static,
366{
367 type Target = ArrayRef<T>;
368
369 #[inline]
370 fn deref(&self) -> &ArrayRef<T> {
371 unsafe { std::mem::transmute(self) }
372 }
373}
374
375impl<T> Borrow<ArrayRef<T>> for Array<T>
376where
377 T: ForeignType + 'static,
378 T::Ref: objc::Message + 'static,
379{
380 fn borrow(&self) -> &ArrayRef<T> {
381 unsafe { std::mem::transmute(self) }
382 }
383}
384
385impl<T> ToOwned for ArrayRef<T>
386where
387 T: ForeignType + 'static,
388 T::Ref: objc::Message + 'static,
389{
390 type Owned = Array<T>;
391
392 fn to_owned(&self) -> Array<T> {
393 unsafe { Array::from_ptr(msg_send![self, retain]) }
394 }
395}
396
397pub enum CAMetalDrawable {}
399
400foreign_obj_type! {
401 type CType = CAMetalDrawable;
402 pub struct MetalDrawable;
403 type ParentType = Drawable;
404}
405
406impl MetalDrawableRef {
407 pub fn texture(&self) -> &TextureRef {
408 unsafe { msg_send![self, texture] }
409 }
410}
411
412pub enum NSObject {}
413
414foreign_obj_type! {
415 type CType = NSObject;
416 pub struct NsObject;
417}
418
419impl NsObjectRef {
420 pub fn conforms_to_protocol<T>(&self) -> Result<bool, String> {
421 let name = ::std::any::type_name::<T>();
422 if let Some(name) = name.split("::").last() {
423 if let Some(protocol) = objc::runtime::Protocol::get(name) {
424 Ok(unsafe { msg_send![self, conformsToProtocol: protocol] })
425 } else {
426 Err(format!("Can not find the protocol for type: {}.", name))
427 }
428 } else {
429 Err(format!("Unexpected type name: {}.", name))
430 }
431 }
432}
433
434pub enum CAMetalLayer {}
436
437foreign_obj_type! {
438 type CType = CAMetalLayer;
439 pub struct MetalLayer;
440}
441
442impl MetalLayer {
443 pub fn new() -> Self {
444 unsafe {
445 let class = class!(CAMetalLayer);
446 msg_send![class, new]
447 }
448 }
449}
450
451impl MetalLayerRef {
452 pub fn device(&self) -> &DeviceRef {
453 unsafe { msg_send![self, device] }
454 }
455
456 pub fn set_device(&self, device: &DeviceRef) {
457 unsafe { msg_send![self, setDevice: device] }
458 }
459
460 pub fn pixel_format(&self) -> MTLPixelFormat {
461 unsafe { msg_send![self, pixelFormat] }
462 }
463
464 pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
465 unsafe { msg_send![self, setPixelFormat: pixel_format] }
466 }
467
468 pub fn drawable_size(&self) -> CGSize {
469 unsafe { msg_send![self, drawableSize] }
470 }
471
472 pub fn set_drawable_size(&self, size: CGSize) {
473 unsafe { msg_send![self, setDrawableSize: size] }
474 }
475
476 pub fn presents_with_transaction(&self) -> bool {
477 unsafe { msg_send_bool![self, presentsWithTransaction] }
478 }
479
480 pub fn set_presents_with_transaction(&self, transaction: bool) {
481 unsafe { msg_send![self, setPresentsWithTransaction: transaction] }
482 }
483
484 pub fn display_sync_enabled(&self) -> bool {
485 unsafe { msg_send_bool![self, displaySyncEnabled] }
486 }
487
488 pub fn set_display_sync_enabled(&self, enabled: bool) {
489 unsafe { msg_send![self, setDisplaySyncEnabled: enabled] }
490 }
491
492 pub fn maximum_drawable_count(&self) -> NSUInteger {
493 unsafe { msg_send![self, maximumDrawableCount] }
494 }
495
496 pub fn set_maximum_drawable_count(&self, count: NSUInteger) {
497 unsafe { msg_send![self, setMaximumDrawableCount: count] }
498 }
499
500 pub fn set_edge_antialiasing_mask(&self, mask: u64) {
501 unsafe { msg_send![self, setEdgeAntialiasingMask: mask] }
502 }
503
504 pub fn set_masks_to_bounds(&self, masks: bool) {
505 unsafe { msg_send![self, setMasksToBounds: masks] }
506 }
507
508 pub fn remove_all_animations(&self) {
509 unsafe { msg_send![self, removeAllAnimations] }
510 }
511
512 pub fn next_drawable(&self) -> Option<&MetalDrawableRef> {
513 unsafe { msg_send![self, nextDrawable] }
514 }
515
516 pub fn contents_scale(&self) -> CGFloat {
517 unsafe { msg_send![self, contentsScale] }
518 }
519
520 pub fn set_contents_scale(&self, scale: CGFloat) {
521 unsafe { msg_send![self, setContentsScale: scale] }
522 }
523
524 pub fn framebuffer_only(&self) -> bool {
526 unsafe { msg_send_bool!(self, framebufferOnly) }
527 }
528
529 pub fn set_framebuffer_only(&self, framebuffer_only: bool) {
530 unsafe { msg_send![self, setFramebufferOnly: framebuffer_only] }
531 }
532
533 pub fn is_opaque(&self) -> bool {
534 unsafe { msg_send_bool!(self, isOpaque) }
535 }
536
537 pub fn set_opaque(&self, opaque: bool) {
538 unsafe { msg_send![self, setOpaque: opaque] }
539 }
540
541 pub fn wants_extended_dynamic_range_content(&self) -> bool {
542 unsafe { msg_send_bool![self, wantsExtendedDynamicRangeContent] }
543 }
544
545 pub fn set_wants_extended_dynamic_range_content(
546 &self,
547 wants_extended_dynamic_range_content: bool,
548 ) {
549 unsafe {
550 msg_send![
551 self,
552 setWantsExtendedDynamicRangeContent: wants_extended_dynamic_range_content
553 ]
554 }
555 }
556}
557
558mod acceleration_structure;
559mod acceleration_structure_pass;
560mod argument;
561mod blitpass;
562mod buffer;
563mod capturedescriptor;
564mod capturemanager;
565mod commandbuffer;
566mod commandqueue;
567mod computepass;
568mod constants;
569mod counters;
570mod depthstencil;
571mod device;
572mod drawable;
573mod encoder;
574mod heap;
575mod indirect_encoder;
576mod library;
577#[cfg(feature = "mps")]
578pub mod mps;
579mod pipeline;
580mod renderpass;
581mod resource;
582mod sampler;
583mod sync;
584mod texture;
585mod types;
586mod vertexdescriptor;
587
588#[rustfmt::skip]
589pub use {
590 acceleration_structure::*,
591 acceleration_structure_pass::*,
592 argument::*,
593 blitpass::*,
594 buffer::*,
595 counters::*,
596 computepass::*,
597 capturedescriptor::*,
598 capturemanager::*,
599 commandbuffer::*,
600 commandqueue::*,
601 constants::*,
602 depthstencil::*,
603 device::*,
604 drawable::*,
605 encoder::*,
606 heap::*,
607 indirect_encoder::*,
608 library::*,
609 pipeline::*,
610 renderpass::*,
611 resource::*,
612 sampler::*,
613 texture::*,
614 types::*,
615 vertexdescriptor::*,
616 sync::*,
617};
618
619#[inline]
620unsafe fn obj_drop<T>(p: *mut T) {
621 msg_send![p.cast::<Object>(), release]
622}
623
624#[inline]
625unsafe fn obj_clone<T: 'static>(p: *mut T) -> *mut T {
626 msg_send![p.cast::<Object>(), retain]
627}
628
629#[allow(non_camel_case_types)]
630type c_size_t = usize;
631
632pub enum NSURL {}
635
636foreign_obj_type! {
637 type CType = NSURL;
638 pub struct URL;
639}
640
641impl URL {
642 pub fn new_with_string(string: &str) -> Self {
643 unsafe {
644 let ns_str = crate::nsstring_from_str(string);
645 let class = class!(NSURL);
646 msg_send![class, URLWithString: ns_str]
647 }
648 }
649}
650
651impl URLRef {
652 pub fn absolute_string(&self) -> &str {
653 unsafe {
654 let absolute_string = msg_send![self, absoluteString];
655 crate::nsstring_as_str(absolute_string)
656 }
657 }
658
659 pub fn path(&self) -> &str {
660 unsafe {
661 let path = msg_send![self, path];
662 crate::nsstring_as_str(path)
663 }
664 }
665}