goext/dataext/bufferedReadCloser.go

173 lines
2.9 KiB
Go
Raw Permalink Normal View History

2022-10-27 16:00:57 +02:00
package dataext
2022-12-20 09:50:13 +01:00
import (
"errors"
"io"
)
type brcMode int
const (
2022-12-22 15:49:10 +01:00
modeSourceReading brcMode = 0
modeSourceFinished brcMode = 1
modeBufferReading brcMode = 2
modeBufferFinished brcMode = 3
2022-12-20 09:50:13 +01:00
)
2022-10-27 16:00:57 +02:00
type BufferedReadCloser interface {
io.ReadCloser
BufferedAll() ([]byte, error)
2022-12-20 09:50:13 +01:00
Reset() error
2022-10-27 16:00:57 +02:00
}
type bufferedReadCloser struct {
2022-12-20 09:50:13 +01:00
buffer []byte
inner io.ReadCloser
mode brcMode
off int
}
func NewBufferedReadCloser(sub io.ReadCloser) BufferedReadCloser {
return &bufferedReadCloser{
buffer: make([]byte, 0, 1024),
inner: sub,
mode: modeSourceReading,
off: 0,
}
2022-10-27 16:00:57 +02:00
}
func (b *bufferedReadCloser) Read(p []byte) (int, error) {
2022-12-20 09:50:13 +01:00
switch b.mode {
case modeSourceReading:
n, err := b.inner.Read(p)
if n > 0 {
b.buffer = append(b.buffer, p[0:n]...)
}
2022-10-27 16:00:57 +02:00
2022-12-20 09:50:13 +01:00
if err == io.EOF {
b.mode = modeSourceFinished
}
2022-10-27 16:00:57 +02:00
2022-12-20 09:50:13 +01:00
return n, err
2022-10-27 16:00:57 +02:00
2022-12-20 09:50:13 +01:00
case modeSourceFinished:
return 0, io.EOF
2022-10-27 16:00:57 +02:00
2022-12-20 09:50:13 +01:00
case modeBufferReading:
if len(b.buffer) <= b.off {
b.mode = modeBufferFinished
if len(p) == 0 {
return 0, nil
}
return 0, io.EOF
}
n := copy(p, b.buffer[b.off:])
b.off += n
return n, nil
case modeBufferFinished:
return 0, io.EOF
default:
return 0, errors.New("object in undefined status")
2022-10-27 16:00:57 +02:00
}
}
func (b *bufferedReadCloser) Close() error {
2022-12-20 09:50:13 +01:00
switch b.mode {
case modeSourceReading:
_, err := b.BufferedAll()
if err != nil {
return err
}
err = b.inner.Close()
if err != nil {
return err
}
b.mode = modeSourceFinished
return nil
case modeSourceFinished:
return nil
case modeBufferReading:
b.mode = modeBufferFinished
return nil
case modeBufferFinished:
return nil
default:
return errors.New("object in undefined status")
2022-10-27 16:00:57 +02:00
}
2022-12-20 09:50:13 +01:00
2022-10-27 16:00:57 +02:00
}
func (b *bufferedReadCloser) BufferedAll() ([]byte, error) {
2022-12-20 09:50:13 +01:00
switch b.mode {
case modeSourceReading:
arr := make([]byte, 1024)
for b.mode == modeSourceReading {
_, err := b.Read(arr)
if err != nil && err != io.EOF {
return nil, err
}
2022-10-27 16:00:57 +02:00
}
if err := b.Reset(); err != nil {
return nil, err
}
2022-12-20 09:50:13 +01:00
return b.buffer, nil
case modeSourceFinished:
return b.buffer, nil
case modeBufferReading:
return b.buffer, nil
case modeBufferFinished:
return b.buffer, nil
default:
return nil, errors.New("object in undefined status")
2022-10-27 16:00:57 +02:00
}
2022-12-20 09:50:13 +01:00
}
2022-10-27 16:00:57 +02:00
// Reset resets the buffer to the beginning of the buffer.
// If the original source is partially read, we will finish reading it and fill our buffer
2022-12-20 09:50:13 +01:00
func (b *bufferedReadCloser) Reset() error {
switch b.mode {
case modeSourceReading:
if b.off == 0 {
return nil // nobody has read anything yet
}
err := b.Close()
if err != nil {
return err
}
b.mode = modeBufferReading
b.off = 0
return nil
2022-12-20 09:50:13 +01:00
case modeSourceFinished:
err := b.Close()
if err != nil {
return err
}
b.mode = modeBufferReading
b.off = 0
return nil
case modeBufferReading:
fallthrough
case modeBufferFinished:
b.mode = modeBufferReading
b.off = 0
return nil
default:
return errors.New("object in undefined status")
}
2022-10-27 16:00:57 +02:00
}