podman

Форк
0
312 строк · 7.8 Кб
1
// Copyright 2015 go-swagger maintainers
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package swag
16

17
import (
18
	"bytes"
19
	"encoding/json"
20
	"log"
21
	"reflect"
22
	"strings"
23
	"sync"
24

25
	"github.com/mailru/easyjson/jlexer"
26
	"github.com/mailru/easyjson/jwriter"
27
)
28

29
// nullJSON represents a JSON object with null type
30
var nullJSON = []byte("null")
31

32
// DefaultJSONNameProvider the default cache for types
33
var DefaultJSONNameProvider = NewNameProvider()
34

35
const comma = byte(',')
36

37
var closers map[byte]byte
38

39
func init() {
40
	closers = map[byte]byte{
41
		'{': '}',
42
		'[': ']',
43
	}
44
}
45

46
type ejMarshaler interface {
47
	MarshalEasyJSON(w *jwriter.Writer)
48
}
49

50
type ejUnmarshaler interface {
51
	UnmarshalEasyJSON(w *jlexer.Lexer)
52
}
53

54
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
55
// so it takes the fastest option available.
56
func WriteJSON(data interface{}) ([]byte, error) {
57
	if d, ok := data.(ejMarshaler); ok {
58
		jw := new(jwriter.Writer)
59
		d.MarshalEasyJSON(jw)
60
		return jw.BuildBytes()
61
	}
62
	if d, ok := data.(json.Marshaler); ok {
63
		return d.MarshalJSON()
64
	}
65
	return json.Marshal(data)
66
}
67

68
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
69
// so it takes the fastest option available
70
func ReadJSON(data []byte, value interface{}) error {
71
	trimmedData := bytes.Trim(data, "\x00")
72
	if d, ok := value.(ejUnmarshaler); ok {
73
		jl := &jlexer.Lexer{Data: trimmedData}
74
		d.UnmarshalEasyJSON(jl)
75
		return jl.Error()
76
	}
77
	if d, ok := value.(json.Unmarshaler); ok {
78
		return d.UnmarshalJSON(trimmedData)
79
	}
80
	return json.Unmarshal(trimmedData, value)
81
}
82

83
// DynamicJSONToStruct converts an untyped json structure into a struct
84
func DynamicJSONToStruct(data interface{}, target interface{}) error {
85
	// TODO: convert straight to a json typed map  (mergo + iterate?)
86
	b, err := WriteJSON(data)
87
	if err != nil {
88
		return err
89
	}
90
	return ReadJSON(b, target)
91
}
92

93
// ConcatJSON concatenates multiple json objects efficiently
94
func ConcatJSON(blobs ...[]byte) []byte {
95
	if len(blobs) == 0 {
96
		return nil
97
	}
98

99
	last := len(blobs) - 1
100
	for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
101
		// strips trailing null objects
102
		last--
103
		if last < 0 {
104
			// there was nothing but "null"s or nil...
105
			return nil
106
		}
107
	}
108
	if last == 0 {
109
		return blobs[0]
110
	}
111

112
	var opening, closing byte
113
	var idx, a int
114
	buf := bytes.NewBuffer(nil)
115

116
	for i, b := range blobs[:last+1] {
117
		if b == nil || bytes.Equal(b, nullJSON) {
118
			// a null object is in the list: skip it
119
			continue
120
		}
121
		if len(b) > 0 && opening == 0 { // is this an array or an object?
122
			opening, closing = b[0], closers[b[0]]
123
		}
124

125
		if opening != '{' && opening != '[' {
126
			continue // don't know how to concatenate non container objects
127
		}
128

129
		if len(b) < 3 { // yep empty but also the last one, so closing this thing
130
			if i == last && a > 0 {
131
				if err := buf.WriteByte(closing); err != nil {
132
					log.Println(err)
133
				}
134
			}
135
			continue
136
		}
137

138
		idx = 0
139
		if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
140
			if err := buf.WriteByte(comma); err != nil {
141
				log.Println(err)
142
			}
143
			idx = 1 // this is not the first or the last so we want to drop the leading bracket
144
		}
145

146
		if i != last { // not the last one, strip brackets
147
			if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
148
				log.Println(err)
149
			}
150
		} else { // last one, strip only the leading bracket
151
			if _, err := buf.Write(b[idx:]); err != nil {
152
				log.Println(err)
153
			}
154
		}
155
		a++
156
	}
157
	// somehow it ended up being empty, so provide a default value
