use std::marker::PhantomData;
#[cfg(feature="cons_mode")]
use std::mem;
#[cfg(feature="cons_mode")]
use std::ptr;
#[cfg(feature="cons_mode")]
use libc::*;
use crate::simulation;
use crate::simulation::point::Point;
use crate::simulation::event::Event;
#[cfg(feature="cons_mode")]
use crate::simulation::error::*;
#[inline]
pub fn cons_disposable<F>(f: F) -> Cons<F>
where F: FnOnce(&Point) -> simulation::Result<()>
{
Cons { f: f }
}
#[inline]
pub fn empty_disposable() -> Empty {
Empty {}
}
#[inline]
pub fn concat_disposables<I, M>(disposables: I) -> Concat<I::IntoIter, M>
where I: IntoIterator<Item = M>,
M: Disposable
{
Concat { disposables: disposables.into_iter(), _phantom: PhantomData }
}
#[inline]
pub fn trace_disposable<M>(msg: String, comp: M) -> Trace<M>
where M: Disposable
{
Trace { comp: comp, msg: msg}
}
pub trait Disposable {
#[doc(hidden)]
fn dispose(self, p: &Point) -> simulation::Result<()>;
#[inline]
fn into_event(self) -> DisposableEvent<Self>
where Self: Sized
{
DisposableEvent { disposable: self }
}
#[inline]
fn merge<U>(self, other: U) -> Merge<Self, U>
where Self: Sized,
U: Disposable
{
Merge { disposable: self, other: other }
}
#[inline]
fn into_boxed(self) -> DisposableBox
where Self: Sized + 'static
{
DisposableBox::new(move |p: &Point| { self.dispose(p) })
}
}
pub trait IntoDisposable {
type Disposable: Disposable;
fn into_disposable(self) -> Self::Disposable;
}
impl<M: Disposable> IntoDisposable for M {
type Disposable = M;
#[inline]
fn into_disposable(self) -> Self::Disposable {
self
}
}
pub struct DisposableBox {
f: Box<dyn DisposableFnBox>
}
impl DisposableBox {
#[doc(hidden)]
#[inline]
fn new<F>(f: F) -> Self
where F: FnOnce(&Point) -> simulation::Result<()> + 'static
{
DisposableBox {
f: Box::new(f)
}
}
#[doc(hidden)]
#[inline]
pub fn call_box(self, arg: (&Point,)) -> simulation::Result<()> {
let DisposableBox { f } = self;
f.call_box(arg)
}
}
impl Disposable for DisposableBox {
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
self.call_box((p,))
}
#[inline]
fn into_boxed(self) -> DisposableBox
where Self: Sized + 'static
{
self
}
}
trait DisposableFnBox {
fn call_box(self: Box<Self>, args: (&Point,)) -> simulation::Result<()>;
}
impl<F> DisposableFnBox for F
where F: for<'a> FnOnce(&'a Point) -> simulation::Result<()>
{
fn call_box(self: Box<Self>, args: (&Point,)) -> simulation::Result<()> {
let this: Self = *self;
this(args.0)
}
}
#[cfg(feature="cons_mode")]
#[repr(C)]
#[derive(Copy, Clone)]
struct DisposableTraitObject {
field1: *mut c_void,
field2: *mut c_void
}
#[cfg(feature="cons_mode")]
#[repr(C)]
pub struct DisposableRepr {
delete: unsafe extern "C" fn(obj: *mut DisposableTraitObject),
callback: unsafe extern "C" fn(obj: *mut DisposableTraitObject, p: *const Point) -> *mut ErrorRepr,
trait_object: DisposableTraitObject
}
#[cfg(feature="cons_mode")]
impl Drop for DisposableRepr {
fn drop(&mut self) {
unsafe {
(self.delete)(&mut self.trait_object);
}
}
}
#[cfg(feature="cons_mode")]
impl DisposableRepr {
#[inline]
pub fn into_repr(comp: DisposableBox) -> DisposableRepr {
unsafe {
DisposableRepr {
delete: delete_disposable_repr,
callback: call_disposable_repr,
trait_object: mem::transmute(comp)
}
}
}
#[inline]
fn call_repr(mut self, p: &Point) -> *mut ErrorRepr {
unsafe {
let x = (self.callback)(&mut self.trait_object, p);
mem::forget(self);
x
}
}
}
#[cfg(feature="cons_mode")]
unsafe extern "C" fn call_disposable_repr(comp: *mut DisposableTraitObject, p: *const Point) -> *mut ErrorRepr {
let comp: DisposableBox = mem::transmute(*comp);
match comp.call_box((&*p,)) {
Result::Ok(()) => ptr::null_mut(),
Result::Err(e) => {
let e = ErrorRepr::new(e);
Box::into_raw(Box::new(e))
}
}
}
#[cfg(feature="cons_mode")]
unsafe extern "C" fn delete_disposable_repr(comp: *mut DisposableTraitObject) {
let _: DisposableBox = mem::transmute(*comp);
}
#[cfg(feature="cons_mode")]
impl Disposable for DisposableRepr {
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
unsafe {
let e = self.call_repr(p);
if e == ptr::null_mut() {
Result::Ok(())
} else {
let e = ffi_error_repr_into_error(e);
Result::Err(e)
}
}
}
}
#[derive(Clone)]
pub struct Cons<F> {
f: F
}
impl<F> Disposable for Cons<F>
where F: FnOnce(&Point) -> simulation::Result<()>
{
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
let Cons { f } = self;
f(p)
}
}
#[derive(Clone)]
pub struct Empty {}
impl Disposable for Empty {
#[doc(hidden)]
#[inline]
fn dispose(self, _p: &Point) -> simulation::Result<()> {
Result::Ok(())
}
}
#[derive(Clone)]
pub struct Merge<M, U> {
disposable: M,
other: U
}
impl<M, U> Disposable for Merge<M, U>
where M: Disposable,
U: Disposable
{
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
let Merge { disposable, other } = self;
disposable.dispose(p)?;
other.dispose(p)
}
}
#[derive(Clone)]
pub struct DisposableEvent<D> {
disposable: D
}
impl<D> Event for DisposableEvent<D>
where D: Disposable
{
type Item = ();
#[doc(hidden)]
#[inline]
fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
let DisposableEvent { disposable } = self;
disposable.dispose(p)
}
}
#[derive(Clone)]
pub struct Concat<I, M> {
disposables: I,
_phantom: PhantomData<M>
}
impl<I, M> Disposable for Concat<I, M>
where I: Iterator<Item = M>,
M: Disposable
{
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
let Concat { disposables, _phantom } = self;
for disposable in disposables {
disposable.dispose(p)?;
}
Result::Ok(())
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Trace<M> {
comp: M,
msg: String
}
impl<M> Disposable for Trace<M>
where M: Disposable
{
#[doc(hidden)]
#[inline]
fn dispose(self, p: &Point) -> simulation::Result<()> {
let Trace { comp, msg } = self;
p.trace(&msg);
comp.dispose(p)
}
}