github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/pointer_reflect.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2012 The Go Authors.  All rights reserved.
     4  // http://code.google.com/p/goprotobuf/
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  // +build appengine
    33  
    34  // This file contains an implementation of proto field accesses using package reflect.
    35  // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
    36  // be used on App Engine.
    37  
    38  package proto
    39  
    40  import (
    41  	"math"
    42  	"reflect"
    43  )
    44  
    45  // A structPointer is a pointer to a struct.
    46  type structPointer struct {
    47  	v reflect.Value
    48  }
    49  
    50  // toStructPointer returns a structPointer equivalent to the given reflect value.
    51  // The reflect value must itself be a pointer to a struct.
    52  func toStructPointer(v reflect.Value) structPointer {
    53  	return structPointer{v}
    54  }
    55  
    56  // IsNil reports whether p is nil.
    57  func structPointer_IsNil(p structPointer) bool {
    58  	return p.v.IsNil()
    59  }
    60  
    61  // Interface returns the struct pointer as an interface value.
    62  func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
    63  	return p.v.Interface()
    64  }
    65  
    66  // A field identifies a field in a struct, accessible from a structPointer.
    67  // In this implementation, a field is identified by the sequence of field indices
    68  // passed to reflect's FieldByIndex.
    69  type field []int
    70  
    71  // toField returns a field equivalent to the given reflect field.
    72  func toField(f *reflect.StructField) field {
    73  	return f.Index
    74  }
    75  
    76  // invalidField is an invalid field identifier.
    77  var invalidField = field(nil)
    78  
    79  // IsValid reports whether the field identifier is valid.
    80  func (f field) IsValid() bool { return f != nil }
    81  
    82  // field returns the given field in the struct as a reflect value.
    83  func structPointer_field(p structPointer, f field) reflect.Value {
    84  	// Special case: an extension map entry with a value of type T
    85  	// passes a *T to the struct-handling code with a zero field,
    86  	// expecting that it will be treated as equivalent to *struct{ X T },
    87  	// which has the same memory layout. We have to handle that case
    88  	// specially, because reflect will panic if we call FieldByIndex on a
    89  	// non-struct.
    90  	if f == nil {
    91  		return p.v.Elem()
    92  	}
    93  
    94  	return p.v.Elem().FieldByIndex(f)
    95  }
    96  
    97  // ifield returns the given field in the struct as an interface value.
    98  func structPointer_ifield(p structPointer, f field) interface{} {
    99  	return structPointer_field(p, f).Addr().Interface()
   100  }
   101  
   102  // Bytes returns the address of a []byte field in the struct.
   103  func structPointer_Bytes(p structPointer, f field) *[]byte {
   104  	return structPointer_ifield(p, f).(*[]byte)
   105  }
   106  
   107  // BytesSlice returns the address of a [][]byte field in the struct.
   108  func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
   109  	return structPointer_ifield(p, f).(*[][]byte)
   110  }
   111  
   112  // Bool returns the address of a *bool field in the struct.
   113  func structPointer_Bool(p structPointer, f field) **bool {
   114  	return structPointer_ifield(p, f).(**bool)
   115  }
   116  
   117  // BoolSlice returns the address of a []bool field in the struct.
   118  func structPointer_BoolSlice(p structPointer, f field) *[]bool {
   119  	return structPointer_ifield(p, f).(*[]bool)
   120  }
   121  
   122  // String returns the address of a *string field in the struct.
   123  func structPointer_String(p structPointer, f field) **string {
   124  	return structPointer_ifield(p, f).(**string)
   125  }
   126  
   127  // StringSlice returns the address of a []string field in the struct.
   128  func structPointer_StringSlice(p structPointer, f field) *[]string {
   129  	return structPointer_ifield(p, f).(*[]string)
   130  }
   131  
   132  // ExtMap returns the address of an extension map field in the struct.
   133  func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
   134  	return structPointer_ifield(p, f).(*map[int32]Extension)
   135  }
   136  
   137  // SetStructPointer writes a *struct field in the struct.
   138  func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
   139  	structPointer_field(p, f).Set(q.v)
   140  }
   141  
   142  // GetStructPointer reads a *struct field in the struct.
   143  func structPointer_GetStructPointer(p structPointer, f field) structPointer {
   144  	return structPointer{structPointer_field(p, f)}
   145  }
   146  
   147  // StructPointerSlice the address of a []*struct field in the struct.
   148  func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
   149  	return structPointerSlice{structPointer_field(p, f)}
   150  }
   151  
   152  // A structPointerSlice represents the address of a slice of pointers to structs
   153  // (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
   154  type structPointerSlice struct {
   155  	v reflect.Value
   156  }
   157  
   158  func (p structPointerSlice) Len() int                  { return p.v.Len() }
   159  func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
   160  func (p structPointerSlice) Append(q structPointer) {
   161  	p.v.Set(reflect.Append(p.v, q.v))
   162  }
   163  
   164  var (
   165  	int32Type   = reflect.TypeOf(int32(0))
   166  	uint32Type  = reflect.TypeOf(uint32(0))
   167  	float32Type = reflect.TypeOf(float32(0))
   168  	int64Type   = reflect.TypeOf(int64(0))
   169  	uint64Type  = reflect.TypeOf(uint64(0))
   170  	float64Type = reflect.TypeOf(float64(0))
   171  )
   172  
   173  // A word32 represents a field of type *int32, *uint32, *float32, or *enum.
   174  // That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
   175  type word32 struct {
   176  	v reflect.Value
   177  }
   178  
   179  // IsNil reports whether p is nil.
   180  func word32_IsNil(p word32) bool {
   181  	return p.v.IsNil()
   182  }
   183  
   184  // Set sets p to point at a newly allocated word with bits set to x.
   185  func word32_Set(p word32, o *Buffer, x uint32) {
   186  	t := p.v.Type().Elem()
   187  	switch t {
   188  	case int32Type:
   189  		if len(o.int32s) == 0 {
   190  			o.int32s = make([]int32, uint32PoolSize)
   191  		}
   192  		o.int32s[0] = int32(x)
   193  		p.v.Set(reflect.ValueOf(&o.int32s[0]))
   194  		o.int32s = o.int32s[1:]
   195  		return
   196  	case uint32Type:
   197  		if len(o.uint32s) == 0 {
   198  			o.uint32s = make([]uint32, uint32PoolSize)
   199  		}
   200  		o.uint32s[0] = x
   201  		p.v.Set(reflect.ValueOf(&o.uint32s[0]))
   202  		o.uint32s = o.uint32s[1:]
   203  		return
   204  	case float32Type:
   205  		if len(o.float32s) == 0 {
   206  			o.float32s = make([]float32, uint32PoolSize)
   207  		}
   208  		o.float32s[0] = math.Float32frombits(x)
   209  		p.v.Set(reflect.ValueOf(&o.float32s[0]))
   210  		o.float32s = o.float32s[1:]
   211  		return
   212  	}
   213  
   214  	// must be enum
   215  	p.v.Set(reflect.New(t))
   216  	p.v.Elem().SetInt(int64(int32(x)))
   217  }
   218  
   219  // Get gets the bits pointed at by p, as a uint32.
   220  func word32_Get(p word32) uint32 {
   221  	elem := p.v.Elem()
   222  	switch elem.Kind() {
   223  	case reflect.Int32:
   224  		return uint32(elem.Int())
   225  	case reflect.Uint32:
   226  		return uint32(elem.Uint())
   227  	case reflect.Float32:
   228  		return math.Float32bits(float32(elem.Float()))
   229  	}
   230  	panic("unreachable")
   231  }
   232  
   233  // Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
   234  func structPointer_Word32(p structPointer, f field) word32 {
   235  	return word32{structPointer_field(p, f)}
   236  }
   237  
   238  // A word32Slice is a slice of 32-bit values.
   239  // That is, v.Type() is []int32, []uint32, []float32, or []enum.
   240  type word32Slice struct {
   241  	v reflect.Value
   242  }
   243  
   244  func (p word32Slice) Append(x uint32) {
   245  	n, m := p.v.Len(), p.v.Cap()
   246  	if n < m {
   247  		p.v.SetLen(n + 1)
   248  	} else {
   249  		t := p.v.Type().Elem()
   250  		p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
   251  	}
   252  	elem := p.v.Index(n)
   253  	switch elem.Kind() {
   254  	case reflect.Int32:
   255  		elem.SetInt(int64(int32(x)))
   256  	case reflect.Uint32:
   257  		elem.SetUint(uint64(x))
   258  	case reflect.Float32:
   259  		elem.SetFloat(float64(math.Float32frombits(x)))
   260  	}
   261  }
   262  
   263  func (p word32Slice) Len() int {
   264  	return p.v.Len()
   265  }
   266  
   267  func (p word32Slice) Index(i int) uint32 {
   268  	elem := p.v.Index(i)
   269  	switch elem.Kind() {
   270  	case reflect.Int32:
   271  		return uint32(elem.Int())
   272  	case reflect.Uint32:
   273  		return uint32(elem.Uint())
   274  	case reflect.Float32:
   275  		return math.Float32bits(float32(elem.Float()))
   276  	}
   277  	panic("unreachable")
   278  }
   279  
   280  // Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
   281  func structPointer_Word32Slice(p structPointer, f field) word32Slice {
   282  	return word32Slice{structPointer_field(p, f)}
   283  }
   284  
   285  // word64 is like word32 but for 64-bit values.
   286  type word64 struct {
   287  	v reflect.Value
   288  }
   289  
   290  func word64_Set(p word64, o *Buffer, x uint64) {
   291  	t := p.v.Type().Elem()
   292  	switch t {
   293  	case int64Type:
   294  		if len(o.int64s) == 0 {
   295  			o.int64s = make([]int64, uint64PoolSize)
   296  		}
   297  		o.int64s[0] = int64(x)
   298  		p.v.Set(reflect.ValueOf(&o.int64s[0]))
   299  		o.int64s = o.int64s[1:]
   300  		return
   301  	case uint64Type:
   302  		if len(o.uint64s) == 0 {
   303  			o.uint64s = make([]uint64, uint64PoolSize)
   304  		}
   305  		o.uint64s[0] = x
   306  		p.v.Set(reflect.ValueOf(&o.uint64s[0]))
   307  		o.uint64s = o.uint64s[1:]
   308  		return
   309  	case float64Type:
   310  		if len(o.float64s) == 0 {
   311  			o.float64s = make([]float64, uint64PoolSize)
   312  		}
   313  		o.float64s[0] = math.Float64frombits(x)
   314  		p.v.Set(reflect.ValueOf(&o.float64s[0]))
   315  		o.float64s = o.float64s[1:]
   316  		return
   317  	}
   318  	panic("unreachable")
   319  }
   320  
   321  func word64_IsNil(p word64) bool {
   322  	return p.v.IsNil()
   323  }
   324  
   325  func word64_Get(p word64) uint64 {
   326  	elem := p.v.Elem()
   327  	switch elem.Kind() {
   328  	case reflect.Int64:
   329  		return uint64(elem.Int())
   330  	case reflect.Uint64:
   331  		return elem.Uint()
   332  	case reflect.Float64:
   333  		return math.Float64bits(elem.Float())
   334  	}
   335  	panic("unreachable")
   336  }
   337  
   338  func structPointer_Word64(p structPointer, f field) word64 {
   339  	return word64{structPointer_field(p, f)}
   340  }
   341  
   342  type word64Slice struct {
   343  	v reflect.Value
   344  }
   345  
   346  func (p word64Slice) Append(x uint64) {
   347  	n, m := p.v.Len(), p.v.Cap()
   348  	if n < m {
   349  		p.v.SetLen(n + 1)
   350  	} else {
   351  		t := p.v.Type().Elem()
   352  		p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
   353  	}
   354  	elem := p.v.Index(n)
   355  	switch elem.Kind() {
   356  	case reflect.Int64:
   357  		elem.SetInt(int64(int64(x)))
   358  	case reflect.Uint64:
   359  		elem.SetUint(uint64(x))
   360  	case reflect.Float64:
   361  		elem.SetFloat(float64(math.Float64frombits(x)))
   362  	}
   363  }
   364  
   365  func (p word64Slice) Len() int {
   366  	return p.v.Len()
   367  }
   368  
   369  func (p word64Slice) Index(i int) uint64 {
   370  	elem := p.v.Index(i)
   371  	switch elem.Kind() {
   372  	case reflect.Int64:
   373  		return uint64(elem.Int())
   374  	case reflect.Uint64:
   375  		return uint64(elem.Uint())
   376  	case reflect.Float64:
   377  		return math.Float64bits(float64(elem.Float()))
   378  	}
   379  	panic("unreachable")
   380  }
   381  
   382  func structPointer_Word64Slice(p structPointer, f field) word64Slice {
   383  	return word64Slice{structPointer_field(p, f)}
   384  }