use std::{ffi::c_char, ptr};
use ffi::{ClepsydreCalendar, ClepsydreCollection};
use gio::ffi::{
GAsyncReadyCallback, GAsyncResult, GCancellable, g_task_new, g_task_propagate_pointer,
g_task_return_error, g_task_return_pointer,
};
use glib::{
ffi::{GError, gpointer},
gobject_ffi::{GObject, g_object_unref},
prelude::*,
subclass::prelude::*,
translate::*,
};
use crate::{Calendar, Collection, PinnedFutureResult, Result};
pub trait CollectionImpl: ObjectImpl + ObjectSubclass<Type: IsA<Collection>> {
fn try_create_calendar(&self, answer: &str) -> Result<Calendar> {
self.parent_try_create_calendar(answer)
}
fn try_create_calendar_future(&self, answer: String) -> PinnedFutureResult<Calendar> {
self.parent_try_create_calendar_future(answer)
}
}
pub trait CollectionImplExt: CollectionImpl {
fn parent_try_create_calendar(&self, answer: &str) -> Result<Calendar> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::ClepsydreCollectionClass;
if let Some(f) = (*parent_class).try_create_calendar {
let mut error = ptr::null_mut();
let result = f(
self.obj().unsafe_cast_ref::<Collection>().to_glib_none().0,
answer.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_try_create_calendar_future(&self, _answer: String) -> PinnedFutureResult<Calendar> {
unimplemented!()
}
}
impl<T: CollectionImpl> CollectionImplExt for T {}
unsafe impl<T: CollectionImpl> IsSubclassable<T> for Collection {
fn class_init(class: &mut ::glib::Class<Self>) {
Self::parent_class_init::<T>(class);
let klass = class.as_mut();
klass.try_create_calendar = Some(manager_try_create_calendar::<T>);
klass.try_create_calendar_async = Some(manager_try_create_calendar_async::<T>);
klass.try_create_calendar_finish = Some(manager_try_create_calendar_finish);
}
}
unsafe extern "C" fn manager_try_create_calendar<T: CollectionImpl>(
collection_ptr: *mut ClepsydreCollection,
answer_ptr: *const c_char,
error_ptr: *mut *mut GError,
) -> *mut ClepsydreCalendar {
unsafe {
let instance = &*(collection_ptr as *mut T::Instance);
let imp = instance.imp();
let answer = glib::GStr::from_ptr(answer_ptr).as_str();
match imp.try_create_calendar(answer) {
Ok(calendar) => calendar.to_glib_full(),
Err(error) => {
if !error_ptr.is_null() {
*error_ptr = error.into_glib_ptr();
}
ptr::null_mut()
}
}
}
}
unsafe extern "C" fn manager_try_create_calendar_async<T: CollectionImpl>(
collection_ptr: *mut ClepsydreCollection,
answer_ptr: *const c_char,
cancellable: *mut GCancellable,
callback: GAsyncReadyCallback,
user_data: gpointer,
) {
unsafe {
let task = g_task_new(collection_ptr as *mut _, cancellable, callback, user_data);
let instance = &*(collection_ptr as *mut T::Instance);
let imp = instance.imp();
let answer = glib::GStr::from_ptr(answer_ptr).to_string();
let future = imp.try_create_calendar_future(answer);
glib::MainContext::ref_thread_default().spawn_local(async move {
match future.await {
Ok(calendar) => {
let calendar_ptr: *mut ClepsydreCalendar = calendar.to_glib_full();
g_task_return_pointer(
task,
calendar_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_try_create_calendar_finish(
_collection_ptr: *mut ClepsydreCollection,
async_result: *mut GAsyncResult,
error_ptr: *mut *mut GError,
) -> *mut ClepsydreCalendar {
unsafe { g_task_propagate_pointer(async_result as *mut _, error_ptr) as *mut _ }
}
#[allow(clippy::missing_safety_doc)]
pub unsafe trait CollectionClassExt: ClassStruct {}
unsafe impl<T: ClassStruct> CollectionClassExt for T where T::Type: CollectionImpl {}