package main import ( "io" "log" "math/rand" ) func main() { reader := NewStreamOfStuff() bufferedReader := NewBufferedReader(reader) lenBits := make([]byte, 1) for i := 0; i < 10; i++ { if n, err := bufferedReader.Read(lenBits); err != nil || n != len(lenBits) { panic(err) } payload := make([]byte, int(lenBits[0])) if n, err := bufferedReader.Read(payload); err != nil || n != len(payload) { panic(err) } log.Printf("[%d] (%d) %q", i, len(payload), payload) } } type BufferedReader struct { buffer []byte reader io.Reader } func (r *BufferedReader) Read(b []byte) (int, error) { for len(b) > len(r.buffer) { more := make([]byte, 8) n, err := r.reader.Read(more) if err != nil { return 0, err } r.buffer = append(r.buffer, more[:n]...) } n := len(b) if copied := copy(b, r.buffer[:n]); copied != n { panic(copied) } r.buffer = r.buffer[n:] return n, nil } func NewBufferedReader(r io.Reader) io.Reader { return &BufferedReader{ buffer: []byte{}, reader: r, } } func NewStreamOfStuff() io.Reader { return jitterReader{} } type jitterReader struct{} func (jitterReader jitterReader) Read(b []byte) (int, error) { n := rand.Int()%len(b) + 1 for i := 0; i < n; i++ { b[i] = 'a' + byte(rand.Int()%26) } return n, nil }