forked from peterbourgon/diskv
/
compression.go
129 lines (112 loc) · 3.39 KB
/
compression.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package diskv
import (
"bytes"
"compress/flate"
"compress/gzip"
"compress/zlib"
"io"
)
// Compression defines an interface that Diskv uses to implement compression of
// data. You may define these methods on your own type, or use one of the
// NewCompression helpers.
type Compression interface {
Compress(dst io.Writer, src io.Reader) error
Decompress(dst io.Writer, src io.Reader) error
}
// compress uses the passed Compression to compress the given value buffer
// and returns the compressed output.
func compress(c Compression, val []byte) ([]byte, error) {
dst, src := &bytes.Buffer{}, bytes.NewBuffer(val)
if err := c.Compress(dst, src); err != nil {
return []byte{}, err
}
return dst.Bytes(), nil
}
// decompress uses the passed Compression to decompress the given value buffer
// and returns the decompressed output.
func decompress(c Compression, val []byte) ([]byte, error) {
dst, src := &bytes.Buffer{}, bytes.NewBuffer(val)
if err := c.Decompress(dst, src); err != nil {
return []byte{}, err
}
return dst.Bytes(), nil
}
//
//
//
// ReaderFunc yields an io.ReadCloser which should perform
// decompression from the passed io.Reader.
type ReaderFunc func(r io.Reader) (io.ReadCloser, error)
// WriterFunc yields an io.WriteCloser which should perform
// compression into the passed io.Writer.
type WriterFunc func(w io.Writer) (io.WriteCloser, error)
// A GenericCompression implements Diskv's Compression interface. Users must
// supply it with two functions: a WriterFunc, which wraps an io.Writer with a
// compression layer, and a ReaderFunc, which wraps an io.Reader with a
// decompression layer.
type GenericCompression struct {
wf WriterFunc
rf ReaderFunc
}
// NewCompression returns a GenericCompression from the passed Writer
// and Reader functions, which you may supply directly.
//
// You may also use one of the NewCompression helpers, which
// automatically provide Writer and Reader functions for some of
// the stdlib compression algorithms.
func NewCompression(wf WriterFunc, rf ReaderFunc) *GenericCompression {
return &GenericCompression{
wf: wf,
rf: rf,
}
}
func (c *GenericCompression) Compress(dst io.Writer, src io.Reader) error {
w, err := c.wf(dst)
if err != nil {
return err
}
if _, err = io.Copy(w, src); err != nil {
return err
}
if err = w.Close(); err != nil {
return err
}
return nil
}
func (c *GenericCompression) Decompress(dst io.Writer, src io.Reader) error {
r, err := c.rf(src)
if err != nil {
return err
}
if _, err = io.Copy(dst, r); err != nil {
return err
}
if err = r.Close(); err != nil {
return err
}
return nil
}
//
//
//
func NewGzipCompression() Compression {
return NewGzipCompressionLevel(flate.DefaultCompression)
}
func NewGzipCompressionLevel(level int) Compression {
return NewCompression(
func(w io.Writer) (io.WriteCloser, error) { return gzip.NewWriterLevel(w, level) },
func(r io.Reader) (io.ReadCloser, error) { return gzip.NewReader(r) },
)
}
func NewZlibCompression() Compression {
return NewZlibCompressionLevel(flate.DefaultCompression)
}
func NewZlibCompressionLevel(level int) Compression {
return NewZlibCompressionLevelDict(level, nil)
}
func NewZlibCompressionLevelDict(level int, dict []byte) Compression {
return NewCompression(
func(w io.Writer) (io.WriteCloser, error) { return zlib.NewWriterLevelDict(w, level, dict) },
func(r io.Reader) (io.ReadCloser, error) { return zlib.NewReaderDict(r, dict) },
)
}