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 }