use_prelude!();
use core::ffi::c_void;
use std::sync::{Arc, Mutex, Weak};
use ffi_sdk::{BoxedDitto, FsComponent};
use serde::Deserialize;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
pub enum FileSystemType {
Directory = 0,
File,
SymLink,
}
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct DiskUsageChild {
pub fs_type: FileSystemType,
pub path: String,
pub size_in_bytes: usize,
pub children: Option<Vec<DiskUsageChild>>,
}
pub struct DiskUsageObserverCtx<F: ?Sized + DiskUsageCallback> {
handle: Option<repr_c::Box<ffi_sdk::DiskUsageObserver>>,
on_update: F,
}
#[doc(hidden)]
#[deprecated(note = "This is now named `DiskUsageObserverCtx`")]
pub type DiskUsageObserver = DiskUsageObserverCtx<dyn DiskUsageCallback>;
trait_alias! {
pub trait DiskUsageCallback = 'static + Send + FnMut(DiskUsageChild)
}
#[allow(type_alias_bounds)]
pub type DiskUsageObserverHandle<F: ?Sized + DiskUsageCallback = dyn DiskUsageCallback> =
Mutex<DiskUsageObserverCtx<F>>;
const _ASSERT_IMPLS: &(dyn Send + Sync) = &::core::marker::PhantomData::<DiskUsageObserverHandle>;
impl<F: DiskUsageCallback> DiskUsageObserverCtx<F> {
fn set_handle(&mut self, handle: repr_c::Box<ffi_sdk::DiskUsageObserver>) {
self.handle = Some(handle);
}
#[track_caller]
unsafe fn borrowing_from_ctx(
ctx: *const c_void,
yielding: impl FnOnce(&Weak<DiskUsageObserverHandle<F>>),
) {
let weak_ctx = ::core::mem::ManuallyDrop::new(Weak::from_raw(
ctx.cast::<DiskUsageObserverHandle<F>>(),
));
yielding(&weak_ctx)
}
unsafe extern "C" fn on_event(ctx: *mut c_void, cbor: c_slice::Ref<'_, u8>) {
Self::borrowing_from_ctx(ctx, |weak_ctx| {
if let Some(strong_ctx) = weak_ctx.upgrade() {
let tree = ::serde_cbor::from_slice(cbor.as_slice()).unwrap();
(strong_ctx.lock().unwrap().on_update)(tree);
}
})
}
unsafe extern "C" fn retain(ctx: *mut c_void) {
Self::borrowing_from_ctx(ctx, |weak_ctx| {
_ = Weak::into_raw(weak_ctx.clone());
});
}
unsafe extern "C" fn release(ctx: *mut c_void) {
drop(Weak::from_raw(ctx.cast::<DiskUsageObserverHandle<F>>()));
}
}
pub struct DiskUsage {
ditto: Arc<BoxedDitto>,
component: FsComponent,
}
impl DiskUsage {
pub(crate) fn new(ditto: Arc<BoxedDitto>, component: FsComponent) -> Self {
Self { ditto, component }
}
pub fn exec(&self) -> DiskUsageChild {
let cval = ffi_sdk::ditto_disk_usage(&self.ditto, self.component);
::serde_cbor::from_slice(cval.as_slice()).unwrap()
}
pub fn observe<F: DiskUsageCallback>(&self, callback: F) -> Arc<DiskUsageObserverHandle> {
let observer: DiskUsageObserverHandle<F> = Mutex::new(DiskUsageObserverCtx::<F> {
on_update: callback,
handle: None,
});
let observer: Arc<DiskUsageObserverHandle<F>> = Arc::new(observer);
let weak_observer = Arc::downgrade(&observer);
let handle = unsafe {
ffi_sdk::ditto_register_disk_usage_callback(
&self.ditto,
self.component,
weak_observer.as_ptr() as *mut _,
Some(DiskUsageObserverCtx::<F>::retain),
Some(DiskUsageObserverCtx::<F>::release),
Some(<unsafe extern "C" fn(_, c_slice::Ref<'_, _>)>::into(
DiskUsageObserverCtx::<F>::on_event,
)),
)
};
drop(weak_observer);
observer.lock().unwrap().set_handle(handle.unwrap());
observer
}
}