readers/line.go
2024-01-21 23:50:07 +00:00

82 lines
1.2 KiB
Go

package readers
import (
"bytes"
"errors"
"io"
)
var EOL error = &eolError{}
type eolError struct{}
func (e *eolError) Error() string { return "EOL" }
func (e *eolError) Unwrap() error { return io.EOF }
type LineReader struct {
err error
r io.Reader
over []byte
}
var _ io.Reader = &LineReader{}
func NewLineReader(r io.Reader) *LineReader {
return &LineReader{nil, r, nil}
}
func (l *LineReader) Err() error {
if errors.Is(l.err, io.EOF) {
return nil
}
return l.err
}
func (l *LineReader) Next() bool {
if l.err == nil || errors.Is(l.err, EOL) {
l.err = nil
return true
}
return false
}
func (l *LineReader) Read(p []byte) (n int, err error) {
if errors.Is(l.err, EOL) {
return 0, io.EOF
}
rOver := bytes.NewBuffer(l.over)
r := io.MultiReader(rOver, l.r)
n, l.err = r.Read(p)
if l.err != nil {
err = eolToEof(l.err)
return
}
nFull := n
nStart := n
n2 := bytes.IndexByte(p, '\n')
if n2 != -1 {
l.err = EOL
n = n2
nStart = n2 + 1
}
if n > 0 && p[n-1] == '\r' {
n--
}
l.over = p[nStart:nFull]
if rOver.Len() > 0 {
l.over = append(p[nStart:nFull], rOver.Bytes()...)
}
return
}
func eolToEof(err error) error {
if errors.Is(err, EOL) {
return io.EOF
}
return err
}