options.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package lz4
  2. import (
  3. "fmt"
  4. "reflect"
  5. "runtime"
  6. "github.com/pierrec/lz4/v4/internal/lz4block"
  7. "github.com/pierrec/lz4/v4/internal/lz4errors"
  8. )
  9. //go:generate go run golang.org/x/tools/cmd/stringer -type=BlockSize,CompressionLevel -output options_gen.go
  10. type (
  11. applier interface {
  12. Apply(...Option) error
  13. private()
  14. }
  15. // Option defines the parameters to setup an LZ4 Writer or Reader.
  16. Option func(applier) error
  17. )
  18. // String returns a string representation of the option with its parameter(s).
  19. func (o Option) String() string {
  20. return o(nil).Error()
  21. }
  22. // Default options.
  23. var (
  24. DefaultBlockSizeOption = BlockSizeOption(Block4Mb)
  25. DefaultChecksumOption = ChecksumOption(true)
  26. DefaultConcurrency = ConcurrencyOption(1)
  27. defaultOnBlockDone = OnBlockDoneOption(nil)
  28. )
  29. const (
  30. Block64Kb BlockSize = 1 << (16 + iota*2)
  31. Block256Kb
  32. Block1Mb
  33. Block4Mb
  34. )
  35. // BlockSizeIndex defines the size of the blocks to be compressed.
  36. type BlockSize uint32
  37. // BlockSizeOption defines the maximum size of compressed blocks (default=Block4Mb).
  38. func BlockSizeOption(size BlockSize) Option {
  39. return func(a applier) error {
  40. switch w := a.(type) {
  41. case nil:
  42. s := fmt.Sprintf("BlockSizeOption(%s)", size)
  43. return lz4errors.Error(s)
  44. case *Writer:
  45. size := uint32(size)
  46. if !lz4block.IsValid(size) {
  47. return fmt.Errorf("%w: %d", lz4errors.ErrOptionInvalidBlockSize, size)
  48. }
  49. w.frame.Descriptor.Flags.BlockSizeIndexSet(lz4block.Index(size))
  50. return nil
  51. }
  52. return lz4errors.ErrOptionNotApplicable
  53. }
  54. }
  55. // BlockChecksumOption enables or disables block checksum (default=false).
  56. func BlockChecksumOption(flag bool) Option {
  57. return func(a applier) error {
  58. switch w := a.(type) {
  59. case nil:
  60. s := fmt.Sprintf("BlockChecksumOption(%v)", flag)
  61. return lz4errors.Error(s)
  62. case *Writer:
  63. w.frame.Descriptor.Flags.BlockChecksumSet(flag)
  64. return nil
  65. }
  66. return lz4errors.ErrOptionNotApplicable
  67. }
  68. }
  69. // ChecksumOption enables/disables all blocks or content checksum (default=true).
  70. func ChecksumOption(flag bool) Option {
  71. return func(a applier) error {
  72. switch w := a.(type) {
  73. case nil:
  74. s := fmt.Sprintf("BlockChecksumOption(%v)", flag)
  75. return lz4errors.Error(s)
  76. case *Writer:
  77. w.frame.Descriptor.Flags.ContentChecksumSet(flag)
  78. return nil
  79. }
  80. return lz4errors.ErrOptionNotApplicable
  81. }
  82. }
  83. // SizeOption sets the size of the original uncompressed data (default=0). It is useful to know the size of the
  84. // whole uncompressed data stream.
  85. func SizeOption(size uint64) Option {
  86. return func(a applier) error {
  87. switch w := a.(type) {
  88. case nil:
  89. s := fmt.Sprintf("SizeOption(%d)", size)
  90. return lz4errors.Error(s)
  91. case *Writer:
  92. w.frame.Descriptor.Flags.SizeSet(size > 0)
  93. w.frame.Descriptor.ContentSize = size
  94. return nil
  95. }
  96. return lz4errors.ErrOptionNotApplicable
  97. }
  98. }
  99. // ConcurrencyOption sets the number of go routines used for compression.
  100. // If n<0, then the output of runtime.GOMAXPROCS(0) is used.
  101. func ConcurrencyOption(n int) Option {
  102. return func(a applier) error {
  103. switch w := a.(type) {
  104. case nil:
  105. s := fmt.Sprintf("ConcurrencyOption(%d)", n)
  106. return lz4errors.Error(s)
  107. case *Writer:
  108. switch n {
  109. case 0, 1:
  110. default:
  111. if n < 0 {
  112. n = runtime.GOMAXPROCS(0)
  113. }
  114. }
  115. w.num = n
  116. return nil
  117. }
  118. return lz4errors.ErrOptionNotApplicable
  119. }
  120. }
  121. // CompressionLevel defines the level of compression to use. The higher the better, but slower, compression.
  122. type CompressionLevel uint32
  123. const (
  124. Fast CompressionLevel = 0
  125. Level1 CompressionLevel = 1 << (8 + iota)
  126. Level2
  127. Level3
  128. Level4
  129. Level5
  130. Level6
  131. Level7
  132. Level8
  133. Level9
  134. )
  135. // CompressionLevelOption defines the compression level (default=Fast).
  136. func CompressionLevelOption(level CompressionLevel) Option {
  137. return func(a applier) error {
  138. switch w := a.(type) {
  139. case nil:
  140. s := fmt.Sprintf("CompressionLevelOption(%s)", level)
  141. return lz4errors.Error(s)
  142. case *Writer:
  143. switch level {
  144. case Fast, Level1, Level2, Level3, Level4, Level5, Level6, Level7, Level8, Level9:
  145. default:
  146. return fmt.Errorf("%w: %d", lz4errors.ErrOptionInvalidCompressionLevel, level)
  147. }
  148. w.level = lz4block.CompressionLevel(level)
  149. return nil
  150. }
  151. return lz4errors.ErrOptionNotApplicable
  152. }
  153. }
  154. func onBlockDone(int) {}
  155. // OnBlockDoneOption is triggered when a block has been processed. For a Writer, it is when is has been compressed,
  156. // for a Reader, it is when it has been uncompressed.
  157. func OnBlockDoneOption(handler func(size int)) Option {
  158. if handler == nil {
  159. handler = onBlockDone
  160. }
  161. return func(a applier) error {
  162. switch rw := a.(type) {
  163. case nil:
  164. s := fmt.Sprintf("OnBlockDoneOption(%s)", reflect.TypeOf(handler).String())
  165. return lz4errors.Error(s)
  166. case *Writer:
  167. rw.handler = handler
  168. case *Reader:
  169. rw.handler = handler
  170. }
  171. return nil
  172. }
  173. }