158
	if buf.Len() == 0 {
159
		if err := buf.WriteByte(opening); err != nil {
160
			log.Println(err)
161
		}
162
		if err := buf.WriteByte(closing); err != nil {
163
			log.Println(err)
164
		}
165
	}
166
	return buf.Bytes()
167
}
168

169
// ToDynamicJSON turns an object into a properly JSON typed structure
170
func ToDynamicJSON(data interface{}) interface{} {
171
	// TODO: convert straight to a json typed map (mergo + iterate?)
172
	b, err := json.Marshal(data)
173
	if err != nil {
174
		log.Println(err)
175
	}
176
	var res interface{}
177
	if err := json.Unmarshal(b, &res); err != nil {
178
		log.Println(err)
179
	}
180
	return res
181
}
182

183
// FromDynamicJSON turns an object into a properly JSON typed structure
184
func FromDynamicJSON(data, target interface{}) error {
185
	b, err := json.Marshal(data)
186
	if err != nil {
187
		log.Println(err)
188
	}
189
	return json.Unmarshal(b, target)
190
}
191

192
// NameProvider represents an object capable of translating from go property names
193
// to json property names
194
// This type is thread-safe.
195
type NameProvider struct {
196
	lock  *sync.Mutex
197
	index map[reflect.Type]nameIndex
198
}
199

200
type nameIndex struct {
201
	jsonNames map[string]string
202
	goNames   map[string]string
203
}
204

205
// NewNameProvider creates a new name provider
206
func NewNameProvider() *NameProvider {
207
	return &NameProvider{
208
		lock:  &sync.Mutex{},
209
		index: make(map[reflect.Type]nameIndex),
210
	}
211
}
212

213
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
214
	for i := 0; i < tpe.NumField(); i++ {
215
		targetDes := tpe.Field(i)
216

217
		if targetDes.PkgPath != "" { // unexported
218
			continue
219
		}
220

221
		if targetDes.Anonymous { // walk embedded structures tree down first
222
			buildnameIndex(targetDes.Type, idx, reverseIdx)
223
			continue
224
		}
225

226
		if tag := targetDes.Tag.Get("json"); tag != "" {
227

228
			parts := strings.Split(tag, ",")
229
			if len(parts) == 0 {
230
				continue
231
			}
232

233
			nm := parts[0]
234
			if nm == "-" {
235
				continue
236
			}
237
			if nm == "" { // empty string means we want to use the Go name
238
				nm = targetDes.Name
239
			}
240

241
			idx[nm] = targetDes.Name
242
			reverseIdx[targetDes.Name] = nm
243
		}
244
	}
245
}
246

247
func newNameIndex(tpe reflect.Type) nameIndex {
248
	var idx = make(map[string]string, tpe.NumField())
249
	var reverseIdx = make(map[string]string, tpe.NumField())
250

251
	buildnameIndex(tpe, idx, reverseIdx)
252
	return nameIndex{jsonNames: idx, goNames: reverseIdx}
253
}
254

255
// GetJSONNames gets all the json property names for a type
256
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
257
	n.lock.Lock()
258
	defer n.lock.Unlock()
259
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
260
	names, ok := n.index[tpe]
261
	if !ok {
262
		names = n.makeNameIndex(tpe)
263
	}
264

265
	res := make([]string, 0, len(names.jsonNames))
266
	for k := range names.jsonNames {
267
		res = append(res, k)
268
	}
269
	return res
270
}
271

272
// GetJSONName gets the json name for a go property name
273
func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
274
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
275
	return n.GetJSONNameForType(tpe, name)
276
}
277

278
// GetJSONNameForType gets the json name for a go property name on a given type
279
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
280
	n.lock.Lock()
281
	defer n.lock.Unlock()
282
	names, ok := n.index[tpe]
283
	if !ok {
284
		names = n.makeNameIndex(tpe)
285
	}
286
	nme, ok := names.goNames[name]
287
	return nme, ok
288
}
289

290
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
291
	names := newNameIndex(tpe)
292
	n.index[tpe] = names
293
	return names
294
}
295

296
// GetGoName gets the go name for a json property name
297
func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
298
	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
299
	return n.GetGoNameForType(tpe, name)
300
}
301

302
// GetGoNameForType gets the go name for a given type for a json property name
303
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
304
	n.lock.Lock()
305
	defer n.lock.Unlock()
306
	names, ok := n.index[tpe]
307
	if !ok {
308
		names = n.makeNameIndex(tpe)
309
	}
310
	nme, ok := names.jsonNames[name]
311
	return nme, ok
312
}
313

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.