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
141
142
143
144
145
146
147
148
149
150
151
152
//! `iron-oxide` provides unsafe [Metal](https://developer.apple.com/documentation/metal?language=objc)
//! bindings for Rust.
//!
//! The Metal documentation for most structs, traits, methods, and functions can be found by
//! googling their names (adjusted from snake_case to camelCase).
//!
//! Not all of Metal's functionality is added. The pointer underlying a MTL(something) can
//! be accessed with `get_ptr`, and messages can be sent to it with `objc`'s `msg_send!`, if
//! necessary functionality isn't yet implemented. This is very unsafe.
//!
//! It is the responsibility of the user to not use methods or functions which do not exist in
//! OS versions below what they support.
//!
//! See the examples directory for examples.
//!
//! This crate is licensed under the MIT license.

use objc::Message;
use std::ops::Deref;

mod commandbuffer;
mod commandqueue;
mod depthstencil;
mod device;
mod drawable;
mod encoder;
mod layer;
mod library;
mod misc;
mod pipeline;
mod resource;
mod sampler;
pub use commandbuffer::*;
pub use commandqueue::*;
pub use depthstencil::*;
pub use device::*;
pub use drawable::*;
pub use encoder::*;
pub use layer::*;
pub use library::*;
pub use misc::*;
pub use pipeline::*;
pub use resource::*;
pub use sampler::*;

/// Reexports important macros for sending messages from the `objc` crate:
/// - `msg_send`
/// - `class`
/// - `sel`
/// - `sel_impl`
pub mod import_objc_macros {
    pub use objc::{class, msg_send, sel, sel_impl};
}

type ObjectPointerMarker = objc::runtime::Object;

#[derive(Copy, Clone)]
#[repr(C)]
/// A messageable pointer to a (presumed) Objective C object.
pub struct ObjectPointer(*mut ObjectPointerMarker);
impl Deref for ObjectPointer {
    type Target = ObjectPointerMarker;

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.0 }
    }
}
unsafe impl Message for ObjectPointer {}

pub trait Array<T: Object>: Object {
    /// Puts in the array at the specified index the specified object.
    unsafe fn set_object_at_indexed_subscript(&self, index: NSUInteger, obj: &T) {
        use crate::import_objc_macros::*;
        msg_send![self.get_ptr(), setObject:obj.get_ptr() atIndexedSubscript:index]
    }
}

/// Represents an Objective C object.
///
/// # Requirements
///
/// There *must* be for an implementation of Object an implementation of Drop using
/// the `handle!` macro. See `handle!` for more information and an example.
pub trait Object: Drop {
    /// Constructs an object from the provided pointer.
    ///
    /// The pointer provided *must* be a valid pointer to an Objective C object which can
    /// accept the messages which the used implementation of Object will send.
    unsafe fn from_ptr(ptr: ObjectPointer) -> Self
    where
        Self: Sized;
    /// Returns the underlying pointer of the object.
    ///
    /// The returned pointer *must* be a valid pointer to an Objective C object.
    fn get_ptr(&self) -> ObjectPointer;
}

/// Aliased exclusively so that, should the watchOS target be added to Rust, NSInteger can
/// conform to watchOS' 32-bit architecture.
pub type NSInteger = i64;
/// Aliased exclusively so that, should the watchOS target be added to Rust, NSUInteger can
/// conform to watchOS' 32-bit architecture.
pub type NSUInteger = u64;
/// Aliased exclusively so that, should the watchOS target be added to Rust, CGFloat can
/// conform to watchOS' 32-bit architecture.
pub type CGFloat = f64;

#[macro_export]
/// Provides an implementation of `Drop` which implements lifetime-based releasing
/// on the implemented type's pointer to an Objective C object.
///
/// This implementation of `Drop` decrements the reference count of the object which the
/// `get_ptr` method returns. This ensures that the object to which the implementor points
/// lives only for the lifetime of the implementor.
///
/// # Requirements
///
/// The ident passed into `handle!` must be the correct local name of a struct or enum which
/// implements `Object`.
///
/// # Example
///
/// ```
/// use iron_oxide::{ObjectPointer, handle, Object};
///
/// struct Wrapper(ObjectPointer);
/// handle!(Wrapper);
///
/// impl Object for Wrapper {
///     unsafe fn from_ptr(ptr: ObjectPointer) -> Self where
///         Self: Sized {
///         Wrapper(ptr)
///     }
///
///     fn get_ptr(&self) -> ObjectPointer {
///         self.0
///     }
///
/// }
/// ```
macro_rules! handle {
    ($name:ident) => {
        impl Drop for $name {
            fn drop(&mut self) {
                use crate::import_objc_macros::*;
                unsafe {
                    let _: () = msg_send![self.get_ptr(), release];
                }
            }
        }
    };
}