| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- // Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads.
- package buffruneio
- import (
- "bufio"
- "container/list"
- "errors"
- "io"
- )
- // Rune to indicate end of file.
- const (
- EOF = -(iota + 1)
- )
- // ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer.
- var ErrNoRuneToUnread = errors.New("no rune to unwind")
- // Reader implements runes buffering for an io.Reader object.
- type Reader struct {
- buffer *list.List
- current *list.Element
- input *bufio.Reader
- }
- // NewReader returns a new Reader.
- func NewReader(rd io.Reader) *Reader {
- return &Reader{
- buffer: list.New(),
- input: bufio.NewReader(rd),
- }
- }
- type runeWithSize struct {
- r rune
- size int
- }
- func (rd *Reader) feedBuffer() error {
- r, size, err := rd.input.ReadRune()
- if err != nil {
- if err != io.EOF {
- return err
- }
- r = EOF
- }
- newRuneWithSize := runeWithSize{r, size}
- rd.buffer.PushBack(newRuneWithSize)
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- }
- return nil
- }
- // ReadRune reads the next rune from buffer, or from the underlying reader if needed.
- func (rd *Reader) ReadRune() (rune, int, error) {
- if rd.current == rd.buffer.Back() || rd.current == nil {
- err := rd.feedBuffer()
- if err != nil {
- return EOF, 0, err
- }
- }
- runeWithSize := rd.current.Value.(runeWithSize)
- rd.current = rd.current.Next()
- return runeWithSize.r, runeWithSize.size, nil
- }
- // UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
- func (rd *Reader) UnreadRune() error {
- if rd.current == rd.buffer.Front() {
- return ErrNoRuneToUnread
- }
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- } else {
- rd.current = rd.current.Prev()
- }
- return nil
- }
- // Forget removes runes stored before the current stream position index.
- func (rd *Reader) Forget() {
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- }
- for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
- }
- }
- // PeekRune returns at most the next n runes, reading from the uderlying source if
- // needed. Does not move the current index. It includes EOF if reached.
- func (rd *Reader) PeekRunes(n int) []rune {
- res := make([]rune, 0, n)
- cursor := rd.current
- for i := 0; i < n; i++ {
- if cursor == nil {
- err := rd.feedBuffer()
- if err != nil {
- return res
- }
- cursor = rd.buffer.Back()
- }
- if cursor != nil {
- r := cursor.Value.(runeWithSize).r
- res = append(res, r)
- if r == EOF {
- return res
- }
- cursor = cursor.Next()
- }
- }
- return res
- }
|