blob: fe695203b80dfc4fb89945a49db85aaf43777e97 [file] [log] [blame]
//! Implementations copied and modified from Fruity.
//!
//! Sources:
//! - <https://github.com/nvzqz/fruity/tree/c1d067e8ec03e20bb6f52f7c3ab63cadd2a2b261>
//!
//! Copyrights:
//! - Copyright (c) 2020 Nikolai Vazquez<br>
//! <https://github.com/nvzqz/fruity/blob/c1d067e8ec03e20bb6f52f7c3ab63cadd2a2b261/LICENSE-MIT#L3>
//! - Modifications copyright (c) 2020 dylni (<https://github.com/dylni>)<br>
//! <https://github.com/dylni/normpath/blob/master/COPYRIGHT>
use std::os::raw::c_char;
macro_rules! __stringify_sel {
( $name:ident ) => {
::std::stringify!($name)
};
( $($name:ident :)+ ) => {
::std::concat!($(::std::stringify!($name), ":"),+)
};
}
macro_rules! selector {
( $($token:tt)* ) => {{
let sel: *const _ = ::std::concat!(__stringify_sel!($($token)*), "\0");
unsafe {
$crate::localize::macos::fruity::sel_registerName(sel.cast())
}
}};
}
#[link(name = "Foundation", kind = "framework")]
extern "C" {}
extern "C" {
pub(super) fn sel_registerName(name: *const c_char) -> objc::SEL;
}
pub(super) mod objc {
use std::cell::UnsafeCell;
use std::ops::Deref;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ptr::NonNull;
#[allow(clippy::upper_case_acronyms)]
pub(super) type BOOL = c_char;
#[allow(clippy::upper_case_acronyms)]
pub(super) const NO: BOOL = 0;
pub(in super::super) type NSUInteger = usize;
#[allow(clippy::upper_case_acronyms)]
#[repr(transparent)]
pub(in super::super) struct SEL(NonNull<c_void>);
#[repr(C)]
pub(in super::super) struct Object(UnsafeCell<[u8; 0]>);
#[repr(C)]
pub(in super::super) struct Class(Object);
impl Class {
pub(super) fn alloc(&self) -> NSObject {
extern "C" {
fn objc_msgSend(obj: &Class, sel: SEL) -> NSObject;
}
let sel = selector!(alloc);
unsafe { objc_msgSend(self, sel) }
}
}
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub(in super::super) struct id(NonNull<Object>);
impl Deref for id {
type Target = Object;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl Drop for id {
fn drop(&mut self) {
extern "C" {
fn objc_release(obj: &Object);
}
unsafe { objc_release(self) }
}
}
#[repr(transparent)]
pub(in super::super) struct NSObject(id);
impl Deref for NSObject {
type Target = id;
fn deref(&self) -> &Self::Target {
&self.0
}
}
}
pub(super) mod foundation {
use std::ops::Deref;
use super::objc::Class;
use super::objc::NSObject;
use super::objc::NSUInteger;
use super::objc::BOOL;
use super::objc::NO;
use super::objc::SEL;
#[repr(transparent)]
pub(in super::super) struct NSStringEncoding(NSUInteger);
impl NSStringEncoding {
pub(in super::super) const UTF8: Self = Self(4);
}
#[repr(transparent)]
pub(in super::super) struct NSString(NSObject);
impl NSString {
fn class() -> &'static Class {
extern "C" {
#[link_name = "OBJC_CLASS_$_NSString"]
static CLASS: Class;
}
unsafe { &CLASS }
}
pub(in super::super) unsafe fn from_str_no_copy(string: &str) -> Self {
extern "C" {
fn objc_msgSend(
obj: NSString,
sel: SEL,
bytes: *const u8,
length: NSUInteger,
encoding: NSStringEncoding,
free_when_done: BOOL,
) -> NSString;
}
let obj = Self(Self::class().alloc());
let sel =
selector!(initWithBytesNoCopy:length:encoding:freeWhenDone:);
let bytes = string.as_ptr();
let length = string.len();
let encoding = NSStringEncoding::UTF8;
let free_when_done = NO;
unsafe {
objc_msgSend(obj, sel, bytes, length, encoding, free_when_done)
}
}
}
impl Deref for NSString {
type Target = NSObject;
fn deref(&self) -> &Self::Target {
&self.0
}
}
}