use std::{fmt, rc::Rc};
use dart_sys::{Dart_Handle, Dart_PersistentHandle};
use medea_macro::dart_bridge;
use crate::platform::utils::{
c_str_into_string, dart_api, dart_string_into_rust,
};
#[dart_bridge("flutter/lib/src/native/platform/object.g.dart")]
mod handle {
use std::{os::raw::c_char, ptr};
use dart_sys::Dart_Handle;
use crate::platform::Error;
extern "C" {
pub fn runtime_type(
handle: Dart_Handle,
) -> Result<ptr::NonNull<c_char>, Error>;
pub fn to_string(
handle: Dart_Handle,
) -> Result<ptr::NonNull<c_char>, Error>;
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DartHandle(Rc<Dart_PersistentHandle>);
impl DartHandle {
#[must_use]
pub unsafe fn new(handle: Dart_Handle) -> Self {
if unsafe { dart_api::is_error(handle) } {
let pointer = unsafe { dart_api::get_error(handle) };
let c_str = unsafe { pointer.as_ref() }.unwrap().into();
let err_msg = unsafe { c_str_into_string(c_str) };
panic!("unexpected Dart error: {err_msg}")
}
Self(Rc::new(unsafe { dart_api::new_persistent_handle(handle) }))
}
#[must_use]
pub fn get(&self) -> Dart_Handle {
unsafe { dart_api::handle_from_persistent(*self.0) }
}
#[must_use]
pub fn name(&self) -> String {
let type_name = unsafe { handle::runtime_type(self.get()) }.unwrap();
unsafe { dart_string_into_rust(type_name) }
}
}
impl fmt::Display for DartHandle {
#[expect(clippy::unwrap_in_result, reason = "unrelated")]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string = unsafe { handle::to_string(self.get()) }.unwrap();
let string = unsafe { dart_string_into_rust(string) };
write!(f, "{string}")
}
}
impl Drop for DartHandle {
fn drop(&mut self) {
if let Some(handle) = Rc::get_mut(&mut self.0) {
unsafe {
dart_api::delete_persistent_handle(*handle);
}
}
}
}