1// Copyright 2017 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package saltpack 5 6// chunker is an interface for a type that emits a sequence of 7// plaintext chunks. 8// 9// Implementations should follow exampleChunker in 10// chunk_reader_test.go pretty closely. 11type chunker interface { 12 // getNextChunk() returns a plaintext chunk with an error. If 13 // the chunk is empty, the error must be non-nil. Once 14 // getNextChunk() returns a non-nil error (which may be 15 // io.EOF), it can assume that it will never be called again. 16 getNextChunk() ([]byte, error) 17} 18 19// chunkReader is an io.Reader adaptor for chunker. 20type chunkReader struct { 21 chunker chunker 22 prevChunk []byte 23 prevErr error 24} 25 26func newChunkReader(chunker chunker) *chunkReader { 27 return &chunkReader{chunker: chunker} 28} 29 30func (r *chunkReader) Read(p []byte) (n int, err error) { 31 // Copy data into p until it is full, or getNextChunk() 32 // returns a non-nil error. 33 for { 34 // Drain r.prevChunk first before checking for an error. 35 if len(r.prevChunk) > 0 { 36 copied := copy(p[n:], r.prevChunk) 37 n += copied 38 r.prevChunk = r.prevChunk[copied:] 39 if len(r.prevChunk) > 0 { 40 // p is full. 41 return n, nil 42 } 43 } 44 45 if r.prevErr != nil { 46 // r.prevChunk is fully drained, so return the 47 // error. 48 return n, r.prevErr 49 } 50 51 r.prevChunk, r.prevErr = r.chunker.getNextChunk() 52 if len(r.prevChunk) == 0 && r.prevErr == nil { 53 panic("empty chunk and nil error") 54 } 55 } 56} 57