buffruneio.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads.
  2. package buffruneio
  3. import (
  4. "bufio"
  5. "container/list"
  6. "errors"
  7. "io"
  8. )
  9. // Rune to indicate end of file.
  10. const (
  11. EOF = -(iota + 1)
  12. )
  13. // ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer.
  14. var ErrNoRuneToUnread = errors.New("no rune to unwind")
  15. // Reader implements runes buffering for an io.Reader object.
  16. type Reader struct {
  17. buffer *list.List
  18. current *list.Element
  19. input *bufio.Reader
  20. }
  21. // NewReader returns a new Reader.
  22. func NewReader(rd io.Reader) *Reader {
  23. return &Reader{
  24. buffer: list.New(),
  25. input: bufio.NewReader(rd),
  26. }
  27. }
  28. type runeWithSize struct {
  29. r rune
  30. size int
  31. }
  32. func (rd *Reader) feedBuffer() error {
  33. r, size, err := rd.input.ReadRune()
  34. if err != nil {
  35. if err != io.EOF {
  36. return err
  37. }
  38. r = EOF
  39. }
  40. newRuneWithSize := runeWithSize{r, size}
  41. rd.buffer.PushBack(newRuneWithSize)
  42. if rd.current == nil {
  43. rd.current = rd.buffer.Back()
  44. }
  45. return nil
  46. }
  47. // ReadRune reads the next rune from buffer, or from the underlying reader if needed.
  48. func (rd *Reader) ReadRune() (rune, int, error) {
  49. if rd.current == rd.buffer.Back() || rd.current == nil {
  50. err := rd.feedBuffer()
  51. if err != nil {
  52. return EOF, 0, err
  53. }
  54. }
  55. runeWithSize := rd.current.Value.(runeWithSize)
  56. rd.current = rd.current.Next()
  57. return runeWithSize.r, runeWithSize.size, nil
  58. }
  59. // UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
  60. func (rd *Reader) UnreadRune() error {
  61. if rd.current == rd.buffer.Front() {
  62. return ErrNoRuneToUnread
  63. }
  64. if rd.current == nil {
  65. rd.current = rd.buffer.Back()
  66. } else {
  67. rd.current = rd.current.Prev()
  68. }
  69. return nil
  70. }
  71. // Forget removes runes stored before the current stream position index.
  72. func (rd *Reader) Forget() {
  73. if rd.current == nil {
  74. rd.current = rd.buffer.Back()
  75. }
  76. for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
  77. }
  78. }
  79. // PeekRune returns at most the next n runes, reading from the uderlying source if
  80. // needed. Does not move the current index. It includes EOF if reached.
  81. func (rd *Reader) PeekRunes(n int) []rune {
  82. res := make([]rune, 0, n)
  83. cursor := rd.current
  84. for i := 0; i < n; i++ {
  85. if cursor == nil {
  86. err := rd.feedBuffer()
  87. if err != nil {
  88. return res
  89. }
  90. cursor = rd.buffer.Back()
  91. }
  92. if cursor != nil {
  93. r := cursor.Value.(runeWithSize).r
  94. res = append(res, r)
  95. if r == EOF {
  96. return res
  97. }
  98. cursor = cursor.Next()
  99. }
  100. }
  101. return res
  102. }