use std::{ffi::c_char, ptr};
use ffi::{ClepsydreManager, ClepsydreSubscription};
use gio::ffi::{
GAsyncReadyCallback, GAsyncResult, GCancellable, GListStore, g_task_new,
g_task_propagate_pointer, g_task_return_error, g_task_return_pointer,
};
use glib::{
DateTime,
ffi::{GDateTime, GError, gpointer},
gobject_ffi::{GObject, g_object_unref},
prelude::*,
subclass::prelude::*,
translate::*,
};
use crate::{Manager, Subscription, ffi};
pub trait ManagerImpl: ObjectImpl + ObjectSubclass<Type: IsA<Manager>> {
fn search_events(&self, search: &str) -> crate::Result<gio::ListStore> {
self.parent_search_events(search)
}
fn search_events_future(&self, search: &str) -> crate::PinnedFutureResult<gio::ListStore> {
self.parent_search_events_future(search)
}
fn new_subscription(&self, start: &DateTime, end: &DateTime) -> crate::Result<Subscription> {
self.parent_new_subscription(start, end)
}
}
pub trait ManagerImplExt: ManagerImpl {
fn parent_search_events(&self, search: &str) -> crate::Result<gio::ListStore> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::ClepsydreManagerClass;
if let Some(f) = (*parent_class).search_events {
let mut error = ptr::null_mut();
let result = f(
self.obj().unsafe_cast_ref::<Manager>().to_glib_none().0,
search.to_glib_none().0,
&mut error,
);
if error.is_null() {
Ok(from_glib_full(result))
} else {
Err(from_glib_full(error))
}
} else {
unimplemented!()
}
}
}
fn parent_search_events_future(
&self,
search: &str,
) -> crate::PinnedFutureResult<gio::ListStore> {
struct ManagerListStoreAsyncData {
finish: unsafe extern "C" fn(
*mut ClepsydreManager,
*mut GAsyncResult,
*mut *mut GError,
) -> *mut GListStore,
sender: gio::GioFutureResult<crate::Result<gio::ListStore>>,
}
unsafe extern "C" fn manager_parent_search_events_trampoline(
source_object: *mut GObject,
result: *mut GAsyncResult,
user_data: gpointer,
) {
unsafe {
let data = Box::from_raw(user_data as *mut ManagerListStoreAsyncData);
let mut error = ptr::null_mut();
let store_ptr =
(data.finish)(source_object as *mut ClepsydreManager, result, &mut error);
let result = if error.is_null() {
Ok(from_glib_full(store_ptr))
} else {
Err(from_glib_full(error))
};
data.sender.resolve(result);
}
}
let search = search.to_string();
let obj = self.obj();
let manager = unsafe { obj.unsafe_cast_ref::<Manager>() };
Box::pin(gio::GioFuture::new(
manager,
move |obj, cancellable, send| unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::ClepsydreManagerClass;
match (
(*parent_class).search_events_async,
(*parent_class).search_events_finish,
) {
(Some(async_fn), Some(finish_fn)) => {
let user_data = Box::new(ManagerListStoreAsyncData {
finish: finish_fn,
sender: send,
});
async_fn(
obj.to_glib_none().0,
search.to_glib_none().0,
cancellable.to_glib_none().0,
Some(manager_parent_search_events_trampoline),
Box::into_raw(user_data) as gpointer,
);
}
_ => unimplemented!(),
}
},
))
}
fn parent_new_subscription(
&self,
start: &DateTime,
end: &DateTime,
) -> crate::Result<Subscription> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::ClepsydreManagerClass;
if let Some(f) = (*parent_class).new_subscription {
let mut error = ptr::null_mut();
let result = f(
self.obj().unsafe_cast_ref::<Manager>().to_glib_none().0,
start.to_glib_none().0,
end.to_glib_none().0,
&mut error,
);
if error.is_null() {
Ok(from_glib_full(result))
} else {
Err(from_glib_full(error))
}
} else {
unimplemented!()
}
}
}
}
impl<T: ManagerImpl> ManagerImplExt for T {}
unsafe impl<T: ManagerImpl> IsSubclassable<T> for Manager {
fn class_init(class: &mut ::glib::Class<Self>) {
Self::parent_class_init::<T>(class);
let klass = class.as_mut();
klass.search_events = Some(manager_search_events::<T>);
klass.search_events_async = Some(manager_search_events_async::<T>);
klass.search_events_finish = Some(manager_search_events_finish);
klass.new_subscription = Some(manager_new_subscription::<T>);
}
}
unsafe extern "C" fn manager_search_events<T: ManagerImpl>(
manager_ptr: *mut ClepsydreManager,
search_ptr: *const c_char,
error_ptr: *mut *mut GError,
) -> *mut GListStore {
unsafe {
let instance = &*(manager_ptr as *mut T::Instance);
let imp = instance.imp();
let search = glib::GStr::from_ptr(search_ptr).as_str();
match imp.search_events(search) {
Ok(store) => store.to_glib_full(),
Err(error) => {
if !error_ptr.is_null() {
*error_ptr = error.into_glib_ptr();
}
ptr::null_mut()
}
}
}
}
unsafe extern "C" fn manager_search_events_async<T: ManagerImpl>(
manager_ptr: *mut ffi::ClepsydreManager,
search_ptr: *const c_char,
cancellable: *mut GCancellable,
callback: GAsyncReadyCallback,
user_data: gpointer,
) {
unsafe {
let task = g_task_new(manager_ptr as *mut _, cancellable, callback, user_data);
let instance = &*(manager_ptr as *mut T::Instance);
let imp = instance.imp();
let search = glib::GStr::from_ptr(search_ptr).to_string().leak();
let future = imp.search_events_future(search);
glib::MainContext::ref_thread_default().spawn_local(async move {
match future.await {
Ok(store) => {
let store_ptr: *mut GListStore = store.to_glib_full();
g_task_return_pointer(
task,
store_ptr as gpointer,
Some(std::mem::transmute::<
unsafe extern "C" fn(*mut GObject),
unsafe extern "C" fn(gpointer),
>(g_object_unref)),
);
}
Err(error) => g_task_return_error(task, error.into_glib_ptr()),
}
g_object_unref(task as *mut _);
});
}
}
unsafe extern "C" fn manager_search_events_finish(
_manager_ptr: *mut ClepsydreManager,
async_result: *mut GAsyncResult,
error_ptr: *mut *mut GError,
) -> *mut GListStore {
unsafe { g_task_propagate_pointer(async_result as *mut _, error_ptr) as *mut _ }
}
unsafe extern "C" fn manager_new_subscription<T: ManagerImpl>(
manager_ptr: *mut ClepsydreManager,
start_ptr: *mut GDateTime,
end_ptr: *mut GDateTime,
error_ptr: *mut *mut GError,
) -> *mut ClepsydreSubscription {
unsafe {
let instance = &*(manager_ptr as *mut T::Instance);
let imp = instance.imp();
let start = DateTime::from_glib_borrow(start_ptr);
let end = DateTime::from_glib_borrow(end_ptr);
match imp.new_subscription(&start, &end) {
Ok(subscription) => subscription.to_glib_full(),
Err(error) => {
if !error_ptr.is_null() {
*error_ptr = error.into_glib_ptr();
}
ptr::null_mut()
}
}
}
}
#[allow(clippy::missing_safety_doc)]
pub unsafe trait ManagerClassExt: ClassStruct {}
unsafe impl<T: ClassStruct> ManagerClassExt for T where T::Type: ManagerImpl {}