David K. Bainbridge | 215e024 | 2017-09-05 23:18:24 -0700 | [diff] [blame] | 1 | // Protocol Buffers for Go with Gadgets |
| 2 | // |
| 3 | // Copyright (c) 2013, The GoGo Authors. All rights reserved. |
| 4 | // http://github.com/gogo/protobuf |
| 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 | // |
| 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | |
| 29 | // +build !appengine,!js |
| 30 | |
| 31 | // This file contains the implementation of the proto field accesses using package unsafe. |
| 32 | |
| 33 | package proto |
| 34 | |
| 35 | import ( |
| 36 | "reflect" |
| 37 | "unsafe" |
| 38 | ) |
| 39 | |
| 40 | func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} { |
| 41 | point := unsafe.Pointer(uintptr(p) + uintptr(f)) |
| 42 | r := reflect.NewAt(t, point) |
| 43 | return r.Interface() |
| 44 | } |
| 45 | |
| 46 | func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} { |
| 47 | point := unsafe.Pointer(uintptr(p) + uintptr(f)) |
| 48 | r := reflect.NewAt(t, point) |
| 49 | if r.Elem().IsNil() { |
| 50 | return nil |
| 51 | } |
| 52 | return r.Elem().Interface() |
| 53 | } |
| 54 | |
| 55 | func copyUintPtr(oldptr, newptr uintptr, size int) { |
| 56 | oldbytes := make([]byte, 0) |
| 57 | oldslice := (*reflect.SliceHeader)(unsafe.Pointer(&oldbytes)) |
| 58 | oldslice.Data = oldptr |
| 59 | oldslice.Len = size |
| 60 | oldslice.Cap = size |
| 61 | newbytes := make([]byte, 0) |
| 62 | newslice := (*reflect.SliceHeader)(unsafe.Pointer(&newbytes)) |
| 63 | newslice.Data = newptr |
| 64 | newslice.Len = size |
| 65 | newslice.Cap = size |
| 66 | copy(newbytes, oldbytes) |
| 67 | } |
| 68 | |
| 69 | func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) { |
| 70 | copyUintPtr(uintptr(oldptr), uintptr(newptr), size) |
| 71 | } |
| 72 | |
| 73 | func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer { |
| 74 | size := typ.Elem().Size() |
| 75 | |
| 76 | oldHeader := structPointer_GetSliceHeader(base, f) |
| 77 | oldSlice := reflect.NewAt(typ, unsafe.Pointer(oldHeader)).Elem() |
| 78 | newLen := oldHeader.Len + 1 |
| 79 | newSlice := reflect.MakeSlice(typ, newLen, newLen) |
| 80 | reflect.Copy(newSlice, oldSlice) |
| 81 | bas := toStructPointer(newSlice) |
| 82 | oldHeader.Data = uintptr(bas) |
| 83 | oldHeader.Len = newLen |
| 84 | oldHeader.Cap = newLen |
| 85 | |
| 86 | return structPointer(unsafe.Pointer(uintptr(unsafe.Pointer(bas)) + uintptr(uintptr(newLen-1)*size))) |
| 87 | } |
| 88 | |
| 89 | func structPointer_FieldPointer(p structPointer, f field) structPointer { |
| 90 | return structPointer(unsafe.Pointer(uintptr(p) + uintptr(f))) |
| 91 | } |
| 92 | |
| 93 | func structPointer_GetRefStructPointer(p structPointer, f field) structPointer { |
| 94 | return structPointer((*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))) |
| 95 | } |
| 96 | |
| 97 | func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader { |
| 98 | return (*reflect.SliceHeader)(unsafe.Pointer(uintptr(p) + uintptr(f))) |
| 99 | } |
| 100 | |
| 101 | func structPointer_Add(p structPointer, size field) structPointer { |
| 102 | return structPointer(unsafe.Pointer(uintptr(p) + uintptr(size))) |
| 103 | } |
| 104 | |
| 105 | func structPointer_Len(p structPointer, f field) int { |
| 106 | return len(*(*[]interface{})(unsafe.Pointer(structPointer_GetRefStructPointer(p, f)))) |
| 107 | } |
| 108 | |
| 109 | func structPointer_StructRefSlice(p structPointer, f field, size uintptr) *structRefSlice { |
| 110 | return &structRefSlice{p: p, f: f, size: size} |
| 111 | } |
| 112 | |
| 113 | // A structRefSlice represents a slice of structs (themselves submessages or groups). |
| 114 | type structRefSlice struct { |
| 115 | p structPointer |
| 116 | f field |
| 117 | size uintptr |
| 118 | } |
| 119 | |
| 120 | func (v *structRefSlice) Len() int { |
| 121 | return structPointer_Len(v.p, v.f) |
| 122 | } |
| 123 | |
| 124 | func (v *structRefSlice) Index(i int) structPointer { |
| 125 | ss := structPointer_GetStructPointer(v.p, v.f) |
| 126 | ss1 := structPointer_GetRefStructPointer(ss, 0) |
| 127 | return structPointer_Add(ss1, field(uintptr(i)*v.size)) |
| 128 | } |