blob: 1d4a21feb3fc6f3ab860f2b5b77bb08b8b535ff1 [file] [log] [blame]
#![allow(clashing_extern_declarations)]
use std::ops::Deref;
use std::os::raw::c_char;
use std::slice;
use std::str;
#[macro_use]
mod fruity;
use fruity::foundation::NSString;
use fruity::foundation::NSStringEncoding;
use fruity::objc::Class;
use fruity::objc::NSObject;
use fruity::objc::NSUInteger;
use fruity::objc::Object;
use fruity::objc::SEL;
impl NSString {
fn is_empty(&self) -> bool {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL) -> NSUInteger;
}
let sel = selector!(length);
let length = unsafe { objc_msgSend(self, sel) };
length == 0
}
fn utf8_length(&self) -> usize {
extern "C" {
fn objc_msgSend(
obj: &Object,
sel: SEL,
enc: NSStringEncoding,
) -> NSUInteger;
}
let sel = selector!(lengthOfBytesUsingEncoding:);
let length =
unsafe { objc_msgSend(self, sel, NSStringEncoding::UTF8) };
if length == 0 {
assert!(self.is_empty());
}
length
}
fn to_utf8_ptr(&self) -> *const u8 {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL) -> *const c_char;
}
let sel = selector!(UTF8String);
unsafe { objc_msgSend(self, sel) }.cast()
}
unsafe fn to_str(&self) -> &str {
let length = self.utf8_length();
// SAFETY: These bytes are encoded using UTF-8.
unsafe {
str::from_utf8_unchecked(slice::from_raw_parts(
self.to_utf8_ptr(),
length,
))
}
}
}
impl ToString for NSString {
fn to_string(&self) -> String {
// SAFETY: The string has a short lifetime.
unsafe { self.to_str() }.to_owned()
}
}
#[repr(transparent)]
struct NSFileManager(NSObject);
impl NSFileManager {
fn class() -> &'static Class {
extern "C" {
#[link_name = "OBJC_CLASS_$_NSFileManager"]
static CLASS: Class;
}
unsafe { &CLASS }
}
fn default() -> Self {
extern "C" {
fn objc_msgSend(obj: &Class, sel: SEL) -> &Object;
fn objc_retain(obj: &Object) -> NSFileManager;
}
let obj = Self::class();
let sel = selector!(defaultManager);
unsafe { objc_retain(objc_msgSend(obj, sel)) }
}
}
impl Deref for NSFileManager {
type Target = NSObject;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub(super) fn name(path: &str) -> String {
extern "C" {
fn objc_msgSend(obj: &Object, sel: SEL, path: NSString) -> &Object;
fn objc_retain(obj: &Object) -> NSString;
}
let obj = NSFileManager::default();
let sel = selector!(displayNameAtPath:);
// SAFETY: This struct is dropped by the end of this method.
let path = unsafe { NSString::from_str_no_copy(path) };
unsafe { objc_retain(objc_msgSend(&obj, sel, path)) }.to_string()
}