diff options
| author | gingerBill <bill@gingerbill.org> | 2020-12-03 15:57:46 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-12-03 15:57:46 +0000 |
| commit | 0ef02e6737ffc382a00fc549811e9fca49bd4089 (patch) | |
| tree | 41c107dab6a0e48c69e2e66e5885faf681974ef3 /core/io | |
| parent | 047586afc69977164567daff0927afea31284519 (diff) | |
Improve packages io and strings; add io.Section_Reader
Diffstat (limited to 'core/io')
| -rw-r--r-- | core/io/io.odin | 15 | ||||
| -rw-r--r-- | core/io/util.odin | 94 |
2 files changed, 102 insertions, 7 deletions
diff --git a/core/io/io.odin b/core/io/io.odin index bc23c4c86..bfa81d417 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -35,13 +35,16 @@ Error :: enum i32 { Invalid_Offset, Invalid_Unread, + Negative_Read, + Negative_Write, + // Empty is returned when a procedure has not been implemented for an io.Stream Empty = -1, } Close_Proc :: distinct proc(using s: Stream) -> Error; Flush_Proc :: distinct proc(using s: Stream) -> Error; -Seek_Proc :: distinct proc(using s: Stream, offset: i64, whence: Seek_From) -> (i64, Error); +Seek_Proc :: distinct proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error); Size_Proc :: distinct proc(using s: Stream) -> i64; Read_Proc :: distinct proc(using s: Stream, p: []byte) -> (n: int, err: Error); Read_At_Proc :: distinct proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error); @@ -120,7 +123,10 @@ destroy :: proc(s: Stream) -> Error { if s.stream_vtable != nil && s.impl_destroy != nil { return s->impl_destroy(); } - return close_err; + if close_err != .None { + return close_err; + } + return .Empty; } read :: proc(s: Reader, p: []byte) -> (n: int, err: Error) { @@ -364,6 +370,11 @@ write_string :: proc(s: Writer, str: string) -> (n: int, err: Error) { } write_rune :: proc(s: Writer, r: rune) -> (n: int, err: Error) { + if r < utf8.RUNE_SELF { + err = write_byte(s, byte(r)); + n = 1 if err == nil else 0; + return; + } buf, w := utf8.encode_rune(r); return write(s, buf[:w]); } diff --git a/core/io/util.odin b/core/io/util.odin index b618a6c23..2036aa570 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -48,7 +48,11 @@ _tee_reader_vtable := &Stream_VTable{ }, }; -// tee_reader +// tee_reader returns a Reader that writes to 'w' what it reads from 'r' +// All reads from 'r' performed through it are matched with a corresponding write to 'w' +// There is no internal buffering done +// The write must complete before th read completes +// Any error encountered whilst writing is reported as a 'read' error // tee_reader must call io.destroy when done with tee_reader :: proc(r: Reader, w: Writer, allocator := context.allocator) -> (out: Reader) { t := new(Tee_Reader, allocator); @@ -61,9 +65,8 @@ tee_reader :: proc(r: Reader, w: Writer, allocator := context.allocator) -> (out } -// A Limited_Reader reads from r but limits the amount of -// data returned to just n bytes. Each call to read -// updates n to reflect the new amount remaining. +// A Limited_Reader reads from r but limits the amount of data returned to just n bytes. +// Each call to read updates n to reflect the new amount remaining. // read returns EOF when n <= 0 or when the underlying r returns EOF. Limited_Reader :: struct { r: Reader, // underlying reader @@ -72,7 +75,7 @@ Limited_Reader :: struct { @(private) _limited_reader_vtable := &Stream_VTable{ - impl_read = proc(using s: Stream, p: []byte) -> (n: int, err: Error) { + impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) { l := (^Limited_Reader)(s.stream_data); if l.n <= 0 { return 0, .EOF; @@ -106,3 +109,84 @@ inline_limited_reader :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader { l.n = n; return limited_reader_to_reader(l); } + +// Section_Reader implements read, seek, and read_at on a section of an underlying Reader_At +Section_Reader :: struct { + r: Reader_At, + base: i64, + off: i64, + limit: i64, +} + +init_section_reader :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) { + s.r = r; + s.off = off; + s.limit = off + n; + return; +} +section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) { + out.stream_data = s; + out.stream_vtable = _section_reader_vtable; + return; +} + +@(private) +_section_reader_vtable := &Stream_VTable{ + impl_read = proc(stream: Stream, p: []byte) -> (n: int, err: Error) { + s := (^Section_Reader)(stream.stream_data); + if s.off >= s.limit { + return 0, .EOF; + } + p := p; + if max := s.limit - s.off; i64(len(p)) > max { + p = p[0:max]; + } + n, err = read_at(s.r, p, s.off); + s.off += i64(n); + return; + }, + impl_read_at = proc(stream: Stream, p: []byte, off: i64) -> (n: int, err: Error) { + s := (^Section_Reader)(stream.stream_data); + p, off := p, off; + + if off < 0 || off >= s.limit - s.base { + return 0, .EOF; + } + off += s.base; + if max := s.limit - off; i64(len(p)) > max { + p = p[0:max]; + n, err = read_at(s.r, p, off); + if err == nil { + err = .EOF; + } + return; + } + return read_at(s.r, p, off); + }, + impl_seek = proc(stream: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + s := (^Section_Reader)(stream.stream_data); + + offset := offset; + switch whence { + case: + return 0, .Invalid_Whence; + case .Start: + offset += s.base; + case .Current: + offset += s.off; + case .End: + offset += s.limit; + } + if offset < s.base { + return 0, .Invalid_Offset; + } + s.off = offset; + n = offset - s.base; + return; + }, + impl_size = proc(stream: Stream) -> i64 { + s := (^Section_Reader)(stream.stream_data); + return s.limit - s.base; + }, +}; + |