ludic/runtime/native/bytes.ludic
Orkuncakilkaya b0b0b62bce feat(lang): L7 memory is safe unless it says unsafe
The typed buffers are slices: words/floats/fixeds/doubles/pointers(n) make
zeroed, bounds-checked []int/[]float/... and the type names mean them. buffer(n)
is a []byte, with text_of, Fs.read_bytes/write_bytes and view(xs, start, n).
bytes(), indexing a raw pointer or bytes, free, resize, Memory.*, raw file calls,
data_of and C externs are refused outside unsafe { } / unsafe function, and a
project's own files may write unsafe only with --unsafe; the runtime and packages
are the platform. A slice passed to an extern goes as its data.

What the change found: Sync's atomics on a slice header, words(n) uninitialised,
input's fixed axes in ints, truetype's fixed outlines as ints, skin matrices
typed int, gl_shader's source table made from raw bytes. render3d gets safe
entry points (safe_api.ludic). Rendering is byte-identical; a frame costs the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 12:53:27 +03:00

43 lines
1.4 KiB
Text

# bytes.ludic — L7: bytes a program can hold without raw memory. A `[]byte` from buffer(n) is
# bounds-checked like any slice; these turn one into text and move one to and from a file. The
# runtime is the platform, so the raw calls underneath (file_read, the NUL-terminated copy) are
# its business, not the caller's.
# the first n bytes of b as text (it stops at b's end, and the text ends at a zero byte if one comes first)
function text_of(b: []byte, n: int) -> string {
var k = n
if b == null { k = 0 }
if k > len(b) { k = len(b) }
if k < 0 { k = 0 }
let out = bytes(k + 1)
var i = 0
while i < k {
out[i] = b[i]
i += 1
}
out[k] = 0
return out
}
# a whole file as bytes - through the asset pack when the file is in one - or null
function fs_read_bytes(path: string) -> []byte {
let f = file_open(path, "rb")
if f == null { return null }
file_seek(f, 0, 2)
let n = file_tell(f)
file_seek(f, 0, 0)
let b = buffer(n)
let got = file_read(f, b, n)
file_close(f)
if got < n { return view(b, 0, got) }
return b
}
# the first `count` bytes of b to a file, replacing it; false when it cannot be written whole
function fs_write_bytes(path: string, b: []byte, count: int) -> bool {
var k = count
if k > len(b) { k = len(b) }
let f = file_open(path, "wb")
if f == null { return false }
let put = file_write(f, b, k)
file_close(f)
return put == k
}