lookahead_reader.odin 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package bufio
  2. import "core:io"
  3. // Lookahead_Reader provides io lookahead.
  4. // This is useful for tokenizers/parsers.
  5. // Lookahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Lookahead_Reader's buffer size
  6. // will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
  7. // This makes sure that the buffer will not be accidentally read beyond the expected size.
  8. Lookahead_Reader :: struct {
  9. r: io.Reader,
  10. buf: []byte,
  11. n: int,
  12. }
  13. lookahead_reader_init :: proc(lr: ^Lookahead_Reader, r: io.Reader, buf: []byte) -> ^Lookahead_Reader {
  14. lr.r = r
  15. lr.buf = buf
  16. lr.n = 0
  17. return lr
  18. }
  19. lookahead_reader_buffer :: proc(lr: ^Lookahead_Reader) -> []byte {
  20. return lr.buf[:lr.n]
  21. }
  22. // lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
  23. // If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
  24. // NOTE: The returned buffer is not a copy of the underlying buffer
  25. lookahead_reader_peek :: proc(lr: ^Lookahead_Reader, n: int) -> ([]byte, io.Error) {
  26. switch {
  27. case n < 0:
  28. return nil, .Negative_Read
  29. case n > len(lr.buf):
  30. return nil, .Buffer_Full
  31. }
  32. n := n
  33. err: io.Error
  34. read_count: int
  35. if lr.n < n {
  36. read_count, err = io.read_at_least(lr.r, lr.buf[lr.n:], n-lr.n)
  37. if err == .Unexpected_EOF {
  38. err = .EOF
  39. }
  40. }
  41. lr.n += read_count
  42. if n > lr.n {
  43. n = lr.n
  44. }
  45. return lr.buf[:n], err
  46. }
  47. // lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
  48. // If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
  49. // NOTE: The returned buffer is not a copy of the underlying buffer
  50. lookahead_reader_peek_all :: proc(lr: ^Lookahead_Reader) -> ([]byte, io.Error) {
  51. return lookahead_reader_peek(lr, len(lr.buf))
  52. }
  53. // lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
  54. lookahead_reader_consume :: proc(lr: ^Lookahead_Reader, n: int) -> io.Error {
  55. switch {
  56. case n == 0:
  57. return nil
  58. case n < 0:
  59. return .Negative_Read
  60. case lr.n < n:
  61. return .Short_Buffer
  62. }
  63. copy(lr.buf, lr.buf[n:lr.n])
  64. lr.n -= n
  65. return nil
  66. }
  67. lookahead_reader_consume_all :: proc(lr: ^Lookahead_Reader) -> io.Error {
  68. return lookahead_reader_consume(lr, lr.n)
  69. }