// ------------------------------------------------------------------------ // Project atila // Active Thing (activething.com) git.activething.com/go // // File name value_packer.go // Created by DEV // Modified 29/01/2024 // // Copyright 2024 activething.com // ------------------------------------------------------------------------ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ------------------------------------------------------------------------ package js import ( "activething.com/go/gogo/packs" "encoding/base32" "encoding/base64" "io" "math" "reflect" "strconv" "time" "unicode/utf8" ) func pack (state *packs.State, value any , flags Flags) { if state.Error != nil { panic(state.Error) } if value == nil { if flags.Quote() { state.WriteByte('"') } _,_ = state.Write(G.nullValue) if flags.Quote() { state.WriteByte('"') } return } switch v := value.(type) { case bool : packBool (state,v,flags) case string : packString(state,v,flags) case uint : packUInt(state,uint64(v),flags) case uint8 : packUInt(state,uint64(v),flags) case uint16 : packUInt(state,uint64(v),flags) case uint32 : packUInt(state,uint64(v),flags) case uint64 : packUInt(state,v,flags) case int : packInt(state,int64(v),flags) case int8 : packInt(state,int64(v),flags) case int16 : packInt(state,int64(v),flags) case int32 : packInt(state,int64(v),flags) case int64 : packInt(state,v,flags) case float32: packFloat(state,float64(v),flags) case float64: packFloat(state,v,flags) case time.Time : PackDate(state,v,flags) case reflect.Value : RPacker(state,v.Elem(),0) default: /* if pb,is := value.(packs.Builder); is { e := pb.Build(pb) if e != nil { state.SetError(e) return } _, _ = state.Write(d) return } if ms,is := value.(json.Marshaler); is { d,e := ms.MarshalJSON() if state.SetError(e) { return } _,_ = state.Write(d) return } rv := reflect.ValueOf(value) switch rv.Kind() { case reflect.Slice, reflect.Array: packListReflected(rv) case reflect.Map: packMapReflected(rv) case reflect.Struct: packObjectReflected(rv) default: d,e := options.encoder.Encode(value) if e != nil { state.SetError(e) return } state.Write(d) } */ } } func packString (state *packs.State, value string , flags Flags) { if state.Error != nil { panic(state.Error) } if len(value) == 0 { state.Write2Byte('"','"') return } state.WriteByte('"') start := 0 for i := 0; i < len(value); { if b := value[i]; b < utf8.RuneSelf { if !G.jsonChars[b].isHtmlUnsafe() || (!flags.EscapeHTML() && !G.jsonChars[b].isUnsafe()) { i++ continue } if start < i { state.WriteString(value[start:i]) } state.WriteByte('\\') switch b { case '\\', '"': state.WriteByte(b) case '\n': state.WriteByte('n') case '\r': state.WriteByte('r') case '\t': state.WriteByte('t') default: state.WriteString(`u00`) state.Write2Byte(G.hex[b>>4], G.hex[b&0xF]) } i++ start = i continue } c, size := utf8.DecodeRuneInString(value[i:]) if c == utf8.RuneError && size == 1 { if start < i { state.WriteString(value[start:i]) } state.WriteString(`\ufffd`) i += size start = i continue } if c == '\u2028' || c == '\u2029' { if start < i { state.WriteString(value[start:i]) } state.WriteString(`\u202`) state.WriteByte(G.hex[c&0xF]) i += size start = i continue } i += size } if start < len(value) { state.WriteString(value[start:]) } state.WriteByte('"') } func packBinary (state *packs.State, value []byte , f Flags) { if state.Error != nil { panic(state.Error) } if value == nil { _,_ = state.Write(G.nullValue) return } if len(value) == 0 { state.Write2Byte('"','"') return } state.WriteByte('"') var ec binEncoder = base64.StdEncoding if f.Bin32() { ec = base32.StdEncoding } ln := ec.EncodedLen(len(value)) if ln <= len(state.Temp) { dst := state.Temp[:ln] ec.Encode(dst, value) _,_= state.Write(dst) } else if ln <= 1024 { dst := make([]byte, ln) ec.Encode(dst, value) _,_ = state.Write(dst) } else { var wc io.WriteCloser if f.Bin32() { wc = base32.NewEncoder(base32.StdEncoding, state) } else if f.Bin64() { wc = base64.NewEncoder(base64.StdEncoding, state) } else { state.SetError(packs.G.ErrUnsupportedType) return } _,_ = wc.Write(value) state.SetError(wc.Close()) return } state.WriteByte('"') } func packBool (state *packs.State, value bool , flags Flags) { if state.Error != nil { panic(state.Error) } if flags.Quote() { state.WriteByte('"') } if value { state.W(G.trueValue) } else { state.W(G.falseValue) } if flags.Quote() { state.WriteByte('"') } } func packInt (state *packs.State, value int64 , flags Flags) { if state.Error != nil { panic(state.Error) } if flags.Quote() { state.WriteByte('"') } if value == 0 { state.WriteByte('0') } else { state.WriteIntStr(value, 10) } if flags.Quote() { state.WriteByte('"') } } func packUInt (state *packs.State, value uint64 , flags Flags) { if state.Error != nil { panic(state.Error) } if flags.Quote() { state.WriteByte('"') } if value == 0 { state.WriteByte('0') } else { state.WriteUIntStr(value, 10) } if flags.Quote() { state.WriteByte('"') } } func packFloat (state *packs.State, value float64, flags Flags) { packFloatString(state, value,64, flags.Quote()) } func packFloatString (state *packs.State, f float64, bits int, quote bool) { if state.Error != nil { panic(state.Error) } if math.IsInf(f, 0) || math.IsNaN(f) { state.SetError(packs.G.ErrInvalidValue) return } abs := math.Abs(f) fmt := byte('f') if abs != 0 { if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { fmt = 'e' } } bf := state.Temp[:0] bf = strconv.AppendFloat(bf, f, fmt, -1, int(bits)) if fmt == 'e' { // clean up e-09 to e-9 n := len(bf) if n >= 4 && bf[n-4] == 'e' && bf[n-3] == '-' && bf[n-2] == '0' { bf[n-2] = bf[n-1] bf = bf[:n-1] } } if quote { state.WriteByte('"') } state.W(bf) if quote { state.WriteByte('"') } } func PackDate (state *packs.State, value time.Time, flags Flags) { if state.Error != nil { panic(state.Error) } state.WriteByte('"') bf := state.Temp[:0] bf = value.AppendFormat(bf,flags.DateFormat()) state.W(bf) state.WriteByte('"') }