File: encoder.go

package info (click to toggle)
golang-gopkg-rethinkdb-rethinkdb-go.v6 6.2.1-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,736 kB
  • sloc: python: 1,382; makefile: 16; sh: 9
file content (82 lines) | stat: -rw-r--r-- 1,770 bytes parent folder | download | duplicates (3)
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
// This code is based on encoding/json and gorilla/schema

package encoding

import (
	"errors"
	"reflect"
	"runtime"
	"sync"
)

type encoderFunc func(v reflect.Value) (interface{}, error)

// Encode returns the encoded value of v.
//
// Encode  traverses the value v recursively and looks for structs. If a struct
// is found then it is checked for tagged fields and convert to
// map[string]interface{}
func Encode(v interface{}) (ev interface{}, err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			if v, ok := r.(string); ok {
				err = errors.New(v)
			} else {
				err = r.(error)
			}
		}
	}()

	return encode(reflect.ValueOf(v))
}

func encode(v reflect.Value) (interface{}, error) {
	return valueEncoder(v)(v)
}

var encoderCache struct {
	sync.RWMutex
	m map[reflect.Type]encoderFunc
}

func valueEncoder(v reflect.Value) encoderFunc {
	if !v.IsValid() {
		return invalidValueEncoder
	}
	return typeEncoder(v.Type())
}

func typeEncoder(t reflect.Type) encoderFunc {
	encoderCache.RLock()
	f := encoderCache.m[t]
	encoderCache.RUnlock()
	if f != nil {
		return f
	}

	// To deal with recursive types, populate the map with an
	// indirect func before we build it. This type waits on the
	// real func (f) to
	//  be ready and then calls it.  This indirect
	// func is only used for recursive types.
	encoderCache.Lock()
	var wg sync.WaitGroup
	wg.Add(1)
	encoderCache.m[t] = func(v reflect.Value) (interface{}, error) {
		wg.Wait()
		return f(v)
	}
	encoderCache.Unlock()

	// Compute fields without lock.
	// Might duplicate effort but won't hold other computations back.
	f = newTypeEncoder(t, true)
	wg.Done()
	encoderCache.Lock()
	encoderCache.m[t] = f
	encoderCache.Unlock()
	return f
}