diff options
| author | 2026-03-06 12:01:14 +0800 | |
|---|---|---|
| committer | 2026-03-06 12:01:14 +0800 | |
| commit | a7df501aff793dcd55168b7440fb531d40bd75c0 (patch) | |
| tree | e48a04d3634a8fbe77638547e675786de86e46de /internal | |
| parent | format/commitgraph: Add package-level doc comments (diff) | |
| signature | No signature | |
internal/iolimit: Add CappedCaptureWriter
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/iolimit/capped_capture_writer.go | 52 | ||||
| -rw-r--r-- | internal/iolimit/capped_capture_writer_test.go | 45 | ||||
| -rw-r--r-- | internal/iolimit/doc.go | 5 | ||||
| -rw-r--r-- | internal/iolimit/expect_length_reader.go | 2 |
4 files changed, 102 insertions, 2 deletions
diff --git a/internal/iolimit/capped_capture_writer.go b/internal/iolimit/capped_capture_writer.go new file mode 100644 index 00000000..2e69806a --- /dev/null +++ b/internal/iolimit/capped_capture_writer.go @@ -0,0 +1,52 @@ +package iolimit + +import "bytes" + +// CappedCaptureWriter captures written bytes up to a fixed limit. +// +// Once the total written bytes would exceed the limit, capture is disabled and +// Bytes() returns nil. Write still reports success for the full input length. +type CappedCaptureWriter struct { + limit int64 + buf bytes.Buffer + full bool +} + +// NewCappedCaptureWriter constructs one capped capture writer. +func NewCappedCaptureWriter(limit int64) *CappedCaptureWriter { + return &CappedCaptureWriter{limit: limit} +} + +// Write captures up to the configured limit and always reports len(src) bytes written. +func (writer *CappedCaptureWriter) Write(src []byte) (int, error) { + if writer.full { + return len(src), nil + } + + room := writer.limit - int64(writer.buf.Len()) + if room <= 0 { + writer.full = true + + return len(src), nil + } + + if int64(len(src)) > room { + _, _ = writer.buf.Write(src[:room]) + writer.full = true + + return len(src), nil + } + + _, _ = writer.buf.Write(src) + + return len(src), nil +} + +// Bytes returns captured bytes, or nil when capture exceeded the limit. +func (writer *CappedCaptureWriter) Bytes() []byte { + if writer.full { + return nil + } + + return writer.buf.Bytes() +} diff --git a/internal/iolimit/capped_capture_writer_test.go b/internal/iolimit/capped_capture_writer_test.go new file mode 100644 index 00000000..e95d06ef --- /dev/null +++ b/internal/iolimit/capped_capture_writer_test.go @@ -0,0 +1,45 @@ +package iolimit_test + +import ( + "bytes" + "testing" + + "codeberg.org/lindenii/furgit/internal/iolimit" +) + +func TestCappedCaptureWriterWithinLimit(t *testing.T) { + t.Parallel() + + writer := iolimit.NewCappedCaptureWriter(8) + + _, _ = writer.Write([]byte("hello")) + _, _ = writer.Write([]byte("!")) + + if got := writer.Bytes(); !bytes.Equal(got, []byte("hello!")) { + t.Fatalf("Bytes() = %q, want %q", got, "hello!") + } +} + +func TestCappedCaptureWriterExceededLimit(t *testing.T) { + t.Parallel() + + writer := iolimit.NewCappedCaptureWriter(4) + + _, _ = writer.Write([]byte("abcd")) + _, _ = writer.Write([]byte("x")) + + if got := writer.Bytes(); got != nil { + t.Fatalf("Bytes() = %q, want nil after overflow", got) + } +} + +func TestCappedCaptureWriterZeroLimit(t *testing.T) { + t.Parallel() + + writer := iolimit.NewCappedCaptureWriter(0) + + _, _ = writer.Write([]byte("x")) + if got := writer.Bytes(); got != nil { + t.Fatalf("Bytes() = %q, want nil at zero limit", got) + } +} diff --git a/internal/iolimit/doc.go b/internal/iolimit/doc.go new file mode 100644 index 00000000..b3e81ce2 --- /dev/null +++ b/internal/iolimit/doc.go @@ -0,0 +1,5 @@ +// Package iolimit provides small internal I/O wrappers with bounded behavior. +// +// It includes helpers for both readers and writers that enforce configured +// limits (length checks, capped capture, etc.). +package iolimit diff --git a/internal/iolimit/expect_length_reader.go b/internal/iolimit/expect_length_reader.go index 288e0e62..a45ad567 100644 --- a/internal/iolimit/expect_length_reader.go +++ b/internal/iolimit/expect_length_reader.go @@ -1,5 +1,3 @@ -// Package iolimit provides small internal reader wrappers for length-constrained -// stream I/O. package iolimit import ( |
