File: interface.go

package info (click to toggle)
golang-github-facebook-ent 0.5.4-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 14,284 kB
  • sloc: javascript: 349; makefile: 8
file content (153 lines) | stat: -rw-r--r-- 3,786 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.

package graphson

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
	"github.com/modern-go/reflect2"
	"github.com/pkg/errors"
)

// DecoratorOfInterface decorates a value decoder of an interface type.
func (decodeExtension) DecoratorOfInterface(typ reflect2.Type, dec jsoniter.ValDecoder) jsoniter.ValDecoder {
	if _, ok := typ.(*reflect2.UnsafeEFaceType); ok {
		return efaceDecoder{typ, dec}
	}
	return dec
}

type efaceDecoder struct {
	typ reflect2.Type
	jsoniter.ValDecoder
}

func (dec efaceDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
	switch next := iter.WhatIsNext(); next {
	case jsoniter.StringValue, jsoniter.BoolValue, jsoniter.NilValue:
		dec.ValDecoder.Decode(ptr, iter)
	case jsoniter.ObjectValue:
		dec.decode(ptr, iter)
	default:
		iter.ReportError("decode empty interface", fmt.Sprintf("unexpected value type: %d", next))
	}
}

func (dec efaceDecoder) decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
	data := iter.SkipAndReturnBytes()
	if iter.Error != nil && iter.Error != io.EOF {
		return
	}

	rtype, err := dec.reflectBytes(data)
	if err != nil {
		iter.ReportError("decode empty interface", err.Error())
		return
	}

	it := config.BorrowIterator(data)
	defer config.ReturnIterator(it)

	var val interface{}
	if rtype != nil {
		val = rtype.New()
		it.ReadVal(val)
		val = rtype.Indirect(val)
	} else {
		if jsoniter.Get(data, TypeKey).LastError() == nil {
			vk := jsoniter.Get(data, ValueKey)
			if vk.LastError() == nil {
				val = vk.GetInterface()
			}
		}
		if val == nil {
			val = it.Read()
		}
	}

	if it.Error != nil && it.Error != io.EOF {
		iter.ReportError("decode empty interface", it.Error.Error())
		return
	}

	// nolint: gas
	dec.typ.UnsafeSet(ptr, unsafe.Pointer(&val))
}

func (dec efaceDecoder) reflectBytes(data []byte) (reflect2.Type, error) {
	typ := Type(jsoniter.Get(data, TypeKey).ToString())
	rtype := dec.reflectType(typ)
	if rtype != nil {
		return rtype, nil
	}

	switch typ {
	case listType:
		return dec.reflectSlice(data)
	case mapType:
		return dec.reflectMap(data)
	default:
		return nil, nil
	}
}

func (efaceDecoder) reflectType(typ Type) reflect2.Type {
	switch typ {
	case doubleType:
		return reflect2.TypeOf(float64(0))
	case floatType:
		return reflect2.TypeOf(float32(0))
	case byteType:
		return reflect2.TypeOf(uint8(0))
	case int16Type:
		return reflect2.TypeOf(int16(0))
	case int32Type:
		return reflect2.TypeOf(int32(0))
	case int64Type, bigIntegerType:
		return reflect2.TypeOf(int64(0))
	case byteBufferType:
		return reflect2.TypeOf([]byte{})
	default:
		return nil
	}
}

func (efaceDecoder) reflectSlice(data []byte) (reflect2.Type, error) {
	var elem interface{}
	if err := Unmarshal(data, &[...]*interface{}{&elem}); err != nil {
		return nil, errors.Wrap(err, "cannot read first list element")
	}

	if elem == nil {
		return reflect2.TypeOf([]interface{}{}), nil
	}

	sliceType := reflect.SliceOf(reflect.TypeOf(elem))
	return reflect2.Type2(sliceType), nil
}

func (efaceDecoder) reflectMap(data []byte) (reflect2.Type, error) {
	var key, elem interface{}
	if err := Unmarshal(
		bytes.Replace(data, []byte(mapType), []byte(listType), 1),
		&[...]*interface{}{&key, &elem},
	); err != nil {
		return nil, errors.Wrap(err, "cannot unmarshal first map item")
	}

	if key == nil {
		return reflect2.TypeOf(map[interface{}]interface{}{}), nil
	} else if elem == nil {
		return nil, errors.New("expect map element, but found only key")
	}

	mapType := reflect.MapOf(reflect.TypeOf(key), reflect.TypeOf(elem))
	return reflect2.Type2(mapType), nil
}