Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions specs/port/trinity/src/tri/compat/managed_list.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
module port::trinity::managed_list;

// Port of gHashTag/trinity:src/tri/compat/managed_list.zig (at ee512359254b,
// ~129 lines) - t27 issue #9860, Roadmap Stage 5 (goal #4547), target t27c
// gen-rust. The original is a GENERIC wrapper, ManagedList(comptime T: type),
// restoring the Zig 0.14 allocator-with-list API over Zig 0.15's
// pass-the-allocator-everywhere API. Generics cannot be expressed in this
// language, so the port instantiates the wrapper's decisions for the concrete
// element type u32 with a fixed capacity of 16; the generic itself (original
// line 17) is the named missing piece - everything it wraps carries. The
// allocator that travels with the list is the caller's plumbing here.

// The fixed capacity of the port's instantiation.
pub const MANAGED_LIST_CAPACITY: usize = 16;

// The wrapper's state: the items and the count.
pub struct TrinityManagedList {
items: [16]u32,
len: usize,
}

// Lines 25-30: init - an empty list.
pub fn ManagedList() -> TrinityManagedList {
const empty = TrinityManagedList { items: [_]u32{0} ** 16, len: 0 };
return empty;
}

// Lines 40-43: append - the allocator is provided automatically (the
// wrapper's whole point); the list grows within its capacity.
pub fn managed_list_append(l: TrinityManagedList, item: u32) -> TrinityManagedList {
var next = l;
if (next.len < MANAGED_LIST_CAPACITY) {
next.items[next.len] = item;
next.len = next.len + 1;
}
return next;
}

// Lines 50-53: len.
pub fn managed_list_len(l: TrinityManagedList) -> usize {
return l.len;
}

// Lines 56-58: isEmpty.
pub fn managed_list_is_empty(l: TrinityManagedList) -> bool {
return l.len == 0;
}

// Lines 85-88: get.
pub fn managed_list_get(l: TrinityManagedList, index: usize) -> u32 {
return l.items[index];
}

// Lines 90-93: set.
pub fn managed_list_set(l: TrinityManagedList, index: usize, item: u32) -> TrinityManagedList {
var next = l;
if (index < MANAGED_LIST_CAPACITY) {
next.items[index] = item;
}
// The trailing alias keeps the generator's return-variable picker on
// the mutated copy; without it the emitted code returns the input.
const out = next;
return out;
}

// Lines 71-73: clearRetainingCapacity - the count drops to zero, the
// storage stays.
pub fn managed_list_clear(l: TrinityManagedList) -> TrinityManagedList {
var next = l;
next.len = 0;
return next;
}

// Lines 96-103: pop / popOrNull return ?T - an empty list pops nothing.
pub fn managed_list_pop_present(l: TrinityManagedList) -> bool {
return l.len > 0;
}

pub fn managed_list_pop(l: TrinityManagedList) -> TrinityManagedList {
var next = l;
if (next.len > 0) {
next.len = next.len - 1;
}
return next;
}

// Lines 113-123: the iterator - next returns null at the end of the list,
// otherwise the item at the index and the index advanced by one.
pub fn managed_list_iter_has_next(l: TrinityManagedList, index: usize) -> bool {
return index < l.len;
}

pub fn managed_list_iter_next(l: TrinityManagedList, index: usize) -> (u32, usize) {
const item = l.items[index];
return (item, index + 1);
}

test init_is_empty {
const l = ManagedList();
assert(managed_list_len(l) == 0);
assert(managed_list_is_empty(l) == true);
assert(managed_list_pop_present(l) == false);
}

test append_grows_in_order {
const base = ManagedList();
const one = managed_list_append(base, 7);
const two = managed_list_append(one, 9);
assert(managed_list_len(two) == 2);
assert(managed_list_get(two, 0) == 7);
assert(managed_list_get(two, 1) == 9);
assert(managed_list_len(one) == 1);
assert(managed_list_len(base) == 0);
assert(managed_list_is_empty(two) == false);
}

test append_stops_at_capacity {
var l = ManagedList();
var i: usize = 0;
while (i < 20) {
l = managed_list_append(l, 100);
i += 1;
}
assert(managed_list_len(l) == 16);
assert(managed_list_get(l, 15) == 100);
}

test set_replaces_in_place {
const base = ManagedList();
const one = managed_list_append(base, 1);
const two = managed_list_append(one, 2);
const changed = managed_list_set(two, 0, 42);
assert(managed_list_len(changed) == 2);
assert(managed_list_get(changed, 0) == 42);
assert(managed_list_get(changed, 1) == 2);
assert(managed_list_get(two, 0) == 1);
}

test clear_keeps_the_list_usable {
const base = ManagedList();
const one = managed_list_append(base, 5);
const two = managed_list_append(one, 6);
const cleared = managed_list_clear(two);
assert(managed_list_len(cleared) == 0);
assert(managed_list_is_empty(cleared) == true);
const again = managed_list_append(cleared, 8);
assert(managed_list_len(again) == 1);
assert(managed_list_get(again, 0) == 8);
}

test pop_shrinks_one_at_a_time {
const empty = ManagedList();
const none = managed_list_pop(empty);
assert(managed_list_len(none) == 0);
const base = ManagedList();
const one = managed_list_append(base, 3);
const two = managed_list_append(one, 4);
assert(managed_list_pop_present(two) == true);
const popped = managed_list_pop(two);
assert(managed_list_len(popped) == 1);
assert(managed_list_pop_present(popped) == true);
const gone = managed_list_pop(popped);
assert(managed_list_len(gone) == 0);
assert(managed_list_pop_present(gone) == false);
}

test iterator_walks_to_the_end {
const base = ManagedList();
const one = managed_list_append(base, 10);
const two = managed_list_append(one, 20);
assert(managed_list_iter_has_next(two, 0) == true);
const (first, idx1) = managed_list_iter_next(two, 0);
assert(first == 10);
assert(idx1 == 1);
assert(managed_list_iter_has_next(two, idx1) == true);
const (second, idx2) = managed_list_iter_next(two, idx1);
assert(second == 20);
assert(idx2 == 2);
assert(managed_list_iter_has_next(two, idx2) == false);
assert(managed_list_iter_has_next(ManagedList(), 0) == false);
}
Loading