-
Notifications
You must be signed in to change notification settings - Fork 0
/
compression.go
184 lines (158 loc) · 4.11 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package config
import (
"compress/gzip"
"fmt"
"io"
"sync"
"github.com/jamespfennell/xz"
)
type CompressionFormat int
const (
Gzip CompressionFormat = 0
Xz CompressionFormat = 1
)
const ExtensionRegex = `gz|xz`
var allFormats = []CompressionFormat{
Gzip,
Xz,
}
type formatImpl struct {
id string
extension string
minLevel int
maxLevel int
defaultLevel int
newReader func(r io.Reader) (io.ReadCloser, error)
newWriter func(w io.Writer, level int) io.WriteCloser
}
var gzipImpl = formatImpl{
id: "gzip",
extension: "gz",
minLevel: gzip.BestSpeed,
maxLevel: gzip.BestCompression,
defaultLevel: 6, // the package uses -1 which doesn't fit well here
newReader: func(r io.Reader) (io.ReadCloser, error) {
return gzip.NewReader(r)
},
newWriter: func(w io.Writer, level int) io.WriteCloser {
// The level is guaranteed to be correct, so the error can be ignored
z, _ := gzip.NewWriterLevel(w, level)
return z
},
}
var xzImpl = formatImpl{
id: "xz",
extension: "xz",
minLevel: xz.BestSpeed,
maxLevel: xz.BestCompression,
defaultLevel: xz.DefaultCompression,
newReader: func(r io.Reader) (io.ReadCloser, error) {
return xz.NewReader(r), nil
},
newWriter: func(w io.Writer, level int) io.WriteCloser {
return xz.NewWriterLevel(w, level)
},
}
var formatToImpl = map[CompressionFormat]formatImpl{
Gzip: gzipImpl,
Xz: xzImpl,
}
func (format *CompressionFormat) impl() formatImpl {
impl, ok := formatToImpl[*format]
if ok {
return impl
}
return gzipImpl
}
func (format *CompressionFormat) Extension() string {
return format.impl().extension
}
func (format *CompressionFormat) String() string {
return format.impl().id
}
func (format *CompressionFormat) UnmarshalYAML(unmarshal func(interface{}) error) error {
var id string
if err := unmarshal(&id); err != nil {
return err
}
parsedFormat, ok := NewFormatFromId(id)
if !ok {
return fmt.Errorf("unknown compression format %q", id)
}
*format = parsedFormat
return nil
}
func (format CompressionFormat) MarshalYAML() (interface{}, error) {
return format.String(), nil
}
func NewFormatFromId(id string) (CompressionFormat, bool) {
for _, format := range allFormats {
if format.impl().id == id {
return format, true
}
}
return Gzip, false
}
func NewFormatFromExtension(extension string) (CompressionFormat, bool) {
for _, format := range allFormats {
if format.impl().extension == extension {
return format, true
}
}
return Gzip, false
}
// Compression is an immutable type that specifies a compression format and level.
type Compression struct {
Format CompressionFormat
Level *int `yaml:",omitempty"`
}
// This is used as part of a hack to get different Compression instances that have the
// same format and same level setting to evaluate as equal using the built-in
// equality operator.
var intToPtr = map[int]*int{}
var intToPtrM sync.Mutex
func NewSpecWithLevel(format CompressionFormat, level int) Compression {
intToPtrM.Lock()
defer intToPtrM.Unlock()
if _, ok := intToPtr[level]; !ok {
intToPtr[level] = &level
}
return Compression{
Format: format,
Level: intToPtr[level],
}
}
func (spec Compression) LevelActual() int {
if spec.Level == nil {
return spec.Format.impl().defaultLevel
}
return *spec.Level
}
func (spec Compression) Equal(other Compression) bool {
return spec.LevelActual() == other.LevelActual() && spec.Format == other.Format
}
func (spec Compression) NewReader(r io.Reader) (io.ReadCloser, error) {
return spec.Format.impl().newReader(r)
}
func (spec Compression) NewWriter(w io.Writer) io.WriteCloser {
spec.fixLevel()
return spec.Format.impl().newWriter(w, spec.LevelActual())
}
func (spec Compression) Equals(other Compression) bool {
return spec.Format == other.Format &&
spec.LevelActual() == other.LevelActual()
}
func (spec *Compression) fixLevel() bool {
if spec.Level == nil {
return false
}
if *spec.Level < spec.Format.impl().minLevel {
*spec.Level = spec.Format.impl().minLevel
return true
}
if *spec.Level > spec.Format.impl().maxLevel {
*spec.Level = spec.Format.impl().maxLevel
return true
}
return false
}