github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/unsafekit/slice.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 "fmt" 10 "reflect" 11 "runtime" 12 "unsafe" 13 14 "github.com/insolar/vanilla/longbits" 15 ) 16 17 // WARNING! The given struct MUST be immutable. Expects struct ptr. 18 // WARNING! This method violates unsafe pointer-conversion rules. 19 // You MUST make sure that (v) stays alive while the resulting ByteString is in use. 20 func WrapSlice(v interface{}) longbits.ByteString { 21 vt := reflect.ValueOf(v) 22 if vt.Kind() != reflect.Slice { 23 panic("illegal value") 24 } 25 return wrapSlice(vt) 26 } 27 28 func wrapSlice(vt reflect.Value) longbits.ByteString { 29 n := uintptr(vt.Len()) * vt.Type().Elem().Size() 30 if n == 0 { 31 return "" 32 } 33 return wrapUnsafePtr(vt.Pointer(), n) 34 } 35 36 func WrapSliceOf(v interface{}, mt MMapSliceType) longbits.ByteString { 37 vt := reflect.ValueOf(v) 38 if vt.Type() != mt.ReflectType() { 39 panic("illegal value type") 40 } 41 return wrapSlice(vt) 42 } 43 44 func UnwrapAsSliceOf(s longbits.ByteString, mt MMapSliceType) interface{} { 45 t := mt.ReflectType() 46 if t.Kind() != reflect.Slice { // double-check 47 panic("illegal value") 48 } 49 50 itemSize := int(t.Elem().Size()) 51 switch { 52 case len(s) == 0: 53 return reflect.Zero(t).Interface() 54 case len(s)%itemSize != 0: 55 panic(fmt.Sprintf("illegal value - length is unaligned: dataLen=%d itemSize=%d", len(s), itemSize)) 56 } 57 58 slice := reflect.New(t) 59 itemCount := len(s) / itemSize 60 sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(slice.Pointer())) 61 sliceHeader.Data = _unwrapUnsafeUintptr(s) 62 sliceHeader.Cap = itemCount 63 sliceHeader.Len = itemCount 64 65 slice = slice.Elem() 66 if slice.Len() != itemCount { 67 panic("unexpected") 68 } 69 runtime.KeepAlive(s) 70 71 return slice.Interface() 72 }