aboutsummaryrefslogtreecommitdiffstats
path: root/formats/packfile/stream.go
diff options
context:
space:
mode:
Diffstat (limited to 'formats/packfile/stream.go')
-rw-r--r--formats/packfile/stream.go95
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
+}