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  }