use alloc::ffi::CString;
use alloc::string::String;
use crate::error::{Error, Result};
use crate::paint::Paint;
use thorvg_sys as sys;
pub struct Accessor<'eng> {
raw: sys::Tvg_Accessor,
_engine: core::marker::PhantomData<&'eng ()>,
}
impl Accessor<'_> {
pub(crate) fn new() -> Self {
let raw = unsafe { sys::tvg_accessor_new() };
assert!(!raw.is_null(), "failed to create Accessor");
Self {
raw,
_engine: core::marker::PhantomData,
}
}
pub unsafe fn set<P: Paint>(
&mut self,
paint: &P,
func: unsafe extern "C" fn(sys::Tvg_Paint, *mut core::ffi::c_void) -> bool,
data: *mut core::ffi::c_void,
) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_accessor_set(self.raw, paint.raw(), Some(func), data) })
}
pub fn for_each<P: Paint, F: FnMut(sys::Tvg_Paint) -> bool>(
&mut self,
paint: &P,
mut func: F,
) -> Result<()> {
unsafe extern "C" fn trampoline<F: FnMut(sys::Tvg_Paint) -> bool>(
paint: sys::Tvg_Paint,
data: *mut core::ffi::c_void,
) -> bool {
let f = unsafe { &mut *data.cast::<F>() };
f(paint)
}
let data = core::ptr::from_mut(&mut func).cast::<core::ffi::c_void>();
Error::from_raw(unsafe {
sys::tvg_accessor_set(self.raw, paint.raw(), Some(trampoline::<F>), data)
})
}
pub fn generate_id(name: &str) -> Option<u32> {
let c_name = CString::new(name).ok()?;
Some(unsafe { sys::tvg_accessor_generate_id(c_name.as_ptr()) })
}
pub fn get_name(&self, id: u32) -> Option<String> {
let ptr = unsafe { sys::tvg_accessor_get_name(self.raw, id) };
if ptr.is_null() {
None
} else {
Some(
unsafe { core::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
)
}
}
}
impl Drop for Accessor<'_> {
fn drop(&mut self) {
unsafe {
sys::tvg_accessor_del(self.raw);
}
}
}
impl core::fmt::Debug for Accessor<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Accessor").finish_non_exhaustive()
}
}