use std::marker::PhantomData;
use libloading::{Library, Symbol};
use crate::{FAsProxy, FProxyFrom, FToC};
type RustIterator<T> = Box<dyn Iterator<Item = T>>;
impl<'l, T> FAsProxy<'l> for RustIterator<T>
where
T: FToC + FAsProxy<'l>,
{
type FSelf = FIterator<'l, T::FSelf, T::CType>;
}
impl<T: FToC> FToC for RustIterator<T> {
type CType = *const ();
fn to_c(self) -> Self::CType {
let cont = FIterContainer::new(self);
let fdyn_iter = Box::new(cont) as Box<dyn FDynIterator>;
let boxed = Box::new(fdyn_iter);
Box::into_raw(boxed) as *const ()
}
}
pub struct FIterator<'l, Proxy, CType> {
proxy_marker: PhantomData<Proxy>,
c_marker: PhantomData<CType>,
handle: *const (), lib: &'l Library,
}
impl<'l, Proxy, CType> FProxyFrom<'l, *const ()> for FIterator<'l, Proxy, CType> {
fn proxy_from(handle: *const (), lib: &'l Library) -> Self {
FIterator {
proxy_marker: PhantomData,
c_marker: PhantomData,
handle,
lib,
}
}
}
pub struct FIterContainer<T: FToC> {
iterator: RustIterator<T>, next: Option<T::CType>, }
impl<T: FToC> FIterContainer<T> {
fn new(iterator: RustIterator<T>) -> Self {
FIterContainer {
iterator,
next: None,
}
}
}
impl<T: FToC> FDynIterator for FIterContainer<T> {
fn next(&mut self) -> *const () {
self.next = self.iterator.next().map(FToC::to_c);
if let Some(item) = self.next.as_ref() {
item as *const T::CType as *const ()
} else {
std::ptr::null()
}
}
}
trait FDynIterator {
fn next(&mut self) -> *const ();
}
impl<'l, Proxy, CType> Iterator for FIterator<'l, Proxy, CType>
where
Proxy: FProxyFrom<'l, CType>
{
type Item = Proxy;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let func: Symbol<unsafe extern "C" fn(*const ()) -> *const ()> =
self.lib.get(b"_fproxy_FIterator_next\0").unwrap();
let ptr = func(self.handle) as *const CType;
if ptr.is_null() {
return None;
}
let c_value: CType = std::mem::transmute_copy(&*ptr);
Some(FProxyFrom::proxy_from(c_value, &self.lib))
}
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn _fproxy_FIterator_next(handle: *const ()) -> *const () {
let fiter = unsafe { &mut *(handle as *mut Box<dyn FDynIterator>) };
fiter.next()
}