podman
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
15package swag
16
17import (
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
30var nullJSON = []byte("null")
31
32// DefaultJSONNameProvider the default cache for types
33var DefaultJSONNameProvider = NewNameProvider()
34
35const comma = byte(',')
36
37var closers map[byte]byte
38
39func init() {
40closers = map[byte]byte{
41'{': '}',
42'[': ']',
43}
44}
45
46type ejMarshaler interface {
47MarshalEasyJSON(w *jwriter.Writer)
48}
49
50type ejUnmarshaler interface {
51UnmarshalEasyJSON(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.
56func WriteJSON(data interface{}) ([]byte, error) {
57if d, ok := data.(ejMarshaler); ok {
58jw := new(jwriter.Writer)
59d.MarshalEasyJSON(jw)
60return jw.BuildBytes()
61}
62if d, ok := data.(json.Marshaler); ok {
63return d.MarshalJSON()
64}
65return 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
70func ReadJSON(data []byte, value interface{}) error {
71trimmedData := bytes.Trim(data, "\x00")
72if d, ok := value.(ejUnmarshaler); ok {
73jl := &jlexer.Lexer{Data: trimmedData}
74d.UnmarshalEasyJSON(jl)
75return jl.Error()
76}
77if d, ok := value.(json.Unmarshaler); ok {
78return d.UnmarshalJSON(trimmedData)
79}
80return json.Unmarshal(trimmedData, value)
81}
82
83// DynamicJSONToStruct converts an untyped json structure into a struct
84func DynamicJSONToStruct(data interface{}, target interface{}) error {
85// TODO: convert straight to a json typed map (mergo + iterate?)
86b, err := WriteJSON(data)
87if err != nil {
88return err
89}
90return ReadJSON(b, target)
91}
92
93// ConcatJSON concatenates multiple json objects efficiently
94func ConcatJSON(blobs ...[]byte) []byte {
95if len(blobs) == 0 {
96return nil
97}
98
99last := len(blobs) - 1
100for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
101// strips trailing null objects
102last--
103if last < 0 {
104// there was nothing but "null"s or nil...
105return nil
106}
107}
108if last == 0 {
109return blobs[0]
110}
111
112var opening, closing byte
113var idx, a int
114buf := bytes.NewBuffer(nil)
115
116for i, b := range blobs[:last+1] {
117if b == nil || bytes.Equal(b, nullJSON) {
118// a null object is in the list: skip it
119continue
120}
121if len(b) > 0 && opening == 0 { // is this an array or an object?
122opening, closing = b[0], closers[b[0]]
123}
124
125if opening != '{' && opening != '[' {
126continue // don't know how to concatenate non container objects
127}
128
129if len(b) < 3 { // yep empty but also the last one, so closing this thing
130if i == last && a > 0 {
131if err := buf.WriteByte(closing); err != nil {
132log.Println(err)
133}
134}
135continue
136}
137
138idx = 0
139if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
140if err := buf.WriteByte(comma); err != nil {
141log.Println(err)
142}
143idx = 1 // this is not the first or the last so we want to drop the leading bracket
144}
145
146if i != last { // not the last one, strip brackets
147if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
148log.Println(err)
149}
150} else { // last one, strip only the leading bracket
151if _, err := buf.Write(b[idx:]); err != nil {
152log.Println(err)
153}
154}
155a++
156}
157// somehow it ended up being empty, so provide a default value
158if buf.Len() == 0 {
159if err := buf.WriteByte(opening); err != nil {
160log.Println(err)
161}
162if err := buf.WriteByte(closing); err != nil {
163log.Println(err)
164}
165}
166return buf.Bytes()
167}
168
169// ToDynamicJSON turns an object into a properly JSON typed structure
170func ToDynamicJSON(data interface{}) interface{} {
171// TODO: convert straight to a json typed map (mergo + iterate?)
172b, err := json.Marshal(data)
173if err != nil {
174log.Println(err)
175}
176var res interface{}
177if err := json.Unmarshal(b, &res); err != nil {
178log.Println(err)
179}
180return res
181}
182
183// FromDynamicJSON turns an object into a properly JSON typed structure
184func FromDynamicJSON(data, target interface{}) error {
185b, err := json.Marshal(data)
186if err != nil {
187log.Println(err)
188}
189return 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.
195type NameProvider struct {
196lock *sync.Mutex
197index map[reflect.Type]nameIndex
198}
199
200type nameIndex struct {
201jsonNames map[string]string
202goNames map[string]string
203}
204
205// NewNameProvider creates a new name provider
206func NewNameProvider() *NameProvider {
207return &NameProvider{
208lock: &sync.Mutex{},
209index: make(map[reflect.Type]nameIndex),
210}
211}
212
213func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
214for i := 0; i < tpe.NumField(); i++ {
215targetDes := tpe.Field(i)
216
217if targetDes.PkgPath != "" { // unexported
218continue
219}
220
221if targetDes.Anonymous { // walk embedded structures tree down first
222buildnameIndex(targetDes.Type, idx, reverseIdx)
223continue
224}
225
226if tag := targetDes.Tag.Get("json"); tag != "" {
227
228parts := strings.Split(tag, ",")
229if len(parts) == 0 {
230continue
231}
232
233nm := parts[0]
234if nm == "-" {
235continue
236}
237if nm == "" { // empty string means we want to use the Go name
238nm = targetDes.Name
239}
240
241idx[nm] = targetDes.Name
242reverseIdx[targetDes.Name] = nm
243}
244}
245}
246
247func newNameIndex(tpe reflect.Type) nameIndex {
248var idx = make(map[string]string, tpe.NumField())
249var reverseIdx = make(map[string]string, tpe.NumField())
250
251buildnameIndex(tpe, idx, reverseIdx)
252return nameIndex{jsonNames: idx, goNames: reverseIdx}
253}
254
255// GetJSONNames gets all the json property names for a type
256func (n *NameProvider) GetJSONNames(subject interface{}) []string {
257n.lock.Lock()
258defer n.lock.Unlock()
259tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
260names, ok := n.index[tpe]
261if !ok {
262names = n.makeNameIndex(tpe)
263}
264
265res := make([]string, 0, len(names.jsonNames))
266for k := range names.jsonNames {
267res = append(res, k)
268}
269return res
270}
271
272// GetJSONName gets the json name for a go property name
273func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
274tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
275return n.GetJSONNameForType(tpe, name)
276}
277
278// GetJSONNameForType gets the json name for a go property name on a given type
279func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
280n.lock.Lock()
281defer n.lock.Unlock()
282names, ok := n.index[tpe]
283if !ok {
284names = n.makeNameIndex(tpe)
285}
286nme, ok := names.goNames[name]
287return nme, ok
288}
289
290func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
291names := newNameIndex(tpe)
292n.index[tpe] = names
293return names
294}
295
296// GetGoName gets the go name for a json property name
297func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
298tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
299return n.GetGoNameForType(tpe, name)
300}
301
302// GetGoNameForType gets the go name for a given type for a json property name
303func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
304n.lock.Lock()
305defer n.lock.Unlock()
306names, ok := n.index[tpe]
307if !ok {
308names = n.makeNameIndex(tpe)
309}
310nme, ok := names.jsonNames[name]
311return nme, ok
312}
313