Exemple #1
0
/**
 *  private marshal
 */
func marshal(v reflect.Value, nullTag, boolTag string, buf *bytes.Buffer) error {
	var err error

	switch v.Kind() {
	case reflect.Bool:
		boolTrue := "true"
		boolFalse := "false"
		if "" != boolTag {
			bs := strings.Split(boolTag, "|")
			if 2 == len(bs) {
				boolTrue = bs[0]
				boolFalse = bs[1]
			}
		}
		bv := v.Bool()
		if bv {
			buf.WriteString(boolTrue)
		} else {
			buf.WriteString(boolFalse)
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b := strconv.AppendInt(scratch[:0], v.Int(), 10)
		buf.Write(b)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		b := strconv.AppendUint(scratch[:0], v.Uint(), 10)
		buf.Write(b)
	case reflect.Float32, reflect.Float64:
		f := v.Float()
		if math.IsInf(f, 0) || math.IsNaN(f) {
			err = errors.New(strconv.FormatFloat(f, 'g', -1, v.Type().Bits()))
		}
		b := strconv.AppendFloat(scratch[:0], f, 'g', -1, v.Type().Bits())
		buf.Write(b)
	case reflect.String:
		if 0 == v.Len() {
			buf.WriteString("\"\"")
		} else {
			buf.WriteByte('"')
			_, err = escapeString(buf, v.String())
			buf.WriteByte('"')
		}

	case reflect.Struct:
		vt := v.Type()
		numTField := vt.NumField()

		if 0 == numTField {
			if "" != nullTag && 0 < buf.Len() {
				buf.WriteString(nullTag)
			}
			break
		}

		if vt.Implements(textMarshalerType) {
			imt := v.Interface().(encoding.TextMarshaler)
			mt, e := imt.MarshalText()
			if nil != e {
				err = e
			} else {
				buf.WriteByte('"')
				buf.Write(mt)
				buf.WriteByte('"')
			}
			break
		}

		buf.WriteByte('{')
		first := true

		for i := 0; i < numTField; i++ {
			childFieldT := vt.Field(i)
			childFieldV := v.Field(i)

			if "" == nullTag && SFReflectUtil.IsNullValue(childFieldV) {
				continue
			}

			keyName := childFieldT.Tag.Get("json")
			if 0 == len(keyName) {
				keyName = childFieldT.Name
			} else if "-" == keyName {
				continue
			}

			if first {
				first = false
			} else {
				buf.WriteByte(',')
			}

			buf.WriteString("\"" + keyName + "\"")
			buf.WriteByte(':')
			marshal(childFieldV, nullTag, boolTag, buf)
		}

		buf.WriteByte('}')
	case reflect.Map:
		if v.Type().Key().Kind() != reflect.String {
			err = errors.New("json: unsupported type: " + v.Type().String())
			break
		}
		if 0 == v.Len() {
			if "" != nullTag && 0 < buf.Len() {
				buf.WriteString(nullTag)
			}
			break
		}

		buf.WriteByte('{')
		first := true
		for _, k := range v.MapKeys() {
			kv := v.MapIndex(k)

			if "" == nullTag && SFReflectUtil.IsNullValue(kv) {
				continue
			}

			if first {
				first = false
			} else {
				buf.WriteByte(',')
			}
			buf.WriteString("\"" + k.String() + "\"")
			buf.WriteByte(':')
			marshal(kv, nullTag, boolTag, buf)
		}
		buf.WriteByte('}')

	case reflect.Array, reflect.Slice:
		if 0 == v.Len() {
			if "" != nullTag && 0 < buf.Len() {
				buf.WriteString(nullTag)
			}
			break
		}
		if v.Type().Elem().Kind() == reflect.Uint8 {

			s := v.Bytes()
			buf.WriteByte('"')
			if len(s) < 1024 {
				// for small buffers, using Encode directly is much faster.
				dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
				base64.StdEncoding.Encode(dst, s)
				buf.Write(dst)
			} else {
				// for large buffers, avoid unnecessary extra temporary
				// buffer space.
				enc := base64.NewEncoder(base64.StdEncoding, buf)
				enc.Write(s)
				enc.Close()
			}
			buf.WriteByte('"')

		} else {
			buf.WriteByte('[')
			first := true
			count := v.Len()
			for i := 0; i < count; i++ {
				v2 := v.Index(i)
				if "" == nullTag && SFReflectUtil.IsNullValue(v2) {
					continue
				}
				if first {
					first = false
				} else {
					buf.WriteByte(',')
				}
				marshal(v2, nullTag, boolTag, buf)
			}
			buf.WriteByte(']')
		}
	case reflect.Interface, reflect.Ptr:
		if v.IsNil() {
			if "" != nullTag {
				buf.WriteString(nullTag)
			}
			break
		}
		marshal(v.Elem(), nullTag, boolTag, buf)
	default:
	}

	return err
}