use alloc::format;
use crate::{
abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName},
api::{ErrorApi, ErrorApiImpl},
codec::{self, arrayvec::ArrayVec, NestedDecode, NestedEncode, TopDecode, TopEncode},
};
use core::marker::PhantomData;
const EMPTY_ENTRY: usize = 0;
static INVALID_INDEX_ERR_MSG: &[u8] = b"Index out of bounds";
#[derive(Clone)]
pub struct SparseArray<E, const CAPACITY: usize>
where
E: ErrorApi,
{
array: [usize; CAPACITY],
len: usize,
_phantom: PhantomData<E>,
}
impl<E, const CAPACITY: usize> SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
pub fn new(len: usize) -> Self {
if len > CAPACITY {
E::error_api_impl().signal_error(b"Length exceeds capacity");
}
SparseArray {
array: [0usize; CAPACITY],
len,
_phantom: PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn as_raw_slice(&self) -> &[usize] {
&self.array[..self.len]
}
pub fn get(&self, index: usize) -> usize {
self.require_valid_index(index);
self.get_item_unchecked(index)
}
pub fn set(&mut self, index: usize, value: usize) {
self.require_valid_index(index);
self.set_item_unchecked(index, value);
}
pub fn swap_remove(&mut self, index: usize) -> usize {
self.require_valid_index(index);
let last_item_index = self.len - 1;
let last_item = self.get_item_unchecked(last_item_index);
let current_item = if index != last_item_index {
let item_at_index = self.get_item_unchecked(index);
self.set_item_unchecked(index, last_item);
item_at_index
} else {
last_item
};
self.set_item_unchecked(last_item_index, EMPTY_ENTRY);
self.len -= 1;
current_item
}
fn get_item_unchecked(&self, index: usize) -> usize {
let value = self.array[index];
if value == EMPTY_ENTRY {
index
} else {
value
}
}
fn set_item_unchecked(&mut self, index: usize, value: usize) {
if index == value {
self.array[index] = EMPTY_ENTRY;
} else {
self.array[index] = value;
}
}
fn require_valid_index(&self, index: usize) {
if index >= self.len {
E::error_api_impl().signal_error(INVALID_INDEX_ERR_MSG);
}
}
pub fn iter(&self) -> SparseArrayIterator<E, CAPACITY> {
SparseArrayIterator::new(self)
}
}
impl<'a, E, const CAPACITY: usize> IntoIterator for &'a SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
type Item = usize;
type IntoIter = SparseArrayIterator<'a, E, CAPACITY>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct SparseArrayIterator<'a, E, const CAPACITY: usize>
where
E: ErrorApi,
{
array_ref: &'a SparseArray<E, CAPACITY>,
current_index: usize,
last_index: usize,
}
impl<'a, E, const CAPACITY: usize> SparseArrayIterator<'a, E, CAPACITY>
where
E: ErrorApi,
{
pub fn new(array: &'a SparseArray<E, CAPACITY>) -> Self {
Self {
array_ref: array,
current_index: 0,
last_index: array.len - 1,
}
}
}
impl<'a, E, const CAPACITY: usize> Iterator for SparseArrayIterator<'a, E, CAPACITY>
where
E: ErrorApi,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let next_index = self.current_index;
if next_index > self.last_index {
return None;
}
self.current_index += 1;
Some(self.array_ref.get(next_index))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.last_index - self.current_index + 1;
(remaining, Some(remaining))
}
}
impl<'a, E, const CAPACITY: usize> ExactSizeIterator for SparseArrayIterator<'a, E, CAPACITY> where
E: ErrorApi
{
}
impl<'a, E, const CAPACITY: usize> DoubleEndedIterator for SparseArrayIterator<'a, E, CAPACITY>
where
E: ErrorApi,
{
fn next_back(&mut self) -> Option<Self::Item> {
let next_index = self.last_index;
if next_index < self.current_index {
return None;
}
self.last_index -= 1;
Some(self.array_ref.get(next_index))
}
}
impl<'a, E, const CAPACITY: usize> Clone for SparseArrayIterator<'a, E, CAPACITY>
where
E: ErrorApi,
{
fn clone(&self) -> Self {
Self {
array_ref: self.array_ref,
current_index: self.current_index,
last_index: self.last_index,
}
}
}
impl<E, const CAPACITY: usize> TopEncode for SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
where
O: codec::TopEncodeOutput,
H: codec::EncodeErrorHandler,
{
let mut nested_buffer = output.start_nested_encode();
for item in self.iter() {
item.dep_encode_or_handle_err(&mut nested_buffer, h)?;
}
output.finalize_nested_encode(nested_buffer);
Ok(())
}
}
impl<E, const CAPACITY: usize> NestedEncode for SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
where
O: codec::NestedEncodeOutput,
H: codec::EncodeErrorHandler,
{
self.len.dep_encode_or_handle_err(dest, h)?;
for item in self.iter() {
item.dep_encode_or_handle_err(dest, h)?;
}
Ok(())
}
}
impl<E, const CAPACITY: usize> TopDecode for SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
where
I: codec::TopDecodeInput,
H: codec::DecodeErrorHandler,
{
match ArrayVec::<usize, CAPACITY>::top_decode(input) {
Ok(array_vec) => {
let len = array_vec.len();
let mut array = [0usize; CAPACITY];
let array_slice = &mut array[..len];
array_slice.copy_from_slice(array_vec.as_slice());
Ok(Self {
array,
len: array_vec.len(),
_phantom: PhantomData,
})
},
Err(e) => Err(h.handle_error(e)),
}
}
}
impl<E, const CAPACITY: usize> NestedDecode for SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
where
I: codec::NestedDecodeInput,
H: codec::DecodeErrorHandler,
{
match ArrayVec::<usize, CAPACITY>::dep_decode(input) {
Ok(array_vec) => {
let len = array_vec.len();
let mut array = [0usize; CAPACITY];
let array_slice = &mut array[..len];
array_slice.copy_from_slice(array_vec.as_slice());
Ok(Self {
array,
len: array_vec.len(),
_phantom: PhantomData,
})
},
Err(e) => Err(h.handle_error(e)),
}
}
}
impl<E, const CAPACITY: usize> TypeAbiFrom<Self> for SparseArray<E, CAPACITY> where E: ErrorApi {}
impl<E, const CAPACITY: usize> TypeAbiFrom<&Self> for SparseArray<E, CAPACITY> where E: ErrorApi {}
impl<E, const CAPACITY: usize> TypeAbi for SparseArray<E, CAPACITY>
where
E: ErrorApi,
{
type Unmanaged = Self;
fn type_name() -> TypeName {
<&[usize] as TypeAbi>::type_name()
}
fn type_name_rust() -> TypeName {
format!("SparseArray<$API, {CAPACITY}usize>")
}
fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
usize::provide_type_descriptions(accumulator);
}
}