use crate::sys::*;
use crate::traits::*;
use crate::Error;
use alloc::boxed::Box;
use core::ffi::c_void;
#[inline]
fn hb_codepoint_t_to_char(input: hb_codepoint_t) -> char {
unsafe { char::from_u32_unchecked(input) }
}
#[non_exhaustive]
#[derive(Debug)]
pub struct UnicodeFuncsBuilder {
raw: *mut hb_unicode_funcs_t,
}
impl UnicodeFuncsBuilder {
pub fn new_with_empty_parent() -> Result<Self, Error> {
let parent = unsafe { hb_unicode_funcs_get_empty() };
let ufuncs = unsafe { hb_unicode_funcs_create(parent) };
if ufuncs == parent {
return Err(Error::Alloc);
}
Ok(Self { raw: ufuncs })
}
pub fn new_with_harfbuzz_default_parent() -> Result<Self, Error> {
let parent = unsafe { hb_unicode_funcs_get_default() };
let ufuncs = unsafe { hb_unicode_funcs_create(parent) };
if ufuncs == parent {
return Err(Error::Alloc);
}
Ok(Self { raw: ufuncs })
}
pub fn set_general_category_func<F: GeneralCategoryFunc>(&mut self, f: Box<F>) {
let general_category_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_general_category<F: GeneralCategoryFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
unicode: hb_codepoint_t,
user_data: *mut c_void,
) -> hb_unicode_general_category_t {
unsafe { &*(user_data as *mut F) }.general_category(hb_codepoint_t_to_char(unicode))
as hb_unicode_general_category_t
}
extern "C" fn destroy_general_category<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_general_category_func(
self.raw,
Some(impl_general_category::<F>),
general_category_ptr as *mut c_void,
Some(destroy_general_category::<F>),
);
}
}
pub fn set_combining_class_func<F: CombiningClassFunc>(&mut self, f: Box<F>) {
let combining_class_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_combining_class<F: CombiningClassFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
unicode: hb_codepoint_t,
user_data: *mut c_void,
) -> hb_unicode_combining_class_t {
unsafe { &*(user_data as *mut F) }.combining_class(hb_codepoint_t_to_char(unicode))
as hb_unicode_combining_class_t
}
extern "C" fn destroy_combining_class<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_combining_class_func(
self.raw,
Some(impl_combining_class::<F>),
combining_class_ptr as *mut c_void,
Some(destroy_combining_class::<F>),
);
}
}
pub fn set_mirroring_func<F: MirroringFunc>(&mut self, f: Box<F>) {
let mirroring_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_mirroring<F: MirroringFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
unicode: hb_codepoint_t,
user_data: *mut c_void,
) -> hb_codepoint_t {
unsafe { &*(user_data as *mut F) }.mirroring(hb_codepoint_t_to_char(unicode))
as hb_codepoint_t
}
extern "C" fn destroy_mirroring<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_mirroring_func(
self.raw,
Some(impl_mirroring::<F>),
mirroring_ptr as *mut c_void,
Some(destroy_mirroring::<F>),
);
}
}
pub fn set_script_func<F: ScriptFunc>(&mut self, f: Box<F>) {
let script_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_script<F: ScriptFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
unicode: hb_codepoint_t,
user_data: *mut c_void,
) -> hb_codepoint_t {
let code = unsafe { &*(user_data as *mut F) }.script(hb_codepoint_t_to_char(unicode));
unsafe { hb_script_from_string(code.as_ptr() as *const i8, 4) }
}
extern "C" fn destroy_script<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_script_func(
self.raw,
Some(impl_script::<F>),
script_ptr as *mut c_void,
Some(destroy_script::<F>),
);
}
}
pub fn set_compose_func<F: ComposeFunc>(&mut self, f: Box<F>) {
let compose_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_compose<F: ComposeFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
a: hb_codepoint_t,
b: hb_codepoint_t,
ab: *mut hb_codepoint_t,
user_data: *mut c_void,
) -> hb_bool_t {
let result = unsafe { &*(user_data as *mut F) }
.compose(hb_codepoint_t_to_char(a), hb_codepoint_t_to_char(b));
match result {
Some(ab_x) => {
unsafe { *ab = ab_x as hb_codepoint_t };
true as hb_bool_t
}
None => false as hb_bool_t,
}
}
extern "C" fn destroy_compose<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_compose_func(
self.raw,
Some(impl_compose::<F>),
compose_ptr as *mut c_void,
Some(destroy_compose::<F>),
);
}
}
pub fn set_decompose_func<F: DecomposeFunc>(&mut self, f: Box<F>) {
let decompose_ptr: *mut F = Box::into_raw(f);
extern "C" fn impl_decompose<F: DecomposeFunc>(
_ufuncs: *mut hb_unicode_funcs_t,
ab: hb_codepoint_t,
a: *mut hb_codepoint_t,
b: *mut hb_codepoint_t,
user_data: *mut c_void,
) -> hb_bool_t {
let result = unsafe { &*(user_data as *mut F) }.decompose(hb_codepoint_t_to_char(ab));
match result {
Some((a_x, b_x)) => {
unsafe { *a = a_x as hb_codepoint_t };
unsafe { *b = b_x as hb_codepoint_t };
true as hb_bool_t
}
None => false as hb_bool_t,
}
}
extern "C" fn destroy_decompose<F>(user_data: *mut c_void) {
let _ = unsafe { Box::from_raw(user_data as *mut F) };
}
unsafe {
hb_unicode_funcs_set_decompose_func(
self.raw,
Some(impl_decompose::<F>),
decompose_ptr as *mut c_void,
Some(destroy_decompose::<F>),
);
}
}
pub fn build(self) -> UnicodeFuncs {
let raw = self.raw;
unsafe {
hb_unicode_funcs_make_immutable(raw);
}
core::mem::forget(self);
unsafe { UnicodeFuncs::from_raw(raw) }
}
pub unsafe fn from_raw(raw: *mut hb_unicode_funcs_t) -> Self {
Self { raw }
}
pub fn into_raw(self) -> *mut hb_unicode_funcs_t {
let ret = self.raw;
core::mem::forget(self);
ret
}
}
impl Drop for UnicodeFuncsBuilder {
fn drop(&mut self) {
unsafe {
hb_unicode_funcs_destroy(self.raw);
}
}
}
pub struct UnicodeFuncs {
raw: *mut hb_unicode_funcs_t,
}
impl UnicodeFuncs {
pub unsafe fn from_raw(raw: *mut hb_unicode_funcs_t) -> Self {
Self { raw }
}
pub fn into_raw(self) -> *mut hb_unicode_funcs_t {
let ret = self.raw;
core::mem::forget(self);
ret
}
pub fn as_ptr(&self) -> *mut hb_unicode_funcs_t {
self.raw
}
}
impl Drop for UnicodeFuncs {
fn drop(&mut self) {
unsafe {
hb_unicode_funcs_destroy(self.raw);
}
}
}