options.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. if n <= 0 {
  109. n = runtime.GOMAXPROCS(0)
  110. }
  111. w.num = n
  112. return nil
  113. }
  114. return lz4errors.ErrOptionNotApplicable
  115. }
  116. }
  117. // CompressionLevel defines the level of compression to use. The higher the better, but slower, compression.
  118. type CompressionLevel uint32
  119. const (
  120. Fast CompressionLevel = 0
  121. Level1 CompressionLevel = 1 << (8 + iota)
  122. Level2
  123. Level3
  124. Level4
  125. Level5
  126. Level6
  127. Level7
  128. Level8
  129. Level9
  130. )
  131. // CompressionLevelOption defines the compression level (default=Fast).
  132. func CompressionLevelOption(level CompressionLevel) Option {
  133. return func(a applier) error {
  134. switch w := a.(type) {
  135. case nil:
  136. s := fmt.Sprintf("CompressionLevelOption(%s)", level)
  137. return lz4errors.Error(s)
  138. case *Writer:
  139. switch level {
  140. case Fast, Level1, Level2, Level3, Level4, Level5, Level6, Level7, Level8, Level9:
  141. default:
  142. return fmt.Errorf("%w: %d", lz4errors.ErrOptionInvalidCompressionLevel, level)
  143. }
  144. w.level = lz4block.CompressionLevel(level)
  145. return nil
  146. }
  147. return lz4errors.ErrOptionNotApplicable
  148. }
  149. }
  150. func onBlockDone(int) {}
  151. // OnBlockDoneOption is triggered when a block has been processed. For a Writer, it is when is has been compressed,
  152. // for a Reader, it is when it has been uncompressed.
  153. func OnBlockDoneOption(handler func(size int)) Option {
  154. if handler == nil {
  155. handler = onBlockDone
  156. }
  157. return func(a applier) error {
  158. switch rw := a.(type) {
  159. case nil:
  160. s := fmt.Sprintf("OnBlockDoneOption(%s)", reflect.TypeOf(handler).String())
  161. return lz4errors.Error(s)
  162. case *Writer:
  163. rw.handler = handler
  164. case *Reader:
  165. rw.handler = handler
  166. }
  167. return nil
  168. }
  169. }