quickscript 0.5.5

A quick programming language with a compiler implemented in Rust.
Documentation
# Array<T>

- [Definition]#definition

## Definition

```rs
/// A resizable and movable array type.
///
/// #[example]
/// ```qs
/// let mut arr: Array<i32> = Array::new();
///
/// // Add an item into the array.
/// arr.push(1); // arr = [1]
/// arr += [2, 3, 4]; // arr = [1, 2, 3, 4]
/// arr = arr + 3; // arr = [1, 2, 3, 4, 3]
///
/// // Remove an item from the array.
/// arr.pop(1); // arr = [1, 3, 4, 3]
/// arr -= 3; // arr = [1, 3, 4]
/// arr = arr - 1; // arr = [1, 4]
///
/// // Get an item in the array.
/// let item = arr.get(0); // item = 1
/// let item = arr[1]; // item = 4
/// ```
///
/// == Serialization Info
///
/// An array is serialized into an array of bytes
/// on the stack. Here's an example:
///
/// QuickScript:
/// ```qs
/// let mut arr: Array<i32> = Array::of(1, 2, 3, 4, 5);
/// ```
///
/// The stack:
/// ```
/// [Length, Item Size, Endianness, Spacer, Items...                     ]
/// [5,      4,         0,          0,      1, 2, 3, 4, 5                ]
/// [0x5,    0x4,       0x0,        0x0,    0x1, 0x2, 0x3, 0x4, 0x5      ]
/// [0b101,  0b100,     0b0,        0b0,    0b1, 0b10, 0b11, 0b100, 0b101]
/// [u32,    u32,       u8,         u8,     ]
/// ```
///
/// A note on endianness:
/// Endianness is represented as 0 being little, and 1 being big.
@Stub
@Since(0.1, status = Status::Stable, feat = "arrays")
@Apply(Format, Clone, Sized)
@Cond(T: Copy, @Apply(Copy))
@Cond(T: Sync, @Apply(Sync))
pub struct Array<T> where T: Sized {
    internal mut len: u32,
    internal mut base_ptr: u32,
    internal mut alloc: Allocator,
}

@Since(0.1, status = Status::Stable, feat = "arrays")
impl<T> Array<T> {
    @Constructor
    pub fn new() -> Self {
        let alloc = Allocator::new();

        Self {
            len: 0,
            base_ptr: alloc.get_ptr(),
            alloc,
        }
    }

    pub fn of(...items: Array<T>) -> Self {
        let mut me = Self::new();

        me.push(items);

        me
    }

    @CanBe(i32, u32, type_var = O)
    pub fn len(&self) -> O {
        self.len as O
    }

    @OperandAlias(Operands::ArrayIndex)
    pub fn get(&self, idx: i32 | u32) -> Option<T> {
        let idx = idx as i32;
        
        if (idx >= self.len) {
            return None;
        }

        if (idx < 0) {
            let idx = self.len - idx;

            if (idx >= self.len || idx < 0) {
                return None;
            }

            self.get(idx)
        }

        let pos: u32 = self.base_ptr + (self.get_item_size() * idx as u32)?;
        let item: &[u8] = self.alloc.read::<T>(pos, self.get_item_size())?;

        core::mem::deserialize_struct(item)
    }

    @Overload
    @OperandAlias(Operands::Add)
    pub fn push(&mut self, item: T, idx: Option<i32 | u32>) -> &mut self;

    @Overload
    @OperandAlias(Operands::Add)
    pub fn push(&mut self, item: Array<T>) -> &mut self;
    
    fn push(&mut self, item: T | Array<T>, idx: Option<i32 | u32>) -> &mut self {
        if (core::types::is_type::<Array<T>>(item)) {
            for (item in item) {
                self.push(item);

                return self;
            }
        }

        let idx = idx.or(self.len);

        self.alloc.reserve(&mut self.base_ptr, self.get_item_size());

        let pos = self.base_ptr + (self.get_item_size() * idx);

        self.alloc.push(item, pos);
        self.len++;
        self
    }

    @OperandAlias(Operands::Subtract)
    pub fn pop(&mut self, idx: Option<i32 | u32>) -> &mut self {
        if (let Some(idx) = idx) {
            let pos = self.base_ptr + (self.get_item_size() * idx);

            self.alloc.pop(pos, self.get_item_size());
            self.len--;
            
            return self;
        }

        let pos = self.base_ptr + (self.get_item_size() * (self.len - 1));

        self.alloc.pop(pos, self.get_item_size());
        self.len--;
            
        self
    }

    const fn get_item_size(&self) -> u32 {
        size_of_type::<T>()
    }
}
```