github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/unsafekit/byte_string.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package unsafekit 7 8 import ( 9 "hash" 10 "io" 11 "reflect" 12 "unsafe" 13 14 "github.com/insolar/vanilla/longbits" 15 ) 16 17 // WARNING! The given array MUST be immutable 18 // WARNING! This method violates unsafe pointer-conversion rules. 19 // You MUST make sure that (b) stays alive while the resulting ByteString is in use. 20 func WrapBytes(b []byte) longbits.ByteString { 21 if len(b) == 0 { 22 return longbits.EmptyByteString 23 } 24 return wrapUnsafe(b) 25 } 26 27 // Expects struct ptr. 28 // WARNING! This method violates unsafe pointer-conversion rules. 29 // You MUST make sure that (v) stays alive while the resulting ByteString is in use. 30 func WrapStruct(v interface{}) longbits.ByteString { 31 vt := reflect.ValueOf(v) 32 if vt.Kind() != reflect.Ptr { 33 panic("illegal value") 34 } 35 return wrapStruct(vt.Elem()) 36 } 37 38 // Expects struct value. Reuses the value. 39 // WARNING! Further unwraps MUST NOT modify the content. 40 // WARNING! This method violates unsafe pointer-conversion rules. 41 // You MUST make sure that (v) stays alive while the resulting ByteString is in use. 42 func WrapValueStruct(v interface{}) longbits.ByteString { 43 return wrapStruct(reflect.ValueOf(v)) 44 } 45 46 func wrapStruct(vt reflect.Value) longbits.ByteString { 47 if vt.Kind() != reflect.Struct { 48 panic("illegal value") 49 } 50 if !vt.CanAddr() { 51 panic("illegal value") 52 } 53 return wrapUnsafePtr(vt.Pointer(), vt.Type().Size()) 54 } 55 56 func WrapOf(v interface{}, mt MMapType) longbits.ByteString { 57 vt := reflect.ValueOf(v) 58 if vt.Kind() == reflect.Ptr { 59 vt = vt.Elem() 60 } 61 if vt.Type() != mt.ReflectType() { 62 panic("illegal value type") 63 } 64 if !vt.CanAddr() { 65 panic("illegal value") 66 } 67 return wrapUnsafePtr(vt.Pointer(), vt.Type().Size()) 68 } 69 70 func UnwrapAs(v longbits.ByteString, mt MMapType) interface{} { 71 if mt.Size() != len(v) { 72 panic("illegal value") 73 } 74 return reflect.NewAt(mt.ReflectType(), _unwrapUnsafe(v)).Interface() 75 } 76 77 func Hash(v longbits.ByteString, h hash.Hash) hash.Hash { 78 unwrapUnsafe(v, func(b []byte) uintptr { 79 _, _ = h.Write(b) 80 return 0 81 }) 82 return h 83 } 84 85 func WriteTo(v longbits.ByteString, w io.Writer) (n int64, err error) { 86 unwrapUnsafe(v, func(b []byte) uintptr { 87 nn := 0 88 nn, err = w.Write(b) 89 n = int64(nn) 90 return 0 91 }) 92 return 93 } 94 95 // WARNING! This method violates unsafe pointer-conversion rules. 96 // You MUST make sure that (b) stays alive while the resulting ByteString is in use. 97 func wrapUnsafe(b []byte) longbits.ByteString { 98 pSlice := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 99 100 var res longbits.ByteString 101 pString := (*reflect.StringHeader)(unsafe.Pointer(&res)) 102 103 pString.Data = pSlice.Data 104 pString.Len = pSlice.Len 105 106 return res 107 } 108 109 // WARNING! This method violates unsafe pointer-conversion rules. 110 // You MUST make sure that (p) stays alive while the resulting ByteString is in use. 111 func wrapUnsafePtr(p uintptr, size uintptr) longbits.ByteString { 112 var res longbits.ByteString 113 pString := (*reflect.StringHeader)(unsafe.Pointer(&res)) 114 115 pString.Data = p 116 pString.Len = int(size) 117 118 return res 119 } 120 121 // WARNING! This method violates unsafe pointer-conversion rules. 122 // You MUST make sure that (p) stays alive while the resulting Pointer is in use. 123 func _unwrapUnsafe(s longbits.ByteString) unsafe.Pointer { 124 if len(s) == 0 { 125 return nil 126 } 127 sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 128 return unsafe.Pointer(sh.Data) 129 } 130 131 func _unwrapUnsafeUintptr(s longbits.ByteString) uintptr { 132 if len(s) == 0 { 133 return 0 134 } 135 return uintptr(_unwrapUnsafe(s)) 136 } 137 138 // nolint 139 func unwrapUnsafe(s longbits.ByteString, fn func([]byte) uintptr) uintptr { 140 return KeepAliveWhile(unsafe.Pointer(&s), func(p unsafe.Pointer) uintptr { 141 pString := (*reflect.StringHeader)(p) 142 143 var b []byte 144 pSlice := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 145 146 pSlice.Data = pString.Data 147 pSlice.Len = pString.Len 148 pSlice.Cap = pString.Len 149 150 r := fn(b) 151 //*pSlice = reflect.SliceHeader{} 152 153 return r 154 }) 155 }