//package std::vector;
public extern len<T>(data: [T]) -> uint64;

public struct Vector<T> {
    private:
        data: [T];
    public:
        length: uint64;
        capacity: uint64;

    Vector(data: [T]) {
        this.length = len(data);
        this.capacity = this.length;
        this.data = data;
    }
    ~Vector() {
        this.data = 0;
        this.length = 0;
        delete this.data;
    }

    /// A function that doesn't have a "self" parameter is a static function
    /// static functions are called like this: "Vector::<T>::function_name()"
    fun with_capacity(capacity: uint64) -> Vector<T> {
        return new Vector<T>(new [T; capacity]);
    }

    /// A function that has a "self" parameter is a method of the struct
    /// and is called like this: "vector_instance.function_name()"
    fun push(this, val: T) {
        if this.capacity <= this.length {
            let new_capacity = this.capacity * 2;

            let new_data = new [T; new_capacity];
            let i = 0;
            while i < this.length {
                new_data[i] = this.data[i];
                i = i + 1;
            }
            let data_to_delete = this.data;
            this.data = new_data;
            this.capacity = new_capacity;

            delete data_to_delete;
        }
        this.data[this.length] = val;
        this.length = this.length + 1;
    }

    fun pop(this) -> T {
        if this.length == 0 {
            std::panic("Cannot pop from an empty vector");
        }
        this.length = this.length - 1;
        return this.data[this.length];
    }
}

fun main() {
  let my_vec = new Vector<int64>([0, 1, 2, 3, 4]);
}
