123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- package json
- import (
- "bytes"
- "encoding/base64"
- "math/big"
- "strconv"
- "github.com/aws/smithy-go/encoding"
- )
- // Value represents a JSON Value type
- // JSON Value types: Object, Array, String, Number, Boolean, and Null
- type Value struct {
- w *bytes.Buffer
- scratch *[]byte
- }
- // newValue returns a new Value encoder
- func newValue(w *bytes.Buffer, scratch *[]byte) Value {
- return Value{w: w, scratch: scratch}
- }
- // String encodes v as a JSON string
- func (jv Value) String(v string) {
- escapeStringBytes(jv.w, []byte(v))
- }
- // Byte encodes v as a JSON number
- func (jv Value) Byte(v int8) {
- jv.Long(int64(v))
- }
- // Short encodes v as a JSON number
- func (jv Value) Short(v int16) {
- jv.Long(int64(v))
- }
- // Integer encodes v as a JSON number
- func (jv Value) Integer(v int32) {
- jv.Long(int64(v))
- }
- // Long encodes v as a JSON number
- func (jv Value) Long(v int64) {
- *jv.scratch = strconv.AppendInt((*jv.scratch)[:0], v, 10)
- jv.w.Write(*jv.scratch)
- }
- // ULong encodes v as a JSON number
- func (jv Value) ULong(v uint64) {
- *jv.scratch = strconv.AppendUint((*jv.scratch)[:0], v, 10)
- jv.w.Write(*jv.scratch)
- }
- // Float encodes v as a JSON number
- func (jv Value) Float(v float32) {
- jv.float(float64(v), 32)
- }
- // Double encodes v as a JSON number
- func (jv Value) Double(v float64) {
- jv.float(v, 64)
- }
- func (jv Value) float(v float64, bits int) {
- *jv.scratch = encoding.EncodeFloat((*jv.scratch)[:0], v, bits)
- jv.w.Write(*jv.scratch)
- }
- // Boolean encodes v as a JSON boolean
- func (jv Value) Boolean(v bool) {
- *jv.scratch = strconv.AppendBool((*jv.scratch)[:0], v)
- jv.w.Write(*jv.scratch)
- }
- // Base64EncodeBytes writes v as a base64 value in JSON string
- func (jv Value) Base64EncodeBytes(v []byte) {
- encodeByteSlice(jv.w, (*jv.scratch)[:0], v)
- }
- // Write writes v directly to the JSON document
- func (jv Value) Write(v []byte) {
- jv.w.Write(v)
- }
- // Array returns a new Array encoder
- func (jv Value) Array() *Array {
- return newArray(jv.w, jv.scratch)
- }
- // Object returns a new Object encoder
- func (jv Value) Object() *Object {
- return newObject(jv.w, jv.scratch)
- }
- // Null encodes a null JSON value
- func (jv Value) Null() {
- jv.w.WriteString(null)
- }
- // BigInteger encodes v as JSON value
- func (jv Value) BigInteger(v *big.Int) {
- jv.w.Write([]byte(v.Text(10)))
- }
- // BigDecimal encodes v as JSON value
- func (jv Value) BigDecimal(v *big.Float) {
- if i, accuracy := v.Int64(); accuracy == big.Exact {
- jv.Long(i)
- return
- }
- // TODO: Should this try to match ES6 ToString similar to stdlib JSON?
- jv.w.Write([]byte(v.Text('e', -1)))
- }
- // Based on encoding/json encodeByteSlice from the Go Standard Library
- // https://golang.org/src/encoding/json/encode.go
- func encodeByteSlice(w *bytes.Buffer, scratch []byte, v []byte) {
- if v == nil {
- w.WriteString(null)
- return
- }
- w.WriteRune(quote)
- encodedLen := base64.StdEncoding.EncodedLen(len(v))
- if encodedLen <= len(scratch) {
- // If the encoded bytes fit in e.scratch, avoid an extra
- // allocation and use the cheaper Encoding.Encode.
- dst := scratch[:encodedLen]
- base64.StdEncoding.Encode(dst, v)
- w.Write(dst)
- } else if encodedLen <= 1024 {
- // The encoded bytes are short enough to allocate for, and
- // Encoding.Encode is still cheaper.
- dst := make([]byte, encodedLen)
- base64.StdEncoding.Encode(dst, v)
- w.Write(dst)
- } else {
- // The encoded bytes are too long to cheaply allocate, and
- // Encoding.Encode is no longer noticeably cheaper.
- enc := base64.NewEncoder(base64.StdEncoding, w)
- enc.Write(v)
- enc.Close()
- }
- w.WriteRune(quote)
- }
|