use std::{ops::Deref, ptr::NonNull};
use jlrs_sys::jlrs_array_data_owner;
use super::{
ArrayBase, Unknown,
data::accessor::{
BitsAccessor, BitsAccessorMut, BitsUnionAccessor, BitsUnionAccessorMut,
IndeterminateAccessor, IndeterminateAccessorMut, InlineAccessor, InlineAccessorMut,
ManagedAccessor, ManagedAccessorMut, ValueAccessor, ValueAccessorMut,
},
};
use crate::{
data::{
layout::{is_bits::IsBits, typed_layout::HasLayout, valid_layout::ValidField},
managed::{array::How, private::ManagedPriv},
types::{
construct_type::{BitsUnionCtor, ConstructType},
typecheck::Typecheck,
},
},
error::{ArrayLayoutError, CANNOT_DISPLAY_TYPE, TypeError},
memory::context::ledger::Ledger,
prelude::{JlrsResult, Managed, Value},
private::Private,
};
#[repr(transparent)]
pub struct TrackedArrayBase<'scope, 'data, T, const N: isize> {
data: ArrayBase<'scope, 'data, T, N>,
}
impl<'scope, 'data, T, const N: isize> TrackedArrayBase<'scope, 'data, T, N> {
pub fn bits_data<'borrow>(&'borrow self) -> BitsAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField + IsBits,
{
unsafe { BitsAccessor::new(&self.data) }
}
pub fn bits_data_with_layout<'borrow, L>(
&'borrow self,
) -> BitsAccessor<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'static, 'static, Layout = L>,
L: IsBits + ValidField,
{
unsafe { BitsAccessor::new(&self.data) }
}
pub fn try_bits_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<BitsAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: IsBits + ValidField,
{
if !self.has_bits_layout() {
Err(ArrayLayoutError::NotBits {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
unsafe { Ok(BitsAccessor::new(&self.data)) }
}
pub unsafe fn bits_data_unchecked<'borrow, L>(
&'borrow self,
) -> BitsAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: IsBits + ValidField,
{
unsafe { BitsAccessor::new(&self.data) }
}
pub fn inline_data<'borrow>(&'borrow self) -> InlineAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField,
{
unsafe { InlineAccessor::new(&self.data) }
}
pub fn inline_data_with_layout<'borrow, L>(
&'borrow self,
) -> InlineAccessor<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'scope, 'data, Layout = L>,
L: ValidField,
{
unsafe { InlineAccessor::new(&self.data) }
}
pub fn try_inline_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<InlineAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: ValidField,
{
if !self.has_inline_layout() {
Err(ArrayLayoutError::NotInline {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
unsafe { Ok(InlineAccessor::new(&self.data)) }
}
pub unsafe fn inline_data_unchecked<'borrow, L>(
&'borrow self,
) -> InlineAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: ValidField,
{
unsafe { InlineAccessor::new(&self.data) }
}
pub fn union_data<'borrow>(&'borrow self) -> BitsUnionAccessor<'borrow, 'scope, 'data, T, N>
where
T: BitsUnionCtor,
{
assert!(
self.has_union_layout(),
"Array does not have a union layout"
);
unsafe { BitsUnionAccessor::new(&self.data) }
}
pub fn try_union_data<'borrow>(
&'borrow self,
) -> JlrsResult<BitsUnionAccessor<'borrow, 'scope, 'data, T, N>> {
if !self.has_union_layout() {
Err(ArrayLayoutError::NotUnion {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
unsafe { Ok(BitsUnionAccessor::new(&self.data)) }
}
pub unsafe fn union_data_unchecked<'borrow>(
&'borrow self,
) -> BitsUnionAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { BitsUnionAccessor::new(&self.data) }
}
pub fn managed_data<'borrow>(&'borrow self) -> ManagedAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe { ManagedAccessor::new(&self.data) }
}
pub fn try_managed_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<ManagedAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: Managed<'scope, 'data> + Typecheck,
{
if !self.has_managed_layout::<L>() {
Err(ArrayLayoutError::NotManaged {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
name: L::NAME.into(),
})?;
}
unsafe { Ok(ManagedAccessor::new(&self.data)) }
}
pub unsafe fn managed_data_unchecked<'borrow, L>(
&'borrow self,
) -> ManagedAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: Managed<'scope, 'data>,
{
unsafe { ManagedAccessor::new(&self.data) }
}
pub fn value_data<'borrow>(&'borrow self) -> ValueAccessor<'borrow, 'scope, 'data, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe { ValueAccessor::new(&self.data) }
}
pub fn try_value_data<'borrow>(
&'borrow self,
) -> JlrsResult<ValueAccessor<'borrow, 'scope, 'data, T, N>> {
if !self.has_value_layout() {
Err(ArrayLayoutError::NotPointer {
element_type: self.element_type().error_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
unsafe { Ok(ValueAccessor::new(&self.data)) }
}
pub unsafe fn value_data_unchecked<'borrow>(
&'borrow self,
) -> ValueAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { ValueAccessor::new(&self.data) }
}
pub fn indeterminate_data<'borrow>(
&'borrow self,
) -> IndeterminateAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { IndeterminateAccessor::new(&self.data) }
}
}
impl<'scope, 'data, T, const N: isize> TrackedArrayBase<'scope, 'data, T, N> {
pub(crate) fn track_shared(array: ArrayBase<'scope, 'data, T, N>) -> JlrsResult<Self> {
unsafe {
let mut array_v = array.as_value();
if array.how() == How::PointerToOwner {
let owner = jlrs_array_data_owner(array.unwrap(Private));
array_v = Value::wrap_non_null(NonNull::new_unchecked(owner), Private);
}
let success = Ledger::try_borrow_shared(array_v)?;
assert!(success);
Ok(TrackedArrayBase { data: array })
}
}
}
impl<'scope, 'data, T, const N: isize> Clone for TrackedArrayBase<'scope, 'data, T, N> {
fn clone(&self) -> Self {
unsafe {
let array = self.data;
let mut array_v = array.as_value();
if array.how() == How::PointerToOwner {
let owner = jlrs_array_data_owner(array.unwrap(Private));
array_v = Value::wrap_non_null(NonNull::new_unchecked(owner), Private);
}
Ledger::try_borrow_shared(array_v).unwrap();
}
Self { data: self.data }
}
}
impl<'scope, 'data, T, const N: isize> Deref for TrackedArrayBase<'scope, 'data, T, N> {
type Target = ArrayBase<'scope, 'data, T, N>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T, const N: isize> Drop for TrackedArrayBase<'_, '_, T, N> {
fn drop(&mut self) {
unsafe {
let array = self.data;
let mut array_v = array.as_value();
if array.how() == How::PointerToOwner {
let owner = jlrs_array_data_owner(array.unwrap(Private));
array_v = Value::wrap_non_null(NonNull::new_unchecked(owner), Private);
}
let _success = Ledger::unborrow_shared(array_v).expect("Failed to untrack shared");
}
}
}
#[repr(transparent)]
pub struct TrackedArrayBaseMut<'scope, 'data, T, const N: isize> {
data: ArrayBase<'scope, 'data, T, N>,
}
impl<'scope, 'data, T, const N: isize> TrackedArrayBaseMut<'scope, 'data, T, N> {
pub unsafe fn bits_data_mut<'borrow>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField + IsBits,
{
unsafe {
BitsAccessorMut::new(&mut self.data)
}
}
pub unsafe fn bits_data_mut_with_layout<'borrow, L>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
T: HasLayout<'static, 'static, Layout = L>,
L: IsBits + ValidField,
{
unsafe {
BitsAccessorMut::new(&mut self.data)
}
}
pub unsafe fn try_bits_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: IsBits + ValidField,
{
unsafe {
if !self.has_bits_layout() {
Err(ArrayLayoutError::NotBits {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsAccessorMut::new(&mut self.data))
}
}
pub unsafe fn bits_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: IsBits + ValidField,
{
unsafe { BitsAccessorMut::new(&mut self.data) }
}
pub unsafe fn inline_data_mut<'borrow>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField,
{
unsafe {
InlineAccessorMut::new(&mut self.data)
}
}
pub unsafe fn inline_data_mut_with_layout<'borrow, L>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'scope, 'data, Layout = L>,
L: ValidField,
{
unsafe {
InlineAccessorMut::new(&mut self.data)
}
}
pub unsafe fn try_inline_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: ValidField,
{
unsafe {
if !self.has_inline_layout() {
Err(ArrayLayoutError::NotInline {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(InlineAccessorMut::new(&mut self.data))
}
}
pub unsafe fn inline_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: ValidField,
{
unsafe { InlineAccessorMut::new(&mut self.data) }
}
pub unsafe fn union_data_mut<'borrow>(
&'borrow mut self,
) -> BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N>
where
T: BitsUnionCtor,
{
unsafe {
assert!(
self.has_union_layout(),
"Array does not have a union layout"
);
BitsUnionAccessorMut::new(&mut self.data)
}
}
pub unsafe fn try_union_data_mut<'borrow>(
&'borrow mut self,
) -> JlrsResult<BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_union_layout() {
Err(ArrayLayoutError::NotUnion {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsUnionAccessorMut::new(&mut self.data))
}
}
pub unsafe fn union_data_mut_unchecked<'borrow>(
&'borrow mut self,
) -> BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { BitsUnionAccessorMut::new(&mut self.data) }
}
pub unsafe fn managed_data_mut<'borrow>(
&'borrow mut self,
) -> ManagedAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ManagedAccessorMut::new(&mut self.data)
}
}
pub unsafe fn try_managed_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<ManagedAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: Managed<'scope, 'data> + Typecheck,
{
unsafe {
if !self.has_managed_layout::<L>() {
Err(ArrayLayoutError::NotManaged {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
name: L::NAME.into(),
})?;
}
Ok(ManagedAccessorMut::new(&mut self.data))
}
}
pub unsafe fn managed_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> ManagedAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: Managed<'scope, 'data>,
{
unsafe { ManagedAccessorMut::new(&mut self.data) }
}
pub unsafe fn value_data_mut<'borrow>(
&'borrow mut self,
) -> ValueAccessorMut<'borrow, 'scope, 'data, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ValueAccessorMut::new(&mut self.data)
}
}
pub unsafe fn try_value_data_mut<'borrow>(
&'borrow mut self,
) -> JlrsResult<ValueAccessorMut<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_value_layout() {
Err(ArrayLayoutError::NotPointer {
element_type: self.element_type().error_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(ValueAccessorMut::new(&mut self.data))
}
}
pub unsafe fn value_data_mut_unchecked<'borrow>(
&'borrow mut self,
) -> ValueAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { ValueAccessorMut::new(&mut self.data) }
}
pub unsafe fn indeterminate_data_mut<'borrow>(
&'borrow mut self,
) -> IndeterminateAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { IndeterminateAccessorMut::new(&mut self.data) }
}
}
impl<'scope, 'data, T, const N: isize> TrackedArrayBaseMut<'scope, 'data, T, N> {
pub(crate) fn track_exclusive(array: ArrayBase<'scope, 'data, T, N>) -> JlrsResult<Self> {
unsafe {
let mut array_v = array.as_value();
if array.how() == How::PointerToOwner {
let owner = jlrs_array_data_owner(array.unwrap(Private));
array_v = Value::wrap_non_null(NonNull::new_unchecked(owner), Private);
}
let success = Ledger::try_borrow_exclusive(array_v)?;
assert!(success);
Ok(TrackedArrayBaseMut { data: array })
}
}
}
impl<'scope, 'data, T, const N: isize> Deref for TrackedArrayBaseMut<'scope, 'data, T, N> {
type Target = TrackedArrayBase<'scope, 'data, T, N>;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(self) }
}
}
impl<T, const N: isize> Drop for TrackedArrayBaseMut<'_, '_, T, N> {
fn drop(&mut self) {
unsafe {
let array = self.data;
let mut array_v = array.as_value();
if array.how() == How::PointerToOwner {
let owner = jlrs_array_data_owner(array.unwrap(Private));
array_v = Value::wrap_non_null(NonNull::new_unchecked(owner), Private);
}
let success = Ledger::unborrow_exclusive(array_v).expect("Failed to untrack shared");
assert!(success);
}
}
}
pub type TrackedArray<'scope, 'data> = TrackedArrayBase<'scope, 'data, Unknown, -1>;
pub type TrackedTypedArray<'scope, 'data, T> = TrackedArrayBase<'scope, 'data, T, -1>;
pub type TrackedRankedArray<'scope, 'data, const N: isize> =
TrackedArrayBase<'scope, 'data, Unknown, N>;
pub type TrackedTypedRankedArray<'scope, 'data, T, const N: isize> =
TrackedArrayBase<'scope, 'data, T, N>;
pub type TrackedVector<'scope, 'data> = TrackedArrayBase<'scope, 'data, Unknown, 1>;
pub type TrackedTypedVector<'scope, 'data, T> = TrackedArrayBase<'scope, 'data, T, 1>;
pub type TrackedMatrix<'scope, 'data> = TrackedArrayBase<'scope, 'data, Unknown, 2>;
pub type TrackedTypedMatrix<'scope, 'data, T> = TrackedArrayBase<'scope, 'data, T, 2>;
pub type TrackedArrayMut<'scope, 'data> = TrackedArrayBaseMut<'scope, 'data, Unknown, -1>;
pub type TrackedTypedArrayMut<'scope, 'data, T> = TrackedArrayBaseMut<'scope, 'data, T, -1>;
pub type TrackedRankedArrayMut<'scope, 'data, const N: isize> =
TrackedArrayBaseMut<'scope, 'data, Unknown, N>;
pub type TrackedTypedRankedArrayMut<'scope, 'data, T, const N: isize> =
TrackedArrayBaseMut<'scope, 'data, T, N>;
pub type TrackedVectorMut<'scope, 'data> = TrackedArrayBaseMut<'scope, 'data, Unknown, 1>;
pub type TrackedTypedVectorMut<'scope, 'data, T> = TrackedArrayBaseMut<'scope, 'data, T, 1>;
pub type TrackedMatrixMut<'scope, 'data> = TrackedArrayBaseMut<'scope, 'data, Unknown, 2>;
pub type TrackedTypedMatrixMut<'scope, 'data, T> = TrackedArrayBaseMut<'scope, 'data, T, 2>;