mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-27 18:57:35 +00:00
types/iox: add function types for Reader and Writer (#14366)
Throughout our codebase we have types that only exist only to implement an io.Reader or io.Writer, when it would have been simpler, cleaner, and more readable to use an inlined function literal that closes over the relevant types. This is arguably more readable since it keeps the semantic logic in place rather than have it be isolated elsewhere. Note that a function literal that closes over some variables is semantic equivalent to declaring a struct with fields and having the Read or Write method mutate those fields. Updates #cleanup Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
parent
6e552f66a0
commit
0045860060
23
types/iox/io.go
Normal file
23
types/iox/io.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Package iox provides types to implement [io] functionality.
|
||||||
|
package iox
|
||||||
|
|
||||||
|
// TODO(https://go.dev/issue/21670): Deprecate or remove this functionality
|
||||||
|
// once the Go language supports implementing an 1-method interface directly
|
||||||
|
// using a function value of a matching signature.
|
||||||
|
|
||||||
|
// ReaderFunc implements [io.Reader] using the underlying function value.
|
||||||
|
type ReaderFunc func([]byte) (int, error)
|
||||||
|
|
||||||
|
func (f ReaderFunc) Read(b []byte) (int, error) {
|
||||||
|
return f(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriterFunc implements [io.Writer] using the underlying function value.
|
||||||
|
type WriterFunc func([]byte) (int, error)
|
||||||
|
|
||||||
|
func (f WriterFunc) Write(b []byte) (int, error) {
|
||||||
|
return f(b)
|
||||||
|
}
|
39
types/iox/io_test.go
Normal file
39
types/iox/io_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package iox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
"testing/iotest"
|
||||||
|
|
||||||
|
"tailscale.com/util/must"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCopy(t *testing.T) {
|
||||||
|
const testdata = "the quick brown fox jumped over the lazy dog"
|
||||||
|
src := testdata
|
||||||
|
bb := new(bytes.Buffer)
|
||||||
|
if got := must.Get(io.Copy(bb, ReaderFunc(func(b []byte) (n int, err error) {
|
||||||
|
n = copy(b[:min(len(b), 7)], src)
|
||||||
|
src = src[n:]
|
||||||
|
if len(src) == 0 {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}))); int(got) != len(testdata) {
|
||||||
|
t.Errorf("copy = %d, want %d", got, len(testdata))
|
||||||
|
}
|
||||||
|
var dst []byte
|
||||||
|
if got := must.Get(io.Copy(WriterFunc(func(b []byte) (n int, err error) {
|
||||||
|
dst = append(dst, b...)
|
||||||
|
return len(b), nil
|
||||||
|
}), iotest.OneByteReader(bb))); int(got) != len(testdata) {
|
||||||
|
t.Errorf("copy = %d, want %d", got, len(testdata))
|
||||||
|
}
|
||||||
|
if string(dst) != testdata {
|
||||||
|
t.Errorf("copy = %q, want %q", dst, testdata)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user