apple-apis 0.1.0

System bindings for Apple APIs
#![allow(dead_code, unused_imports, unused_macros)]

// pointers in rust have very few guarantees, notably no aliasing or immutabillity
// guarantees/requirements. meaning the swift value behind pointers can change
// and the rust compiler doesn't assume it won't?
pub type Ptr = *mut ();

/// Helper to declare `extern "C"` functions while respecting `sys` feature
///
/// # Examples
///
/// ```no_run
/// sys! {
///    pub fn extern_function();
///    pub fn extern_function2();
///    pub fn not_sure_what_to_put_here();
/// }
/// ```
macro_rules! sys {
	{ @impl $($tt:tt)* } => {
		#[allow(unused_imports)]
		use super::*;

		unsafe extern "C" { $($tt)* }
	};

	{ $feature:literal $($tt:tt)* } => {
		cfg_select! {
			feature = "unstable-sys" => {
				#[cfg_attr(docsrs, doc(cfg(all(
					feature = $feature,
					feature = "unstable-sys"
				))))]
				pub mod sys {
					$crate::util::sys! { @impl $($tt)* }
				}
			}
			_ => {
				mod sys {
					$crate::util::sys! { @impl $($tt)* }
				}
			}
		}
	};
}
pub(crate) use sys;

/// Declare a safe wrapper type and some common impls
///
/// This macro declares the struct, provides `_new()`, and `_as_ptr(&self)`
/// functions, as well as implements [`Drop`]. Optionally, you can also provide
/// raw functions to handle cloning the underlying Swift class.
///
/// `pub`, `new`, `clone`, and `clone_from` are optional. Providing `new` also
/// implements [`Default`]. You must provide `clone` to be able to provide
/// `clone_from`.
///
/// # Expected function signatures
///
/// - `new`: `fn() -> Ptr`
/// - `clone`: `fn(Ptr) -> Ptr`
/// - `clone_from`: `fn(Ptr, Ptr)` (argument order following
///   [`Clone::clone_from`], ie. `self` is the first argument,
///   `source` is the second)
/// - `drop`: `fn(Ptr)`
///
/// # Examples
///
/// ```no_run
/// wrapper! {
///    pub struct Test;
///    new: sys::test_new;
///    clone: sys::test_clone;
///    clone_from: sys::test_clone_from;
///    drop: sys::drop;
/// }
/// ```
macro_rules! wrapper {
	{
		$vis:vis struct $struct:ident;
		$(new: $new:path;)?
		$(
			clone: $clone:path;
			$(clone_from: $clone_from:path;)?
		)?
		drop: $drop:path;
	} => {
		$vis struct $struct {
			__ptr: $crate::util::Ptr
		}

		impl $struct {
			#[allow(dead_code)]
			unsafe fn _new(ptr: $crate::util::Ptr) -> Self {
				Self { __ptr: ptr }
			}

			#[allow(dead_code)]
			pub(crate) fn as_ptr(&self) -> $crate::util::Ptr {
				self.__ptr
			}
		}

		$(
			impl $struct {
				pub fn new() -> Self {
					unsafe { Self::_new($new()) }
				}
			}

			impl Default for $struct {
				fn default() -> Self {
					Self::new()
				}
			}
		)?

		$(
			impl Clone for $struct {
				fn clone(&self) -> Self {
					let ptr = unsafe { $clone(self._as_ptr()) };
					unsafe { Self::_new(ptr) }
				}

				$(
					fn clone_from(&mut self, source: &Self) {
						unsafe { $clone_from(self.as_ptr(), source._as_ptr()) }
					}
				)?
			}
		)?

		impl Drop for $struct {
			fn drop(&mut self) {
				unsafe { $drop(self.as_ptr()) }
			}
		}
	}
}
pub(crate) use wrapper;