Add more documentation and error handling

This commit is contained in:
Alexander Neumann 2014-09-18 22:20:12 +02:00
parent 0377b346dc
commit 8e24a8b811
2 changed files with 38 additions and 17 deletions

View File

@ -43,12 +43,17 @@ type Chunk struct {
// A chunker takes a stream of bytes and emits average size chunks. // A chunker takes a stream of bytes and emits average size chunks.
type Chunker interface { type Chunker interface {
// Next returns the next chunk of data. If an error occurs while reading,
// the error is returned. The state of the current chunk is undefined. When
// the last chunk has been returned, all subsequent calls yield a nil chunk
// and an io.EOF error.
Next() (*Chunk, error) Next() (*Chunk, error)
} }
// A chunker internally holds everything needed to split content. // A chunker internally holds everything needed to split content.
type chunker struct { type chunker struct {
rd io.Reader rd io.Reader
closed bool
window []byte window []byte
wpos int wpos int
@ -141,13 +146,25 @@ func (c *chunker) Next() (*Chunk, error) {
err = nil err = nil
} }
if err != nil { // io.ReadFull only returns io.EOF when no bytes could be read. If
// this is the case and we're in this branch, there are no more
// bytes to buffer, so this was the last chunk. If a different
// error has occurred, return that error and abandon the current
// chunk.
if err == io.EOF && !c.closed {
c.closed = true
// return current chunk
return &Chunk{ return &Chunk{
Start: c.start, Start: c.start,
Length: c.count, Length: c.count,
Cut: c.digest, Cut: c.digest,
Data: c.data, Data: c.data,
}, err }, nil
}
if err != nil {
return nil, err
} }
c.bpos = 0 c.bpos = 0

View File

@ -50,14 +50,8 @@ func test_with_data(t *testing.T, chunker chunker.Chunker, chunks []chunk) {
for i, chunk := range chunks { for i, chunk := range chunks {
c, err := chunker.Next() c, err := chunker.Next()
if i < len(chunks)-1 { if err != nil {
if err != nil { t.Fatalf("Error returned with chunk %d: %v", i, err)
t.Fatalf("Error returned with chunk %d: %v", i, err)
}
} else {
if err != io.EOF {
t.Fatalf("EOF not returned with chunk %d", i)
}
} }
if c == nil { if c == nil {
@ -76,6 +70,16 @@ func test_with_data(t *testing.T, chunker chunker.Chunker, chunks []chunk) {
} }
} }
} }
c, err := chunker.Next()
if c != nil {
t.Fatal("additional non-nil chunk returned")
}
if err != io.EOF {
t.Fatal("wrong error returned after last chunk")
}
} }
func get_random(seed, count int) []byte { func get_random(seed, count int) []byte {
@ -117,15 +121,15 @@ func BenchmarkChunker(b *testing.B) {
for { for {
_, err := ch.Next() _, err := ch.Next()
chunks++
if err != nil && err != io.EOF {
b.Fatalf("Unexpected error occurred: %v", err)
}
if err == io.EOF { if err == io.EOF {
break break
} }
if err != nil {
b.Fatalf("Unexpected error occurred: %v", err)
}
chunks++
} }
} }