use crate::interop::{InteropRecive,InteropSend,InteropClass};
use crate::Class;
use crate::gc::{GCHandle,gc_unsafe_enter,gc_unsafe_exit};
use crate::{Object,ObjectTrait};
use core::marker::PhantomData;
use crate::domain::Domain;
use crate::binds::MonoArray;
pub struct Array<const DIMENSIONS:u32,T:InteropSend + InteropRecive + InteropClass> where [();DIMENSIONS as usize]:Copy{
#[cfg(not(feature = "referneced_objects"))]
arr_ptr:*mut MonoArray,
#[cfg(feature = "referneced_objects")]
handle:GCHandle,
pd:PhantomData<T>,
lengths:[u32;DIMENSIONS as usize],
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
fn get_index(&self,indices:[usize;DIMENSIONS as usize])->usize{
let mut size = 1;
let mut index = 0;
for (n, ind) in indices.iter().enumerate(){
let len = self.lengths[n] as usize;
#[cfg(not(feature = "unsafe_arrays"))]
assert!(*ind < len,"index ({}) outside of array bound ({})",ind,len);
index += ind * size;
size *= len;
}
index
}
pub fn get(&self,indices:[usize;DIMENSIONS as usize])->T{
let index = self.get_index(indices);
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let src:T::SourceType = unsafe{*(crate::binds::mono_array_addr_with_size(self.get_ptr(),std::mem::size_of::<T::SourceType>() as i32,index) as *const T::SourceType)};
let rr = T::get_rust_rep(src);
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
rr
}
pub fn set(&mut self,indices:[usize;DIMENSIONS as usize],value:T){
let tmp = T::get_mono_rep(value);
let index = self.get_index(indices);
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let ptr = unsafe{crate::binds::mono_array_addr_with_size(
self.get_ptr(),std::mem::size_of::<T::TargetType>() as i32,index)
as *mut T::TargetType};
unsafe{(*ptr) = tmp};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
}
pub fn len(&self)->usize{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let len = unsafe{crate::binds::mono_array_length(self.get_ptr())};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
len
}
pub fn is_empty(&self)->bool{
0 == self.len()
}
pub unsafe fn from_ptr(ptr:*mut MonoArray)->Option<Self>{
use crate::{Method,MethodTrait};
if ptr.is_null(){
return None;
}
#[cfg(not(feature = "referneced_objects"))]
let mut res = Array{arr_ptr:ptr,pd:PhantomData,lengths:[0;DIMENSIONS as usize]};
#[cfg(feature = "referneced_objects")]
let mut res = Array{handle:GCHandle::create_default(ptr as *mut MonoObject),pd:PhantomData,lengths:[0;DIMENSIONS as usize]};
#[cfg(not(feature = "unsafe_arrays"))]
{
let rank = res.get_class().get_rank();
assert!(rank == DIMENSIONS,"Array dimension mismatch got:{}, expected:{}",rank,DIMENSIONS);
let sclass = res.to_object().get_class();
let tclass = <Self as InteropClass>::get_mono_class();
if sclass.get_element_class() != tclass.get_element_class(){
panic!("tried to create array of type `{}` from object of type `{}`",&tclass.get_name(),&sclass.get_name());
}
}
{
let dim:Method<i32> = Method::get_from_name(&Class::get_array(),"GetLength",1)
.expect("Array type does not have GetLength method, even toug it is impossible.");
for i in 0..DIMENSIONS{
let dim_obj = dim.invoke(Some(res.to_object()),i as i32).expect("Got an exception while calling Array.GetLength").expect("Got null instead of int");
res.lengths[i as usize] = dim_obj.unbox::<i32>() as u32;
}
}
Some(res)
}
pub fn to_object(&self)->Object{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let res = unsafe{Object::from_ptr(self.get_ptr() as *mut crate::binds::MonoObject)}.expect("Could not create object from array!");
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
pub fn new(domain:&Domain,size:&[usize;DIMENSIONS as usize])->Self{
let class = <T as InteropClass>::get_mono_class().get_array_class(DIMENSIONS);
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let arr = unsafe{Self::from_ptr(
crate::binds::mono_array_new_full(domain.get_ptr(),class.get_ptr(),size as *const [usize] as *mut usize,null_mut())
)}.expect("could not create a new array!");
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
arr
}
pub fn get_ptr(&self)->*mut crate::binds::MonoArray{
#[cfg(not(feature = "referneced_objects"))]
return self.arr_ptr;
#[cfg(feature = "referneced_objects")]
return self.handle.get_target() as *mut MonoArray;
}
pub fn clone_managed_array(&self)->Self{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let res = unsafe{Self::from_ptr(crate::binds::mono_array_clone(self.get_ptr()))}.expect("coud not create copy of an array!");
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
pub fn get_class()->Class{
Class::get_array_class(&<T as InteropClass>::get_mono_class(),DIMENSIONS)
}
pub fn get_lenghts(&self)->[u32; DIMENSIONS as usize]{
self.lengths
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> InteropRecive for Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
type SourceType = *mut crate::binds::MonoArray;
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn get_rust_rep(arg:Self::SourceType)->Self{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
use crate::exception::except_managed;
let opt = unsafe{Self::from_ptr(arg)};
let res = except_managed(opt,"Got null in an not nullable type. For nullable support use Option<Array>");
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> InteropSend for Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
type TargetType = *mut crate::binds::MonoArray;
fn get_mono_rep(arg:Self)->Self::TargetType{
arg.get_ptr()
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> InteropClass for Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
fn get_mono_class()->Class{
Self::get_class()
}
}
use core::ptr::null_mut;
use crate::binds::MonoObject;
use crate::mstring::MString;
use crate::Exception;
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> crate::object::ObjectTrait for Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
fn hash(&self)->i32{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let hash = unsafe{crate::binds::mono_object_hash(self.get_ptr() as *mut MonoObject)};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
hash
}
fn get_domain(&self)->crate::domain::Domain{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let dom = unsafe{crate::domain::Domain::from_ptr(crate::binds::mono_object_get_domain(self.get_ptr() as *mut MonoObject))};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
dom
}
fn get_size(&self)->u32{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let size = unsafe{crate::binds:: mono_object_get_size(self.get_ptr() as *mut MonoObject)};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
size
}
fn reflection_get_token(&self)->u32{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let token = unsafe{crate::binds::mono_reflection_get_token(self.get_ptr() as *mut MonoObject)};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
token
}
fn get_class(&self)->crate::class::Class{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let class = unsafe{crate::class::Class::from_ptr(
crate::binds::mono_object_get_class(self.get_ptr() as *mut MonoObject)
).expect("Could not get class of an object")};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
class
}
fn to_mstring(&self)->Result<Option<MString>,Exception>{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let mut exc:*mut crate::binds::MonoException = core::ptr::null_mut();
let res = unsafe{MString::from_ptr(
crate::binds::mono_object_to_string(self.get_ptr() as *mut crate::binds::MonoObject,&mut exc as *mut *mut crate::binds::MonoException as *mut *mut crate::binds::MonoObject)
)};
let exc = unsafe{Exception::from_ptr(exc)};
let res = match exc{
Some(e)=>Err(e),
None=>Ok(res),
};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
fn cast_to_object(&self)->Object{
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let obj = unsafe{Object::from_ptr(self.get_ptr() as *mut MonoObject)}.unwrap(); #[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
obj
}
fn cast_from_object(object:&Object)->Option<Array<DIMENSIONS,T>>{
let sclass = object.get_class();
let tclass = <Self as InteropClass>::get_mono_class();
if sclass.get_element_class() != tclass.get_element_class(){
return None;
}
unsafe{Self::from_ptr(object.get_ptr() as *mut crate::binds::MonoArray)}
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> InteropRecive for Option<Array<DIMENSIONS,T>> where [();DIMENSIONS as usize]:Copy{
type SourceType = *mut crate::binds::MonoArray;
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn get_rust_rep(arg:Self::SourceType)->Self{
unsafe{Array::<DIMENSIONS,T>::from_ptr(arg)}
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> InteropSend for Option<Array<DIMENSIONS,T>> where [();DIMENSIONS as usize]:Copy{
type TargetType = *mut crate::binds::MonoArray;
fn get_mono_rep(arg:Self)->Self::TargetType{
match arg{Some(arg)=>arg.get_ptr(),None=>null_mut()}
}
}
impl<T:InteropSend + InteropRecive + InteropClass, const DIMENSIONS:u32> Clone for Array<DIMENSIONS,T> where [();DIMENSIONS as usize]:Copy{
fn clone(&self)->Self{
unsafe{Self::from_ptr(self.get_ptr()).unwrap()} }
}
impl<const DIMENSIONS:u32,T:InteropSend + InteropRecive + InteropClass,O:ObjectTrait> PartialEq<O> for Array<DIMENSIONS, T> where [();DIMENSIONS as usize]:Copy{
fn eq(&self,other:&O)->bool{
self.get_ptr() as *mut _ == other.cast_to_object().get_ptr()
}
}
impl<T:InteropSend + InteropRecive + InteropClass + Clone> From<&[T]> for Array<1,T>{
fn from(src:&[T])->Self{
let size = src.len();
let dom = Domain::get_current().expect("Can't create arrays before JIT starts!");
let mut res:Array<1,T> = Array::new(&dom,&[size]);
for (i, src) in src.iter().enumerate(){
res.set([i],src.clone());
}
res
}
}