use std::{ffi::{c_void, CString}, fmt::Display, ptr::null};
use crate::{UIErrorKind, UIResult};
use super::{CFAllocatorRef, CFData, CFDataRef, CFIndex, CFRange, CFSerializable, CFType};
pub type CFStringRef = *const c_void;
#[derive(Debug, Clone)]
pub struct CFString {
inner: CFType,
}
impl CFString {
pub fn new(s: &str) -> Option<Self> {
let s = CString::new(s).unwrap();
let alloc = null();
let c_str = s.as_ptr() as *const u8;
let encoding = CFStringEncoding::Utf8;
let reference = unsafe { CFStringCreateWithCString(alloc, c_str, encoding) };
let Some(inner) = CFType::from_create(reference) else {
return None;
};
Some(Self { inner })
}
#[must_use]
pub fn from_get(str_ref: CFType) -> Option<Self> {
Some(Self {
inner: str_ref,
})
}
#[must_use]
pub fn from_create(str_ref: CFStringRef) -> Option<Self> {
Some(Self {
inner: CFType::from_create(str_ref)?,
})
}
pub fn to_string(&self) -> UIResult<String> {
let alloc = null();
let data_ref = unsafe {
CFStringCreateExternalRepresentation(alloc, self.inner.ptr(), CFStringEncoding::Utf8, b'?')
};
let Some(data) = CFData::from_create(data_ref) else {
return Err(UIErrorKind::AllocationFailed { resource: "CFStringCreateExternalRepresentation" }.into());
};
Ok(String::from_utf8_lossy(data.as_slice()).to_string())
}
}
impl Display for CFString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_string().unwrap().fmt(f)
}
}
impl From<&'static str> for CFString {
fn from(value: &'static str) -> Self {
Self::new(value).unwrap()
}
}
impl CFSerializable for CFString {
fn from_ptr(ptr: *const c_void) -> Self {
Self {
inner: CFType::from_get(ptr).unwrap(),
}
}
fn to_ptr(&self) -> *const c_void {
self.inner.ptr()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum CFStringEncoding {
Utf8 = 0x08000100,
}
#[allow(unused)]
extern "C-unwind" {
pub(super) fn CFStringCreateWithCString(alloc: CFAllocatorRef, c_str: *const u8, encoding: CFStringEncoding) -> CFStringRef;
pub(super) fn CFStringGetBytes(the_string: CFStringRef, range: CFRange, encoding: CFStringEncoding, loss_byte: u8, is_external_representation: bool, buffer: *mut u8, max_buf_len: CFIndex, used_buf_len: *mut CFIndex) -> CFIndex;
pub(super) fn CFStringCreateExternalRepresentation(alloc: CFAllocatorRef, the_string: CFStringRef, encoding: CFStringEncoding, loss_byte: u8) -> CFDataRef;
}