package runes import ( "bufio" "bytes" "io" "strings" "sync" ) // feeder is a generic implementation of the output interfaces of Feeder type Feeder struct { sync.Mutex in io.RuneReader out []rune sz []int err error } // NewFeederBytes creates a new Feeder using an slice of bytes as input func NewFeederBytes(b []byte) *Feeder { return NewFeeder(bytes.NewReader(b)) } // NewFeederString creates a new Feeder using a string as input func NewFeederString(s string) *Feeder { return NewFeeder(strings.NewReader(s)) } // NewFeeder creates a new Feeder using a Reader as input func NewFeeder(in io.Reader) *Feeder { rd, ok := in.(io.RuneReader) if !ok { rd = bufio.NewReader(in) } return &Feeder{in: rd} } // Skip drops n runes from the head of the buffer func (f *Feeder) Skip(n int) (int, bool) { f.Lock() defer f.Unlock() if l := f.skip(n); l > 0 { return l, true } else { return 0, false } } func (f *Feeder) skip(n int) int { if l := len(f.out); l > n { f.out = f.out[n:] f.sz = f.sz[n:] return l - n } else { f.out = f.out[:0] f.sz = f.sz[:0] return 0 } } // ReadRune returns the next rune func (f *Feeder) ReadRune() (r rune, size int, err error) { f.Lock() defer f.Unlock() if f.atLeast(1) { r = f.out[0] size = f.sz[0] f.skip(1) } err = f.Err() return } // AtLeast blocks until there are at least n runes on the buffer, or an error or EOF has occurred func (f *Feeder) AtLeast(n int) (out []rune, err error) { f.Lock() defer f.Unlock() if !f.atLeast(n) { err = f.err } if len(f.out) > 0 { out = f.out } return } func (f *Feeder) atLeast(n int) bool { for len(f.out) < n { r, size, err := f.in.ReadRune() if err != nil && f.err == nil { // store first error f.err = err } if size > 0 { f.out = append(f.out, r) f.sz = append(f.sz, size) } else if f.err != nil { break } } return len(f.out) >= n } // Currently buffered runes func (f *Feeder) Runes() []rune { return f.out } // Count of currently buffered runes func (f *Feeder) Buffered() int { return len(f.out) } // Feeder has reached EOF func (f *Feeder) EOF() bool { return f.err == io.EOF } // Feeder encountered an error func (f *Feeder) Err() error { if f.err == io.EOF { return nil } return f.err }