aboutsummaryrefslogtreecommitdiff
path: root/decompress.go
diff options
context:
space:
mode:
Diffstat (limited to 'decompress.go')
-rw-r--r--decompress.go79
1 files changed, 79 insertions, 0 deletions
diff --git a/decompress.go b/decompress.go
new file mode 100644
index 0000000..0d12659
--- /dev/null
+++ b/decompress.go
@@ -0,0 +1,79 @@
+package main
+
+import (
+ "errors"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/flate"
+)
+
+// A Decompressor returns a new decompressing reader, reading from r.
+// The ReadCloser's Close method must be used to release associated resources.
+// The Decompressor itself must be safe to invoke from multiple goroutines
+// simultaneously, but each returned reader will be used only by
+// one goroutine at a time.
+type Decompressor func(r io.Reader) io.ReadCloser
+
+var flateReaderPool sync.Pool
+
+func newFlateReader(r io.Reader) io.ReadCloser {
+ fr, ok := flateReaderPool.Get().(io.ReadCloser)
+ if ok {
+ fr.(flate.Resetter).Reset(r, nil)
+ } else {
+ fr = flate.NewReader(r)
+ }
+ return &pooledFlateReader{fr: fr}
+}
+
+type pooledFlateReader struct {
+ mu sync.Mutex // guards Close and Read
+ fr io.ReadCloser
+}
+
+func (r *pooledFlateReader) Read(p []byte) (n int, err error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.fr == nil {
+ return 0, errors.New("Read after Close")
+ }
+ return r.fr.Read(p)
+}
+
+func (r *pooledFlateReader) Close() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ var err error
+ if r.fr != nil {
+ err = r.fr.Close()
+ flateReaderPool.Put(r.fr)
+ r.fr = nil
+ }
+ return err
+}
+
+var (
+ decompressors sync.Map // map[uint16]Decompressor
+)
+
+func init() {
+ decompressors.Store(Store, Decompressor(io.NopCloser))
+ decompressors.Store(Deflate, Decompressor(newFlateReader))
+}
+
+// RegisterDecompressor allows custom decompressors for a specified method ID.
+// The common methods Store and Deflate are built in.
+func RegisterDecompressor(method uint16, dcomp Decompressor) {
+ if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
+ panic("decompressor already registered")
+ }
+}
+
+func decompressor(method uint16) Decompressor {
+ di, ok := decompressors.Load(method)
+ if !ok {
+ return nil
+ }
+ return di.(Decompressor)
+}