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  }