mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Update to new io interface
This commit is contained in:
+15
-59
@@ -2,123 +2,79 @@ package io
|
||||
|
||||
to_reader :: proc(s: Stream) -> (r: Reader, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = .Read in query(s)
|
||||
return
|
||||
}
|
||||
to_writer :: proc(s: Stream) -> (w: Writer, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = .Write in query(s)
|
||||
return
|
||||
}
|
||||
|
||||
to_closer :: proc(s: Stream) -> (c: Closer, ok: bool = true) #optional_ok {
|
||||
c.stream = s
|
||||
if s.stream_vtable == nil || s.impl_close == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = .Close in query(s)
|
||||
return
|
||||
}
|
||||
to_flusher :: proc(s: Stream) -> (f: Flusher, ok: bool = true) #optional_ok {
|
||||
f.stream = s
|
||||
if s.stream_vtable == nil || s.impl_flush == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = .Flush in query(s)
|
||||
return
|
||||
}
|
||||
to_seeker :: proc(s: Stream) -> (seeker: Seeker, ok: bool = true) #optional_ok {
|
||||
seeker.stream = s
|
||||
if s.stream_vtable == nil || s.impl_seek == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = .Seek in query(s)
|
||||
return
|
||||
}
|
||||
|
||||
to_read_writer :: proc(s: Stream) -> (r: Read_Writer, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Read, .Write}
|
||||
return
|
||||
}
|
||||
to_read_closer :: proc(s: Stream) -> (r: Read_Closer, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read == nil || s.impl_close == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Read, .Close}
|
||||
return
|
||||
}
|
||||
to_read_write_closer :: proc(s: Stream) -> (r: Read_Write_Closer, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil || s.impl_close == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Read, .Write, .Close}
|
||||
return
|
||||
}
|
||||
to_read_write_seeker :: proc(s: Stream) -> (r: Read_Write_Seeker, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil || s.impl_seek == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Read, .Write, .Seek}
|
||||
return
|
||||
}
|
||||
to_write_flusher :: proc(s: Stream) -> (w: Write_Flusher, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write == nil || s.impl_flush == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Write, .Flush}
|
||||
return
|
||||
}
|
||||
to_write_flush_closer :: proc(s: Stream) -> (w: Write_Flush_Closer, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write == nil || s.impl_flush == nil || s.impl_close == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Write, .Flush, .Close}
|
||||
return
|
||||
}
|
||||
|
||||
to_reader_at :: proc(s: Stream) -> (r: Reader_At, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read_at == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Read_At}
|
||||
return
|
||||
}
|
||||
to_writer_at :: proc(s: Stream) -> (w: Writer_At, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write_at == nil {
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
to_reader_from :: proc(s: Stream) -> (r: Reader_From, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read_from == nil {
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
to_writer_to :: proc(s: Stream) -> (w: Writer_To, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write_to == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Write_At}
|
||||
return
|
||||
}
|
||||
to_write_closer :: proc(s: Stream) -> (w: Write_Closer, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write == nil || s.impl_close == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Write, .Close}
|
||||
return
|
||||
}
|
||||
to_write_seeker :: proc(s: Stream) -> (w: Write_Seeker, ok: bool = true) #optional_ok {
|
||||
w.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write == nil || s.impl_seek == nil {
|
||||
ok = false
|
||||
}
|
||||
ok = query(s) >= {.Write, .Seek}
|
||||
return
|
||||
}
|
||||
|
||||
+136
-283
@@ -53,54 +53,27 @@ Error :: enum i32 {
|
||||
Empty = -1,
|
||||
}
|
||||
|
||||
Close_Proc :: proc(using s: Stream) -> Error
|
||||
Flush_Proc :: proc(using s: Stream) -> Error
|
||||
Seek_Proc :: proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
|
||||
Size_Proc :: proc(using s: Stream) -> i64
|
||||
Read_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error)
|
||||
Read_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error)
|
||||
Read_From_Proc :: proc(using s: Stream, r: Reader) -> (n: i64, err: Error)
|
||||
Read_Byte_Proc :: proc(using s: Stream) -> (byte, Error)
|
||||
Read_Rune_Proc :: proc(using s: Stream) -> (ch: rune, size: int, err: Error)
|
||||
Unread_Byte_Proc :: proc(using s: Stream) -> Error
|
||||
Unread_Rune_Proc :: proc(using s: Stream) -> Error
|
||||
Write_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error)
|
||||
Write_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error)
|
||||
Write_To_Proc :: proc(using s: Stream, w: Writer) -> (n: i64, err: Error)
|
||||
Write_Byte_Proc :: proc(using s: Stream, c: byte) -> Error
|
||||
Write_Rune_Proc :: proc(using s: Stream, r: rune) -> (size: int, err: Error)
|
||||
Destroy_Proc :: proc(using s: Stream) -> Error
|
||||
Stream_Mode :: enum {
|
||||
Close,
|
||||
Flush,
|
||||
Read,
|
||||
Read_At,
|
||||
Write,
|
||||
Write_At,
|
||||
Seek,
|
||||
Size,
|
||||
Destroy,
|
||||
Query, // query what modes are available
|
||||
}
|
||||
|
||||
Stream_Mode_Set :: distinct bit_set[Stream_Mode; i64]
|
||||
|
||||
Stream_Proc :: #type proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
|
||||
|
||||
Stream :: struct {
|
||||
using stream_vtable: ^Stream_VTable,
|
||||
stream_data: rawptr,
|
||||
procedure: Stream_Proc,
|
||||
data: rawptr,
|
||||
}
|
||||
Stream_VTable :: struct {
|
||||
impl_close: Close_Proc,
|
||||
impl_flush: Flush_Proc,
|
||||
|
||||
impl_seek: Seek_Proc,
|
||||
impl_size: Size_Proc,
|
||||
|
||||
impl_read: Read_Proc,
|
||||
impl_read_at: Read_At_Proc,
|
||||
impl_read_byte: Read_Byte_Proc,
|
||||
impl_read_rune: Read_Rune_Proc,
|
||||
impl_write_to: Write_To_Proc,
|
||||
|
||||
impl_write: Write_Proc,
|
||||
impl_write_at: Write_At_Proc,
|
||||
impl_write_byte: Write_Byte_Proc,
|
||||
impl_write_rune: Write_Rune_Proc,
|
||||
impl_read_from: Read_From_Proc,
|
||||
|
||||
impl_unread_byte: Unread_Byte_Proc,
|
||||
impl_unread_rune: Unread_Rune_Proc,
|
||||
|
||||
impl_destroy: Destroy_Proc,
|
||||
}
|
||||
|
||||
|
||||
Reader :: struct {using stream: Stream}
|
||||
Writer :: struct {using stream: Stream}
|
||||
@@ -120,70 +93,66 @@ Write_Flush_Closer :: struct {using stream: Stream}
|
||||
|
||||
Reader_At :: struct {using stream: Stream}
|
||||
Writer_At :: struct {using stream: Stream}
|
||||
Reader_From :: struct {using stream: Stream}
|
||||
Writer_To :: struct {using stream: Stream}
|
||||
|
||||
|
||||
destroy :: proc(s: Stream) -> Error {
|
||||
close_err := close({s})
|
||||
if s.stream_vtable != nil && s.impl_destroy != nil {
|
||||
return s->impl_destroy()
|
||||
destroy :: proc(s: Stream) -> (err: Error) {
|
||||
_ = flush({s})
|
||||
_ = close({s})
|
||||
if s.procedure != nil {
|
||||
_, err = s.procedure(s.data, .Destroy, nil, 0, nil)
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
if close_err != .None {
|
||||
return close_err
|
||||
}
|
||||
return .Empty
|
||||
return
|
||||
}
|
||||
|
||||
query :: proc(s: Stream) -> (set: Stream_Mode_Set) {
|
||||
if s.procedure != nil {
|
||||
n, _ := s.procedure(s.data, .Query, nil, 0, nil)
|
||||
set = transmute(Stream_Mode_Set)n
|
||||
if set != nil {
|
||||
set += {.Query}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
query_utility :: #force_inline proc "contextless" (set: Stream_Mode_Set) -> (n: i64, err: Error) {
|
||||
return transmute(i64)set, nil
|
||||
}
|
||||
|
||||
_i64_err :: #force_inline proc "contextless" (n: int, err: Error) -> (i64, Error) {
|
||||
return i64(n), err
|
||||
}
|
||||
|
||||
|
||||
// read reads up to len(p) bytes into s. It returns the number of bytes read and any error if occurred.
|
||||
//
|
||||
// When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of
|
||||
// bytes read along with the error.
|
||||
read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_read != nil {
|
||||
n, err = s->impl_read(p)
|
||||
if n_read != nil {
|
||||
n_read^ += n
|
||||
}
|
||||
return
|
||||
} else if s.impl_read_byte != nil {
|
||||
bytes_read := 0
|
||||
defer if n_read != nil {
|
||||
n_read^ += bytes_read
|
||||
}
|
||||
for _, i in p {
|
||||
p[i] = s->impl_read_byte() or_return
|
||||
bytes_read += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
if s.procedure != nil {
|
||||
n64: i64
|
||||
n64, err = s.procedure(s.data, .Read, p, 0, nil)
|
||||
n = int(n64)
|
||||
if n_read != nil { n_read^ += n }
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
return 0, .Empty
|
||||
return
|
||||
}
|
||||
|
||||
// write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred.
|
||||
write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_write != nil {
|
||||
n, err = s->impl_write(p)
|
||||
if n_written != nil {
|
||||
n_written^ += n
|
||||
}
|
||||
return
|
||||
} else if s.impl_write_byte != nil {
|
||||
bytes_written := 0
|
||||
defer if n_written != nil {
|
||||
n_written^ += bytes_written
|
||||
}
|
||||
for c in p {
|
||||
s->impl_write_byte(c) or_return
|
||||
bytes_written += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
if s.procedure != nil {
|
||||
n64: i64
|
||||
n64, err = s.procedure(s.data, .Write, p, 0, nil)
|
||||
n = int(n64)
|
||||
if n_written != nil { n_written^ += n }
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
return 0, .Empty
|
||||
return
|
||||
}
|
||||
|
||||
// seek sets the offset of the next read or write to offset.
|
||||
@@ -194,57 +163,46 @@ write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Erro
|
||||
//
|
||||
// seek returns the new offset to the start of the file/stream, and any error if occurred.
|
||||
seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_seek != nil {
|
||||
return s->impl_seek(offset, whence)
|
||||
if s.procedure != nil {
|
||||
n, err = s.procedure(s.data, .Seek, nil, offset, whence)
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
return 0, .Empty
|
||||
return
|
||||
}
|
||||
|
||||
// The behaviour of close after the first call is stream implementation defined.
|
||||
// Different streams may document their own behaviour.
|
||||
close :: proc(s: Closer) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_close != nil {
|
||||
return s->impl_close()
|
||||
close :: proc(s: Closer) -> (err: Error) {
|
||||
if s.procedure != nil {
|
||||
_, err = s.procedure(s.data, .Close, nil, 0, nil)
|
||||
}
|
||||
// Instead of .Empty, .None is fine in this case
|
||||
return .None
|
||||
return
|
||||
}
|
||||
|
||||
flush :: proc(s: Flusher) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_flush != nil {
|
||||
return s->impl_flush()
|
||||
flush :: proc(s: Flusher) -> (err: Error) {
|
||||
if s.procedure != nil {
|
||||
_, err = s.procedure(s.data, .Flush, nil, 0, nil)
|
||||
}
|
||||
// Instead of .Empty, .None is fine in this case
|
||||
return .None
|
||||
return
|
||||
}
|
||||
|
||||
// size returns the size of the stream. If the stream does not support querying its size, 0 will be returned.
|
||||
size :: proc(s: Stream) -> i64 {
|
||||
if s.stream_vtable == nil {
|
||||
return 0
|
||||
size :: proc(s: Stream) -> (n: i64, err: Error) {
|
||||
if s.procedure != nil {
|
||||
n, err = s.procedure(s.data, .Size, nil, 0, nil)
|
||||
if err == .Empty {
|
||||
seeker := Seeker{s}
|
||||
n = 0
|
||||
curr := seek(seeker, 0, .Current) or_return
|
||||
end := seek(seeker, 0, .End) or_return
|
||||
seek(seeker, curr, .Start) or_return
|
||||
n = end
|
||||
}
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
if s.impl_size != nil {
|
||||
return s->impl_size()
|
||||
}
|
||||
if s.impl_seek == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
curr, end: i64
|
||||
err: Error
|
||||
if curr, err = s->impl_seek(0, .Current); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if end, err = s->impl_seek(0, .End); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if _, err = s->impl_seek(curr, .Start); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return end
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -256,29 +214,26 @@ size :: proc(s: Stream) -> i64 {
|
||||
//
|
||||
// If n == len(p), err may be either nil or .EOF
|
||||
read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
defer if n_read != nil {
|
||||
n_read^ += n
|
||||
}
|
||||
|
||||
if r.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if r.impl_read_at != nil {
|
||||
return r->impl_read_at(p, offset)
|
||||
}
|
||||
if r.impl_seek == nil || r.impl_read == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
curr_offset := r->impl_seek(offset, .Current) or_return
|
||||
|
||||
n, err = r->impl_read(p)
|
||||
_, err1 := r->impl_seek(curr_offset, .Start)
|
||||
if err1 != nil && err == nil {
|
||||
err = err1
|
||||
if r.procedure != nil {
|
||||
n64: i64
|
||||
n64, err = r.procedure(r.data, .Read_At, p, offset, nil)
|
||||
if err != .Empty {
|
||||
n = int(n64)
|
||||
} else {
|
||||
seeker := Seeker{r}
|
||||
reader := Reader{r}
|
||||
curr := seek(seeker, offset, .Current) or_return
|
||||
n, err = read(reader, p)
|
||||
_, err1 := seek(seeker, curr, .Start)
|
||||
if err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
if n_read != nil { n_read^ += n }
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// write_at writes len(p) bytes into p starting with the provided offset in the underlying Writer_At stream w.
|
||||
@@ -287,97 +242,41 @@ read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n:
|
||||
// If write_at is writing to a Writer_At which has a seek offset, then write_at should not affect the underlying
|
||||
// seek offset.
|
||||
write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
defer if n_written != nil {
|
||||
n_written^ += n
|
||||
}
|
||||
|
||||
if w.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if w.impl_write_at != nil {
|
||||
return w->impl_write_at(p, offset)
|
||||
}
|
||||
if w.impl_seek == nil || w.impl_write == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
curr_offset: i64
|
||||
curr_offset, err = w->impl_seek(offset, .Current)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n, err = w->impl_write(p)
|
||||
_, err1 := w->impl_seek(curr_offset, .Start)
|
||||
if err1 != nil && err == nil {
|
||||
err = err1
|
||||
if w.procedure != nil {
|
||||
n64: i64
|
||||
n64, err = w.procedure(w.data, .Write_At, p, offset, nil)
|
||||
if err != .Empty {
|
||||
n = int(n64)
|
||||
} else {
|
||||
seeker := Seeker{w}
|
||||
writer := Writer{w}
|
||||
curr := seek(seeker, offset, .Current) or_return
|
||||
n, err = write(writer, p)
|
||||
_, err1 := seek(seeker, curr, .Start)
|
||||
if err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
if n_written != nil { n_written^ += n }
|
||||
} else {
|
||||
err = .Empty
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
write_to :: proc(r: Writer_To, w: Writer) -> (n: i64, err: Error) {
|
||||
if r.stream_vtable == nil || w.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if r.impl_write_to != nil {
|
||||
return r->impl_write_to(w)
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) {
|
||||
if r.stream_vtable == nil || w.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if r.impl_read_from != nil {
|
||||
return w->impl_read_from(r)
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
// read_byte reads and returns the next byte from r.
|
||||
read_byte :: proc(r: Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += 1
|
||||
}
|
||||
|
||||
if r.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if r.impl_read_byte != nil {
|
||||
return r->impl_read_byte()
|
||||
}
|
||||
if r.impl_read == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
buf: [1]byte
|
||||
_, err = r->impl_read(buf[:])
|
||||
return buf[0], err
|
||||
_, err = read(r, buf[:], n_read)
|
||||
b = buf[0]
|
||||
return
|
||||
}
|
||||
|
||||
write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error {
|
||||
return _write_byte(auto_cast w, c, n_written)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> (err: Error) {
|
||||
defer if err == nil && n_written != nil {
|
||||
n_written^ += 1
|
||||
}
|
||||
if w.stream_vtable == nil {
|
||||
return .Empty
|
||||
}
|
||||
if w.impl_write_byte != nil {
|
||||
return w->impl_write_byte(c)
|
||||
}
|
||||
if w.impl_write == nil {
|
||||
return .Empty
|
||||
}
|
||||
|
||||
b := [1]byte{c}
|
||||
_, err = w->impl_write(b[:])
|
||||
return err
|
||||
buf: [1]byte
|
||||
buf[0] = c
|
||||
write(w, buf[:], n_written) or_return
|
||||
return nil
|
||||
}
|
||||
|
||||
// read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes.
|
||||
@@ -385,19 +284,9 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err:
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += size
|
||||
}
|
||||
if br.stream_vtable == nil {
|
||||
return 0, 0, .Empty
|
||||
}
|
||||
if br.impl_read_rune != nil {
|
||||
return br->impl_read_rune()
|
||||
}
|
||||
if br.impl_read == nil {
|
||||
return 0, 0, .Empty
|
||||
}
|
||||
|
||||
b: [utf8.UTF_MAX]byte
|
||||
_, err = br->impl_read(b[:1])
|
||||
|
||||
_, err = read(br, b[:1])
|
||||
|
||||
s0 := b[0]
|
||||
ch = rune(s0)
|
||||
@@ -415,7 +304,7 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err:
|
||||
return
|
||||
}
|
||||
sz := int(x&7)
|
||||
size, err = br->impl_read(b[1:sz])
|
||||
size, err = read(br, b[1:sz])
|
||||
if err != nil || size+1 < sz {
|
||||
ch = utf8.RUNE_ERROR
|
||||
return
|
||||
@@ -425,28 +314,6 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err:
|
||||
return
|
||||
}
|
||||
|
||||
unread_byte :: proc(s: Stream) -> Error {
|
||||
if s.stream_vtable == nil {
|
||||
return .Empty
|
||||
}
|
||||
if s.impl_unread_byte != nil {
|
||||
return s->impl_unread_byte()
|
||||
}
|
||||
if s.impl_seek != nil {
|
||||
_, err := s->impl_seek(-1, .Current)
|
||||
return err
|
||||
}
|
||||
|
||||
return .Empty
|
||||
}
|
||||
unread_rune :: proc(s: Writer) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_unread_rune != nil {
|
||||
return s->impl_unread_rune()
|
||||
}
|
||||
return .Empty
|
||||
}
|
||||
|
||||
|
||||
// write_string writes the contents of the string s to w.
|
||||
write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
return write(s, transmute([]byte)str, n_written)
|
||||
@@ -457,14 +324,6 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err
|
||||
defer if err == nil && n_written != nil {
|
||||
n_written^ += size
|
||||
}
|
||||
|
||||
if s.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if s.impl_write_rune != nil {
|
||||
return s->impl_write_rune(r)
|
||||
}
|
||||
|
||||
if r < utf8.RUNE_SELF {
|
||||
err = write_byte(s, byte(r))
|
||||
if err == nil {
|
||||
@@ -542,21 +401,15 @@ copy_n :: proc(dst: Writer, src: Reader, n: i64) -> (written: i64, err: Error) {
|
||||
|
||||
@(private)
|
||||
_copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err: Error) {
|
||||
if dst.stream_vtable == nil || src.stream_vtable == nil {
|
||||
if dst.procedure == nil || src.procedure == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if src.impl_write_to != nil {
|
||||
return src->impl_write_to(dst)
|
||||
}
|
||||
if src.impl_read_from != nil {
|
||||
return dst->impl_read_from(src)
|
||||
}
|
||||
buf := buf
|
||||
if buf == nil {
|
||||
DEFAULT_SIZE :: 4 * 1024
|
||||
size := DEFAULT_SIZE
|
||||
if src.stream_vtable == _limited_reader_vtable {
|
||||
l := (^Limited_Reader)(src.stream_data)
|
||||
if src.procedure == _limited_reader_proc {
|
||||
l := (^Limited_Reader)(src.data)
|
||||
if i64(size) > l.n {
|
||||
if l.n < 1 {
|
||||
size = 1
|
||||
|
||||
+48
-40
@@ -5,33 +5,37 @@ Multi_Reader :: struct {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_multi_reader_vtable := &Stream_VTable{
|
||||
impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
|
||||
mr := (^Multi_Reader)(s.stream_data)
|
||||
for len(mr.readers) > 0 {
|
||||
r := mr.readers[0]
|
||||
n, err = read(r, p)
|
||||
if err == .EOF {
|
||||
ordered_remove(&mr.readers, 0)
|
||||
}
|
||||
if n > 0 || err != .EOF {
|
||||
if err == .EOF && len(mr.readers) > 0 {
|
||||
// Don't return EOF yet, more readers remain
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
_multi_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
if mode == .Query {
|
||||
return query_utility({.Read, .Query})
|
||||
} else if mode != .Read {
|
||||
return 0, .Empty
|
||||
}
|
||||
mr := (^Multi_Reader)(stream_data)
|
||||
for len(mr.readers) > 0 {
|
||||
r := mr.readers[0]
|
||||
n, err = _i64_err(read(r, p))
|
||||
if err == .EOF {
|
||||
ordered_remove(&mr.readers, 0)
|
||||
}
|
||||
return 0, .EOF
|
||||
},
|
||||
if n > 0 || err != .EOF {
|
||||
if err == .EOF && len(mr.readers) > 0 {
|
||||
// Don't return EOF yet, more readers remain
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return 0, .EOF
|
||||
}
|
||||
|
||||
|
||||
multi_reader_init :: proc(mr: ^Multi_Reader, readers: ..Reader, allocator := context.allocator) -> (r: Reader) {
|
||||
all_readers := make([dynamic]Reader, 0, len(readers), allocator)
|
||||
|
||||
for w in readers {
|
||||
if w.stream_vtable == _multi_reader_vtable {
|
||||
other := (^Multi_Reader)(w.stream_data)
|
||||
if w.procedure == _multi_reader_proc {
|
||||
other := (^Multi_Reader)(w.data)
|
||||
append(&all_readers, ..other.readers[:])
|
||||
} else {
|
||||
append(&all_readers, w)
|
||||
@@ -40,8 +44,8 @@ multi_reader_init :: proc(mr: ^Multi_Reader, readers: ..Reader, allocator := con
|
||||
|
||||
mr.readers = all_readers
|
||||
|
||||
r.stream_vtable = _multi_reader_vtable
|
||||
r.stream_data = mr
|
||||
r.procedure = _multi_reader_proc
|
||||
r.data = mr
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,38 +59,42 @@ Multi_Writer :: struct {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_multi_writer_vtable := &Stream_VTable{
|
||||
impl_write = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
|
||||
mw := (^Multi_Writer)(s.stream_data)
|
||||
for w in mw.writers {
|
||||
n, err = write(w, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != len(p) {
|
||||
err = .Short_Write
|
||||
return
|
||||
}
|
||||
_multi_writer_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
if mode == .Query {
|
||||
return query_utility({.Write, .Query})
|
||||
} else if mode != .Write {
|
||||
return 0, .Empty
|
||||
}
|
||||
mw := (^Multi_Writer)(stream_data)
|
||||
for w in mw.writers {
|
||||
n, err = _i64_err(write(w, p))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != i64(len(p)) {
|
||||
err = .Short_Write
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
},
|
||||
return i64(len(p)), nil
|
||||
}
|
||||
|
||||
|
||||
multi_writer_init :: proc(mw: ^Multi_Writer, writers: ..Writer, allocator := context.allocator) -> (out: Writer) {
|
||||
mw.writers = make([dynamic]Writer, 0, len(writers), allocator)
|
||||
|
||||
for w in writers {
|
||||
if w.stream_vtable == _multi_writer_vtable {
|
||||
other := (^Multi_Writer)(w.stream_data)
|
||||
if w.procedure == _multi_writer_proc {
|
||||
other := (^Multi_Writer)(w.data)
|
||||
append(&mw.writers, ..other.writers[:])
|
||||
} else {
|
||||
append(&mw.writers, w)
|
||||
}
|
||||
}
|
||||
|
||||
out.stream_vtable = _multi_writer_vtable
|
||||
out.stream_data = mw
|
||||
out.procedure = _multi_writer_proc
|
||||
out.data = mw
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+43
-36
@@ -292,17 +292,21 @@ Tee_Reader :: struct {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_tee_reader_vtable := &Stream_VTable{
|
||||
impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
|
||||
t := (^Tee_Reader)(s.stream_data)
|
||||
n, err = read(t.r, p)
|
||||
_tee_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
t := (^Tee_Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
n, err = _i64_err(read(t.r, p))
|
||||
if n > 0 {
|
||||
if wn, werr := write(t.w, p[:n]); werr != nil {
|
||||
return wn, werr
|
||||
return i64(wn), werr
|
||||
}
|
||||
}
|
||||
return
|
||||
},
|
||||
case .Query:
|
||||
return query_utility({.Read, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
// tee_reader_init returns a Reader that writes to 'w' what it reads from 'r'
|
||||
@@ -317,8 +321,8 @@ tee_reader_init :: proc(t: ^Tee_Reader, r: Reader, w: Writer, allocator := conte
|
||||
}
|
||||
|
||||
tee_reader_to_reader :: proc(t: ^Tee_Reader) -> (r: Reader) {
|
||||
r.stream_data = t
|
||||
r.stream_vtable = _tee_reader_vtable
|
||||
r.data = t
|
||||
r.procedure = _tee_reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
@@ -332,9 +336,10 @@ Limited_Reader :: struct {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_limited_reader_vtable := &Stream_VTable{
|
||||
impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
|
||||
l := (^Limited_Reader)(s.stream_data)
|
||||
_limited_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
l := (^Limited_Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
if l.n <= 0 {
|
||||
return 0, .EOF
|
||||
}
|
||||
@@ -342,10 +347,13 @@ _limited_reader_vtable := &Stream_VTable{
|
||||
if i64(len(p)) > l.n {
|
||||
p = p[0:l.n]
|
||||
}
|
||||
n, err = read(l.r, p)
|
||||
n, err = _i64_err(read(l.r, p))
|
||||
l.n -= i64(n)
|
||||
return
|
||||
},
|
||||
case .Query:
|
||||
return query_utility({.Read, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
|
||||
@@ -355,8 +363,8 @@ limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
|
||||
}
|
||||
|
||||
limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) {
|
||||
r.stream_vtable = _limited_reader_vtable
|
||||
r.stream_data = l
|
||||
r.procedure = _limited_reader_proc
|
||||
r.data = l
|
||||
return
|
||||
}
|
||||
|
||||
@@ -375,15 +383,16 @@ section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64)
|
||||
return
|
||||
}
|
||||
section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) {
|
||||
out.stream_data = s
|
||||
out.stream_vtable = _section_reader_vtable
|
||||
out.data = s
|
||||
out.procedure = _section_reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_section_reader_vtable := &Stream_VTable{
|
||||
impl_read = proc(stream: Stream, p: []byte) -> (n: int, err: Error) {
|
||||
s := (^Section_Reader)(stream.stream_data)
|
||||
_section_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
s := (^Section_Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
if s.off >= s.limit {
|
||||
return 0, .EOF
|
||||
}
|
||||
@@ -391,13 +400,11 @@ _section_reader_vtable := &Stream_VTable{
|
||||
if max := s.limit - s.off; i64(len(p)) > max {
|
||||
p = p[0:max]
|
||||
}
|
||||
n, err = read_at(s.r, p, s.off)
|
||||
n, err = _i64_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
|
||||
case .Read_At:
|
||||
p, off := p, offset
|
||||
|
||||
if off < 0 || off >= s.limit - s.base {
|
||||
return 0, .EOF
|
||||
@@ -405,17 +412,15 @@ _section_reader_vtable := &Stream_VTable{
|
||||
off += s.base
|
||||
if max := s.limit - off; i64(len(p)) > max {
|
||||
p = p[0:max]
|
||||
n, err = read_at(s.r, p, off)
|
||||
n, err = _i64_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)
|
||||
return _i64_err(read_at(s.r, p, off))
|
||||
|
||||
case .Seek:
|
||||
offset := offset
|
||||
switch whence {
|
||||
case:
|
||||
@@ -433,10 +438,12 @@ _section_reader_vtable := &Stream_VTable{
|
||||
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
|
||||
},
|
||||
}
|
||||
case .Size:
|
||||
n = s.limit - s.base
|
||||
return
|
||||
case .Query:
|
||||
return query_utility({.Read, .Read_At, .Seek, .Size, .Query})
|
||||
}
|
||||
return 0, nil
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user