//! returns: 0 //! Test slice .append() method with inline allocator. /// Simple bump allocator for testing. record Arena: Copy { data: *mut [u8], offset: u32, } fn newArena(data: *mut [u8]) -> Arena { return Arena { data, offset: 0 }; } fn arenaAlloc(arena: *mut Arena, size: u32, al: u32) -> *mut opaque { let aligned = (arena.offset + al - 1) / al * al; let newOffset = aligned + size; assert newOffset <= arena.data.len as u32; let base: *mut u8 = &mut arena.data[aligned]; set arena.offset = newOffset; return base as *mut opaque; } /// Allocator record matching the compiler's expected layout. record Allocator: Copy { func: fn(*mut opaque, u32, u32) -> *mut opaque, ctx: *mut opaque, } fn arenaAllocFn(ctx: *mut opaque, size: u32, al: u32) -> *mut opaque { let arena = ctx as *mut Arena; return arenaAlloc(arena, size, al); } fn arenaAllocator(arena: *mut Arena) -> Allocator { return Allocator { func: arenaAllocFn, ctx: arena as *mut opaque, }; } static BUF: [u8; 4096] = undefined; @default fn main() -> i32 { let mut arena = newArena(&mut BUF[..]); let a = arenaAllocator(&mut arena); // Allocate initial capacity of 4. let ptr = arenaAlloc(&mut arena, @sizeOf(i32) * 4, @alignOf(i32)); let mut nums = @sliceOf(ptr as *mut i32, 0, 4); // Append within capacity. nums.append(10, a); nums.append(20, a); nums.append(30, a); if nums.len <> 3 { return 1; } if nums.cap <> 4 { return 2; } if nums[0] <> 10 { return 3; } if nums[1] <> 20 { return 4; } if nums[2] <> 30 { return 5; } // Append to fill capacity. nums.append(40, a); if nums.len <> 4 { return 6; } if nums.cap <> 4 { return 7; } // Append past capacity -- triggers growth. nums.append(50, a); if nums.len <> 5 { return 8; } // Cap should have grown (cap * 2 | 1 = 4 * 2 | 1 = 9). if nums.cap <> 9 { return 9; } if nums[4] <> 50 { return 10; } // Verify old elements survived the copy. if nums[0] <> 10 { return 11; } if nums[3] <> 40 { return 12; } // Append from empty (cap == 0 triggers growth with cap = 1). let mut empty = @sliceOf(ptr as *mut i32, 0, 0); empty.append(99, a); if empty.len <> 1 { return 13; } if empty.cap <> 1 { return 14; } if empty[0] <> 99 { return 15; } // Sum all elements in nums. let mut sum: i32 = 0; for n in nums { set sum += n; } if sum <> 150 { return 16; } // Test append with u8 elements (stride = 1). let bytePtr = arenaAlloc(&mut arena, 2, 1); let mut bytes = @sliceOf(bytePtr as *mut u8, 0, 2); bytes.append(0xAB, a); bytes.append(0xCD, a); if bytes.len <> 2 { return 17; } if bytes[0] <> 0xAB { return 18; } if bytes[1] <> 0xCD { return 19; } // Trigger growth on u8 slice. bytes.append(0xEF, a); if bytes.len <> 3 { return 20; } if bytes.cap <> 5 { return 21; } if bytes[2] <> 0xEF { return 22; } // Verify old u8 elements survived. if bytes[0] <> 0xAB { return 23; } // Test that .append() returns the slice, allowing rebinding. let ptr2 = arenaAlloc(&mut arena, @sizeOf(i32) * 2, @alignOf(i32)); let mut vals = @sliceOf(ptr2 as *mut i32, 0, 2); // Append within capacity, rebind via return value. set vals = vals.append(42, a); assert vals.len == 1; assert vals[0] == 42; set vals = vals.append(43, a); assert vals.len == 2; // Append past capacity -- triggers growth and returns updated slice. let oldPtr = &vals[0] as *opaque; set vals = vals.append(44, a); assert vals.len == 3; assert vals.cap == 5; // After growth, the data pointer should have changed. let newPtr = &vals[0] as *opaque; assert oldPtr <> newPtr; // Verify all elements survived. assert vals[0] == 42; assert vals[1] == 43; assert vals[2] == 44; return 0; }