123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- package io
- import "core:intrinsics"
- import "core:runtime"
- import "core:unicode/utf8"
- Seek_From :: enum {
- Start = 0, // seek relative to the origin of the file
- Current = 1, // seek relative to the current offset
- End = 2, // seek relative to the end
- }
- Error :: enum i32 {
- // No Error
- None = 0,
- // EOF is the error returned by `read` when no more input is available
- EOF,
- // Unexpected_EOF means that EOF was encountered in the middle of reading a fixed-sized block of data
- Unexpected_EOF,
- // Short_Write means that a write accepted fewer bytes than requested but failed to return an explicit error
- Short_Write,
- // Invalid_Write means that a write returned an impossible count
- Invalid_Write,
- // Short_Buffer means that a read required a longer buffer than was provided
- Short_Buffer,
- // No_Progress is returned by some implementations of `io.Reader` when many calls
- // to `read` have failed to return any data or error.
- // This is usually a signed of a broken `io.Reader` implementation
- No_Progress,
- Invalid_Whence,
- Invalid_Offset,
- Invalid_Unread,
- Negative_Read,
- Negative_Write,
- Negative_Count,
- Buffer_Full,
- // Unknown means that an error has occurred but cannot be categorized
- Unknown,
- // Empty is returned when a procedure has not been implemented for an io.Stream
- 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 :: struct {
- using stream_vtable: ^Stream_VTable,
- stream_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}
- Closer :: struct {using stream: Stream}
- Flusher :: struct {using stream: Stream}
- Seeker :: struct {using stream: Stream}
- Read_Writer :: struct {using stream: Stream}
- Read_Closer :: struct {using stream: Stream}
- Read_Write_Closer :: struct {using stream: Stream}
- Read_Write_Seeker :: struct {using stream: Stream}
- Write_Closer :: struct {using stream: Stream}
- Write_Seeker :: struct {using stream: Stream}
- Write_Flusher :: struct {using stream: Stream}
- 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}
- Byte_Reader :: struct {using stream: Stream}
- Byte_Scanner :: struct {using stream: Stream}
- Byte_Writer :: struct {using stream: Stream}
- Rune_Reader :: struct {using stream: Stream}
- Rune_Scanner :: 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()
- }
- if close_err != .None {
- return close_err
- }
- return .Empty
- }
- read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
- if s.stream_vtable != nil && s.impl_read != nil {
- n, err = s->impl_read(p)
- if n_read != nil {
- n_read^ += n
- }
- return
- }
- return 0, .Empty
- }
- write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
- if s.stream_vtable != nil && s.impl_write != nil {
- n, err = s->impl_write(p)
- if n_written != nil {
- n_written^ += n
- }
- return
- }
- return 0, .Empty
- }
- 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)
- }
- return 0, .Empty
- }
- close :: proc(s: Closer) -> Error {
- if s.stream_vtable != nil && s.impl_close != nil {
- return s->impl_close()
- }
- // Instead of .Empty, .None is fine in this case
- return .None
- }
- flush :: proc(s: Flusher) -> Error {
- if s.stream_vtable != nil && s.impl_flush != nil {
- return s->impl_flush()
- }
- // Instead of .Empty, .None is fine in this case
- return .None
- }
- size :: proc(s: Stream) -> i64 {
- if s.stream_vtable == nil {
- return 0
- }
- 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
- }
- 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: i64
- curr_offset, err = r->impl_seek(offset, .Current)
- if err != nil {
- return 0, err
- }
- n, err = r->impl_read(p)
- _, err1 := r->impl_seek(curr_offset, .Start)
- if err1 != nil && err == nil {
- err = err1
- }
- return
- }
- 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
- }
- 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 :: proc(r: Byte_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
- }
- write_byte :: proc{
- write_byte_to_byte_writer,
- write_byte_to_writer,
- }
- write_byte_to_byte_writer :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> Error {
- return _write_byte(w, c, n_written)
- }
- write_byte_to_writer :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error {
- return _write_byte(auto_cast w, c, n_written)
- }
- @(private)
- _write_byte :: proc(w: Byte_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
- }
- read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
- 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])
-
- s0 := b[0]
- ch = rune(s0)
- size = 1
- if err != nil {
- return
- }
- if ch < utf8.RUNE_SELF {
- return
- }
- x := utf8.accept_sizes[s0]
- if x >= 0xf0 {
- mask := rune(x) << 31 >> 31
- ch = ch &~ mask | utf8.RUNE_ERROR&mask
- return
- }
- sz := int(x&7)
- size, err = br->impl_read(b[1:sz])
- if err != nil || size+1 < sz {
- ch = utf8.RUNE_ERROR
- return
- }
- ch, size = utf8.decode_rune(b[:sz])
- return
- }
- unread_byte :: proc(s: Byte_Scanner) -> Error {
- if s.stream_vtable != nil && s.impl_unread_byte != nil {
- return s->impl_unread_byte()
- }
- return .Empty
- }
- unread_rune :: proc(s: Rune_Scanner) -> Error {
- if s.stream_vtable != nil && s.impl_unread_rune != nil {
- return s->impl_unread_rune()
- }
- return .Empty
- }
- write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) {
- return write(s, transmute([]byte)str, n_written)
- }
- write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
- defer if err == nil && n_written != nil {
- n_written^ += size
- }
-
- if s.stream_vtable != nil && 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 {
- size = 1
- }
- return
- }
- buf, w := utf8.encode_rune(r)
- return write(s, buf[:w])
- }
- read_full :: proc(r: Reader, buf: []byte) -> (n: int, err: Error) {
- return read_at_least(r, buf, len(buf))
- }
- read_at_least :: proc(r: Reader, buf: []byte, min: int) -> (n: int, err: Error) {
- if len(buf) < min {
- return 0, .Short_Buffer
- }
- for n < min && err == nil {
- nn: int
- nn, err = read(r, buf[n:])
- n += nn
- }
- if n >= min {
- err = nil
- } else if n > 0 && err == .EOF {
- err = .Unexpected_EOF
- }
- return
- }
- // copy copies from src to dst till either EOF is reached on src or an error occurs
- // It returns the number of bytes copied and the first error that occurred whilst copying, if any.
- copy :: proc(dst: Writer, src: Reader) -> (written: i64, err: Error) {
- return _copy_buffer(dst, src, nil)
- }
- // copy_buffer is the same as copy except that it stages through the provided buffer (if one is required)
- // rather than allocating a temporary one on the stack through `intrinsics.alloca`
- // If buf is `nil`, it is allocate through `intrinsics.alloca`; otherwise if it has zero length, it will panic
- copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err: Error) {
- if buf != nil && len(buf) == 0 {
- panic("empty buffer in io.copy_buffer")
- }
- return _copy_buffer(dst, src, buf)
- }
- // copy_n copies n bytes (or till an error) from src to dst.
- // It returns the number of bytes copied and the first error that occurred whilst copying, if any.
- // On return, written == n IFF err == nil
- copy_n :: proc(dst: Writer, src: Reader, n: i64) -> (written: i64, err: Error) {
- nsrc := limited_reader_init(&Limited_Reader{}, src, n)
- written, err = copy(dst, nsrc)
- if written == n {
- return n, nil
- }
- if written < n && err == nil {
- // src stopped early and must have been an EOF
- err = .EOF
- }
- return
- }
- @(private)
- _copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err: Error) {
- if dst.stream_vtable == nil || src.stream_vtable == 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 i64(size) > l.n {
- if l.n < 1 {
- size = 1
- } else {
- size = int(l.n)
- }
- }
- }
- // NOTE(bill): alloca is fine here
- buf = transmute([]byte)runtime.Raw_Slice{intrinsics.alloca(size, 2*align_of(rawptr)), size}
- }
- for {
- nr, er := read(src, buf)
- if nr > 0 {
- nw, ew := write(dst, buf[0:nr])
- if nw > 0 {
- written += i64(nw)
- }
- if ew != nil {
- err = ew
- break
- }
- if nr != nw {
- err = .Short_Write
- break
- }
- }
- if er != nil {
- if er != .EOF {
- err = er
- }
- break
- }
- }
- return
- }
|