~apreiml/hare

a568f1fb6ec73206147f48c0d7af4609bd71ea99 — Armin Preiml 2 years ago ac3e274
io: add scriptwriter to +test

scriptwrite is a tool to test short writes or errors::again behavior on streams.

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>
1 files changed, 56 insertions(+), 0 deletions(-)

A io/+test/script.ha
A io/+test/script.ha => io/+test/script.ha +56 -0
@@ 0,0 1,56 @@
use errors;
use math::random;

export type scriptstream = struct {
	vtable: stream,
	sink: handle,
	script: [](size | error),
	sc: size,
};

const scriptvtable: vtable = vtable {
	writer = &script_writer,
	...
};

// Create an overlay stream that passes errors or data as chunks according to
// 'script' to the 'sink'.
export fn scriptwriter(sink: handle, script: [](size | error)) scriptstream = {
	return scriptstream {
		vtable = &scriptvtable,
		sink = sink,
		script = script,
		sc = 0,
	};
};

fn script_writer(s: *stream, buf: const []u8) (size | error) = {
	let s = s: *scriptstream;

	assert(s.sc < len(s.script), "scriptwriter script EOF");
	defer s.sc += 1;

	match (s.script[s.sc]) {
	case let n: size =>
		return write(s.sink, buf[..n]);
	case let e: error =>
		return e;
	};
};

// Writes an entire buffer, perhaps issuing several [[write]] calls to do so and
// retries on [[errors::again]].
export fn script_writeall(out: handle, buf: []u8) (size | error) = {
	let z: size = 0;
	for (z < len(buf)) {
		z += match (write(out, buf[z..])) {
		case let s: size =>
			yield s;
		case errors::again =>
			yield 0;
		case let e: error =>
			return e;
		};
	};
	return z;
};