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