Vector\<T>
Vector<T> is a growable, owning array of T. It holds a heap buffer that doubles whenever it fills up: element access is O(1) and push is amortised O(1). The vector calls libc malloc/free directly and is not tracked by Glide's auto-drop, so you must release it explicitly with free() — pair it with defer to make leaks impossible.
Import
No import needed — Vector<T> is built in.
The struct
pub struct Vector<T> {
data: *T, // heap buffer; null while cap == 0
len: i32, // number of initialised elements (<= cap)
cap: i32, // allocation size in elements (power of two once non-zero)
is_arena: bool, // true when the buffer was arena-allocated (LSP path)
}
All four fields are private; interact with the vector only through its methods.
Construction
| Function | Signature | Description |
|---|---|---|
new |
fn new() -> *Vector<T> |
Empty vector with no allocation. The first push allocates. |
with_cap |
fn with_cap(cap: i32) -> *Vector<T> |
Empty vector pre-sized to hold at least cap elements without reallocating. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push(10);
v.push(20);
let w: *Vector<i32> = Vector::with_cap(64);
defer w.free();
for let i: i32 = 0; i < 64; i++ { w.push(i); }
println!(w.len()); // 64
return 0;
}
Element access & mutation
| Method | Signature | Description |
|---|---|---|
push |
fn push(self: *Vector<T>, x: T) |
Append x. Reallocates (capacity doubles) when full; amortised O(1). |
pop |
fn pop(self: *Vector<T>) -> T |
Remove and return the last element. UB if empty — check is_empty() first. |
get |
fn get(self: *Vector<T>, i: i32) -> T |
Read element i. No bounds check. |
set |
fn set(self: *Vector<T>, i: i32, x: T) |
Overwrite element i. No bounds check. |
first |
fn first(self: *Vector<T>) -> T |
First element. UB if empty. |
last |
fn last(self: *Vector<T>) -> T |
Last element. UB if empty. |
swap |
fn swap(self: *Vector<T>, i: i32, j: i32) |
Swap elements at i and j in place. |
swap_remove |
fn swap_remove(self: *Vector<T>, i: i32) -> T |
Remove and return element i in O(1) by swapping with the last; reorders remaining elements. |
reverse |
fn reverse(self: *Vector<T>) |
Reverse elements in place. O(n). |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push(10);
v.push(20);
v.push(30);
println!(v.get(0)); // 10
v.set(1, 99);
println!(v.get(1)); // 99
println!(v.first()); // 10
println!(v.last()); // 30
let last: i32 = v.pop(); // 30
println!(last); // 30
println!(v.len()); // 2
return 0;
}
swap, swap_remove, and reverse rearrange in place:
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30, 40);
v.swap(0, 3); // [40, 20, 30, 10]
let removed: i32 = v.swap_remove(1); // removes 20 -> [40, 10, 30]
println!(removed); // 20
v.reverse(); // [30, 10, 40]
println!(v.first(), v.last()); // 30 40
return 0;
}
Size & lifetime
| Method | Signature | Description |
|---|---|---|
len |
fn len(self: *Vector<T>) -> i32 |
Number of initialised elements. |
is_empty |
fn is_empty(self: *Vector<T>) -> bool |
true when len() == 0. |
truncate |
fn truncate(self: *Vector<T>, n: i32) |
Shorten to at most n elements. No-op if already shorter; capacity is not reduced. |
clear |
fn clear(self: *Vector<T>) |
Drop every element (len → 0). Capacity is preserved. |
extend |
fn extend(self: *Vector<T>, other: *Vector<T>) |
Append every element of other; other is left intact. |
free |
fn free(self: *Vector<T>) |
Release the buffer and the struct. The pointer is dangling afterwards. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30, 40);
v.truncate(2); // [10, 20] — capacity unchanged
println!(v.len()); // 2
let other: *Vector<i32> = Vector::new();
defer other.free();
other.push_all!(7, 8);
v.extend(other); // v is now [10, 20, 7, 8]; other unchanged
println!(v.len()); // 4
println!(other.len()); // 2
v.clear();
println!(v.is_empty()); // true
return 0;
}
The push_all! macro
macro push_all!($($x:expr),*) {
$( self.push($x); )*
}
Pushes every passed element. Three call shapes are equivalent:
v.push_all!(1, 2, 3);
Vector::push_all!(v, 4, 5);
Vector::new().push_all!(7, 8, 9);
The vec_of! builtin
vec_of!(a, b, c) builds and returns a *Vector<T> in one expression — the element type T is inferred from the first argument. It is a compiler builtin, so it is available everywhere with no import:
let v: *Vector<i32> = vec_of!(10, 20, 30);
defer v.free();
let names = vec_of!("alice", "bob"); // inferred *Vector<string>
Because it is an expression, it works anywhere a value does — a let initializer, a function argument, or a return:
fn sum(v: *Vector<i32>) -> i32 { /* … */ }
let total = sum(vec_of!(1, 2, 3, 4, 5)); // 15
All elements must share one type; a mixed call (vec_of!(1, "two")) or an empty call (vec_of!(), which has nothing to infer T from — use Vector::new()) is rejected at compile time with a clear error.
Iteration
iter / VecIter<T>
fn iter(self: *Vector<T>) -> *VecIter<T>
pub struct VecIter<T> {
vec: *Vector<T>,
idx: i32,
}
impl<T> VecIter<T> {
pub fn next(self: *VecIter<T>) -> ?T
}
iter() builds an iterator that yields each element by value; next() returns some(x) until the end, then none(). The iterator borrows the vector's buffer for the walk — mutating the vector mid-iteration is undefined behaviour.
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(10, 20, 30);
let it: *VecIter<i32> = v.iter();
let mut total: i32 = 0;
while true {
match it.next() {
some(x) => { total = total + x; },
none() => break,
}
}
println!(total); // 60
return 0;
}
Functional combinators
These methods are generic over any Vector<T>. The transforming ones (map/filter/take/skip/take_while/skip_while) return a new *Vector that you own and must free.
| Method | Signature | Description |
|---|---|---|
map |
fn map<U>(self: *Vector<T>, f: fn(T) -> U) -> *Vector<U> |
Apply f to each element; return a new vector. |
filter |
fn filter(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Keep only elements where p is true. |
fold |
fn fold<U>(self: *Vector<T>, init: U, f: fn(U, T) -> U) -> U |
Reduce with accumulator; f(acc, item) returns the new accumulator. |
take |
fn take(self: *Vector<T>, n: i32) -> *Vector<T> |
First n elements (clamped to length). |
skip |
fn skip(self: *Vector<T>, n: i32) -> *Vector<T> |
All but the first n elements. |
take_while |
fn take_while(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Elements until p returns false (then stop). |
skip_while |
fn skip_while(self: *Vector<T>, p: fn(T) -> bool) -> *Vector<T> |
Drop leading elements while p is true; keep the rest from first false. |
any |
fn any(self: *Vector<T>, p: fn(T) -> bool) -> bool |
true if any element matches. Short-circuits. |
all |
fn all(self: *Vector<T>, p: fn(T) -> bool) -> bool |
true if all match. Empty vector → true (vacuous truth). |
find |
fn find(self: *Vector<T>, p: fn(T) -> bool) -> ?T |
First matching element, or none(). |
map / filter / fold
fn double(x: i32) -> i32 { return x * 2; }
fn is_even(x: i32) -> bool { return x % 2 == 0; }
fn add(acc: i32, x: i32) -> i32 { return acc + x; }
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(1, 2, 3, 4, 5);
// Bind each stage so each owned result gets freed.
let doubled: *Vector<i32> = v.map(double);
defer doubled.free(); // [2, 4, 6, 8, 10]
let evens: *Vector<i32> = doubled.filter(is_even);
defer evens.free(); // [2, 4, 6, 8, 10]
println!(evens.fold(0, add)); // 30
println!(v.any(is_even)); // true
println!(v.all(is_even)); // false
match v.find(is_even) {
some(x) => println!(x), // 2
none() => println!("none"),
}
return 0;
}
fold is the general reducer — init seeds the accumulator and the result type U may differ from the element type. map<U> likewise changes element type (e.g. Vector<i32> → Vector<string>).
take / skip / take_while / skip_while
take/skip slice by count; take_while/skip_while slice by predicate. All four return a fresh owned vector.
fn lt5(x: i32) -> bool { return x < 5; }
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(1, 3, 7, 2, 9);
let head: *Vector<i32> = v.take(3);
defer head.free(); // [1, 3, 7]
let clamped: *Vector<i32> = v.take(99);
defer clamped.free();
println!(clamped.len()); // 5 (clamped to len)
let tail: *Vector<i32> = v.skip(2);
defer tail.free(); // [7, 2, 9]
let tw: *Vector<i32> = v.take_while(lt5);
defer tw.free(); // [1, 3] (stops at first >= 5)
let sw: *Vector<i32> = v.skip_while(lt5);
defer sw.free(); // [7, 2, 9] (keeps all from first >= 5)
println!(tw.len(), sw.len()); // 2 3
return 0;
}
Element-typed methods
Glide has no generic numeric/ordering trait yet, so reducers that need to add or compare elements live in concrete impl Vector<T> blocks per element type. They are only available when T is exactly the listed type.
Vector<i32>
| Method | Signature | Description |
|---|---|---|
sum |
pub fn sum(self: *Vector<i32>) -> i32 |
Sum of all elements. Empty → 0. |
max |
pub fn max(self: *Vector<i32>) -> ?i32 |
Largest element, or none() if empty. |
min |
pub fn min(self: *Vector<i32>) -> ?i32 |
Smallest element, or none() if empty. |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
v.push_all!(3, 7, 2, 9, 4);
println!(v.sum()); // 25
match v.max() { some(x) => println!(x), none() => {}, } // 9
match v.min() { some(x) => println!(x), none() => {}, } // 2
return 0;
}
Vector<f64>
| Method | Signature | Description |
|---|---|---|
sum |
pub fn sum(self: *Vector<f64>) -> f64 |
Sum of all elements. Empty → 0.0. |
max |
pub fn max(self: *Vector<f64>) -> ?f64 |
Largest element, or none() if empty. |
min |
pub fn min(self: *Vector<f64>) -> ?f64 |
Smallest element, or none() if empty. |
avg |
pub fn avg(self: *Vector<f64>) -> ?f64 |
Arithmetic mean, or none() if empty. |
fn main() -> i32 {
let v: *Vector<f64> = Vector::new();
defer v.free();
v.push_all!(2.0, 4.0, 6.0);
println!(v.sum()); // 12.0
match v.avg() { some(x) => println!(x), none() => {}, } // 4.0
match v.max() { some(x) => println!(x), none() => {}, } // 6.0
match v.min() { some(x) => println!(x), none() => {}, } // 2.0
return 0;
}
Vector<string>
| Method | Signature | Description |
|---|---|---|
join |
pub fn join(self: *Vector<string>, sep: string) -> string |
Concatenate elements with sep between them. Empty → "". |
concat |
pub fn concat(self: *Vector<string>) -> string |
Concatenate elements with no separator. Empty → "". |
max |
pub fn max(self: *Vector<string>) -> ?string |
Lexicographically largest element, or none(). |
min |
pub fn min(self: *Vector<string>) -> ?string |
Lexicographically smallest element, or none(). |
fn main() -> i32 {
let v: *Vector<string> = Vector::new();
defer v.free();
v.push_all!("apple", "banana", "cherry");
println!(v.join(", ")); // apple, banana, cherry
println!(v.concat()); // applebananacherry
match v.max() { some(s) => println!(s), none() => {}, } // cherry
match v.min() { some(s) => println!(s), none() => {}, } // apple
return 0;
}
Vector<bool>
| Method | Signature | Description |
|---|---|---|
count_true |
pub fn count_true(self: *Vector<bool>) -> i32 |
Number of true elements. |
count_false |
pub fn count_false(self: *Vector<bool>) -> i32 |
Number of false elements. |
all_true |
pub fn all_true(self: *Vector<bool>) -> bool |
true if every element is true. Empty → true (vacuous truth). |
any_true |
pub fn any_true(self: *Vector<bool>) -> bool |
true if at least one element is true. Empty → false. |
fn main() -> i32 {
let v: *Vector<bool> = Vector::new();
defer v.free();
v.push_all!(true, false, true, true);
println!(v.count_true()); // 3
println!(v.count_false()); // 1
println!(v.all_true()); // false
println!(v.any_true()); // true
return 0;
}
Empty-vector conventions
Reducers that can't produce a sensible value on an empty vector return ?T; the additive/boolean ones use fixed identities. Memorise these to avoid surprises:
| Call | Empty result |
|---|---|
sum (i32/f64) |
0 / 0.0 |
max / min / avg |
none() |
all (combinator) / all_true |
true (vacuous truth) |
any (combinator) / any_true |
false |
count_true / count_false |
0 |
join / concat |
"" |
fn main() -> i32 {
let v: *Vector<i32> = Vector::new();
defer v.free();
println!(v.sum()); // 0
match v.max() {
some(x) => println!(x),
none() => println!("empty max"), // taken
}
let b: *Vector<bool> = Vector::new();
defer b.free();
println!(b.all_true()); // true (vacuous truth)
println!(b.any_true()); // false
return 0;
}