diff --git a/core/bytes/reader.odin b/core/bytes/reader.odin index deaaf4ac6..2032616d0 100644 --- a/core/bytes/reader.odin +++ b/core/bytes/reader.odin @@ -4,9 +4,9 @@ import "core:io" import "core:unicode/utf8" Reader :: struct { - s: []byte, - i: i64, // current reading index - prev_rune: int, // previous reading index of rune or < 0 + s: []byte, // read-only buffer + i: i64, // current reading index + prev_rune: int, // previous reading index of rune or < 0 } reader_init :: proc(r: ^Reader, s: []byte) { diff --git a/core/strings/reader.odin b/core/strings/reader.odin index 46256641f..468c2f836 100644 --- a/core/strings/reader.odin +++ b/core/strings/reader.odin @@ -4,140 +4,174 @@ import "core:io" import "core:unicode/utf8" Reader :: struct { - using stream: io.Stream, - s: string, - i: i64, // current reading index - prev_rune: int, // previous reading index of rune or < 0 + s: string, // read-only buffer + i: i64, // current reading index + prev_rune: int, // previous reading index of rune or < 0 } -reader_reset :: proc(r: ^Reader, s: string) { - r.stream_data = r; - r.stream_vtable = _reader_vtable; +reader_init :: proc(r: ^Reader, s: string) { r.s = s; r.i = 0; r.prev_rune = -1; } -new_reader :: proc(s: string, allocator := context.allocator) -> ^Reader { - r := new(Reader, allocator); - reader_reset(r, s); - return r; +reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) { + s.stream_data = r; + s.stream_vtable = _reader_vtable; + return; } +reader_length :: proc(r: ^Reader) -> int { + if r.i >= i64(len(r.s)) { + return 0; + } + return int(i64(len(r.s)) - r.i); +} + +reader_size :: proc(r: ^Reader) -> i64 { + return i64(len(r.s)); +} + +reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) { + if r.i >= i64(len(r.s)) { + return 0, .EOF; + } + r.prev_rune = -1; + n = copy(p, r.s[r.i:]); + r.i += i64(n); + return; +} +reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) { + if off < 0 { + return 0, .Invalid_Offset; + } + if off >= i64(len(r.s)) { + return 0, .EOF; + } + n = copy(p, r.s[off:]); + if n < len(p) { + err = .EOF; + } + return; +} +reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) { + r.prev_rune = -1; + if r.i >= i64(len(r.s)) { + return 0, .EOF; + } + b := r.s[r.i]; + r.i += 1; + return b, nil; +} +reader_unread_byte :: proc(r: ^Reader) -> io.Error { + if r.i <= 0 { + return .Invalid_Unread; + } + r.prev_rune = -1; + r.i -= 1; + return nil; +} +reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) { + if r.i >= i64(len(r.s)) { + r.prev_rune = -1; + return 0, 0, .EOF; + } + r.prev_rune = int(r.i); + if c := r.s[r.i]; c < utf8.RUNE_SELF { + r.i += 1; + return rune(c), 1, nil; + } + ch, size = utf8.decode_rune_in_string(r.s[r.i:]); + r.i += i64(size); + return; +} +reader_unread_rune :: proc(r: ^Reader) -> io.Error { + if r.i <= 0 { + return .Invalid_Unread; + } + if r.prev_rune < 0 { + return .Invalid_Unread; + } + r.i = i64(r.prev_rune); + r.prev_rune = -1; + return nil; +} +reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { + r.prev_rune = -1; + abs: i64; + switch whence { + case .Start: + abs = offset; + case .Current: + abs = r.i + offset; + case .End: + abs = i64(len(r.s)) + offset; + case: + return 0, .Invalid_Whence; + } + + if abs < 0 { + return 0, .Invalid_Offset; + } + r.i = abs; + return abs, nil; +} +reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { + r.prev_rune = -1; + if r.i >= i64(len(r.s)) { + return 0, nil; + } + s := r.s[r.i:]; + m: int; + m, err = io.write_string(w, s); + if m > len(s) { + panic("bytes.Reader.write_to: invalid io.write_string count"); + } + r.i += i64(m); + n = i64(m); + if m != len(s) && err == nil { + err = .Short_Write; + } + return; +} + + @(private) _reader_vtable := &io.Stream_VTable{ impl_size = proc(s: io.Stream) -> i64 { r := (^Reader)(s.stream_data); - return i64(len(r.s)); + return reader_size(r); }, impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { r := (^Reader)(s.stream_data); - if r.i >= i64(len(r.s)) { - return 0, .EOF; - } - r.prev_rune = -1; - n = copy(p, r.s[r.i:]); - r.i += i64(n); - return; + return reader_read(r, p); }, impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) { r := (^Reader)(s.stream_data); - if off < 0 { - return 0, .Invalid_Offset; - } - if off >= i64(len(r.s)) { - return 0, .EOF; - } - n = copy(p, r.s[off:]); - if n < len(p) { - err = .EOF; - } - return; + return reader_read_at(r, p, off); }, impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) { r := (^Reader)(s.stream_data); - r.prev_rune = -1; - if r.i >= i64(len(r.s)) { - return 0, .EOF; - } - b := r.s[r.i]; - r.i += 1; - return b, nil; + return reader_read_byte(r); }, impl_unread_byte = proc(s: io.Stream) -> io.Error { r := (^Reader)(s.stream_data); - if r.i <= 0 { - return .Invalid_Unread; - } - r.prev_rune = -1; - r.i -= 1; - return nil; + return reader_unread_byte(r); }, impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) { r := (^Reader)(s.stream_data); - if r.i >= i64(len(r.s)) { - r.prev_rune = -1; - return 0, 0, .EOF; - } - r.prev_rune = int(r.i); - if c := r.s[r.i]; c < utf8.RUNE_SELF { - r.i += 1; - return rune(c), 1, nil; - } - ch, size = utf8.decode_rune_in_string(r.s[r.i:]); - r.i += i64(size); - return; + return reader_read_rune(r); }, impl_unread_rune = proc(s: io.Stream) -> io.Error { r := (^Reader)(s.stream_data); - if r.i <= 0 { - return .Invalid_Unread; - } - if r.prev_rune < 0 { - return .Invalid_Unread; - } - r.i = i64(r.prev_rune); - r.prev_rune = -1; - return nil; + return reader_unread_rune(r); }, impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { r := (^Reader)(s.stream_data); - r.prev_rune = -1; - abs: i64; - switch whence { - case .Start: - abs = offset; - case .Current: - abs = r.i + offset; - case .End: - abs = i64(len(r.s)) + offset; - case: - return 0, .Invalid_Whence; - } - - if abs < 0 { - return 0, .Invalid_Offset; - } - r.i = abs; - return abs, nil; + return reader_seek(r, offset, whence); }, impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { r := (^Reader)(s.stream_data); - r.prev_rune = -1; - if r.i >= i64(len(r.s)) { - return 0, nil; - } - s := r.s[r.i:]; - m: int; - m, err = io.write_string(w, s); - if m > len(s) { - panic("strings.Reader.write_to: invalid io.write_string count"); - } - r.i += i64(m); - n = i64(m); - if m != len(s) && err == nil { - err = .Short_Write; - } - return; + return reader_write_to(r, w); }, };