commit 678e4f644cfd39043150f015ac7339d0d7555800
parent 599f127d5a2470a1382afa4d968d1ccbe6a3dc1c
Author: Armin Preiml <apreiml@strohwolke.at>
Date: Thu, 28 Sep 2023 07:58:08 +0200
bufio::scanner: implement io::reader
Diffstat:
2 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/bufio/scanner.ha b/bufio/scanner.ha
@@ -11,7 +11,13 @@ use types;
def BUFSZ: size = 4096;
+const scanner_vtable = io::vtable {
+ reader = &scan_read,
+ ...
+};
+
export type scanner = struct {
+ stream: io::stream,
src: io::handle,
buffer: []u8,
// Number of bytes available in buffer
@@ -31,6 +37,7 @@ export type scanner = struct {
// reached.
export fn newscanner(src: io::handle, maxread: size) scanner = {
return scanner {
+ stream = &scanner_vtable,
src = src,
buffer = alloc([0...], BUFSZ),
maxread = maxread,
@@ -45,6 +52,7 @@ export fn newscanner(src: io::handle, maxread: size) scanner = {
// they wish to free the underlying buffer through bufio.
export fn newscanner_static(src: io::handle, buffer: []u8) scanner = {
return scanner {
+ stream = &scanner_vtable,
src = src,
buffer = buffer,
maxread = len(buffer),
@@ -59,6 +67,25 @@ export fn finish(scan: *scanner) void = {
free(scan.buffer);
};
+fn scan_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
+ let scan = s: *scanner;
+ if (scan.pending == 0) {
+ match (scan_readahead(scan)?) {
+ case io::EOF =>
+ return io::EOF;
+ case size =>
+ yield;
+ };
+ };
+
+ // Consume previous read, if any
+ scan_shift(scan);
+
+ const n = if (len(buf) > scan.pending) scan.pending else len(buf);
+ buf[..n] = scan_consume(scan, n)[..];
+ return n;
+};
+
// Fills up the scanner buffer with data from the underlying I/O handle. If no
// space remains in the read buffer, it is expanded by BUFSZ (up to maxread).
// Then, one read from the underlying I/O handle is performed and scan.pending
diff --git a/bufio/scanner_test+test.ha b/bufio/scanner_test+test.ha
@@ -111,3 +111,15 @@ use strings;
};
};
};
+
+@test fn scan_read() void = {
+ const expected: [_]u8 = [
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ ];
+ let in = memio::fixed(expected);
+
+ let scanner = newscanner(&in, 2);
+ let result = io::drain(&scanner)!;
+ defer free(result);
+ assert(bytes::equal(expected, result));
+};