Files
ww/lib/hash/hash.ww
Hojun-Cho 3daf134395 lib: retire os.assert/abort shims — assert/abort are builtins (#58 respell)
The flat checker scope makes ANY decl named assert/abort anywhere in
the combined unit disable the builtin unit-wide (the #45 shadow shape:
scope_lookup_prefer's cross-module fallback finds it). lib carried
three colliding @symbol("rt_abort") shims (os, time, strconv/stof)
plus the os.assert wrapper, so a bare assert(cond) in ANY program
importing os mis-bound os.assert and failed arity — a hard blocker for
regex fold-5 (regex.ha:660/670 bring builtin-assert mass). Ruled
respell-now per the recurrence test (#45 -> #58).

Delete the shims and the os.assert wrapper; every bare abort(msg)
caller (regex, strings, utf8, hash, getopt, encoding/*, time, stof)
now lands on the builtin, and the ~40 os.assert(c, m) sites respell to
the builtin assert(c, m) — restoring the exact Hare spelling the lib
ports diverged from (e.g. ref/hare/bytes/tokenize.ha:23). os.assert
had no Hare counterpart (Hare's assert is a language builtin); rule-9
wrapper removed. temp/dirs/bufio already use the non-colliding rtabort
spelling and keep it.

Now-dead 'import os;' lines kept (pre-existing precedent:
lib/strconv/strconv.ww carries one); a tree-wide dead-import sweep is
a separate concern. regex.ww's if+abort workarounds citing #58 stay
for the fold-5 owner to fold back into assert.

combined.ww regenerated for all five selfhost tools + the smoke
fixture via make.
2026-06-04 22:42:47 +09:00

90 lines
3.5 KiB
Plaintext

// hash — the general-purpose hashing-function interface. Port of
// ref/hare/hash/hash.ha. A hash is an io-write-only stream you feed
// data to, plus sum()/reset()/sz()/bsz(). Concrete hashes (crypto/sha256
// and, eventually, the lib/hash/* checksums) embed [[hash]] as their
// first field so a `*state` is castable to `*hash` for these dispatchers.
//
// The existing lib/hash/* submodules (crc32, siphash, …) are reduced
// one-shot forms WITHOUT this interface; this is the first module to
// ship it, riding the proven io.stream + inline-vtable shape.
//
// DIVERGENCE (inline vtable). Hare's `hash` carries `stream: io::stream`
// — and Hare's `io::stream` is itself `*vtable` (ref/hare/io/stream.ha:33),
// pointing at a separate module-level const vtable. ww's io collapse
// (#94) makes the io dispatchers take the vtable pointer directly
// (handle's stream arm is `stream` = `*vtable`, NOT `*stream`; see
// lib/io/types.ww:53), so the dispatch arg the callbacks receive must BE
// the outer state pointer. That requires the vtable embedded INLINE at
// offset 0, exactly as lib/encoding/base64, lib/memio, and lib/io's own
// callers do it. So `hash` opens with `vt: io.vtable` (inline) rather
// than a `*vtable` field; otherwise the port is 1:1.
package hash;
import io;
import os;
// ref/hare/hash/hash.ha:8-25. `vt` (inline io.vtable) replaces Hare's
// `stream: io::stream` per the header divergence — it MUST stay the
// first field so `*state -> *hash -> &h.vt` all alias offset 0. `reset`
// is nullable: Hare's `nullable *fn(...)`; ww spells it `(*fn(...) | void)`
// (#192, the Nullable-kept ruling). `sum`/`reset` are inline `*fn(...)`
// fields, the same shape as lib/errors `strerror` (errors.ww:66).
export type hash = struct {
vt: io.vtable,
sum: *fn(h: *hash, buf: []u8) void,
reset: (*fn(h: *hash) void | void),
sz: size,
bsz: size,
};
// write — feed `buf` to the hash. ref/hare/hash/hash.ha:28-29. Hare's
// `io::write(h, buf) as size`; ww has the same `as` but the io.error arm
// is impossible by contract (a hash stream never errors — its writer
// only buffers), so the mismatch aborts rather than propagating.
export fn write(h: *hash, buf: []u8) size = {
match (io.write(&h.vt, buf)) {
case let n: size => return n;
case let e: io.error =>
abort("hash.write: hash stream returned an io error");
};
};
// close — discard the running checksum and release resources.
// ref/hare/hash/hash.ha:32. Hare's `io::close(h)!`.
export fn close(h: *hash) void = {
match (io.close(&h.vt)) {
case void => void;
case let e: io.error =>
abort("hash.close: hash stream returned an io error");
};
};
// sum — write the current digest into `buf`, which must be at least
// [[sz]] bytes. ref/hare/hash/hash.ha:35-38. ww spells Hare's `h.sum(...)`
// as the explicit fn-ptr call `(*h.sum)(...)` (#193).
export fn sum(h: *hash, buf: []u8) void = {
assert((buf.len: size) >= h.sz,
"hash.sum buffer does not meet minimum required size for this hash function");
(*h.sum)(h, buf);
};
// reset — return the hash to its initial state.
// ref/hare/hash/hash.ha:41-48.
export fn reset(h: *hash) void = {
match (h.reset) {
case let f: *fn(h: *hash) void => (*f)(h);
case void => abort("this hash cannot be reset");
};
};
// sz — digest size in bytes, independent of hash state.
// ref/hare/hash/hash.ha:52.
export fn sz(h: *hash) size = {
return h.sz;
};
// bsz — internal block size in bytes. ref/hare/hash/hash.ha:55.
export fn bsz(h: *hash) size = {
return h.bsz;
};