pr47 0.1.3

A semi-experimental programming language. Still working in progress.
Documentation
use std::future::Future;
use std::pin::Pin;

use xjbutil::void::Void;

use crate::data::Value;
use crate::data::generic::GenericTypeRef;
use crate::data::exception::UncheckedException;
use crate::data::traits::{StaticBase};
use crate::data::wrapper::{OwnershipInfo, Wrapper};
use crate::data::wrapper::{
    OWN_INFO_OWNED_MASK,
    OWN_INFO_READ_MASK,
    OWN_INFO_WRITE_MASK
};
use crate::ffi::{FFIException, Signature};
use crate::util::serializer::{CoroutineSharedData, Serializer};

pub trait AsyncVMContext: 'static + Sized + Send + Sync {
    type VMData;

    fn serializer(&self) -> &Serializer<(CoroutineSharedData, Self::VMData)>;
}

pub trait AsyncFunctionBase: 'static {
    fn signature() -> Signature;

    fn call_tyck<ACTX: AsyncVMContext>(context: &ACTX, args: &[Value])
        -> Result<Promise, FFIException>;

    unsafe fn call_rtlc<ACTX: AsyncVMContext>(context: &ACTX, args: &[Value])
        -> Result<Promise, FFIException>;
}

pub trait AsyncFunction<ACTX: AsyncVMContext>: 'static {
    fn signature(&self) -> Signature;

    fn call_tyck(&self, context: &ACTX, args: &[Value]) -> Result<Promise, FFIException>;

    unsafe fn call_rtlc(&self, context: &ACTX, args: &[Value]) -> Result<Promise, FFIException>;
}

impl<AFBase, CTX> AsyncFunction<CTX> for AFBase where
    AFBase: AsyncFunctionBase,
    CTX: AsyncVMContext
{
    fn signature(&self) -> Signature {
        <AFBase as AsyncFunctionBase>::signature()
    }

    fn call_tyck(&self, context: &CTX, args: &[Value]) -> Result<Promise, FFIException> {
        <AFBase as AsyncFunctionBase>::call_tyck(context, args)
    }

    unsafe fn call_rtlc(&self, context: &CTX, args: &[Value]) -> Result<Promise, FFIException> {
        <AFBase as AsyncFunctionBase>::call_rtlc(context, args)
    }
}

#[derive(Copy, Clone)]
pub struct AsyncResetGuard {
    wrapper_ptr: *mut Wrapper<()>,
    original: u8
}

#[derive(Copy, Clone)]
pub struct AsyncShareGuard {
    wrapper_ptr: *mut Wrapper<()>
}

pub union AsyncOwnershipGuard {
    reset_guard: AsyncResetGuard,
    share_guard: AsyncShareGuard
}

impl AsyncOwnershipGuard {
    #[cfg_attr(not(debug_assertions), inline(always))]
    pub fn reset(&self) {
        let wrapper_ref: &mut Wrapper<()> = unsafe { &mut *self.reset_guard.wrapper_ptr };
        wrapper_ref.ownership_info = unsafe { self.reset_guard.original }
    }

    #[cfg_attr(not(debug_assertions), inline(always))]
    pub fn un_share(&self) {
        let wrapper_ref: &mut Wrapper<()> = unsafe { &mut *self.share_guard.wrapper_ptr };
        wrapper_ref.refcount -= 1;
        if wrapper_ref.refcount == 0 {
            wrapper_ref.ownership_info = wrapper_ref.ownership_info2;
        }
    }
}

impl From<AsyncResetGuard> for AsyncOwnershipGuard {
    fn from(reset_guard: AsyncResetGuard) -> Self {
        Self { reset_guard }
    }
}

impl From<AsyncShareGuard> for AsyncOwnershipGuard {
    #[inline(always)]
    fn from(share_guard: AsyncShareGuard) -> Self {
        Self { share_guard }
    }
}

pub struct AsyncReturnType(pub Result<Box<[Value]>, FFIException>);

unsafe impl Send for AsyncReturnType {}
unsafe impl Sync for AsyncReturnType {}

pub struct PromiseGuard {
    pub guards: Box<[AsyncOwnershipGuard]>,
    pub reset_guard_count: usize
}

impl Drop for PromiseGuard {
    fn drop(&mut self) {
        let guard_count: usize = self.guards.len();
        for i in 0..self.reset_guard_count {
            unsafe { self.guards.get_unchecked(i).reset() }
        }
        for i in self.reset_guard_count..guard_count {
            unsafe { self.guards.get_unchecked(i).un_share() }
        }
    }
}

pub struct Promise {
    pub fut: Pin<Box<dyn Future<Output=AsyncReturnType> + Send + 'static>>,
    pub guard: PromiseGuard
}

