use std::{
any::TypeId,
fmt::{Debug, Formatter},
mem::{replace, take, transmute, transmute_copy},
ops::{Bound, RangeBounds},
ptr::{null, null_mut},
str::from_utf8,
sync::Arc,
};
use crate::{
report::{debug_unreachable, system_panic},
runtime::{
coercion::{Upcasted, UpcastedChain},
memory::{Grant, MemorySlice},
NumericOperationKind,
Origin,
RuntimeError,
RuntimeResult,
ScriptType,
TypeMeta,
Upcast,
},
};
pub trait MapRef<'a, From: 'static> {
type To: Upcast<'a>;
fn map(self, from: &'a From) -> RuntimeResult<Self::To>;
}
impl<'a, From, To, F> MapRef<'a, From> for F
where
From: 'static,
To: Upcast<'a>,
F: FnOnce(&'a From) -> RuntimeResult<To>,
{
type To = To;
#[inline(always)]
fn map(self, from: &'a From) -> RuntimeResult<Self::To> {
self(from)
}
}
pub trait MapMut<'a, From: 'static> {
type To: Upcast<'a>;
fn map(self, from: &'a mut From) -> RuntimeResult<Self::To>;
}
impl<'a, From, To, F> MapMut<'a, From> for F
where
From: 'static,
To: Upcast<'a>,
F: FnOnce(&'a mut From) -> RuntimeResult<To>,
{
type To = To;
#[inline(always)]
fn map(self, from: &'a mut From) -> RuntimeResult<Self::To> {
self(from)
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct Cell(Option<Arc<Chain>>);
impl Debug for Cell {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match &self.0 {
None => formatter.write_str("Nil"),
Some(chain) => Debug::fmt(chain, formatter),
}
}
}
impl Default for Cell {
#[inline(always)]
fn default() -> Self {
Self::nil()
}
}
impl Cell {
#[inline(always)]
pub const fn nil() -> Self {
Self(None)
}
pub fn give(origin: Origin, data: impl Upcast<'static>) -> RuntimeResult<Self> {
let to = match Upcast::upcast(origin, data)?.into_chain(origin)? {
UpcastedChain::Cell(cell) => return Ok(cell),
UpcastedChain::Slice(memory_slice) => memory_slice,
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from: Default::default(),
to,
grant: None,
})))))
}
pub fn give_vec<T: ScriptType>(origin: Origin, data: Vec<T>) -> RuntimeResult<Self> {
let to = match data.into_chain(origin)? {
UpcastedChain::Cell(cell) => return Ok(cell),
UpcastedChain::Slice(memory_slice) => memory_slice,
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from: Default::default(),
to,
grant: None,
})))))
}
#[inline(always)]
pub fn is_nil(&self) -> bool {
self.0.is_none()
}
#[inline(always)]
pub fn origin(&self) -> Origin {
match &self.0 {
None => Origin::Rust(TypeMeta::nil().origin()),
Some(chain) => chain.0.data_origin(),
}
}
#[inline(always)]
pub fn ty(&self) -> &'static TypeMeta {
match &self.0 {
None => TypeMeta::nil(),
Some(chain) => {
match chain.0.to.is_unicode() && chain.0.to.ty() == &TypeId::of::<u8>() {
true => <str>::type_meta(),
false => chain.0.to.ty(),
}
}
}
}
#[inline(always)]
pub fn is<T: ScriptType + ?Sized>(&self) -> bool {
let id = TypeId::of::<T>();
match &self.0 {
None => id == TypeId::of::<()>(),
Some(chain) => {
let ty = chain.0.to.ty();
if ty == &id {
return true;
}
let str_type = TypeId::of::<str>();
let u8_type = TypeId::of::<u8>();
chain.0.to.is_unicode() && ty == &u8_type && id == str_type
}
}
}
#[inline(always)]
pub fn length(&self) -> usize {
match &self.0 {
None => 0,
Some(chain) => chain.0.to.length(),
}
}
#[inline]
pub fn take<T: ScriptType>(mut self, origin: Origin) -> RuntimeResult<T> {
match take(&mut self.0) {
None => {
if TypeId::of::<T>() == TypeId::of::<()>() {
return Ok(unsafe { transmute_copy::<(), T>(&()) });
}
Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type: TypeMeta::nil(),
expected_types: Vec::from([T::type_meta()]),
})
}
Some(chain) => chain.take_first(origin),
}
}
pub fn take_vec<T: ScriptType>(mut self, origin: Origin) -> RuntimeResult<Vec<T>> {
match take(&mut self.0) {
None => {
if TypeId::of::<T>() == TypeId::of::<()>() {
let vector = Vec::from([(); 1]);
return Ok(unsafe { transmute_copy::<Vec<()>, Vec<T>>(&vector) });
}
Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type: TypeMeta::nil(),
expected_types: Vec::from([T::type_meta()]),
})
}
Some(chain) => chain.take_vec(origin),
}
}
pub fn take_string(mut self, origin: Origin) -> RuntimeResult<String> {
match take(&mut self.0) {
None => Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type: TypeMeta::nil(),
expected_types: Vec::from([<str>::type_meta()]),
}),
Some(chain) => {
let is_unicode = chain.0.to.is_unicode();
let bytes = chain.take_vec::<u8>(origin)?;
match is_unicode {
true => {
#[cfg(debug_assertions)]
{
match String::from_utf8(bytes) {
Ok(string) => Ok(string),
Err(error) => {
system_panic!(format!(
"Unicode byte slice decoding failure.\n{}",
error.utf8_error()
))
}
}
}
#[cfg(not(debug_assertions))]
{
Ok(unsafe { String::from_utf8_unchecked(bytes) })
}
}
false => Ok(String::from_utf8_lossy(bytes.as_ref()).into_owned()),
}
}
}
}
#[inline]
pub fn borrow_ref<T: ScriptType>(&mut self, origin: Origin) -> RuntimeResult<&T> {
let length = self.length();
if length != 1 {
return Err(RuntimeError::NonSingleton {
access_origin: origin,
actual: length,
});
}
let slice = self.borrow_slice_ref::<T>(origin)?;
match slice.first() {
Some(singleton) => Ok(singleton),
None => unsafe { debug_unreachable!("Missing slice first item.") },
}
}
pub fn borrow_slice_ref<T: ScriptType>(&mut self, origin: Origin) -> RuntimeResult<&[T]> {
match take(&mut self.0) {
None => Err(RuntimeError::Nil {
access_origin: origin,
}),
Some(chain) => {
let data_type = chain.0.to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
self.0 = Some(chain.value_ref(origin)?);
match &self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(unsafe { chain.0.to.as_slice_ref::<T>() }),
}
}
}
}
pub fn borrow_str(&mut self, origin: Origin) -> RuntimeResult<&str> {
match take(&mut self.0) {
None => Err(RuntimeError::Nil {
access_origin: origin,
}),
Some(chain) => {
let data_type = chain.0.to.ty();
let expected_type = <u8>::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
self.0 = Some(chain.value_ref(origin)?);
match &self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => {
let slice = unsafe { chain.0.to.as_slice_ref::<u8>() };
match chain.0.to.is_unicode() {
true => {
#[cfg(debug_assertions)]
{
match from_utf8(slice) {
Ok(string) => Ok(string),
Err(error) => {
system_panic!(format!(
"Unicode byte slice decoding failure.\n{}",
error
))
}
}
}
#[cfg(not(debug_assertions))]
{
Ok(unsafe { std::str::from_utf8_unchecked(slice) })
}
}
false => match from_utf8(slice) {
Ok(string) => Ok(string),
Err(error) => Err(RuntimeError::Utf8Decoding {
access_origin: origin,
cause: Box::new(error),
}),
},
}
}
}
}
}
}
#[inline]
pub fn borrow_mut<T: ScriptType>(&mut self, origin: Origin) -> RuntimeResult<&mut T> {
let length = self.length();
if length != 1 {
return Err(RuntimeError::NonSingleton {
access_origin: origin,
actual: length,
});
}
let slice = self.borrow_slice_mut::<T>(origin)?;
match slice.first_mut() {
Some(singleton) => Ok(singleton),
None => unsafe { debug_unreachable!("Missing slice first item.") },
}
}
pub fn borrow_slice_mut<'a, T: ScriptType>(
&'a mut self,
origin: Origin,
) -> RuntimeResult<&'a mut [T]> {
match take(&mut self.0) {
None => Err(RuntimeError::Nil {
access_origin: origin,
}),
Some(chain) => {
let data_type = chain.0.to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
self.0 = Some(chain.value_mut(origin)?);
match &self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(unsafe { chain.0.to.as_slice_mut::<T>() }),
}
}
}
}
pub fn map_str(mut self, origin: Origin) -> RuntimeResult<Self> {
let to = {
let from = self.borrow_str(origin)?;
let upcasted = Upcast::upcast(origin, from)?;
let to = upcasted.into_chain(origin)?;
to
};
let to = match to {
UpcastedChain::Cell(cell) => return Ok(cell),
UpcastedChain::Slice(slice) => slice,
};
let from = match to.is_owned() {
true => Self(None),
false => self,
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from,
to,
grant: None,
})))))
}
pub fn map_ref<From>(
mut self,
origin: Origin,
map: impl for<'a> MapRef<'a, From>,
) -> RuntimeResult<Self>
where
From: ScriptType,
{
let to = {
let from = self.borrow_ref::<From>(origin)?;
let mapped = map.map(from)?;
let upcasted = Upcast::upcast(origin, mapped)?;
let to = upcasted.into_chain(origin)?;
to
};
let to = match to {
UpcastedChain::Cell(cell) => return Ok(cell),
UpcastedChain::Slice(slice) => slice,
};
let from = match to.is_owned() {
true => Self(None),
false => self,
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from,
to,
grant: None,
})))))
}
pub fn map_mut<From>(
mut self,
origin: Origin,
map: impl for<'a> MapMut<'a, From>,
) -> RuntimeResult<Self>
where
From: ScriptType,
{
let to = {
let from = self.borrow_mut::<From>(origin)?;
let mapped = map.map(from)?;
let upcasted = Upcast::upcast(origin, mapped)?;
let to = upcasted.into_chain(origin)?;
to
};
let to = match to {
UpcastedChain::Cell(cell) => return Ok(cell),
UpcastedChain::Slice(slice) => slice,
};
let from = match to.is_owned() {
true => Self(None),
false => self,
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from,
to,
grant: None,
})))))
}
pub fn map_ptr<From, To>(
self,
origin: Origin,
by_ref: Option<unsafe fn(from: *const From) -> *const To>,
by_mut: Option<unsafe fn(from: *mut From) -> *mut To>,
) -> RuntimeResult<Self>
where
From: ScriptType,
To: ScriptType,
{
let chain = match self.0 {
Some(chain) => chain,
None => {
return Err(RuntimeError::Nil {
access_origin: origin,
})
}
};
let length = chain.0.to.length();
if length != 1 {
return Err(RuntimeError::NonSingleton {
access_origin: origin,
actual: length,
});
}
let data_type = chain.0.to.ty();
let expected_type = From::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type: chain.0.to.ty(),
expected_types: <Vec<_> as ::std::convert::From<[_; 1]>>::from([expected_type]),
});
}
let by_ref = match by_ref {
Some(by_ref) if chain.0.to.is_readable() => {
let place = chain.clone().place_ref(origin)?;
let from = unsafe { place.0.to.as_ptr_ref::<From>() };
let to = unsafe { by_ref(from) };
drop(place);
to
}
_ => null(),
};
let by_mut = match by_mut {
Some(by_mut) if chain.0.to.is_writeable() => {
let place = chain.clone().place_mut(origin)?;
let from = unsafe { place.0.to.as_ptr_mut::<From>() };
let to = unsafe { by_mut(from) };
drop(place);
to
}
_ => null_mut(),
};
if by_ref.is_null() && by_mut.is_null() {
return Ok(Self::default());
}
let to = unsafe { MemorySlice::register_ptr(origin, by_ref, by_mut) }?;
let from = match to.is_owned() {
true => Self(None),
false => Self(Some(chain)),
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from,
to,
grant: None,
})))))
}
pub fn map_slice(self, origin: Origin, bounds: impl RangeBounds<usize>) -> RuntimeResult<Self> {
let start_bound = match bounds.start_bound() {
Bound::Included(bound) => *bound,
Bound::Excluded(bound) => match bound.checked_add(1) {
Some(bound) => bound,
None => {
return Err(RuntimeError::NumericOperation {
invoke_origin: origin,
kind: NumericOperationKind::Add,
lhs: (<usize>::type_meta(), Arc::new(*bound)),
rhs: Some((<usize>::type_meta(), Arc::new(1))),
target: <usize>::type_meta(),
})
}
},
Bound::Unbounded => 0,
};
let end_bound = match bounds.end_bound() {
Bound::Included(bound) => match bound.checked_add(1) {
Some(bound) => bound,
None => {
return Err(RuntimeError::NumericOperation {
invoke_origin: origin,
kind: NumericOperationKind::Add,
lhs: (<usize>::type_meta(), Arc::new(*bound)),
rhs: Some((<usize>::type_meta(), Arc::new(1))),
target: <usize>::type_meta(),
})
}
},
Bound::Excluded(bound) => *bound,
Bound::Unbounded => self.length(),
};
if start_bound > end_bound {
return Err(RuntimeError::MalformedRange {
access_origin: origin,
start_bound,
end_bound,
});
}
let chain = match self.0 {
Some(chain) => chain,
None => return Ok(Self::nil()),
};
let length = chain.0.to.length();
if end_bound > length && chain.0.to.ty().size() > 0 {
return Err(RuntimeError::OutOfBounds {
access_origin: origin,
index: end_bound.checked_sub(1).unwrap_or_default(),
length,
});
}
let to =
match (chain.0.to.is_readable(), chain.0.to.is_writeable()) {
(false, false) => return Ok(Self::nil()),
(true, false) => unsafe {
chain.clone().place_ref(origin)?.0.to.subslice(
origin,
start_bound,
end_bound,
)?
},
(_, true) => unsafe {
chain.clone().place_mut(origin)?.0.to.subslice(
origin,
start_bound,
end_bound,
)?
},
};
let from = match to.is_owned() {
true => Self(None),
false => Self(Some(chain)),
};
Ok(Self(Some(Arc::new(Chain(ChainInner {
from,
to,
grant: None,
})))))
}
#[allow(unused)]
fn value_ref(mut self, origin: Origin) -> RuntimeResult<Self> {
if self.0.is_none() {
return Ok(self);
}
match self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(Self(Some(chain.value_ref(origin)?))),
}
}
#[allow(unused)]
fn value_mut(mut self, origin: Origin) -> RuntimeResult<Self> {
if self.0.is_none() {
return Ok(self);
}
match self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(Self(Some(chain.value_mut(origin)?))),
}
}
fn place_ref(self, origin: Origin) -> RuntimeResult<Self> {
if self.0.is_none() {
return Ok(self);
}
match self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(Self(Some(chain.place_ref(origin)?))),
}
}
fn place_mut(self, origin: Origin) -> RuntimeResult<Self> {
if self.0.is_none() {
return Ok(self);
}
match self.0 {
None => unsafe { debug_unreachable!("Nil Cell borrowing.") },
Some(chain) => Ok(Self(Some(chain.place_mut(origin)?))),
}
}
}
#[repr(transparent)]
struct Chain(ChainInner);
unsafe impl Send for Chain {}
unsafe impl Sync for Chain {}
impl Debug for Chain {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.0, formatter)
}
}
impl Drop for Chain {
fn drop(&mut self) {
self.0.release();
}
}
impl Chain {
#[inline(always)]
fn value_ref(self: Arc<Self>, origin: Origin) -> RuntimeResult<Arc<Self>> {
match Arc::try_unwrap(self) {
Err(this) => Ok(Arc::new(Self(this.0.value_ref(origin)?))),
Ok(this) => {
Ok(Arc::new(Self(unsafe {
this.into_inner().into_value_ref(origin)?
})))
}
}
}
#[inline(always)]
fn value_mut(self: Arc<Self>, origin: Origin) -> RuntimeResult<Arc<Self>> {
match Arc::try_unwrap(self) {
Err(this) => Ok(Arc::new(Self(this.0.value_mut(origin)?))),
Ok(this) => {
Ok(Arc::new(Self(unsafe {
this.into_inner().into_value_mut(origin)?
})))
}
}
}
#[inline(always)]
fn place_ref(self: Arc<Self>, origin: Origin) -> RuntimeResult<Arc<Self>> {
match Arc::try_unwrap(self) {
Err(this) => Ok(Arc::new(Self(this.0.place_ref(origin)?))),
Ok(this) => {
Ok(Arc::new(Self(unsafe {
this.into_inner().into_place_ref(origin)?
})))
}
}
}
#[inline(always)]
fn place_mut(self: Arc<Self>, origin: Origin) -> RuntimeResult<Arc<Self>> {
match Arc::try_unwrap(self) {
Err(this) => Ok(Arc::new(Self(this.0.place_mut(origin)?))),
Ok(this) => {
Ok(Arc::new(Self(unsafe {
this.into_inner().into_place_mut(origin)?
})))
}
}
}
#[inline(always)]
fn take_first<T: ScriptType>(self: Arc<Self>, origin: Origin) -> RuntimeResult<T> {
match Arc::try_unwrap(self) {
Err(this) => this.0.clone_inner_first(origin),
Ok(this) => {
unsafe { this.into_inner().take_first(origin) }
}
}
}
#[inline(always)]
fn take_vec<T: ScriptType>(self: Arc<Self>, origin: Origin) -> RuntimeResult<Vec<T>> {
match Arc::try_unwrap(self) {
Err(this) => Ok(this.0.clone_inner_slice(origin)?.into_vec()),
Ok(this) => {
unsafe { this.into_inner().take_vec(origin) }
}
}
}
#[inline(always)]
fn into_inner(self) -> ChainInner {
let mut inner = unsafe { transmute::<Self, ChainInner>(self) };
inner.release();
inner
}
}
struct ChainInner {
from: Cell,
to: Arc<MemorySlice>,
grant: Option<Grant>,
}
impl Debug for ChainInner {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Cell")
.field("from", &self.from)
.field("to", &self.to)
.field("grant", &self.grant)
.finish()
}
}
impl ChainInner {
#[inline(always)]
fn data_origin(&self) -> Origin {
match &self.grant {
None => *self.to.data_origin(),
Some(grant) => unsafe { self.to.grant_origin(grant) },
}
}
#[inline(always)]
fn value_ref(&self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_readable() {
return Err(RuntimeError::WriteOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
let from = self.from.clone().place_ref(origin)?;
let mut result = Self {
from,
to: self.to.clone(),
grant: None,
};
unsafe { result.grant_value_ref(origin)? };
Ok(result)
}
#[inline(always)]
fn value_mut(&self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_writeable() {
return Err(RuntimeError::ReadOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
let from = self.from.clone().place_mut(origin)?;
let mut result = Self {
from,
to: self.to.clone(),
grant: None,
};
unsafe { result.grant_value_mut(origin)? };
Ok(result)
}
#[inline(always)]
fn place_ref(&self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_readable() {
return Err(RuntimeError::WriteOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
let from = self.from.clone().place_ref(origin)?;
let mut result = Self {
from,
to: self.to.clone(),
grant: None,
};
unsafe { result.grant_place_ref(origin)? };
Ok(result)
}
#[inline(always)]
fn place_mut(&self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_writeable() {
return Err(RuntimeError::ReadOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
let from = self.from.clone().place_mut(origin)?;
let mut result = Self {
from,
to: self.to.clone(),
grant: None,
};
unsafe { result.grant_place_mut(origin)? };
Ok(result)
}
#[inline(always)]
fn clone_inner_first<T: ScriptType>(&self, origin: Origin) -> RuntimeResult<T> {
let data_type = self.to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
let prototype = expected_type.prototype();
match &self.grant {
Some(Grant::ValueRef(_)) | Some(Grant::ValueMut(_)) => {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
return unsafe {
prototype.clone_first::<T>(&origin, self.to.data_origin(), slice)
};
}
_ => (),
}
if self.to.is_readable() {
let grant = self.to.grant_value_ref(origin)?;
let first_clone = {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
unsafe { prototype.clone_first::<T>(&origin, self.to.data_origin(), slice) }
};
unsafe { self.to.release_grant(grant) };
return first_clone;
}
if self.to.is_writeable() {
let grant = self.to.grant_value_mut(origin)?;
let first_clone = {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
unsafe { prototype.clone_first::<T>(&origin, self.to.data_origin(), slice) }
};
unsafe { self.to.release_grant(grant) };
return Ok(first_clone?);
}
unsafe { debug_unreachable!("Chain without access.") }
}
#[inline(always)]
fn clone_inner_slice<T: ScriptType>(&self, origin: Origin) -> RuntimeResult<Box<[T]>> {
let data_type = self.to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
let prototype = expected_type.prototype();
match &self.grant {
Some(Grant::ValueRef(_)) | Some(Grant::ValueMut(_)) => {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
return unsafe {
prototype.clone_slice::<T>(&origin, self.to.data_origin(), slice)
};
}
_ => (),
}
if self.to.is_readable() {
let grant = self.to.grant_value_ref(origin)?;
let slice_clone = {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
unsafe { prototype.clone_slice::<T>(&origin, self.to.data_origin(), slice) }
};
unsafe { self.to.release_grant(grant) };
return slice_clone;
}
if self.to.is_writeable() {
let grant = self.to.grant_value_mut(origin)?;
let slice_clone = {
let slice: &[T] = unsafe { self.to.as_slice_ref::<T>() };
unsafe { prototype.clone_slice::<T>(&origin, self.to.data_origin(), slice) }
};
unsafe { self.to.release_grant(grant) };
return slice_clone;
}
unsafe { debug_unreachable!("Chain without access.") }
}
#[inline(always)]
unsafe fn into_value_ref(mut self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_readable() {
return Err(RuntimeError::WriteOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
self.from = self.from.place_ref(origin)?;
unsafe { self.grant_value_ref(origin)? };
Ok(self)
}
#[inline(always)]
unsafe fn into_value_mut(mut self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_writeable() {
return Err(RuntimeError::ReadOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
self.from = self.from.place_mut(origin)?;
unsafe { self.grant_value_mut(origin)? };
Ok(self)
}
#[inline(always)]
unsafe fn into_place_ref(mut self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_readable() {
return Err(RuntimeError::WriteOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
self.from = self.from.place_ref(origin)?;
unsafe { self.grant_place_ref(origin)? };
Ok(self)
}
#[inline(always)]
unsafe fn into_place_mut(mut self, origin: Origin) -> RuntimeResult<Self> {
if !self.to.is_writeable() {
return Err(RuntimeError::ReadOnly {
access_origin: origin,
data_origin: self.data_origin(),
});
}
self.from = self.from.place_mut(origin)?;
unsafe { self.grant_place_mut(origin)? };
Ok(self)
}
#[inline]
unsafe fn take_first<T: ScriptType>(mut self, origin: Origin) -> RuntimeResult<T> {
debug_assert!(
self.grant.is_none(),
"An attempt to move borrowed data out of Cell.",
);
if self.to.is_owned() {
self.to = match Arc::try_unwrap(self.to) {
Err(to) => to,
Ok(to) => {
let data_type = to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
let length = to.length();
if length != 1 {
return Err(RuntimeError::NonSingleton {
access_origin: origin,
actual: length,
});
}
let vector = unsafe { to.into_vec() };
return match vector.into_iter().next() {
Some(first) => Ok(first),
None => unsafe { debug_unreachable!("Missing slice first item.") },
};
}
}
}
self.clone_inner_first(origin)
}
#[inline]
unsafe fn take_vec<T: ScriptType>(mut self, origin: Origin) -> RuntimeResult<Vec<T>> {
debug_assert!(
self.grant.is_none(),
"An attempt to move borrowed data out of Cell.",
);
if self.to.is_owned() {
self.to = match Arc::try_unwrap(self.to) {
Err(to) => to,
Ok(to) => {
let data_type = to.ty();
let expected_type = T::type_meta();
if data_type != expected_type {
return Err(RuntimeError::TypeMismatch {
access_origin: origin,
data_type,
expected_types: Vec::from([expected_type]),
});
}
return Ok(unsafe { to.into_vec() });
}
}
}
Ok(self.clone_inner_slice(origin)?.into_vec())
}
#[inline(always)]
unsafe fn grant_value_ref(&mut self, origin: Origin) -> RuntimeResult<()> {
let grant = self.to.grant_value_ref(origin)?;
if replace(&mut self.grant, Some(grant)).is_some() {
unsafe {
debug_unreachable!("An attempt to set new borrow grant without prior release.");
}
}
Ok(())
}
#[inline(always)]
unsafe fn grant_value_mut(&mut self, origin: Origin) -> RuntimeResult<()> {
let grant = self.to.grant_value_mut(origin)?;
if replace(&mut self.grant, Some(grant)).is_some() {
unsafe {
debug_unreachable!("An attempt to set new borrow grant without prior release.");
}
}
Ok(())
}
#[inline(always)]
unsafe fn grant_place_ref(&mut self, origin: Origin) -> RuntimeResult<()> {
let grant = self.to.grant_place_ref(origin)?;
if replace(&mut self.grant, Some(grant)).is_some() {
unsafe {
debug_unreachable!("An attempt to set new borrow grant without prior release.");
}
}
Ok(())
}
#[inline(always)]
unsafe fn grant_place_mut(&mut self, origin: Origin) -> RuntimeResult<()> {
let grant = self.to.grant_place_mut(origin)?;
if replace(&mut self.grant, Some(grant)).is_some() {
unsafe {
debug_unreachable!("An attempt to set new borrow grant without prior release.");
}
}
Ok(())
}
#[inline(always)]
fn release(&mut self) {
if let Some(grant) = take(&mut self.grant) {
unsafe { self.to.release_grant(grant) }
}
}
}