github.com/wfusion/gofusion@v1.1.14/common/utils/encode/codec.go (about)

     1  package encode
     2  
     3  import (
     4  	"bytes"
     5  	"runtime"
     6  
     7  	"github.com/wfusion/gofusion/common/utils"
     8  	"github.com/wfusion/gofusion/common/utils/cipher"
     9  	"github.com/wfusion/gofusion/common/utils/compress"
    10  )
    11  
    12  type codec struct {
    13  	buf              *bytes.Buffer
    14  	encOpts, decOpts []utils.OptionExtender
    15  
    16  	queue   [][2]int
    17  	release func()
    18  }
    19  
    20  // From a byte slice or a string, not concurrent safe
    21  func From[T ~[]byte | ~string](src T) (c Codecable) {
    22  	buf, cb := utils.BytesBufferPool.Get(nil)
    23  
    24  	switch v := any(src).(type) {
    25  	case []byte:
    26  		buf.Write(v)
    27  	case string:
    28  		buf.WriteString(v)
    29  	default:
    30  		buf.Write([]byte(src))
    31  	}
    32  
    33  	c = &codec{
    34  		buf:     buf,
    35  		release: cb,
    36  	}
    37  
    38  	runtime.SetFinalizer(c, func(c *codec) { c.release() })
    39  	return
    40  }
    41  
    42  func (c *codec) Encode(opts ...utils.OptionExtender) Codecable {
    43  	for i, p := 0, len(c.encOpts); i < len(opts); i++ {
    44  		c.queue = append(c.queue, [2]int{p + i, 0})
    45  	}
    46  	c.encOpts = append(c.encOpts, opts...)
    47  	return c
    48  }
    49  func (c *codec) Decode(opts ...utils.OptionExtender) Codecable {
    50  	for i, p := 0, len(c.decOpts); i < len(opts); i++ {
    51  		c.queue = append(c.queue, [2]int{p + i, 1})
    52  	}
    53  	c.decOpts = append(c.decOpts, opts...)
    54  	return c
    55  }
    56  func (c *codec) ToBytes() (dst []byte, err error) {
    57  	if err = c.transform(); err != nil {
    58  		return
    59  	}
    60  	dst = make([]byte, c.buf.Len())
    61  	copy(dst, c.buf.Bytes())
    62  	return
    63  }
    64  func (c *codec) ToString() (dst string, err error) {
    65  	if err = c.transform(); err != nil {
    66  		return
    67  	}
    68  	dst = c.buf.String()
    69  	return
    70  }
    71  
    72  func (c *codec) transform() (err error) {
    73  	for _, elem := range c.queue {
    74  		idx, isEnc := elem[0], elem[1] == 0
    75  		if isEnc {
    76  			if err = c.encode(c.encOpts[idx]); err != nil {
    77  				return
    78  			}
    79  		} else {
    80  			if err = c.decode(c.decOpts[idx]); err != nil {
    81  				return
    82  			}
    83  
    84  		}
    85  	}
    86  
    87  	return
    88  }
    89  func (c *codec) encode(opt utils.OptionExtender) (err error) {
    90  	var enc func([]byte) ([]byte, error)
    91  
    92  	switch option := utils.ApplyOptions[option](opt); parseEncodedType(opt) {
    93  	case EncodedTypeCompress:
    94  		enc = compress.EncodeBytesFunc(option.compressAlgo)
    95  	case EncodedTypeCipher:
    96  		enc, err = cipher.EncryptBytesFunc(option.cipherAlgo, option.cipherMode, option.key, option.iv)
    97  	case EncodedTypeEncode:
    98  		enc = NewEncodeFunc(option.printableAlgo)
    99  	default:
   100  		return ErrEncodeMethodNotFound
   101  	}
   102  	if err != nil {
   103  		return
   104  	}
   105  
   106  	dst, err := enc(c.buf.Bytes())
   107  	if err != nil {
   108  		return
   109  	}
   110  	c.buf.Reset()
   111  	c.buf.Write(dst)
   112  	return
   113  }
   114  func (c *codec) decode(opt utils.OptionExtender) (err error) {
   115  	var dec func([]byte) ([]byte, error)
   116  
   117  	switch option := utils.ApplyOptions[option](opt); parseEncodedType(opt) {
   118  	case EncodedTypeCompress:
   119  		dec = compress.DecodeBytesFunc(option.compressAlgo)
   120  	case EncodedTypeCipher:
   121  		dec, err = cipher.DecryptBytesFunc(option.cipherAlgo, option.cipherMode, option.key, option.iv)
   122  	case EncodedTypeEncode:
   123  		dec = NewDecodeFunc(option.printableAlgo)
   124  	default:
   125  		return ErrEncodeMethodNotFound
   126  	}
   127  	if err != nil {
   128  		return
   129  	}
   130  
   131  	dst, err := dec(c.buf.Bytes())
   132  	if err != nil {
   133  		return
   134  	}
   135  	c.buf.Reset()
   136  	c.buf.Write(dst)
   137  	return
   138  }