impl Unpin for Promise {}

impl Future for Promise {
    type Output = AsyncReturnType;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::into_inner(self).fut.poll_unpin(cx)
    }
}

impl StaticBase<Promise> for Void {
    fn type_name() -> String {
        "promise".to_string()
    }
}

pub use crate::ffi::sync_fn::{
    value_copy,
    value_copy_norm,
    value_move_out,
    value_move_out_norm,
    value_move_out_check,
    value_move_out_check_norm
};
use std::task::{Context, Poll};
use futures::FutureExt;

#[inline] pub unsafe fn value_into_ref<'a, T>(
    value: Value
) -> Result<(&'a T, AsyncShareGuard), FFIException>
    where T: 'static,
          Void: StaticBase<T>
{
    let wrapper_ptr: *mut Wrapper<()> = value.ptr_repr.ptr as *mut _;
    let original: u8 = (*wrapper_ptr).ownership_info;
    if original & OWN_INFO_READ_MASK != 0 {
        let data_ptr: *const T = value.get_as_mut_ptr_norm() as *const T;
        if original & OWN_INFO_WRITE_MASK != 0 {
            (*wrapper_ptr).ownership_info2 = original;
            (*wrapper_ptr).ownership_info = original & (OWN_INFO_READ_MASK | OWN_INFO_OWNED_MASK);
            (*wrapper_ptr).refcount = 1;
        } else {
            (*wrapper_ptr).refcount += 1;
        }
        Ok((
            &*data_ptr,
            AsyncShareGuard { wrapper_ptr }
        ))
    } else {
        Err(FFIException::Right(UncheckedException::OwnershipCheckFailure {
            object: value,
            expected_mask: OWN_INFO_READ_MASK
        }))
    }
}

#[inline] pub unsafe fn container_into_ref<CR>(
    value: Value
) -> Result<(CR, AsyncShareGuard), FFIException>
    where CR: GenericTypeRef
{
    let wrapper_ptr: *mut Wrapper<()> = value.untagged_ptr_field() as *mut _;
    let original: u8 = (*wrapper_ptr).ownership_info;
    if original & OWN_INFO_READ_MASK != 0 {
        if original != OwnershipInfo::SharedToRust as u8 {
            (*wrapper_ptr).ownership_info2 = original;
            (*wrapper_ptr).ownership_info = OwnershipInfo::SharedToRust as u8;
            (*wrapper_ptr).refcount = 1;
        } else {
            (*wrapper_ptr).refcount -= 1;
        }
        Ok((
            CR::create_ref(wrapper_ptr),
            AsyncShareGuard { wrapper_ptr }
        ))
    } else {
        Err(FFIException::Right(UncheckedException::OwnershipCheckFailure {
            object: value,
            expected_mask: OWN_INFO_READ_MASK
        }))
    }
}

#[inline] pub unsafe fn value_into_mut_ref<'a, T>(
    value: Value
) -> Result<(&'a mut T, AsyncResetGuard), FFIException>
    where T: 'static,
          Void: StaticBase<T>
{
    let wrapper_ptr: *mut Wrapper<()> = value.ptr_repr.ptr as *mut _;
    let original: u8 = (*wrapper_ptr).ownership_info;
    if original & OWN_INFO_WRITE_MASK != 0 {
        let data_ptr: *mut T = value.get_as_mut_ptr_norm() as *mut T;
        (*wrapper_ptr).ownership_info = OwnershipInfo::MutSharedToRust as u8;
        Ok((
            &mut *data_ptr,
            AsyncResetGuard { wrapper_ptr, original }
        ))
    } else {
        Err(FFIException::Right(UncheckedException::OwnershipCheckFailure {
            object: value,
            expected_mask: OWN_INFO_WRITE_MASK
        }))
    }
}

#[inline] pub unsafe fn container_into_mut_ref<CR>(
    value: Value
) -> Result<(CR, AsyncResetGuard), FFIException>
    where CR: GenericTypeRef
{
    let wrapper_ptr: *mut Wrapper<()> = value.untagged_ptr_field() as *mut _;
    let original: u8 = (*wrapper_ptr).ownership_info;
    if original & OWN_INFO_WRITE_MASK != 0 {
        (*wrapper_ptr).ownership_info = OwnershipInfo::MutSharedToRust as u8;
        Ok((
            CR::create_ref(wrapper_ptr),
            AsyncResetGuard { wrapper_ptr, original }
        ))
    } else {
        Err(FFIException::Right(UncheckedException::OwnershipCheckFailure {
            object: value,
            expected_mask: OWN_INFO_WRITE_MASK
        }))
    }
}