diff options
Diffstat (limited to 'formats/packfile/stream.go')
-rw-r--r-- | formats/packfile/stream.go | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/formats/packfile/stream.go b/formats/packfile/stream.go new file mode 100644 index 0000000..41266b1 --- /dev/null +++ b/formats/packfile/stream.go @@ -0,0 +1,95 @@ +package packfile + +import ( + "io" + + "gopkg.in/src-d/go-git.v3/core" +) + +// Stream implements ReadRecaller for the io.Reader of a packfile. This +// implementation keeps all remembered objects referenced in maps for +// quick access. +type Stream struct { + io.Reader + count int64 + offsetToObject map[int64]core.Object + hashToObject map[core.Hash]core.Object +} + +// NewStream returns a new Stream that reads form r. +func NewStream(r io.Reader) *Stream { + return &Stream{ + Reader: r, + count: 0, + hashToObject: make(map[core.Hash]core.Object, 0), + offsetToObject: make(map[int64]core.Object, 0), + } +} + +// Read reads up to len(p) bytes into p. +func (r *Stream) Read(p []byte) (n int, err error) { + n, err = r.Reader.Read(p) + r.count += int64(n) + + return +} + +// ReadByte reads a byte. +func (r *Stream) ReadByte() (byte, error) { + var p [1]byte + _, err := r.Reader.Read(p[:]) + r.count++ + + return p[0], err +} + +// Offset returns the number of bytes read. +func (r *Stream) Offset() (int64, error) { + return r.count, nil +} + +// Remember stores references to the passed object to be used later by +// RecalByHash and RecallByOffset. It receives the object and the offset +// of its object entry in the packfile. +func (r *Stream) Remember(o int64, obj core.Object) error { + h := obj.Hash() + if _, ok := r.hashToObject[h]; ok { + return ErrDuplicatedObject.AddDetails("with hash %s", h) + } + r.hashToObject[h] = obj + + if _, ok := r.offsetToObject[o]; ok { + return ErrDuplicatedObject.AddDetails("with offset %d", o) + } + r.offsetToObject[o] = obj + + return nil +} + +// ForgetAll forgets all previously remembered objects. +func (r *Stream) ForgetAll() { + r.hashToObject = make(map[core.Hash]core.Object) + r.offsetToObject = make(map[int64]core.Object) +} + +// RecallByHash returns an object that has been previously Remember-ed by +// its hash. +func (r *Stream) RecallByHash(h core.Hash) (core.Object, error) { + obj, ok := r.hashToObject[h] + if !ok { + return nil, ErrCannotRecall.AddDetails("by hash %s", h) + } + + return obj, nil +} + +// RecallByOffset returns an object that has been previously Remember-ed by +// the offset of its object entry in the packfile. +func (r *Stream) RecallByOffset(o int64) (core.Object, error) { + obj, ok := r.offsetToObject[o] + if !ok { + return nil, ErrCannotRecall.AddDetails("no object found at offset %d", o) + } + + return obj, nil +} |