| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- package strings
- import "core:io"
- import "core:unicode/utf8"
- /*
- io stream data for a string reader that can read based on bytes or runes
- implements the vtable when using the `io.Reader` variants
- "read" calls advance the current reading offset `i`
- */
- Reader :: struct {
- s: string, // read-only buffer
- i: i64, // current reading index
- prev_rune: int, // previous reading index of rune or < 0
- }
- /*
- Initializes a string Reader with the provided string
- Inputs:
- - r: A pointer to a Reader struct
- - s: The input string to be read
- */
- reader_init :: proc(r: ^Reader, s: string) {
- r.s = s
- r.i = 0
- r.prev_rune = -1
- }
- /*
- Converts a Reader into an `io.Stream`
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - s: An io.Stream for the given Reader
- */
- reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
- s.data = r
- s.procedure = _reader_proc
- return
- }
- /*
- Initializes a string Reader and returns an `io.Reader` for the given string
- Inputs:
- - r: A pointer to a Reader struct
- - s: The input string to be read
- Returns:
- - res: An io.Reader for the given string
- */
- to_reader :: proc(r: ^Reader, s: string) -> (res: io.Reader) {
- reader_init(r, s)
- rr, _ := io.to_reader(reader_to_stream(r))
- return rr
- }
- /*
- Initializes a string Reader and returns an `io.Reader_At` for the given string
- Inputs:
- - r: A pointer to a Reader struct
- - s: The input string to be read
- Returns:
- - res: An `io.Reader_At` for the given string
- */
- to_reader_at :: proc(r: ^Reader, s: string) -> (res: io.Reader_At) {
- reader_init(r, s)
- rr, _ := io.to_reader_at(reader_to_stream(r))
- return rr
- }
- /*
- Returns the remaining length of the Reader
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - res: The remaining length of the Reader
- */
- reader_length :: proc(r: ^Reader) -> (res: int) {
- if r.i >= i64(len(r.s)) {
- return 0
- }
- return int(i64(len(r.s)) - r.i)
- }
- /*
- Returns the length of the string stored in the Reader
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - res: The length of the string stored in the Reader
- */
- reader_size :: proc(r: ^Reader) -> (res: i64) {
- return i64(len(r.s))
- }
- /*
- Reads len(p) bytes from the Reader's string and copies into the provided slice.
- Inputs:
- - r: A pointer to a Reader struct
- - p: A byte slice to copy data into
- Returns:
- - n: The number of bytes read
- - err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
- */
- 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
- }
- /*
- Reads len(p) bytes from the Reader's string and copies into the provided slice, at the specified offset from the current index.
- Inputs:
- - r: A pointer to a Reader struct
- - p: A byte slice to copy data into
- - off: The offset from which to read
- Returns:
- - n: The number of bytes read
- - err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
- */
- 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
- }
- /*
- Reads and returns a single byte from the Reader's string
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - The byte read from the Reader
- - err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
- */
- reader_read_byte :: proc(r: ^Reader) -> (res: byte, err: 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
- }
- /*
- Decrements the Reader's index (i) by 1
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - err: An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success.
- */
- reader_unread_byte :: proc(r: ^Reader) -> (err: io.Error) {
- if r.i <= 0 {
- return .Invalid_Unread
- }
- r.prev_rune = -1
- r.i -= 1
- return nil
- }
- /*
- Reads and returns a single rune and its `size` from the Reader's string
- Inputs:
- - r: A pointer to a Reader struct
- Returns:
- - rr: The rune read from the Reader
- - size: The size of the rune in bytes
- - err: An `io.Error` if an error occurs while reading
- */
- reader_read_rune :: proc(r: ^Reader) -> (rr: 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
- }
- rr, size = utf8.decode_rune_in_string(r.s[r.i:])
- r.i += i64(size)
- return
- }
- /*
- Decrements the Reader's index (i) by the size of the last read rune
- Inputs:
- - r: A pointer to a Reader struct
- WARNING: May only be used once and after a valid `read_rune` call
- Returns:
- - err: An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success.
- */
- reader_unread_rune :: proc(r: ^Reader) -> (err: 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
- }
- /*
- Seeks the Reader's index to a new position
- Inputs:
- - r: A pointer to a Reader struct
- - offset: The new offset position
- - whence: The reference point for the new position (`.Start`, `.Current`, or `.End`)
- Returns:
- - The absolute offset after seeking
- - err: An `io.Error` if an error occurs while seeking (`.Invalid_Whence`, `.Invalid_Offset`)
- */
- reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (res: i64, err: 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
- }
- /*
- Writes the remaining content of the Reader's string into the provided `io.Writer`
- Inputs:
- - r: A pointer to a Reader struct
- - w: The io.Writer to write the remaining content into
- WARNING: Panics if writer writes more bytes than remainig length of string.
- Returns:
- - n: The number of bytes written
- - err: An io.Error if an error occurs while writing (`.Short_Write`)
- */
- 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
- }
- /*
- VTable containing implementations for various `io.Stream` methods
- This VTable is used by the Reader struct to provide its functionality
- as an `io.Stream`.
- */
- @(private)
- _reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
- r := (^Reader)(stream_data)
- #partial switch mode {
- case .Size:
- n = reader_size(r)
- return
- case .Read:
- return io._i64_err(reader_read(r, p))
- case .Read_At:
- return io._i64_err(reader_read_at(r, p, offset))
- case .Seek:
- n, err = reader_seek(r, offset, whence)
- return
- case .Query:
- return io.query_utility({.Size, .Read, .Read_At, .Seek, .Query})
- }
- return 0, .Empty
- }
|