210 lines
5.7 KiB
Go
210 lines
5.7 KiB
Go
package iox
|
|
|
|
import (
|
|
`bytes`
|
|
`context`
|
|
`io`
|
|
`sync`
|
|
)
|
|
|
|
type (
|
|
/*
|
|
RuneWriter matches the behavior of [bytes.Buffer.WriteRune] and [bufio.Writer.WriteRune].
|
|
|
|
(Note that this package does not have a "RuneReader"; see [io.RuneReader] instead.)
|
|
*/
|
|
RuneWriter interface {
|
|
WriteRune(r rune) (n int, err error)
|
|
}
|
|
|
|
// Copier matches the signature/behavior of [io.Copy]. Implemented by [XIO].
|
|
Copier interface {
|
|
Copy(dst io.Writer, src io.Reader) (written int64, err error)
|
|
}
|
|
|
|
// CopyBufferer matches the signature/behavior of [io.CopyBuffer]. Implemented by [XIO].
|
|
CopyBufferer interface {
|
|
CopyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error)
|
|
}
|
|
|
|
// SizedCopier matches the signature/behavior of [io.CopyN]. Implemented by [XIO].
|
|
SizedCopier interface {
|
|
CopyN(dst io.Writer, src io.Reader, n int64) (written int64, err error)
|
|
}
|
|
|
|
// SizedCopyBufferer matches the signature/behavior of [CopyBufN]. Implemented by [XIO].
|
|
SizedCopyBufferer interface {
|
|
CopyBufN(dst io.Writer, src io.Reader, n int64) (written int64, err error)
|
|
}
|
|
|
|
// SizedCopyBufferInvoker matches the signature/behavior of [CopyBufWith]. Implemented by [XIO].
|
|
SizedCopyBufferInvoker interface {
|
|
CopyBufWith(dst io.Writer, src io.Reader, bufFunc func() (b []byte)) (written int64, err error)
|
|
}
|
|
|
|
// DynamicSizedCopyBufferInvoker matches the signature/behavior of [CopyBufWithDynamic]. Implemented by [XIO].
|
|
DynamicSizedCopyBufferInvoker interface {
|
|
CopyBufWithDynamic(dst io.Writer, src io.Reader, bufFunc func() (b []byte)) (written int64, err error)
|
|
}
|
|
|
|
/*
|
|
Chunker is used by both [ContextReader] and [ContextWriter] to set/get the current chunk size.
|
|
Chunking is inherently required to be specified in order to interrupt reads/writes/copies with a [context.Context].
|
|
|
|
Implementations *must* use a [sync.RWMutex] to get (RLock) and set (Lock) the chunk size.
|
|
The chunk size *must not* be directly accessible to maintain concurrency safety assumptions.
|
|
*/
|
|
Chunker interface {
|
|
// GetChunkLen returns the current chunk size/length in bytes.
|
|
GetChunkLen() (size uint)
|
|
// SetChunkLen sets the current chunk size/length in bytes.
|
|
SetChunkLen(size uint) (err error)
|
|
}
|
|
|
|
/*
|
|
ChunkReader implements a chunking reader.
|
|
Third-party implementations *must* respect the chunk size locking (see [Chunker]).
|
|
|
|
The Read method should read in chunks of the internal chunk size.
|
|
*/
|
|
ChunkReader interface {
|
|
io.Reader
|
|
Chunker
|
|
}
|
|
|
|
/*
|
|
ChunkWriter implements a chunking writer.
|
|
Third-party implementations *must* respect the chunk size locking (see [Chunker]).
|
|
|
|
The Write method should write out in chunks of the internal chunk size.
|
|
*/
|
|
ChunkWriter interface {
|
|
io.Writer
|
|
Chunker
|
|
}
|
|
|
|
// ChunkReadWriter implements a chunking reader/writer.
|
|
ChunkReadWriter interface {
|
|
ChunkReader
|
|
ChunkWriter
|
|
}
|
|
|
|
/*
|
|
ContextSetter allows one to set an internal context.
|
|
|
|
A nil context should return an error.
|
|
*/
|
|
ContextSetter interface {
|
|
SetContext(context context.Context) (err error)
|
|
}
|
|
|
|
/*
|
|
ContextCopier is defined to allow for consumer-provided types. See [CtxIO] for a package-provided type.
|
|
|
|
The Copy method should use an internal context and chunk size
|
|
(and thus wrap [CopyCtxBufN] internally on an external call to Copy, etc.).
|
|
*/
|
|
ContextCopier interface {
|
|
Copier
|
|
Chunker
|
|
ContextSetter
|
|
SizedCopyBufferer
|
|
}
|
|
|
|
/*
|
|
ContextReader is primarily here to allow for consumer-provided types. See [CtxIO] for a package-provided type.
|
|
|
|
The Read method should use an internal context and chunk size.
|
|
|
|
The ReadWithContext method should use an internal chunk size.
|
|
*/
|
|
ContextReader interface {
|
|
ChunkReader
|
|
ContextSetter
|
|
ReadWithContext(ctx context.Context, p []byte) (n int64, err error)
|
|
}
|
|
|
|
/*
|
|
ContextWriter is primarily here to allow for consumer-provided types. See [CtxIO] for a package-provided type.
|
|
|
|
The Write method should use an internal context.
|
|
|
|
The WriteWithContext should use an internal chunk size.
|
|
*/
|
|
ContextWriter interface {
|
|
ChunkWriter
|
|
ContextSetter
|
|
WriteWithContext(ctx context.Context, p []byte) (n int64, err error)
|
|
WriteNWithContext(ctx context.Context, p []byte, n int64) (written int64, err error)
|
|
}
|
|
|
|
/*
|
|
ContextReadWriter is primarily here to allow for consumer-provided types.
|
|
|
|
See [CtxIO] for a package-provided type.
|
|
*/
|
|
ContextReadWriter interface {
|
|
ContextReader
|
|
ContextWriter
|
|
}
|
|
)
|
|
|
|
type (
|
|
// ChunkLocker implements [Chunker].
|
|
ChunkLocker struct {
|
|
lock sync.RWMutex
|
|
chunkLen uint
|
|
}
|
|
|
|
/*
|
|
CtxIO is a type used to demonstrate "stateful" I/O introduced by this package.
|
|
It implements:
|
|
|
|
* [Copier]
|
|
* [Chunker]
|
|
* [RuneWriter]
|
|
* [ChunkReader]
|
|
* [ChunkWriter]
|
|
* [ContextCopier]
|
|
* [ContextSetter]
|
|
* [ContextReader]
|
|
* [ContextWriter]
|
|
* [ChunkReadWriter]
|
|
* [ContextReadWriter]
|
|
* [SizedCopyBufferer]
|
|
|
|
Unlike [XIO], it must be non-nil (see [NewCtxIO]) since it maintains state
|
|
(though technically, one does not need to call [NewCtxIO] if they call
|
|
[CtxIO.SetChunkLen] and [CtxIO.SetContext] before any other methods).
|
|
|
|
[CtxIO.Read] and other Read methods writes to an internal buffer,
|
|
and [CtxIO.Write] and other Write methods writes out from it.
|
|
*/
|
|
CtxIO struct {
|
|
r io.Reader
|
|
w io.Writer
|
|
l ChunkLocker
|
|
buf bytes.Buffer
|
|
ctx context.Context
|
|
}
|
|
|
|
/*
|
|
XIO is a type used to demonstrate "stateless" I/O introduced by this package.
|
|
It implements:
|
|
|
|
* [Copier]
|
|
* [CopyBufferer]
|
|
* [SizedCopier]
|
|
* [SizedCopyBufferer]
|
|
* [SizedCopyBufferInvoker]
|
|
* [DynamicSizedCopyBufferInvoker]
|
|
|
|
Unlike [CtxIO], the zero-value is ready to use since it holds no state
|
|
or configuration whatsoever.
|
|
|
|
A nil XIO is perfectly usable but if you want something more idiomatic,
|
|
see [NewXIO].
|
|
*/
|
|
XIO struct{}
|
|
)
|