Edva separates text and byte buffers into two paired types: - String: Immutable, NUL-reserved 16-byte fat pointer { i64 len, ptr data } with arena generation-tag safety. - Builder: Mutable, growable 24-byte arena buffer { i64 len, ptr data, i64 cap } that freezes into a String in \(O(1)\) via unary +b.
9.1 Architecture and ABI comparison
Property
String
Builder
Runtime layout
{ i64 len, ptr data } (16 bytes)
{ i64 len, ptr data, i64 cap } (24 bytes)
Mutability
Strictly immutable (s(0) = x rejected)
Mutable in place (+=, = (...), ?b = n, @[&b] = x)
NUL-reserved tail
Guaranteed data[len] == '\0' on whole strings
Guaranteed upon +b freeze
Generation tag
Upper 16 bits of len (len >> 48); traps with E4010 on stale read
Allocated in active arena
Aliasing semantics
Value descriptor sharing immutable bytes
Shared descriptor until +b detaches buffer and resets descriptor to {0, null, 0}
9.2String literals, margin stripping, and interpolation
9.3 Arena generation tags and stale-read protection (E4010)
Mechanism
Specification
Tag encoding
Upper 16 bits of the 64-bit len word (len >> 48) store the arena scope generation; actual byte length is len & 0x0000FFFFFFFFFFFF
Tag 0 (Immortal)
String literals and top-level allocations outside restore scopes carry tag 0 and never expire
Active scope validation
Scoped arena restores track active generation IDs (1..65535, wrapping to 1 and skipping active IDs). Reading a String whose tag is no longer active traps with E4010
FFI pointer masking
&s returns the raw data pointer directly (NUL-terminated); %ptrmask is available for tagged raw addresses
9.4String and Builder operations
Operation
Syntax
Operand
Result Type
Semantics
Byte length
?s / ?b
String / Builder
Int
Number of UTF-8 bytes currently stored (.len is rejected with E3065)
Rune count
??s
String
Int
Number of UTF-8 Unicode codepoints
Data pointer
&s / &b
String / Builder
Addr
Raw pointer to byte buffer (&s is NUL-terminated for C FFI)
Byte index
s(i)
String, i: Int
Int
Unsigned byte value (0..255) at i (aborts on out-of-bounds)