gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/encoding/decoder.go (about)

     1  package encoding
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"runtime"
     7  	"sync"
     8  )
     9  
    10  var byteSliceType = reflect.TypeOf([]byte(nil))
    11  
    12  type decoderFunc func(dv reflect.Value, sv reflect.Value) error
    13  
    14  // Decode decodes map[string]interface{} into a struct. The first parameter
    15  // must be a pointer.
    16  func Decode(dst interface{}, src interface{}) (err error) {
    17  	return decode(dst, src, true)
    18  }
    19  
    20  func Merge(dst interface{}, src interface{}) (err error) {
    21  	return decode(dst, src, false)
    22  }
    23  
    24  func decode(dst interface{}, src interface{}, blank bool) (err error) {
    25  	defer func() {
    26  		if r := recover(); r != nil {
    27  			if _, ok := r.(runtime.Error); ok {
    28  				panic(r)
    29  			}
    30  			if v, ok := r.(string); ok {
    31  				err = errors.New(v)
    32  			} else {
    33  				err = r.(error)
    34  			}
    35  		}
    36  	}()
    37  
    38  	dv := reflect.ValueOf(dst)
    39  	sv := reflect.ValueOf(src)
    40  	if dv.Kind() != reflect.Ptr {
    41  		return &DecodeTypeError{
    42  			DestType: dv.Type(),
    43  			SrcType:  sv.Type(),
    44  			Reason:   "must be a pointer",
    45  		}
    46  	}
    47  
    48  	dv = dv.Elem()
    49  	if !dv.CanAddr() {
    50  		return &DecodeTypeError{
    51  			DestType: dv.Type(),
    52  			SrcType:  sv.Type(),
    53  			Reason:   "must be addressable",
    54  		}
    55  	}
    56  
    57  	return decodeValue(dv, sv, blank)
    58  }
    59  
    60  // decodeValue decodes the source value into the destination value
    61  func decodeValue(dv, sv reflect.Value, blank bool) error {
    62  	return valueDecoder(dv, sv, blank)(dv, sv)
    63  }
    64  
    65  type decoderCacheKey struct {
    66  	dt, st reflect.Type
    67  }
    68  
    69  var decoderCache struct {
    70  	sync.RWMutex
    71  	m map[decoderCacheKey]decoderFunc
    72  }
    73  
    74  func valueDecoder(dv, sv reflect.Value, blank bool) decoderFunc {
    75  	if !sv.IsValid() {
    76  		return invalidValueDecoder
    77  	}
    78  
    79  	if dv.IsValid() {
    80  		dv = indirect(dv, false)
    81  		if sv.Kind() == reflect.Ptr {
    82  			sv = indirect(sv, false)
    83  			dv.Set(sv)
    84  		} else if blank {
    85  			dv.Set(reflect.Zero(dv.Type()))
    86  		}
    87  	}
    88  
    89  	return typeDecoder(dv.Type(), sv.Type(), blank)
    90  }
    91  
    92  func typeDecoder(dt, st reflect.Type, blank bool) decoderFunc {
    93  	decoderCache.RLock()
    94  	f := decoderCache.m[decoderCacheKey{dt, st}]
    95  	decoderCache.RUnlock()
    96  	if f != nil {
    97  		return f
    98  	}
    99  
   100  	// To deal with recursive types, populate the map with an
   101  	// indirect func before we build it. This type waits on the
   102  	// real func (f) to be ready and then calls it.  This indirect
   103  	// func is only used for recursive types.
   104  	decoderCache.Lock()
   105  	var wg sync.WaitGroup
   106  	wg.Add(1)
   107  	decoderCache.m[decoderCacheKey{dt, st}] = func(dv, sv reflect.Value) error {
   108  		wg.Wait()
   109  		return f(dv, sv)
   110  	}
   111  	decoderCache.Unlock()
   112  
   113  	// Compute fields without lock.
   114  	// Might duplicate effort but won't hold other computations back.
   115  	f = newTypeDecoder(dt, st, blank)
   116  	wg.Done()
   117  	decoderCache.Lock()
   118  	decoderCache.m[decoderCacheKey{dt, st}] = f
   119  	decoderCache.Unlock()
   120  	return f
   121  }
   122  
   123  // indirect walks down v allocating pointers as needed,
   124  // until it gets to a non-pointer.
   125  func indirect(v reflect.Value, decodeNull bool) reflect.Value {
   126  	// If v is a named type and is addressable,
   127  	// start with its address, so that if the type has pointer methods,
   128  	// we find them.
   129  	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
   130  		v = v.Addr()
   131  	}
   132  	for {
   133  		// Load value from interface, but only if the result will be
   134  		// usefully addressable.
   135  		if v.Kind() == reflect.Interface && !v.IsNil() {
   136  			e := v.Elem()
   137  			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodeNull || e.Elem().Kind() == reflect.Ptr) {
   138  				v = e
   139  				continue
   140  			}
   141  		}
   142  
   143  		if v.Kind() != reflect.Ptr {
   144  			break
   145  		}
   146  
   147  		if v.IsNil() {
   148  			v.Set(reflect.New(v.Type().Elem()))
   149  		}
   150  		v = v.Elem()
   151  	}
   152  	return v
   153  }