...

Source file src/github.com/pierrec/lz4/v4/options.go

Documentation: github.com/pierrec/lz4/v4

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

View as plain text