use std::{
fmt::Debug,
mem,
ops::Deref,
ptr::{self, NonNull},
sync::atomic::{fence, AtomicUsize, Ordering},
};
use cef_dll_sys::cef_base_ref_counted_t;
pub trait Rc {
unsafe fn add_ref(&self) {
self.as_base().add_ref();
}
unsafe fn release(&self) -> bool {
self.as_base().release()
}
fn has_one_ref(&self) -> bool {
self.as_base().has_one_ref()
}
fn has_at_least_one_ref(&self) -> bool {
self.as_base().has_at_least_one_ref()
}
fn as_base(&self) -> &cef_base_ref_counted_t;
}
impl Rc for cef_base_ref_counted_t {
unsafe fn add_ref(&self) {
if let Some(add_ref) = self.add_ref {
add_ref(ptr::from_ref(self) as *mut _);
}
}
fn has_one_ref(&self) -> bool {
if let Some(has_one_ref) = self.has_one_ref {
let result = unsafe { has_one_ref(ptr::from_ref(self) as *mut _) };
return result == 1;
}
false
}
fn has_at_least_one_ref(&self) -> bool {
if let Some(has_at_least_one_ref) = self.has_at_least_one_ref {
let result = unsafe { has_at_least_one_ref(ptr::from_ref(self) as *mut _) };
return result == 1;
}
false
}
unsafe fn release(&self) -> bool {
if let Some(release) = self.release {
return release(ptr::from_ref(self) as *mut _) == 1;
}
false
}
fn as_base(&self) -> &Self {
self
}
}
pub trait ConvertParam<T: Sized> {
fn into_raw(self) -> T;
}
impl<T, U> ConvertParam<U> for T
where
T: Sized + Into<U>,
U: Sized,
{
fn into_raw(self) -> U {
self.into()
}
}
impl<T> ConvertParam<*mut T> for &RefGuard<T>
where
T: Sized + Rc,
{
fn into_raw(self) -> *mut T {
unsafe { self.into_raw() }
}
}
pub struct WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
value: T,
output: Option<NonNull<P>>,
}
impl<T, P> Drop for WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
fn drop(&mut self) {
if let Some(output) = &mut self.output {
let output = unsafe { output.as_mut() };
let mut value = unsafe { mem::zeroed() };
mem::swap(&mut self.value, &mut value);
*output = value.into();
}
}
}
impl<T, P> From<*mut P> for WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
fn from(value: *mut P) -> Self {
let mut output = NonNull::new(value);
let value = output
.as_mut()
.map(|p| {
let mut value = unsafe { mem::zeroed() };
mem::swap(unsafe { p.as_mut() }, &mut value);
value.into()
})
.unwrap_or_else(|| unsafe { mem::zeroed() });
Self { value, output }
}
}
impl<T, P> From<*const P> for WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn from(value: *const P) -> Self {
let value = unsafe { value.as_ref() }
.map(|value| (*value).into())
.unwrap_or_else(|| unsafe { mem::zeroed() });
Self {
value,
output: None,
}
}
}
impl<T, P> AsMut<T> for WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
fn as_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T, P> AsRef<T> for WrapParamRef<T, P>
where
T: Sized + Into<P>,
P: Sized + Copy + Into<T>,
{
fn as_ref(&self) -> &T {
&self.value
}
}
pub trait ConvertReturnValue<T: Sized> {
fn wrap_result(self) -> T;
}
impl<T, U> ConvertReturnValue<U> for T
where
T: Sized + Into<U>,
U: Sized,
{
fn wrap_result(self) -> U {
self.into()
}
}
pub struct RefGuard<T: Rc> {
object: *mut T,
}
impl<T: Debug + Rc> Debug for RefGuard<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let object_ref = unsafe { self.object.as_ref() };
write!(f, "RefGuard({object_ref:#?})")
}
}
impl<T: Rc> RefGuard<T> {
pub unsafe fn from_raw(ptr: *mut T) -> RefGuard<T> {
RefGuard { object: ptr }
}
pub unsafe fn from_raw_add_ref(ptr: *mut T) -> RefGuard<T> {
let guard = RefGuard { object: ptr };
guard.add_ref();
guard
}
pub unsafe fn into_raw(&self) -> *mut T {
self.object
}
pub unsafe fn convert<U: Rc>(&self) -> RefGuard<U> {
RefGuard::from_raw_add_ref(self.into_raw().cast())
}
}
unsafe impl<T: Rc> Send for RefGuard<T> {}
unsafe impl<T: Rc> Sync for RefGuard<T> {}
impl<T: Rc> Clone for RefGuard<T> {
fn clone(&self) -> RefGuard<T> {
unsafe { self.add_ref() };
RefGuard {
object: self.object,
}
}
}
impl<T: Rc> Deref for RefGuard<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.object }
}
}
impl<T: Rc> Drop for RefGuard<T> {
fn drop(&mut self) {
unsafe { self.release() };
}
}
#[repr(C)]
pub struct RcImpl<T, I> {
pub cef_object: T,
pub interface: I,
ref_count: AtomicUsize,
}
impl<T, I> RcImpl<T, I> {
pub fn new(mut cef_object: T, interface: I) -> *mut RcImpl<T, I> {
let base: &mut cef_base_ref_counted_t =
unsafe { &mut *(ptr::from_mut(&mut cef_object).cast()) };
base.size = std::mem::size_of::<T>();
base.add_ref = Some(add_ref::<T, I>);
base.has_one_ref = Some(has_one_ref::<T, I>);
base.has_at_least_one_ref = Some(has_at_least_one_ref::<T, I>);
base.release = Some(release::<T, I>);
Box::into_raw(Box::new(RcImpl {
cef_object,
interface,
ref_count: AtomicUsize::new(1),
}))
}
pub fn get<'a>(ptr: *mut T) -> &'a mut RcImpl<T, I> {
unsafe { &mut *(ptr.cast()) }
}
}
extern "C" fn add_ref<T, I>(this: *mut cef_base_ref_counted_t) {
let obj = RcImpl::<T, I>::get(this.cast());
obj.ref_count.fetch_add(1, Ordering::Relaxed);
}
extern "C" fn has_one_ref<T, I>(this: *mut cef_base_ref_counted_t) -> i32 {
let obj = RcImpl::<T, I>::get(this.cast());
if obj.ref_count.load(Ordering::Relaxed) == 1 {
1
} else {
0
}
}
extern "C" fn has_at_least_one_ref<T, I>(this: *mut cef_base_ref_counted_t) -> i32 {
let obj = RcImpl::<T, I>::get(this.cast());
if obj.ref_count.load(Ordering::Relaxed) >= 1 {
1
} else {
0
}
}
pub extern "C" fn release<T, I>(this: *mut cef_base_ref_counted_t) -> i32 {
let obj = RcImpl::<T, I>::get(this.cast());
if obj.ref_count.fetch_sub(1, Ordering::Release) != 1 {
0
} else {
fence(Ordering::Acquire);
let _: Box<RcImpl<T, I>> = unsafe { Box::from_raw(this.cast()) };
1
}
}