pr47 0.1.4-CHARLIE

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::exception::{ExceptionInner, UncheckedException};
use crate::data::generic::GenericTypeRef;
use crate::data::traits::{StaticBase};
use crate::data::wrapper::{OwnershipInfo, Wrapper};
use crate::data::wrapper::{
    OWN_INFO_GLOBAL_MASK,
    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 LockedCtx: VMContext + Send {}

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

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

pub trait AsyncFunctionBase: 'static {
    fn signature(tyck_info_pool: &mut TyckInfoPool) -> Signature;

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

pub trait AsyncFunction<LC: LockedCtx, ACTX: AsyncVMContext>: 'static {
    fn signature(&self, tyck_info_pool: &mut TyckInfoPool) -> Signature;

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

impl<AFBase, LC, ACTX> AsyncFunction<LC, ACTX> for AFBase where
    AFBase: AsyncFunctionBase,
    LC: LockedCtx,
    ACTX: AsyncVMContext<Locked=LC>
{
    fn signature(&self, tyck_info_pool: &mut TyckInfoPool) -> Signature {
        <AFBase as AsyncFunctionBase>::signature(tyck_info_pool)
    }

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

pub struct AsyncResetGuard {
    wrapper_ptr: *mut Wrapper<()>,
    original: u8
}

impl Drop for AsyncResetGuard {
    fn drop(&mut self) {
        let wrapper_ref: &mut Wrapper<()> = unsafe { &mut *self.wrapper_ptr };
        wrapper_ref.ownership_info = self.original;
    }
}

unsafe impl Send for AsyncResetGuard {}
unsafe impl Sync for AsyncResetGuard {}

pub struct AsyncShareGuard {
    wrapper_ptr: *mut Wrapper<()>
}

impl Drop for AsyncShareGuard {
    fn drop(&mut self) {
        let wrapper_ref: &mut Wrapper<()> = unsafe { &mut *self.wrapper_ptr };
        if wrapper_ref.ownership_info & OWN_INFO_GLOBAL_MASK == 0 {
            wrapper_ref.refcount -= 1;
            if wrapper_ref.refcount == 0 {
                wrapper_ref.ownership_info = wrapper_ref.ownership_info2;
            }
        }
    }
}

unsafe impl Send for AsyncShareGuard {}
unsafe impl Sync for AsyncShareGuard {}

pub trait AsyncReturnType<LC: LockedCtx> : Send + Sync {
    fn is_err(&self) -> bool;

    fn resolve(
        self: Box<Self>,
        locked_ctx: &mut LC,
        dests: &[*mut Value]
    ) -> Result<usize, ExceptionInner>;
}

pub type PromiseResult<LC> = Box<dyn AsyncReturnType<LC>>;

pub struct Promise<LC: LockedCtx>(pub Pin<Box<dyn Future<Output=PromiseResult<LC>> + Send>>);

impl<LC: LockedCtx> StaticBase<Promise<LC>> 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_check,
    value_move_out_check_norm,
    value_move_out_check_norm_noalias,
    value_move_out_norm,
    value_move_out_norm_noalias
};
use crate::data::tyck::TyckInfoPool;
use crate::ffi::sync_fn::VMContext;

#[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_GLOBAL_MASK == 0 {
            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::Unchecked(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::Unchecked(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::Unchecked(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::Unchecked(UncheckedException::OwnershipCheckFailure {
            object: value,
            expected_mask: OWN_INFO_WRITE_MASK
        }))
    }
}