mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-14 02:57:52 +08:00
58 lines
1.1 KiB
Go
58 lines
1.1 KiB
Go
package async
|
|
|
|
import (
|
|
"io"
|
|
"time"
|
|
"bufio"
|
|
)
|
|
|
|
// ReadRuneRet packs the return value of (*bufio.Reader).ReadRune.
|
|
type ReadRuneRet struct {
|
|
r rune
|
|
size int
|
|
err error
|
|
}
|
|
|
|
// RuneReader wraps bufio.Reader to support ReadRune with timeout.
|
|
type RuneReader struct {
|
|
*bufio.Reader
|
|
rets chan ReadRuneRet
|
|
}
|
|
|
|
func NewRuneReader(r io.Reader) *RuneReader {
|
|
rr := RuneReader{bufio.NewReaderSize(r, 0), make(chan ReadRuneRet)}
|
|
go rr.serve()
|
|
return &rr
|
|
}
|
|
|
|
func (rr *RuneReader) serve() {
|
|
for {
|
|
r, size, err := rr.Reader.ReadRune()
|
|
rr.rets <- ReadRuneRet{r, size, err}
|
|
}
|
|
}
|
|
|
|
// ReadRuneTimeout is like ReadRune but blocks for at most d. If there was no
|
|
// rune read, err is set to Timeout.
|
|
func (rr *RuneReader) ReadRuneTimeout(d time.Duration) (r rune, size int, err error) {
|
|
select {
|
|
case rt := <-rr.rets:
|
|
return rt.r, rt.size, rt.err
|
|
case <- after(d):
|
|
return 0, 0, Timeout
|
|
}
|
|
}
|
|
|
|
func (rr *RuneReader) ReadRune() (rune, int, error) {
|
|
return rr.ReadRuneTimeout(0)
|
|
}
|
|
|
|
// after is like time.After but d == 0 returns a channel that is never sent
|
|
// to.
|
|
func after(d time.Duration) <-chan time.Time {
|
|
if d > 0 {
|
|
return time.After(d)
|
|
}
|
|
return make(chan time.Time)
|
|
}
|