diff --git a/lego/sys/codec/codec.go b/lego/sys/codec/codec.go new file mode 100644 index 000000000..ab057de18 --- /dev/null +++ b/lego/sys/codec/codec.go @@ -0,0 +1,180 @@ +package codec + +import ( + "sync" + + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/extractor" + "go_dreamfactory/lego/sys/codec/factory" + "go_dreamfactory/lego/sys/codec/stream" + + "github.com/modern-go/reflect2" +) + +func newSys(options core.Options) (sys *codec, err error) { + sys = &codec{ + options: &options, + decoderCache: new(sync.Map), + encoderCache: new(sync.Map), + streamPool: &sync.Pool{ + New: func() interface{} { + return stream.NewStream(sys, 512) + }, + }, + extraPool: &sync.Pool{ + New: func() interface{} { + return extractor.NewExtractor(sys) + }, + }, + } + return +} + +type codec struct { + options *core.Options + decoderCache *sync.Map + encoderCache *sync.Map + streamPool *sync.Pool + extraPool *sync.Pool +} + +func (this *codec) Options() *core.Options { + return this.options +} + +//序列化Josn +func (this *codec) MarshalJson(val interface{}, option ...core.ExecuteOption) (buf []byte, err error) { + stream := this.BorrowStream() + defer this.ReturnStream(stream) + stream.WriteVal(val) + if stream.Error() != nil { + return nil, stream.Error() + } + result := stream.Buffer() + copied := make([]byte, len(result)) + copy(copied, result) + return copied, nil +} + +func (this *codec) UnmarshalJson(data []byte, v interface{}) error { + extra := this.BorrowExtractor(data) + defer this.ReturnExtractor(extra) + extra.ReadVal(v) + return extra.Error() +} + +func (this *codec) addDecoderToCache(cacheKey uintptr, decoder core.IDecoder) { + this.decoderCache.Store(cacheKey, decoder) +} +func (this *codec) addEncoderToCache(cacheKey uintptr, encoder core.IEncoder) { + this.encoderCache.Store(cacheKey, encoder) +} + +func (this *codec) GetEncoderFromCache(cacheKey uintptr) core.IEncoder { + encoder, found := this.encoderCache.Load(cacheKey) + if found { + return encoder.(core.IEncoder) + } + return nil +} + +func (this *codec) GetDecoderFromCache(cacheKey uintptr) core.IDecoder { + decoder, found := this.decoderCache.Load(cacheKey) + if found { + return decoder.(core.IDecoder) + } + return nil +} + +func (this *codec) EncoderOf(typ reflect2.Type) core.IEncoder { + cacheKey := typ.RType() + encoder := this.GetEncoderFromCache(cacheKey) + if encoder != nil { + return encoder + } + ctx := &core.Ctx{ + ICodec: this, + Prefix: "", + Decoders: map[reflect2.Type]core.IDecoder{}, + Encoders: map[reflect2.Type]core.IEncoder{}, + } + encoder = factory.EncoderOfType(ctx, typ) + if typ.LikePtr() { + encoder = factory.NewonePtrEncoder(encoder) + } + this.addEncoderToCache(cacheKey, encoder) + return encoder +} + +func (this *codec) DecoderOf(typ reflect2.Type) core.IDecoder { + cacheKey := typ.RType() + decoder := this.GetDecoderFromCache(cacheKey) + if decoder != nil { + return decoder + } + ctx := &core.Ctx{ + ICodec: this, + Prefix: "", + Decoders: map[reflect2.Type]core.IDecoder{}, + Encoders: map[reflect2.Type]core.IEncoder{}, + } + ptrType := typ.(*reflect2.UnsafePtrType) + decoder = factory.DecoderOfType(ctx, ptrType.Elem()) + this.addDecoderToCache(cacheKey, decoder) + return decoder +} + +func (this *codec) BorrowStream() core.IStream { + stream := this.streamPool.Get().(core.IStream) + return stream +} + +func (this *codec) ReturnStream(stream core.IStream) { + this.streamPool.Put(stream) +} + +func (this *codec) BorrowExtractor(buf []byte) core.IExtractor { + extra := this.extraPool.Get().(core.IExtractor) + extra.ResetBytes(buf) + return extra +} + +func (this *codec) ReturnExtractor(extra core.IExtractor) { + this.extraPool.Put(extra) +} + +///日志*********************************************************************** +func (this *codec) Debug() bool { + return this.options.Debug +} + +func (this *codec) Debugf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Debugf("[SYS Gin] "+format, a...) + } +} +func (this *codec) Infof(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Infof("[SYS Gin] "+format, a...) + } +} +func (this *codec) Warnf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Warnf("[SYS Gin] "+format, a...) + } +} +func (this *codec) Errorf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Errorf("[SYS Gin] "+format, a...) + } +} +func (this *codec) Panicf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Panicf("[SYS Gin] "+format, a...) + } +} +func (this *codec) Fatalf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Fatalf("[SYS Gin] "+format, a...) + } +} diff --git a/lego/sys/codec/core.go b/lego/sys/codec/core.go new file mode 100644 index 000000000..69f61d93e --- /dev/null +++ b/lego/sys/codec/core.go @@ -0,0 +1,24 @@ +package codec + +import ( + "go_dreamfactory/lego/sys/codec/core" +) + +type ( + ISys interface { + MarshalJson(v interface{}, option ...core.ExecuteOption) ([]byte, error) + UnmarshalJson(data []byte, v interface{}) error + } +) + +var defsys ISys + +func OnInit(config map[string]interface{}, option ...core.Option) (err error) { + defsys, err = newSys(newOptions(config, option...)) + return +} + +func NewSys(option ...core.Option) (sys ISys, err error) { + sys, err = newSys(newOptionsByOption(option...)) + return +} diff --git a/lego/sys/codec/core/core.go b/lego/sys/codec/core/core.go new file mode 100644 index 000000000..df31b3cc4 --- /dev/null +++ b/lego/sys/codec/core/core.go @@ -0,0 +1,146 @@ +package core + +import ( + "unsafe" + + "github.com/modern-go/reflect2" +) + +//数据类型 +type CodecType int8 + +const ( + Json CodecType = iota //json 格式数据 + Bytes //byte 字节流数据 + Proto //proto google protobuff 数据 +) + +//结构值类型 +type ValueType int + +const ( + // InvalidValue invalid JSON element + InvalidValue ValueType = iota + // StringValue JSON element "string" + StringValue + // NumberValue JSON element 100 or 0.10 + NumberValue + // NilValue JSON element null + NilValue + // BoolValue JSON element true or false + BoolValue + // ArrayValue JSON element [] + ArrayValue + // ObjectValue JSON element {} + ObjectValue +) + +type ( + ICodec interface { + Options() *Options + GetEncoderFromCache(cacheKey uintptr) IEncoder + GetDecoderFromCache(cacheKey uintptr) IDecoder + EncoderOf(typ reflect2.Type) IEncoder + DecoderOf(typ reflect2.Type) IDecoder + BorrowExtractor(buf []byte) IExtractor //借 提取器 + ReturnExtractor(extra IExtractor) //还 提取器 + BorrowStream() IStream //借 输出对象 + ReturnStream(stream IStream) //换 输出对象 + } + IExtractor interface { + ReadVal(obj interface{}) //读取指定类型对象 + WhatIsNext() ValueType + Read() interface{} + ReadNil() (ret bool) //读取空 null + ReadArrayStart() (ret bool) //读数组开始 [ + CheckNextIsArrayEnd() (ret bool) //下一个是否是数组结束符 不影响数据游标位置 + ReadArrayEnd() (ret bool) //读数组结束 ] + ReadObjectStart() (ret bool) //读对象或Map开始 { + CheckNextIsObjectEnd() (ret bool) //下一个是否是数对象结束符 不影响数据游标位置 + ReadObjectEnd() (ret bool) //读对象或Map结束 } + ReadMemberSplit() (ret bool) //读成员分割符 , + ReadKVSplit() (ret bool) //读取key value 分割符 : + ReadKeyStart() (ret bool) //读取字段名 开始 + ReadKeyEnd() (ret bool) //读取字段名 结束 + Skip() //跳过一个数据单元 容错处理 + ReadBool() (ret bool) + ReadInt8() (ret int8) + ReadInt16() (ret int16) + ReadInt32() (ret int32) + ReadInt64() (ret int64) + ReadUint8() (ret uint8) + ReadUint16() (ret uint16) + ReadUint32() (ret uint32) + ReadUint64() (ret uint64) + ReadFloat32() (ret float32) + ReadFloat64() (ret float64) + ReadString() (ret string) + ResetBytes(d []byte) + Error() error + SetErr(err error) + } + IStream interface { + WriteVal(val interface{}) //写入一个对象 + WriteNil() //写空 null + WriteEmptyArray() //写空数组 [] + WriteArrayStart() //写数组开始 [ + WriteArrayEnd() //写数组结束 ] + WriteEmptyObject() //写空对象 {} + WriteObjectStart() //写对象或Map开始 { + WriteObjectEnd() //写对象或Map结束 } + WriteMemberSplit() //写成员分割符 , + WriteKVSplit() //写key value 分割符 : + WriteKeyStart() //写入字段名 开始 + WriteKeyEnd() //写入字段名 结束 + WriteObjectFieldName(val string) //写入对象字段名 + WriteBool(val bool) + WriteInt8(val int8) + WriteInt16(val int16) + WriteInt32(val int32) + WriteInt64(val int64) + WriteUint8(val uint8) + WriteUint16(val uint16) + WriteUint32(val uint32) + WriteUint64(val uint64) + WriteFloat32(val float32) + WriteFloat64(val float64) + WriteString(val string) + WriteBytes(val []byte) + Buffer() []byte //返回缓存区数据 + Error() error + SetErr(err error) + } + //编码器 + IEncoder interface { + IsEmpty(ptr unsafe.Pointer) bool + Encode(ptr unsafe.Pointer, stream IStream) + } + //解码器 + IDecoder interface { + Decode(ptr unsafe.Pointer, extra IExtractor) + } + //空校验 + CheckIsEmpty interface { + IsEmpty(ptr unsafe.Pointer) bool + } + //内嵌指针是否是空 + IsEmbeddedPtrNil interface { + IsEmbeddedPtrNil(ptr unsafe.Pointer) bool + } +) + +type Ctx struct { + ICodec + Prefix string + Encoders map[reflect2.Type]IEncoder + Decoders map[reflect2.Type]IDecoder +} + +func (this *Ctx) Append(prefix string) *Ctx { + return &Ctx{ + ICodec: this.ICodec, + Prefix: this.Prefix + " " + prefix, + Encoders: this.Encoders, + Decoders: this.Decoders, + } +} diff --git a/lego/sys/codec/core/options.go b/lego/sys/codec/core/options.go new file mode 100644 index 000000000..1524d0ddb --- /dev/null +++ b/lego/sys/codec/core/options.go @@ -0,0 +1,30 @@ +package core + +import ( + "go_dreamfactory/lego/sys/log" +) + +type Option func(*Options) +type Options struct { + IndentionStep int //缩进步骤 + ObjectFieldMustBeSimpleString bool //对象字段必须是简单字符串 + OnlyTaggedField bool //仅仅处理标签字段 + DisallowUnknownFields bool //禁止未知字段 + CaseSensitive bool //是否区分大小写 + TagKey string //标签 + Debug bool //日志是否开启 + Log log.ILog +} + +//执行选项 +type ExecuteOption func(*ExecuteOptions) +type ExecuteOptions struct { +} + +func NewExecuteOptions(opts ...ExecuteOption) ExecuteOptions { + options := ExecuteOptions{} + for _, o := range opts { + o(&options) + } + return options +} diff --git a/lego/sys/codec/extractor/json.go b/lego/sys/codec/extractor/json.go new file mode 100644 index 000000000..5c6bf78ea --- /dev/null +++ b/lego/sys/codec/extractor/json.go @@ -0,0 +1,866 @@ +package extractor + +import ( + "fmt" + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/utils" + "io" + "math/big" + "reflect" + "unicode/utf16" + + "github.com/modern-go/reflect2" +) + +const maxDepth = 10000 + +var hexDigits []byte +var valueTypes []core.ValueType + +func init() { + hexDigits = make([]byte, 256) + for i := 0; i < len(hexDigits); i++ { + hexDigits[i] = 255 + } + for i := '0'; i <= '9'; i++ { + hexDigits[i] = byte(i - '0') + } + for i := 'a'; i <= 'f'; i++ { + hexDigits[i] = byte((i - 'a') + 10) + } + for i := 'A'; i <= 'F'; i++ { + hexDigits[i] = byte((i - 'A') + 10) + } + valueTypes = make([]core.ValueType, 256) + for i := 0; i < len(valueTypes); i++ { + valueTypes[i] = core.InvalidValue + } + valueTypes['"'] = core.StringValue + valueTypes['-'] = core.NumberValue + valueTypes['0'] = core.NumberValue + valueTypes['1'] = core.NumberValue + valueTypes['2'] = core.NumberValue + valueTypes['3'] = core.NumberValue + valueTypes['4'] = core.NumberValue + valueTypes['5'] = core.NumberValue + valueTypes['6'] = core.NumberValue + valueTypes['7'] = core.NumberValue + valueTypes['8'] = core.NumberValue + valueTypes['9'] = core.NumberValue + valueTypes['t'] = core.BoolValue + valueTypes['f'] = core.BoolValue + valueTypes['n'] = core.NilValue + valueTypes['['] = core.ArrayValue + valueTypes['{'] = core.ObjectValue +} +func NewExtractor(codec core.ICodec) *JsonExtractor { + return &JsonExtractor{ + codec: codec, + buf: nil, + head: 0, + tail: 0, + depth: 0, + err: nil, + } +} + +type JsonExtractor struct { + codec core.ICodec + buf []byte + head int + tail int + depth int + err error +} + +func (this *JsonExtractor) ReadVal(obj interface{}) { + depth := this.depth + cacheKey := reflect2.RTypeOf(obj) + decoder := this.codec.GetDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(obj) + if typ == nil || typ.Kind() != reflect.Ptr { + this.reportError("ReadVal", "can only unmarshal into pointer") + return + } + decoder = this.codec.DecoderOf(typ) + } + ptr := reflect2.PtrOf(obj) + if ptr == nil { + this.reportError("ReadVal", "can not read into nil pointer") + return + } + decoder.Decode(ptr, this) + if this.depth != depth { + this.reportError("ReadVal", "unexpected mismatched nesting") + return + } +} +func (this *JsonExtractor) WhatIsNext() core.ValueType { + valueType := valueTypes[this.nextToken()] + this.unreadByte() + return valueType +} +func (this *JsonExtractor) Read() interface{} { + valueType := this.WhatIsNext() + switch valueType { + case core.StringValue: + return this.ReadString() + case core.NumberValue: + return this.ReadFloat64() + case core.NilValue: + this.skipFourBytes('n', 'u', 'l', 'l') + return nil + case core.BoolValue: + return this.ReadBool() + case core.ArrayValue: + arr := []interface{}{} + this.ReadArrayCB(func(extra core.IExtractor) bool { + var elem interface{} + extra.ReadVal(&elem) + arr = append(arr, elem) + return true + }) + return arr + case core.ObjectValue: + obj := map[string]interface{}{} + this.ReadMapCB(func(extra core.IExtractor, field string) bool { + var elem interface{} + this.ReadVal(&elem) + obj[field] = elem + return true + }) + return obj + default: + this.reportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) + return nil + } +} +func (this *JsonExtractor) ReadNil() (ret bool) { + c := this.nextToken() + if c == 'n' { + this.skipThreeBytes('u', 'l', 'l') // null + return true + } + this.unreadByte() + return false +} + +func (this *JsonExtractor) ReadArrayStart() (ret bool) { + c := this.nextToken() + if c == '[' { + return true + } + this.reportError("ReadArrayStart", `expect [ but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) CheckNextIsArrayEnd() (ret bool) { + c := this.nextToken() + this.unreadByte() + if c == ']' { + return true + } + return +} +func (this *JsonExtractor) ReadArrayEnd() (ret bool) { + c := this.nextToken() + if c == ']' { + return true + } + this.reportError("ReadArrayEnd", `expect ] but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadObjectStart() (ret bool) { + c := this.nextToken() + if c == '{' { + return this.incrementDepth() + } + this.reportError("ReadObjectStart", `expect { but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) CheckNextIsObjectEnd() (ret bool) { + c := this.nextToken() + this.unreadByte() + if c == '}' { + return true + } + return +} +func (this *JsonExtractor) ReadObjectEnd() (ret bool) { + c := this.nextToken() + if c == '}' { + return this.decrementDepth() + } + this.reportError("ReadObjectEnd", `expect } but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadMemberSplit() (ret bool) { + c := this.nextToken() + if c == ',' { + return true + } + this.unreadByte() + return +} +func (this *JsonExtractor) ReadKVSplit() (ret bool) { + c := this.nextToken() + if c == ':' { + return true + } + this.reportError("ReadKVSplit", `expect : but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadKeyStart() (ret bool) { + c := this.nextToken() + if c == '"' { + return true + } + this.reportError("ReadKeyStart", `expect " but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadKeyEnd() (ret bool) { + c := this.nextToken() + if c == '"' { + return true + } + this.reportError("ReadKeyEnd", `expect " but found `+string([]byte{c})) + return +} + +func (this *JsonExtractor) Skip() { + c := this.nextToken() + switch c { + case '"': + this.skipString() + case 'n': + this.skipThreeBytes('u', 'l', 'l') // null + case 't': + this.skipThreeBytes('r', 'u', 'e') // true + case 'f': + this.skipFourBytes('a', 'l', 's', 'e') // false + case '0': + this.unreadByte() + this.ReadFloat32() + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + this.skipNumber() + case '[': + this.skipArray() + case '{': + this.skipObject() + default: + this.reportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) + return + } +} +func (this *JsonExtractor) ReadBool() (ret bool) { + c := this.nextToken() + if c == 't' { + this.skipThreeBytes('r', 'u', 'e') + return true + } + if c == 'f' { + this.skipFourBytes('a', 'l', 's', 'e') + return false + } + this.reportError("ReadBool", "expect t or f, but found "+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadInt8() (ret int8) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt8ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt8", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt16() (ret int16) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt16ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt32() (ret int32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt64() (ret int64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint8() (ret uint8) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint8ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint8", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint16() (ret uint16) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint16ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint16", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint32() (ret uint32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint64() (ret uint64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadFloat32() (ret float32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadFloat32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadFloat32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadFloat64() (ret float64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadFloat64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadFloat64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadString() (ret string) { + c := this.nextToken() + if c == '"' { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + if c == '"' { + ret = string(this.buf[this.head:i]) + this.head = i + 1 + return ret + } else if c == '\\' { + break + } else if c < ' ' { + this.reportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return + } + } + return this.readStringSlowPath() + } else if c == 'n' { + this.skipThreeBytes('u', 'l', 'l') + return "" + } + this.reportError("ReadString", `expects " or n, but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ResetBytes(d []byte) { + this.buf = d + this.head = 0 + this.tail = len(d) +} +func (this *JsonExtractor) Error() error { + return this.err +} +func (this *JsonExtractor) SetErr(err error) { + this.err = err +} + +//----------------------------------------------------------------------------------------------------------------------------------- +func (this *JsonExtractor) readByte() (ret byte) { + if this.head == this.tail { + return 0 + } + ret = this.buf[this.head] + this.head++ + return ret +} +func (this *JsonExtractor) readStringSlowPath() (ret string) { + var str []byte + var c byte + for this.err == nil { + c = this.readByte() + if c == '"' { + return string(str) + } + if c == '\\' { + c = this.readByte() + str = this.readEscapedChar(c, str) + } else { + str = append(str, c) + } + } + this.reportError("readStringSlowPath", "unexpected end of input") + return +} +func (this *JsonExtractor) readEscapedChar(c byte, str []byte) []byte { + switch c { + case 'u': + r := this.readU4() + if utf16.IsSurrogate(r) { + c = this.readByte() + if this.err != nil { + return nil + } + if c != '\\' { + this.unreadByte() + str = utils.AppendRune(str, r) + return str + } + c = this.readByte() + if this.err != nil { + return nil + } + if c != 'u' { + str = utils.AppendRune(str, r) + return this.readEscapedChar(c, str) + } + r2 := this.readU4() + if this.err != nil { + return nil + } + combined := utf16.DecodeRune(r, r2) + if combined == '\uFFFD' { + str = utils.AppendRune(str, r) + str = utils.AppendRune(str, r2) + } else { + str = utils.AppendRune(str, combined) + } + } else { + str = utils.AppendRune(str, r) + } + case '"': + str = append(str, '"') + case '\\': + str = append(str, '\\') + case '/': + str = append(str, '/') + case 'b': + str = append(str, '\b') + case 'f': + str = append(str, '\f') + case 'n': + str = append(str, '\n') + case 'r': + str = append(str, '\r') + case 't': + str = append(str, '\t') + default: + this.reportError("readEscapedChar", + `invalid escape char after \`) + return nil + } + return str +} +func (this *JsonExtractor) readU4() (ret rune) { + for i := 0; i < 4; i++ { + c := this.readByte() + if this.err != nil { + return + } + if c >= '0' && c <= '9' { + ret = ret*16 + rune(c-'0') + } else if c >= 'a' && c <= 'f' { + ret = ret*16 + rune(c-'a'+10) + } else if c >= 'A' && c <= 'F' { + ret = ret*16 + rune(c-'A'+10) + } else { + this.reportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) + return + } + } + return ret +} +func (this *JsonExtractor) nextToken() byte { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + this.head = i + 1 + return c + } + return 0 +} +func (this *JsonExtractor) unreadByte() { + if this.err != nil { + return + } + this.head-- + return +} +func (this *JsonExtractor) skipNumber() { + if !this.trySkipNumber() { + this.unreadByte() + if this.err != nil && this.err != io.EOF { + return + } + this.ReadFloat64() + if this.err != nil && this.err != io.EOF { + this.err = nil + this.ReadBigFloat() + } + } +} +func (this *JsonExtractor) ReadBigFloat() (ret *big.Float) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadBigFloatForString(this.buf[this.head:]); err != nil { + this.reportError("ReadBigFloat", err.Error()) + return + } + this.head += n + return +} +func (iter *JsonExtractor) trySkipNumber() bool { + dotFound := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + case '.': + if dotFound { + iter.reportError("validateNumber", `more than one dot found in number`) + return true // already failed + } + if i+1 == iter.tail { + return false + } + c = iter.buf[i+1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + iter.reportError("validateNumber", `missing digit after dot`) + return true // already failed + } + dotFound = true + default: + switch c { + case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } + iter.head = i + return true // must be valid + } + return false // may be invalid + } + } + return false +} +func (this *JsonExtractor) skipString() { + if !this.trySkipString() { + this.unreadByte() + this.ReadString() + } +} +func (this *JsonExtractor) trySkipString() bool { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + if c == '"' { + this.head = i + 1 + return true // valid + } else if c == '\\' { + return false + } else if c < ' ' { + this.reportError("trySkipString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return true // already failed + } + } + return false +} +func (this *JsonExtractor) skipObject() { + this.unreadByte() + this.ReadObjectCB(func(extra core.IExtractor, field string) bool { + extra.Skip() + return true + }) +} +func (this *JsonExtractor) skipArray() { + this.unreadByte() + this.ReadArrayCB(func(extra core.IExtractor) bool { + extra.Skip() + return true + }) +} +func (this *JsonExtractor) skipThreeBytes(b1, b2, b3 byte) { + if this.readByte() != b1 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if this.readByte() != b2 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if this.readByte() != b3 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } +} +func (this *JsonExtractor) skipFourBytes(b1, b2, b3, b4 byte) { + if this.readByte() != b1 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b2 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b3 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b4 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } +} +func (this *JsonExtractor) reportError(operation string, msg string) { + if this.err != nil { + if this.err != io.EOF { + return + } + } + peekStart := this.head - 10 + if peekStart < 0 { + peekStart = 0 + } + peekEnd := this.head + 10 + if peekEnd > this.tail { + peekEnd = this.tail + } + parsing := string(this.buf[peekStart:peekEnd]) + contextStart := this.head - 50 + if contextStart < 0 { + contextStart = 0 + } + contextEnd := this.head + 50 + if contextEnd > this.tail { + contextEnd = this.tail + } + context := string(this.buf[contextStart:contextEnd]) + this.err = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", + operation, msg, this.head-peekStart, parsing, context) +} +func (this *JsonExtractor) incrementDepth() (success bool) { + this.depth++ + if this.depth <= maxDepth { + return true + } + this.reportError("incrementDepth", "exceeded max depth") + return false +} +func (this *JsonExtractor) decrementDepth() (success bool) { + this.depth-- + if this.depth >= 0 { + return true + } + this.reportError("decrementDepth", "unexpected negative nesting") + return false +} +func (iter *JsonExtractor) ReadObjectCB(callback func(core.IExtractor, string) bool) bool { + c := iter.nextToken() + var field string + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.reportError("ReadObjectCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.reportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *JsonExtractor) ReadMapCB(callback func(core.IExtractor, string) bool) bool { + c := iter.nextToken() + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + if iter.nextToken() != ':' { + iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + if iter.nextToken() != ':' { + iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.reportError("ReadMapCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.reportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *JsonExtractor) ReadArrayCB(callback func(core.IExtractor) bool) (ret bool) { + c := iter.nextToken() + if c == '[' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != ']' { + iter.reportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + return iter.decrementDepth() + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) + return false +} diff --git a/lego/sys/codec/factory/factory.go b/lego/sys/codec/factory/factory.go new file mode 100644 index 000000000..5099c9c0f --- /dev/null +++ b/lego/sys/codec/factory/factory.go @@ -0,0 +1,179 @@ +package factory + +import ( + "fmt" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type sortableBindings []*Binding + +func (this sortableBindings) Len() int { + return len(this) +} + +func (this sortableBindings) Less(i, j int) bool { + left := this[i].levels + right := this[j].levels + k := 0 + for { + if left[k] < right[k] { + return true + } else if left[k] > right[k] { + return false + } + k++ + } +} + +func (this sortableBindings) Swap(i, j int) { + this[i], this[j] = this[j], this[i] +} + +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- +func EncoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + encoder := ctx.Encoders[typ] + if encoder != nil { + return encoder + } + root := &rootEncoder{} + ctx.Encoders[typ] = root + encoder = _createEncoderOfType(ctx, typ) + root.encoder = encoder + return encoder +} + +func _createEncoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + var encoder core.IEncoder + encoder = createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return encoderOfStruct(ctx, typ) + case reflect.Array: + return encoderOfArray(ctx, typ) + case reflect.Slice: + return encoderOfSlice(ctx, typ) + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return encoderOfOptional(ctx, typ) + default: + return &lazyErrorEncoder{err: fmt.Errorf("%s %s is unsupported type", ctx.Prefix, typ.String())} + } +} + +func DecoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + decoder := ctx.Decoders[typ] + if decoder != nil { + return decoder + } + root := &rootDecoder{} + ctx.Decoders[typ] = root + decoder = _createDecoderOfType(ctx, typ) + root.decoder = decoder + return decoder +} + +func _createDecoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + var decoder core.IDecoder + + decoder = createDecoderOfNative(ctx, typ) + if decoder != nil { + return decoder + } + switch typ.Kind() { + case reflect.Interface: + ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) + if isIFace { + return &ifaceDecoder{valType: ifaceType} + } + return &efaceDecoder{} + case reflect.Struct: + return decoderOfStruct(ctx, typ) + case reflect.Array: + return decoderOfArray(ctx, typ) + case reflect.Slice: + return decoderOfSlice(ctx, typ) + case reflect.Map: + return decoderOfMap(ctx, typ) + case reflect.Ptr: + return decoderOfOptional(ctx, typ) + default: + return &lazyErrorDecoder{err: fmt.Errorf("%s %s is unsupported type", ctx.Prefix, typ.String())} + } +} + +//根节点 ------------------------------------------------------------------- +type rootDecoder struct { + decoder core.IDecoder +} + +func (this *rootDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + this.decoder.Decode(ptr, extra) +} + +type rootEncoder struct { + encoder core.IEncoder +} + +func (this *rootEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + this.encoder.Encode(ptr, stream) +} + +func (this *rootEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return this.encoder.IsEmpty(ptr) +} + +//onePtrEncoder--------------------------------------------------------------- +func NewonePtrEncoder(encoder core.IEncoder) core.IEncoder { + return &onePtrEncoder{encoder} +} + +type onePtrEncoder struct { + encoder core.IEncoder +} + +func (encoder *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +func (encoder *onePtrEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +//错误节点 ------------------------------------------------------------------ +type lazyErrorDecoder struct { + err error +} + +func (this *lazyErrorDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.Error() == nil { + extra.SetErr(this.err) + } +} + +type lazyErrorEncoder struct { + err error +} + +func (this *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if ptr == nil { + stream.WriteNil() + } else if stream.Error() == nil { + stream.SetErr(this.err) + } +} + +func (this *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} diff --git a/lego/sys/codec/factory/factory_array.go b/lego/sys/codec/factory/factory_array.go new file mode 100644 index 000000000..0bb52f99e --- /dev/null +++ b/lego/sys/codec/factory/factory_array.go @@ -0,0 +1,94 @@ +package factory + +import ( + "fmt" + "io" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfArray(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + decoder := DecoderOfType(ctx.Append("[arrayElem]"), arrayType.Elem()) + return &arrayDecoder{arrayType, decoder} +} + +func encoderOfArray(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + if arrayType.Len() == 0 { + return emptyArrayEncoder{} + } + encoder := EncoderOfType(ctx.Append("[arrayElem]"), arrayType.Elem()) + return &arrayEncoder{arrayType, encoder} +} + +//array------------------------------------------------------------------------------------------------------------------------------- +type arrayEncoder struct { + arrayType *reflect2.UnsafeArrayType + elemEncoder core.IEncoder +} + +func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(ptr) + encoder.elemEncoder.Encode(elemPtr, stream) + for i := 1; i < encoder.arrayType.Len(); i++ { + stream.WriteMemberSplit() + elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v: %s", encoder.arrayType, stream.Error().Error())) + } +} + +func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type arrayDecoder struct { + arrayType *reflect2.UnsafeArrayType + elemDecoder core.IDecoder +} + +func (this *arrayDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + arrayType := this.arrayType + if extra.ReadNil() { + return + } + if extra.ReadArrayStart() { + return + } + if extra.CheckNextIsArrayEnd() { + return + } + elemPtr := arrayType.UnsafeGetIndex(ptr, 0) + this.elemDecoder.Decode(elemPtr, extra) + length := 1 + for extra.ReadMemberSplit() { + idx := length + length += 1 + elemPtr = arrayType.UnsafeGetIndex(ptr, idx) + this.elemDecoder.Decode(elemPtr, extra) + } + if extra.ReadArrayEnd() { + return + } + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%v: %s", this.arrayType, extra.Error().Error())) + } +} + +type emptyArrayEncoder struct{} + +func (this emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteEmptyArray() +} + +func (this emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return true +} diff --git a/lego/sys/codec/factory/factory_interface.go b/lego/sys/codec/factory/factory_interface.go new file mode 100644 index 000000000..1d91f3b76 --- /dev/null +++ b/lego/sys/codec/factory/factory_interface.go @@ -0,0 +1,74 @@ +package factory + +import ( + "errors" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type dynamicEncoder struct { + valType reflect2.Type +} + +func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + obj := encoder.valType.UnsafeIndirect(ptr) + stream.WriteVal(obj) +} + +func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.valType.UnsafeIndirect(ptr) == nil +} + +type efaceDecoder struct { +} + +func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + pObj := (*interface{})(ptr) + obj := *pObj + if obj == nil { + *pObj = extra.Read() + return + } + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + *pObj = extra.Read() + return + } + ptrType := typ.(*reflect2.UnsafePtrType) + ptrElemType := ptrType.Elem() + if extra.WhatIsNext() == core.NilValue { + if ptrElemType.Kind() != reflect.Ptr { + extra.ReadNil() + *pObj = nil + return + } + } + if reflect2.IsNil(obj) { + obj := ptrElemType.New() + extra.ReadVal(obj) + *pObj = obj + return + } + extra.ReadVal(obj) +} + +type ifaceDecoder struct { + valType *reflect2.UnsafeIFaceType +} + +func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadNil() { + decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) + return + } + obj := decoder.valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + extra.SetErr(errors.New("decode non empty interface can not unmarshal into nil")) + return + } + extra.ReadVal(obj) +} diff --git a/lego/sys/codec/factory/factory_map.go b/lego/sys/codec/factory/factory_map.go new file mode 100644 index 000000000..4bbfb6444 --- /dev/null +++ b/lego/sys/codec/factory/factory_map.go @@ -0,0 +1,196 @@ +package factory + +import ( + "fmt" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfMap(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + mapType := typ.(*reflect2.UnsafeMapType) + keyDecoder := decoderOfMapKey(ctx.Append("[mapKey]"), mapType.Key()) + elemDecoder := DecoderOfType(ctx.Append("[mapElem]"), mapType.Elem()) + return &mapDecoder{ + mapType: mapType, + keyType: mapType.Key(), + elemType: mapType.Elem(), + keyDecoder: keyDecoder, + elemDecoder: elemDecoder, + } +} + +func encoderOfMap(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + mapType := typ.(*reflect2.UnsafeMapType) + return &mapEncoder{ + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.Append("[mapKey]"), mapType.Key()), + elemEncoder: EncoderOfType(ctx.Append("[mapElem]"), mapType.Elem()), + } +} + +func decoderOfMapKey(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + switch typ.Kind() { + case reflect.String: + return DecoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyDecoder{DecoderOfType(ctx, typ)} + default: + return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +func encoderOfMapKey(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + switch typ.Kind() { + case reflect.String: + return EncoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyEncoder{EncoderOfType(ctx, typ)} + default: + if typ.Kind() == reflect.Interface { + return &dynamicMapKeyEncoder{ctx, typ} + } + return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +//Map-------------------------------------------------------------------------------------------------------------------------------------- +type mapEncoder struct { + mapType *reflect2.UnsafeMapType + keyEncoder core.IEncoder + elemEncoder core.IEncoder +} + +func (this *mapEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *(*unsafe.Pointer)(ptr) == nil { + stream.WriteNil() + return + } + stream.WriteObjectStart() + iter := this.mapType.UnsafeIterate(ptr) + for i := 0; iter.HasNext(); i++ { + if i != 0 { + stream.WriteMemberSplit() + } + key, elem := iter.UnsafeNext() + this.keyEncoder.Encode(key, stream) + stream.WriteKVSplit() + this.elemEncoder.Encode(elem, stream) + } + stream.WriteObjectEnd() +} + +func (this *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := this.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type mapDecoder struct { + mapType *reflect2.UnsafeMapType + keyType reflect2.Type + elemType reflect2.Type + keyDecoder core.IDecoder + elemDecoder core.IDecoder +} + +func (this *mapDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + mapType := this.mapType + if extra.ReadNil() { + *(*unsafe.Pointer)(ptr) = nil + mapType.UnsafeSet(ptr, mapType.UnsafeNew()) + return + } + if mapType.UnsafeIsNil(ptr) { + mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) + } + if !extra.ReadObjectStart() { + return + } + if extra.CheckNextIsObjectEnd() { + extra.ReadObjectEnd() + return + } + key := this.keyType.UnsafeNew() + this.keyDecoder.Decode(key, extra) + if !extra.ReadKVSplit() { + return + } + elem := this.elemType.UnsafeNew() + this.elemDecoder.Decode(elem, extra) + this.mapType.UnsafeSetIndex(ptr, key, elem) + for extra.ReadMemberSplit() { + key := this.keyType.UnsafeNew() + this.keyDecoder.Decode(key, extra) + if !extra.ReadKVSplit() { + return + } + elem := this.elemType.UnsafeNew() + this.elemDecoder.Decode(elem, extra) + this.mapType.UnsafeSetIndex(ptr, key, elem) + } + extra.ReadObjectEnd() +} + +//NumericMap------------------------------------------------------------------------------------------------------------------------------- +type numericMapKeyDecoder struct { + decoder core.IDecoder +} + +func (this *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadKeyStart() { + return + } + this.decoder.Decode(ptr, extra) + if extra.ReadKeyEnd() { + return + } +} + +type numericMapKeyEncoder struct { + encoder core.IEncoder +} + +func (this *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteKeyStart() + this.encoder.Encode(ptr, stream) + stream.WriteKeyEnd() +} + +func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +//------------------------------------------------------------------------------------------------------------------ +type dynamicMapKeyEncoder struct { + ctx *core.Ctx + valType reflect2.Type +} + +func (this *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + obj := this.valType.UnsafeIndirect(ptr) + encoderOfMapKey(this.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) +} + +func (this *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + obj := this.valType.UnsafeIndirect(ptr) + return encoderOfMapKey(this.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) +} diff --git a/lego/sys/codec/factory/factory_native.go b/lego/sys/codec/factory/factory_native.go new file mode 100644 index 000000000..bd4f4dd72 --- /dev/null +++ b/lego/sys/codec/factory/factory_native.go @@ -0,0 +1,397 @@ +package factory + +import ( + "reflect" + "strconv" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +const ptrSize = 32 << uintptr(^uintptr(0)>>63) //计算int的大小 是32 还是64 + +func createDecoderOfNative(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + typeName := typ.String() + switch typ.Kind() { + case reflect.String: + if typeName != "string" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +func createEncoderOfNative(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + typeName := typ.String() + kind := typ.Kind() + switch kind { + case reflect.String: + if typeName != "string" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +type stringCodec struct { +} + +func (codec *stringCodec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + *((*string)(ptr)) = extra.ReadString() +} + +func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream core.IStream) { + str := *((*string)(ptr)) + stream.WriteString(str) +} + +func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +type int8Codec struct { +} + +func (codec *int8Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int8)(ptr)) = extra.ReadInt8() + } +} + +func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt8(*((*int8)(ptr))) +} + +func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int8)(ptr)) == 0 +} + +type int16Codec struct { +} + +func (codec *int16Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int16)(ptr)) = extra.ReadInt16() + } +} + +func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt16(*((*int16)(ptr))) +} + +func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int16)(ptr)) == 0 +} + +type int32Codec struct { +} + +func (codec *int32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int32)(ptr)) = extra.ReadInt32() + } +} + +func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt32(*((*int32)(ptr))) +} +func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int32)(ptr)) == 0 +} + +type int64Codec struct { +} + +func (codec *int64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int64)(ptr)) = extra.ReadInt64() + } +} + +func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt64(*((*int64)(ptr))) +} + +func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int64)(ptr)) == 0 +} + +type uint8Codec struct { +} + +func (codec *uint8Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint8)(ptr)) = extra.ReadUint8() + } +} + +func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint8(*((*uint8)(ptr))) +} + +func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint8)(ptr)) == 0 +} + +type uint16Codec struct { +} + +func (codec *uint16Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint16)(ptr)) = extra.ReadUint16() + } +} + +func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint16(*((*uint16)(ptr))) +} + +func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint16)(ptr)) == 0 +} + +type uint32Codec struct { +} + +func (codec *uint32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint32)(ptr)) = extra.ReadUint32() + } +} + +func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint32(*((*uint32)(ptr))) +} +func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint32)(ptr)) == 0 +} + +type uint64Codec struct { +} + +func (codec *uint64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint64)(ptr)) = extra.ReadUint64() + } +} + +func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint64(*((*uint64)(ptr))) +} + +func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint64)(ptr)) == 0 +} + +type float32Codec struct { +} + +func (codec *float32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*float32)(ptr)) = extra.ReadFloat32() + } +} + +func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteFloat32(*((*float32)(ptr))) +} + +func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type float64Codec struct { +} + +func (codec *float64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*float64)(ptr)) = extra.ReadFloat64() + } +} + +func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteFloat64(*((*float64)(ptr))) +} + +func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +type boolCodec struct { +} + +func (codec *boolCodec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*bool)(ptr)) = extra.ReadBool() + } +} + +func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteBool(*((*bool)(ptr))) +} + +func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { + return !(*((*bool)(ptr))) +} diff --git a/lego/sys/codec/factory/factory_optional.go b/lego/sys/codec/factory/factory_optional.go new file mode 100644 index 000000000..2bdbf218b --- /dev/null +++ b/lego/sys/codec/factory/factory_optional.go @@ -0,0 +1,130 @@ +package factory + +import ( + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfOptional(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + decoder := DecoderOfType(ctx, elemType) + return &OptionalDecoder{elemType, decoder} +} + +func encoderOfOptional(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elemEncoder := EncoderOfType(ctx, elemType) + encoder := &OptionalEncoder{elemEncoder} + return encoder +} + +//Optional-------------------------------------------------------------------------------------------------------------------- +type OptionalDecoder struct { + ValueType reflect2.Type + ValueDecoder core.IDecoder +} + +func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadNil() { + *((*unsafe.Pointer)(ptr)) = nil + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + newPtr := decoder.ValueType.UnsafeNew() + decoder.ValueDecoder.Decode(newPtr, extra) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), extra) + } + } +} + +type OptionalEncoder struct { + ValueEncoder core.IEncoder +} + +func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*unsafe.Pointer)(ptr)) == nil +} + +//reference-------------------------------------------------------------------------------------------------------------------- +type referenceEncoder struct { + encoder core.IEncoder +} + +func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +type referenceDecoder struct { + decoder core.IDecoder +} + +func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + decoder.decoder.Decode(unsafe.Pointer(&ptr), extra) +} + +//dereference-------------------------------------------------------------------------------------------------------------------- +type dereferenceDecoder struct { + valueType reflect2.Type + valueDecoder core.IDecoder +} + +func (this *dereferenceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if *((*unsafe.Pointer)(ptr)) == nil { + newPtr := this.valueType.UnsafeNew() + this.valueDecoder.Decode(newPtr, extra) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + this.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), extra) + } +} + +type dereferenceEncoder struct { + ValueEncoder core.IEncoder +} + +func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + dePtr := *((*unsafe.Pointer)(ptr)) + if dePtr == nil { + return true + } + return encoder.ValueEncoder.IsEmpty(dePtr) +} + +func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + deReferenced := *((*unsafe.Pointer)(ptr)) + if deReferenced == nil { + return true + } + isEmbeddedPtrNil, converted := encoder.ValueEncoder.(core.IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := unsafe.Pointer(deReferenced) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} diff --git a/lego/sys/codec/factory/factory_slice.go b/lego/sys/codec/factory/factory_slice.go new file mode 100644 index 000000000..456e613ec --- /dev/null +++ b/lego/sys/codec/factory/factory_slice.go @@ -0,0 +1,91 @@ +package factory + +import ( + "fmt" + "io" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfSlice(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + decoder := DecoderOfType(ctx.Append("[sliceElem]"), sliceType.Elem()) + return &sliceDecoder{sliceType, decoder} +} +func encoderOfSlice(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + encoder := EncoderOfType(ctx.Append("[sliceElem]"), sliceType.Elem()) + return &sliceEncoder{sliceType, encoder} +} + +type sliceEncoder struct { + sliceType *reflect2.UnsafeSliceType + elemEncoder core.IEncoder +} + +func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if encoder.sliceType.UnsafeIsNil(ptr) { + stream.WriteNil() + return + } + length := encoder.sliceType.UnsafeLengthOf(ptr) + if length == 0 { + stream.WriteEmptyArray() + return + } + stream.WriteArrayStart() + encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream) + for i := 1; i < length; i++ { + stream.WriteMemberSplit() + elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v: %s", encoder.sliceType, stream.Error().Error())) + } +} + +func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.sliceType.UnsafeLengthOf(ptr) == 0 +} + +type sliceDecoder struct { + sliceType *reflect2.UnsafeSliceType + elemDecoder core.IDecoder +} + +func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + sliceType := decoder.sliceType + if extra.ReadNil() { + sliceType.UnsafeSetNil(ptr) + return + } + if !extra.ReadArrayStart() { + return + } + if extra.CheckNextIsArrayEnd() { + sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) + return + } + sliceType.UnsafeGrow(ptr, 1) + elemPtr := sliceType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, extra) + length := 1 + for extra.ReadMemberSplit() { + idx := length + length += 1 + sliceType.UnsafeGrow(ptr, length) + elemPtr = sliceType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, extra) + } + if extra.ReadArrayEnd() { + return + } + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%v: %s", decoder.sliceType, extra.Error().Error())) + } +} diff --git a/lego/sys/codec/factory/factory_struct.go b/lego/sys/codec/factory/factory_struct.go new file mode 100644 index 000000000..f71befc7e --- /dev/null +++ b/lego/sys/codec/factory/factory_struct.go @@ -0,0 +1,383 @@ +package factory + +import ( + "fmt" + "io" + "reflect" + "sort" + "strings" + "unicode" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type StructDescriptor struct { + Type reflect2.Type + Fields []*Binding +} + +type Binding struct { + levels []int + Field reflect2.StructField + FromNames []string + ToNames []string + Encoder core.IEncoder + Decoder core.IDecoder +} + +func encoderOfStruct(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + type bindingTo struct { + binding *Binding + toName string + ignored bool + } + orderedBindings := []*bindingTo{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, toName := range binding.ToNames { + new := &bindingTo{ + binding: binding, + toName: toName, + } + for _, old := range orderedBindings { + if old.toName != toName { + continue + } + old.ignored, new.ignored = resolveConflictBinding(ctx.Options(), old.binding, new.binding) + } + orderedBindings = append(orderedBindings, new) + } + } + if len(orderedBindings) == 0 { + return &emptyStructEncoder{} + } + finalOrderedFields := []structFieldTo{} + for _, bindingTo := range orderedBindings { + if !bindingTo.ignored { + finalOrderedFields = append(finalOrderedFields, structFieldTo{ + encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + toName: bindingTo.toName, + }) + } + } + return &structEncoder{typ, finalOrderedFields} +} + +func decoderOfStruct(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + bindings := map[string]*Binding{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, fromName := range binding.FromNames { + old := bindings[fromName] + if old == nil { + bindings[fromName] = binding + continue + } + ignoreOld, ignoreNew := resolveConflictBinding(ctx.Options(), old, binding) + if ignoreOld { + delete(bindings, fromName) + } + if !ignoreNew { + bindings[fromName] = binding + } + } + } + fields := map[string]*structFieldDecoder{} + for k, binding := range bindings { + fields[k] = binding.Decoder.(*structFieldDecoder) + } + + if !ctx.Options().CaseSensitive { + for k, binding := range bindings { + if _, found := fields[strings.ToLower(k)]; !found { + fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) + } + } + } + return createStructDecoder(ctx.Options(), typ, fields) +} + +//结构第编辑码构建 +func describeStruct(ctx *core.Ctx, typ reflect2.Type) *StructDescriptor { + structType := typ.(*reflect2.UnsafeStructType) + embeddedBindings := []*Binding{} + bindings := []*Binding{} + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + tag, hastag := field.Tag().Lookup(ctx.Options().TagKey) + if ctx.Options().OnlyTaggedField && !hastag && !field.Anonymous() { + continue + } + if tag == "-" || field.Name() == "_" { + continue + } + tagParts := strings.Split(tag, ",") + if field.Anonymous() && (tag == "" || tagParts[0] == "") { + if field.Type().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, field.Type()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } else if field.Type().Kind() == reflect.Ptr { + ptrType := field.Type().(*reflect2.UnsafePtrType) + if ptrType.Elem().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, ptrType.Elem()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &dereferenceEncoder{binding.Encoder} + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } + } + } + fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) + decoder := DecoderOfType(ctx.Append(field.Name()), field.Type()) + encoder := EncoderOfType(ctx.Append(field.Name()), field.Type()) + binding := &Binding{ + Field: field, + FromNames: fieldNames, + ToNames: fieldNames, + Decoder: decoder, + Encoder: encoder, + } + binding.levels = []int{i} + bindings = append(bindings, binding) + } + return createStructDescriptor(ctx, typ, bindings, embeddedBindings) +} + +func createStructDescriptor(ctx *core.Ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + structDescriptor := &StructDescriptor{ + Type: typ, + Fields: bindings, + } + processTags(structDescriptor, ctx.ICodec) + allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + sort.Sort(allBindings) + structDescriptor.Fields = allBindings + return structDescriptor +} + +func processTags(structDescriptor *StructDescriptor, codec core.ICodec) { + for _, binding := range structDescriptor.Fields { + shouldOmitEmpty := false + tagParts := strings.Split(binding.Field.Tag().Get(codec.Options().TagKey), ",") + for _, tagPart := range tagParts[1:] { + if tagPart == "omitempty" { + shouldOmitEmpty = true + } + } + binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + } +} + +func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { + // ignore? + if wholeTag == "-" { + return []string{} + } + // rename? + var fieldNames []string + if tagProvidedFieldName == "" { + fieldNames = []string{originalFieldName} + } else { + fieldNames = []string{tagProvidedFieldName} + } + // private? + isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_' + if isNotExported { + fieldNames = []string{} + } + return fieldNames +} + +func createStructDecoder(opt *core.Options, typ reflect2.Type, fields map[string]*structFieldDecoder) core.IDecoder { + if opt.DisallowUnknownFields { + return &structDecoder{typ: typ, fields: fields, disallowUnknownFields: true} + } else { + return &structDecoder{opt, typ, fields, false} + } +} + +func resolveConflictBinding(opt *core.Options, old, new *Binding) (ignoreOld, ignoreNew bool) { + newTagged := new.Field.Tag().Get(opt.TagKey) != "" + oldTagged := old.Field.Tag().Get(opt.TagKey) != "" + if newTagged { + if oldTagged { + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } else { + return true, false + } + } else { + if oldTagged { + return true, false + } + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } +} + +//结构对象 编解码----------------------------------------------------------------------------------------------------------------------- +type structEncoder struct { + typ reflect2.Type + fields []structFieldTo +} + +func (this *structEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteObjectStart() + isNotFirst := false + for _, field := range this.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if field.encoder.IsEmbeddedPtrNil(ptr) { + continue + } + if isNotFirst { + stream.WriteMemberSplit() + } + stream.WriteObjectFieldName(field.toName) + field.encoder.Encode(ptr, stream) + isNotFirst = true + } + stream.WriteObjectEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v.%s", this.typ, stream.Error().Error())) + } +} + +func (this *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type structDecoder struct { + opt *core.Options + typ reflect2.Type + fields map[string]*structFieldDecoder + disallowUnknownFields bool +} + +func (this *structDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadObjectStart() { + return + } + this.decodeField(ptr, extra) + for extra.ReadMemberSplit() { + this.decodeField(ptr, extra) + } + if extra.Error() != nil && extra.Error() != io.EOF && len(this.typ.Type1().Name()) != 0 { + extra.SetErr(fmt.Errorf("%v.%s", this.typ, extra.Error().Error())) + } + extra.ReadObjectEnd() +} + +func (this *structDecoder) decodeField(ptr unsafe.Pointer, extra core.IExtractor) { + var field string + var fieldDecoder *structFieldDecoder + + field = extra.ReadString() + fieldDecoder = this.fields[field] + if fieldDecoder == nil && !this.opt.CaseSensitive { + fieldDecoder = this.fields[strings.ToLower(field)] + } + + if fieldDecoder == nil { + if this.disallowUnknownFields { + msg := "found unknown field: " + field + extra.SetErr(fmt.Errorf("decodeField %s", msg)) + return + } + if !extra.ReadKVSplit() { + return + } + extra.Skip() //跳过一个数据单元 + return + } + if !extra.ReadKVSplit() { + return + } + fieldDecoder.Decode(ptr, extra) +} + +//结构对象字段 编解码----------------------------------------------------------------------------------------------------------------------- +type structFieldTo struct { + encoder *structFieldEncoder + toName string +} +type structFieldEncoder struct { + field reflect2.StructField + fieldEncoder core.IEncoder + omitempty bool +} + +func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + fieldPtr := encoder.field.UnsafeGet(ptr) + encoder.fieldEncoder.Encode(fieldPtr, stream) + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error().Error())) + } +} + +func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := encoder.field.UnsafeGet(ptr) + return encoder.fieldEncoder.IsEmpty(fieldPtr) +} + +func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + isEmbeddedPtrNil, converted := encoder.fieldEncoder.(core.IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := encoder.field.UnsafeGet(ptr) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type structFieldDecoder struct { + field reflect2.StructField + fieldDecoder core.IDecoder +} + +func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + fieldPtr := decoder.field.UnsafeGet(ptr) + decoder.fieldDecoder.Decode(fieldPtr, extra) + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%s: %s", decoder.field.Name(), extra.Error().Error())) + } +} + +//Empty----------------------------------------------------------------------------------------------------------------------- +type emptyStructEncoder struct { +} + +func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} diff --git a/lego/sys/codec/options.go b/lego/sys/codec/options.go new file mode 100644 index 000000000..40c2cfc37 --- /dev/null +++ b/lego/sys/codec/options.go @@ -0,0 +1,29 @@ +package codec + +import ( + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/utils/mapstructure" +) + +func newOptions(config map[string]interface{}, opts ...core.Option) core.Options { + options := core.Options{ + IndentionStep: 2, + } + if config != nil { + mapstructure.Decode(config, &options) + } + for _, o := range opts { + o(&options) + } + return options +} + +func newOptionsByOption(opts ...core.Option) core.Options { + options := core.Options{ + IndentionStep: 2, + } + for _, o := range opts { + o(&options) + } + return options +} diff --git a/lego/sys/codec/stream/json.go b/lego/sys/codec/stream/json.go new file mode 100644 index 000000000..abc581c7a --- /dev/null +++ b/lego/sys/codec/stream/json.go @@ -0,0 +1,201 @@ +package stream + +import ( + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/utils" + + "github.com/modern-go/reflect2" +) + +func NewStream(codec core.ICodec, bufSize int) *JsonStream { + return &JsonStream{ + codec: codec, + buf: make([]byte, 0, bufSize), + err: nil, + indention: 0, + } +} + +type JsonStream struct { + codec core.ICodec + err error + buf []byte + indention int +} + +//写入对象 +func (this *JsonStream) WriteVal(val interface{}) { + if nil == val { + this.WriteNil() + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := this.codec.GetEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = this.codec.EncoderOf(typ) + } + encoder.Encode(reflect2.PtrOf(val), this) +} + +func (this *JsonStream) WriteNil() { + this.writeFourBytes('n', 'u', 'l', 'l') +} +func (this *JsonStream) WriteEmptyArray() { + this.writeTwoBytes('[', ']') +} +func (this *JsonStream) WriteArrayStart() { + this.indention += this.codec.Options().IndentionStep + this.writeByte('[') + this.writeIndention(0) +} +func (this *JsonStream) WriteArrayEnd() { + this.writeIndention(this.codec.Options().IndentionStep) + this.indention -= this.codec.Options().IndentionStep + this.writeByte(']') +} +func (this *JsonStream) WriteEmptyObject() { + this.writeTwoBytes('{', '}') +} +func (this *JsonStream) WriteObjectStart() { + this.indention += this.codec.Options().IndentionStep + this.writeByte('{') + this.writeIndention(0) +} +func (this *JsonStream) WriteObjectEnd() { + this.writeIndention(this.codec.Options().IndentionStep) + this.indention -= this.codec.Options().IndentionStep + this.writeByte('}') +} +func (this *JsonStream) WriteMemberSplit() { + this.writeByte(',') + this.writeIndention(0) +} +func (this *JsonStream) WriteKVSplit() { + this.writeByte(':') +} +func (this *JsonStream) WriteKeyStart() { + this.writeByte('"') +} +func (this *JsonStream) WriteKeyEnd() { + this.writeByte('"') +} +func (this *JsonStream) WriteObjectFieldName(val string) { + this.WriteString(val) + if this.indention > 0 { + this.writeTwoBytes(':', ' ') + } else { + this.writeByte(':') + } +} +func (this *JsonStream) WriteBool(val bool) { + if val { + this.writeTrue() + } else { + this.writeFalse() + } +} +func (this *JsonStream) WriteInt8(val int8) { + utils.WriteInt8ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt16(val int16) { + utils.WriteInt16ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt32(val int32) { + utils.WriteInt32ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt64(val int64) { + utils.WriteInt64ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint8(val uint8) { + utils.WriteUint8ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint16(val uint16) { + utils.WriteUint16ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint32(val uint32) { + utils.WriteUint32ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint64(val uint64) { + utils.WriteUint64ToString(&this.buf, val) +} +func (this *JsonStream) WriteFloat32(val float32) { + utils.WriteFloat32ToString(&this.buf, val) +} +func (this *JsonStream) WriteFloat64(val float64) { + utils.WriteFloat64ToString(&this.buf, val) +} +func (this *JsonStream) WriteString(val string) { + valLen := len(val) + this.buf = append(this.buf, '"') + i := 0 + for ; i < valLen; i++ { + c := val[i] + if c > 31 && c != '"' && c != '\\' { + this.buf = append(this.buf, c) + } else { + break + } + } + if i == valLen { + this.buf = append(this.buf, '"') + return + } + utils.WriteStringSlowPath(&this.buf, i, val, valLen) +} + +func (this *JsonStream) WriteBytes(val []byte) { + this.buf = append(this.buf, val...) +} +func (this *JsonStream) Buffer() []byte { + return this.buf +} +func (this *JsonStream) Error() error { + return this.err +} +func (this *JsonStream) SetErr(err error) { + this.err = err +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +// WriteTrue write true to stream +func (stream *JsonStream) writeTrue() { + stream.writeFourBytes('t', 'r', 'u', 'e') +} + +// WriteFalse write false to stream +func (stream *JsonStream) writeFalse() { + stream.writeFiveBytes('f', 'a', 'l', 's', 'e') +} + +func (this *JsonStream) writeByte(c byte) { + this.buf = append(this.buf, c) +} + +func (this *JsonStream) writeTwoBytes(c1 byte, c2 byte) { + this.buf = append(this.buf, c1, c2) +} + +func (this *JsonStream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { + this.buf = append(this.buf, c1, c2, c3) +} + +func (this *JsonStream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { + this.buf = append(this.buf, c1, c2, c3, c4) +} + +func (this *JsonStream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { + this.buf = append(this.buf, c1, c2, c3, c4, c5) +} + +func (stream *JsonStream) writeIndention(delta int) { + if stream.indention == 0 { + return + } + stream.writeByte('\n') + toWrite := stream.indention - delta + for i := 0; i < toWrite; i++ { + stream.buf = append(stream.buf, ' ') + } +} diff --git a/lego/sys/codec/sys_test.go b/lego/sys/codec/sys_test.go new file mode 100644 index 000000000..679baf03f --- /dev/null +++ b/lego/sys/codec/sys_test.go @@ -0,0 +1,36 @@ +package codec_test + +import ( + "fmt" + "testing" + + "go_dreamfactory/lego/sys/codec" + "go_dreamfactory/lego/sys/log" +) + +type TestData struct { + Name string + Value int + Array []interface{} + Data map[string]interface{} +} +type Test1Data struct { + Name string + Value int +} + +func Test_sys(t *testing.T) { + if err := log.OnInit(nil); err != nil { + fmt.Printf("log init err:%v", err) + return + } + if sys, err := codec.NewSys(); err != nil { + fmt.Printf("gin init err:%v", err) + } else { + d, err := sys.MarshalJson(&TestData{Name: "liwe1idao", Value: 10, Array: []interface{}{1, "dajiahao", &Test1Data{Name: "liwe1dao", Value: 123}}, Data: map[string]interface{}{"hah": 1, "asd": 999}}) + fmt.Printf("codec Marshal d:%s err:%v", d, err) + data := &TestData{} + err = sys.UnmarshalJson(d, data) + fmt.Printf("codec UnmarshalJson data:%v err:%v", data, err) + } +} diff --git a/lego/sys/codec/utils/float.go b/lego/sys/codec/utils/float.go new file mode 100644 index 000000000..58c1a2b8d --- /dev/null +++ b/lego/sys/codec/utils/float.go @@ -0,0 +1,416 @@ +package utils + +import ( + "errors" + "fmt" + "math" + "math/big" + "strconv" + "strings" + "unsafe" +) + +var pow10 []uint64 +var floatDigits []int8 + +const invalidCharForNumber = int8(-1) +const endOfNumber = int8(-2) +const dotInNumber = int8(-3) + +func init() { + pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} + floatDigits = make([]int8, 256) + for i := 0; i < len(floatDigits); i++ { + floatDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + floatDigits[i] = i - int8('0') + } + floatDigits[','] = endOfNumber + floatDigits[']'] = endOfNumber + floatDigits['}'] = endOfNumber + floatDigits[' '] = endOfNumber + floatDigits['\t'] = endOfNumber + floatDigits['\n'] = endOfNumber + floatDigits['.'] = dotInNumber +} + +//Read Float For String------------------------------------------------------------------------------------------------------------------------------------------------------------- +//从字符串中读取float 对象 +func ReadBigFloatForString(buf []byte) (ret *big.Float, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err == nil { + return + } + prec := 64 + if len(str) > prec { + prec = len(str) + } + ret, _, err = big.ParseFloat(str, 10, uint(prec), big.ToZero) + return +} +func ReadFloat32ForString(buf []byte) (ret float32, n int, err error) { + if buf[0] == '-' { + ret, n, err = readPositiveFloat32(buf[1:]) + ret = -ret + return + } + return readPositiveFloat32(buf) +} +func ReadFloat64ForString(buf []byte) (ret float64, n int, err error) { + if buf[0] == '-' { + ret, n, err = readPositiveFloat64(buf[1:]) + ret = -ret + return + } + return readPositiveFloat64(buf) +} + +//读取float32 +func readPositiveFloat32(buf []byte) (ret float32, n int, err error) { + i := 0 + // first char + if len(buf) == 0 { + return readFloat32SlowPath(buf) + } + c := buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat32SlowPath(buf) + case endOfNumber: + err = errors.New("readFloat32 empty number") + return + case dotInNumber: + err = errors.New("readFloat32 leading dot is invalid") + return + case 0: + if i == len(buf) { + return readFloat32SlowPath(buf) + } + c = buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + err = errors.New("readFloat32 leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat32SlowPath(buf) + case endOfNumber: + n = i + ret = float32(value) + return + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return readFloat32SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == len(buf) { + return readFloat32SlowPath(buf) + } + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + n = i + ret = float32(float64(value) / float64(pow10[decimalPlaces])) + return + } + // too many decimal places + return readFloat32SlowPath(buf) + case invalidCharForNumber, dotInNumber: + return readFloat32SlowPath(buf) + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return readFloat32SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return readFloat32SlowPath(buf) +} +func readFloat32SlowPath(buf []byte) (ret float32, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err != nil { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + err = errors.New(errMsg) + return + } + var val float64 + if val, err = strconv.ParseFloat(str, 32); err != nil { + return + } + ret = float32(val) + return +} + +//读取float64 +func readPositiveFloat64(buf []byte) (ret float64, n int, err error) { + i := 0 + // first char + if i == len(buf) { + return readFloat64SlowPath(buf) + } + c := buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat64SlowPath(buf) + case endOfNumber: + err = errors.New("readFloat64 empty number") + return + case dotInNumber: + err = errors.New("readFloat64 leading dot is invalid") + return + case 0: + if i == len(buf) { + return readFloat64SlowPath(buf) + } + c = buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + err = errors.New("readFloat64 leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat64SlowPath(buf) + case endOfNumber: + n = i + ret = float64(value) + return + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return readFloat64SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == len(buf) { + return readFloat64SlowPath(buf) + } + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + n = i + ret = float64(value) / float64(pow10[decimalPlaces]) + return + } + // too many decimal places + return readFloat64SlowPath(buf) + case invalidCharForNumber, dotInNumber: + return readFloat64SlowPath(buf) + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return readFloat64SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) + if value > maxFloat64 { + return readFloat64SlowPath(buf) + } + } + } + return readFloat64SlowPath(buf) +} + +func readFloat64SlowPath(buf []byte) (ret float64, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err != nil { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + err = fmt.Errorf("readFloat64SlowPath:%v", errMsg) + return + } + ret, err = strconv.ParseFloat(str, 64) + return +} + +//读取字符串数字 +func readNumberAsString(buf []byte) (ret string, n int, err error) { + strBuf := [16]byte{} + str := strBuf[0:0] +load_loop: + for i := 0; i < len(buf); i++ { + c := buf[i] + switch c { + case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + str = append(str, c) + continue + default: + n = i + break load_loop + } + } + if len(str) == 0 { + err = errors.New("readNumberAsString invalid number") + } + ret = *(*string)(unsafe.Pointer(&str)) + return +} + +//字符串float 错误检验 +func validateFloat(str string) string { + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} + +//Write Float To String------------------------------------------------------------------------------------------------------------------------------------------------------------- +func WriteFloat32ToString(buff *[]byte, val float32) (err error) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(float64(val)) + fmt := byte('f') + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + *buff = strconv.AppendFloat(*buff, float64(val), fmt, -1, 32) + return +} + +//float32 写入只有 6 位精度的流,但速度要快得多 +func WriteFloat32LossyToString(buf *[]byte, val float32) (err error) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + WriteChar(buf, '-') + val = -val + } + if val > 0x4ffffff { + WriteFloat32ToString(buf, val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val)*float64(exp) + 0.5) + WriteUint64ToString(buf, lval/exp) + fval := lval % exp + if fval == 0 { + return + } + WriteChar(buf, '.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + WriteChar(buf, '0') + } + WriteUint64ToString(buf, fval) + temp := *buf + for temp[len(temp)-1] == '0' { + temp = temp[:len(temp)-1] + } + buf = &temp + return +} + +func WriteFloat64ToString(buf *[]byte, val float64) (err error) { + if math.IsInf(val, 0) || math.IsNaN(val) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + *buf = strconv.AppendFloat(*buf, float64(val), fmt, -1, 64) + return +} + +//将 float64 写入只有 6 位精度的流,但速度要快得多 +func WriteFloat64LossyToString(buf *[]byte, val float64) (err error) { + if math.IsInf(val, 0) || math.IsNaN(val) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + WriteChar(buf, '-') + val = -val + } + if val > 0x4ffffff { + WriteFloat64ToString(buf, val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(val*float64(exp) + 0.5) + WriteUint64ToString(buf, lval/exp) + fval := lval % exp + if fval == 0 { + return + } + WriteChar(buf, '.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + WriteChar(buf, '0') + } + WriteUint64ToString(buf, fval) + temp := *buf + for temp[len(temp)-1] == '0' { + temp = temp[:len(temp)-1] + } + buf = &temp + return +} diff --git a/lego/sys/codec/utils/int.go b/lego/sys/codec/utils/int.go new file mode 100644 index 000000000..ba3c9b483 --- /dev/null +++ b/lego/sys/codec/utils/int.go @@ -0,0 +1,543 @@ +package utils + +import ( + "errors" + "math" + "strconv" +) + +var digits []uint32 +var intDigits []int8 + +const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 +const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 +const maxFloat64 = 1<<53 - 1 + +func init() { + digits = make([]uint32, 1000) + for i := uint32(0); i < 1000; i++ { + digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' + if i < 10 { + digits[i] += 2 << 24 + } else if i < 100 { + digits[i] += 1 << 24 + } + } + + intDigits = make([]int8, 256) + for i := 0; i < len(intDigits); i++ { + intDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + intDigits[i] = i - int8('0') + } +} + +//Read Int For String-------------------------------------------------------------------------------------------------------------------------------- +func ReadInt8ForString(buf []byte) (ret int8, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt8+1 { + err = errors.New("ReadInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int8(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt8 { + err = errors.New("ReadInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int8(val) + return +} + +func ReadInt16ForString(buf []byte) (ret int16, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt16+1 { + err = errors.New("ReadInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int16(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt16 { + err = errors.New("ReadInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int16(val) + return +} + +func ReadInt32ForString(buf []byte) (ret int32, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt32+1 { + err = errors.New("ReadInt32ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int32(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt32 { + err = errors.New("ReadInt32ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int32(val) + return +} + +func ReadInt64ForString(buf []byte) (ret int64, n int, err error) { + var ( + val uint64 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint64ForString(buf[1:]) + if val > math.MaxInt64+1 { + err = errors.New("ReadInt64ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int64(val) + return + } + val, n, err = ReadUint64ForString(buf) + if val > math.MaxInt64 { + err = errors.New("ReadInt64ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int64(val) + return +} + +func ReadUint8ForString(buf []byte) (ret uint8, n int, err error) { + var ( + val uint32 + ) + val, n, err = ReadUint32ForString(buf) + if val > math.MaxUint8 { + err = errors.New("ReadUInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = uint8(val) + return +} + +func ReadUint16ForString(buf []byte) (ret uint16, n int, err error) { + var ( + val uint32 + ) + val, n, err = ReadUint32ForString(buf) + if val > math.MaxUint16 { + err = errors.New("ReadUInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = uint16(val) + return +} + +func ReadUint32ForString(buf []byte) (ret uint32, n int, err error) { + ind := intDigits[buf[0]] + if ind == 0 { + err = assertInteger(buf[1:]) + return + } + if ind == invalidCharForNumber { + err = errors.New("ReadUint32ForString unexpected character: " + string([]byte{byte(ind)})) + return + } + ret = uint32(ind) + if len(buf) > 10 { + i := 0 + ind2 := intDigits[buf[i]] + if ind2 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + i++ + ind3 := intDigits[buf[i]] + if ind3 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10 + uint32(ind2) + return + } + i++ + ind4 := intDigits[buf[i]] + if ind4 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100 + uint32(ind2)*10 + uint32(ind3) + return + } + i++ + ind5 := intDigits[buf[i]] + if ind5 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) + return + } + i++ + ind6 := intDigits[buf[i]] + if ind6 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) + return + } + i++ + ind7 := intDigits[buf[i]] + if ind7 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) + return + } + i++ + ind8 := intDigits[buf[i]] + if ind8 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) + return + } + i++ + ind9 := intDigits[buf[i]] + ret = ret*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) + n = i + if ind9 == invalidCharForNumber { + err = assertInteger(buf[i:]) + return + } + } + for i := 1; i < len(buf); i++ { + ind = intDigits[buf[i]] + if ind == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + if ret > uint32SafeToMultiply10 { + value2 := (ret << 3) + (ret << 1) + uint32(ind) + if value2 < ret { + err = errors.New("ReadUint32ForString overflow") + return + } + ret = value2 + continue + } + ret = (ret << 3) + (ret << 1) + uint32(ind) + } + return +} + +func ReadUint64ForString(buf []byte) (ret uint64, n int, err error) { + ind := intDigits[buf[0]] + if ind == 0 { + err = assertInteger(buf[1:]) + return + } + if ind == invalidCharForNumber { + err = errors.New("ReadUint64ForString unexpected character: " + string([]byte{byte(ind)})) + return + } + ret = uint64(ind) + if len(buf) > 10 { + i := 0 + ind2 := intDigits[buf[i]] + if ind2 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + i++ + ind3 := intDigits[buf[i]] + if ind3 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10 + uint64(ind2) + return + } + i++ + ind4 := intDigits[buf[i]] + if ind4 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100 + uint64(ind2)*10 + uint64(ind3) + return + } + i++ + ind5 := intDigits[buf[i]] + if ind5 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) + return + } + i++ + ind6 := intDigits[buf[i]] + if ind6 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) + return + } + i++ + ind7 := intDigits[buf[i]] + if ind7 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) + return + } + i++ + ind8 := intDigits[buf[i]] + if ind8 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) + return + } + i++ + ind9 := intDigits[buf[i]] + ret = ret*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) + n = i + if ind9 == invalidCharForNumber { + err = assertInteger(buf[i:]) + return + } + } + for i := 1; i < len(buf); i++ { + ind = intDigits[buf[i]] + if ind == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + if ret > uint64SafeToMultiple10 { + value2 := (ret << 3) + (ret << 1) + uint64(ind) + if value2 < ret { + err = errors.New("ReadUint64ForString overflow") + return + } + ret = value2 + continue + } + ret = (ret << 3) + (ret << 1) + uint64(ind) + } + return +} + +func assertInteger(buf []byte) (err error) { + if len(buf) > 0 && buf[0] == '.' { + err = errors.New("assertInteger can not decode float as int") + } + return +} + +//Write Int To String-------------------------------------------------------------------------------------------------------------------------------- +func WriteChar(buff *[]byte, c byte) { + *buff = append(*buff, c) +} + +// WriteUint8 write uint8 to stream +func WriteUint8ToString(buf *[]byte, val uint8) { + *buf = writeFirstBuf(*buf, digits[val]) + return +} + +// WriteInt8 write int8 to stream +func WriteInt8ToString(buf *[]byte, nval int8) { + var val uint8 + if nval < 0 { + val = uint8(-nval) + *buf = append(*buf, '-') + } else { + val = uint8(nval) + } + *buf = writeFirstBuf(*buf, digits[val]) + return +} + +// WriteUint16 write uint16 to stream +func WriteUint16ToString(buf *[]byte, val uint16) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt16 write int16 to stream +func WriteInt16ToString(buf *[]byte, nval int16) { + var val uint16 + if nval < 0 { + val = uint16(-nval) + *buf = append(*buf, '-') + } else { + val = uint16(nval) + } + WriteUint16ToString(buf, val) + return +} + +// WriteUint32 write uint32 to stream +func WriteUint32ToString(buf *[]byte, val uint32) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + *buf = writeFirstBuf(*buf, digits[q2]) + } else { + r3 := q2 - q3*1000 + *buf = append(*buf, byte(q3+'0')) + *buf = writeBuf(*buf, digits[r3]) + } + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt32 write int32 to stream +func WriteInt32ToString(buf *[]byte, nval int32) { + var val uint32 + if nval < 0 { + val = uint32(-nval) + *buf = append(*buf, '-') + } else { + val = uint32(nval) + } + WriteUint32ToString(buf, val) + return +} + +// WriteUint64 write uint64 to stream +func WriteUint64ToString(buf *[]byte, val uint64) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + *buf = writeFirstBuf(*buf, digits[q2]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + *buf = writeFirstBuf(*buf, digits[q3]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + *buf = writeFirstBuf(*buf, digits[q4]) + *buf = writeBuf(*buf, digits[r4]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + *buf = writeFirstBuf(*buf, digits[q5]) + } else { + *buf = writeFirstBuf(*buf, digits[q6]) + r6 := q5 - q6*1000 + *buf = writeBuf(*buf, digits[r6]) + } + *buf = writeBuf(*buf, digits[r5]) + *buf = writeBuf(*buf, digits[r4]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt64 write int64 to stream +func WriteInt64ToString(buf *[]byte, nval int64) { + var val uint64 + if nval < 0 { + val = uint64(-nval) + *buf = append(*buf, '-') + } else { + val = uint64(nval) + } + WriteUint64ToString(buf, val) + return +} + +// WriteInt write int to stream +func WriteIntToString(buf *[]byte, val int) { + WriteInt64ToString(buf, int64(val)) + return +} + +// WriteUint write uint to stream +func WriteUint(buf *[]byte, val uint) { + WriteUint64ToString(buf, uint64(val)) + return +} + +func writeFirstBuf(space []byte, v uint32) []byte { + start := v >> 24 + if start == 0 { + space = append(space, byte(v>>16), byte(v>>8)) + } else if start == 1 { + space = append(space, byte(v>>8)) + } + space = append(space, byte(v)) + return space +} + +func writeBuf(buf []byte, v uint32) []byte { + return append(buf, byte(v>>16), byte(v>>8), byte(v)) +} diff --git a/lego/sys/codec/utils/string.go b/lego/sys/codec/utils/string.go new file mode 100644 index 000000000..fb92add1b --- /dev/null +++ b/lego/sys/codec/utils/string.go @@ -0,0 +1,349 @@ +package utils + +import "unicode/utf8" + +var htmlSafeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': false, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': false, + '=': true, + '>': false, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var safeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': true, + '=': true, + '>': true, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var hex = "0123456789abcdef" + +func WriteStringSlowPathWithHTMLEscaped(buf *[]byte, i int, s string, valLen int) { + start := i + // for the remaining parts, we process them char by char + for i < valLen { + if b := s[i]; b < utf8.RuneSelf { + if htmlSafeSet[b] { + i++ + continue + } + if start < i { + *buf = append(*buf, s[start:i]...) + } + switch b { + case '\\', '"': + *buf = append(*buf, '\\', b) + case '\n': + *buf = append(*buf, '\\', 'n') + case '\r': + *buf = append(*buf, '\\', 'r') + case '\t': + *buf = append(*buf, '\\', 't') + default: + *buf = append(*buf, `\u00`...) + *buf = append(*buf, hex[b>>4], hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + *buf = append(*buf, s[start:i]...) + } + *buf = append(*buf, `\ufffd`...) + i++ + start = i + continue + } + + if c == '\u2028' || c == '\u2029' { + if start < i { + *buf = append(*buf, s[start:i]...) + } + *buf = append(*buf, `\u202`...) + *buf = append(*buf, hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(s) { + *buf = append(*buf, s[start:]...) + } + *buf = append(*buf, '"') +} + +func WriteStringSlowPath(buf *[]byte, i int, s string, valLen int) { + start := i + for i < valLen { + if b := s[i]; b < utf8.RuneSelf { + if safeSet[b] { + i++ + continue + } + if start < i { + *buf = append(*buf, s[start:i]...) + } + switch b { + case '\\', '"': + *buf = append(*buf, '\\', b) + case '\n': + *buf = append(*buf, '\\', 'n') + case '\r': + *buf = append(*buf, '\\', 'r') + case '\t': + *buf = append(*buf, '\\', 't') + default: + *buf = append(*buf, `\u00`...) + *buf = append(*buf, hex[b>>4], hex[b&0xF]) + } + i++ + start = i + continue + } + i++ + continue + } + if start < len(s) { + *buf = append(*buf, s[start:]...) + } + *buf = append(*buf, '"') +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + + surrogateMin = 0xD800 + surrogateMax = 0xDFFF + + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. + runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" +) + +func AppendRune(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p = append(p, byte(r)) + return p + case i <= rune2Max: + p = append(p, t2|byte(r>>6)) + p = append(p, tx|byte(r)&maskx) + return p + case i > maxRune, surrogateMin <= i && i <= surrogateMax: + r = runeError + fallthrough + case i <= rune3Max: + p = append(p, t3|byte(r>>12)) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + default: + p = append(p, t4|byte(r>>18)) + p = append(p, tx|byte(r>>12)&maskx) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + } +}