codeberg.org/gruf/go-mangler@v1.3.0/helpers.go (about) 1 package mangler 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 "github.com/modern-go/reflect2" 8 ) 9 10 type ( 11 byteser interface{ Bytes() []byte } 12 stringer interface{ String() string } 13 binarymarshaler interface{ MarshalBinary() ([]byte, error) } 14 textmarshaler interface{ MarshalText() ([]byte, error) } 15 jsonmarshaler interface{ MarshalJSON() ([]byte, error) } 16 ) 17 18 func append_uint16(b []byte, u uint16) []byte { 19 return append(b, // LE 20 byte(u), 21 byte(u>>8), 22 ) 23 } 24 25 func append_uint32(b []byte, u uint32) []byte { 26 return append(b, // LE 27 byte(u), 28 byte(u>>8), 29 byte(u>>16), 30 byte(u>>24), 31 ) 32 } 33 34 func append_uint64(b []byte, u uint64) []byte { 35 return append(b, // LE 36 byte(u), 37 byte(u>>8), 38 byte(u>>16), 39 byte(u>>24), 40 byte(u>>32), 41 byte(u>>40), 42 byte(u>>48), 43 byte(u>>56), 44 ) 45 } 46 47 func deref_ptr_mangler(rtype reflect.Type, mangle Mangler, count int) Mangler { 48 if rtype == nil || mangle == nil || count == 0 { 49 panic("bad input") 50 } 51 52 // Get reflect2's type for later 53 // unsafe interface data repacking, 54 type2 := reflect2.Type2(rtype) 55 56 return func(buf []byte, value any) []byte { 57 // Get raw value data. 58 ptr := eface_data(value) 59 60 // Deref n - 1 number times. 61 for i := 0; i < count-1; i++ { 62 63 if ptr == nil { 64 // Check for nil values 65 buf = append(buf, '0') 66 return buf 67 } 68 69 // Further deref ptr 70 buf = append(buf, '1') 71 ptr = *(*unsafe.Pointer)(ptr) 72 } 73 74 if ptr == nil { 75 // Final nil value check. 76 buf = append(buf, '0') 77 return buf 78 } 79 80 // Repack and mangle fully deref'd 81 value = type2.UnsafeIndirect(ptr) 82 buf = append(buf, '1') 83 return mangle(buf, value) 84 } 85 } 86 87 func iter_slice_mangler(rtype reflect.Type, mangle Mangler) Mangler { 88 if rtype == nil || mangle == nil { 89 panic("bad input") 90 } 91 92 // Get reflect2's type for later 93 // unsafe slice data manipulation. 94 slice2 := reflect2.Type2(rtype).(*reflect2.UnsafeSliceType) 95 96 return func(buf []byte, value any) []byte { 97 // Get raw value data. 98 ptr := eface_data(value) 99 100 // Get length of slice value. 101 n := slice2.UnsafeLengthOf(ptr) 102 103 for i := 0; i < n; i++ { 104 // Mangle data at each slice index. 105 e := slice2.UnsafeGetIndex(ptr, i) 106 buf = mangle(buf, e) 107 buf = append(buf, ',') 108 } 109 110 if n > 0 { 111 // Drop final comma. 112 buf = buf[:len(buf)-1] 113 } 114 115 return buf 116 } 117 } 118 119 func iter_array_mangler(rtype reflect.Type, mangle Mangler) Mangler { 120 if rtype == nil || mangle == nil { 121 panic("bad input") 122 } 123 124 // Get reflect2's type for later 125 // unsafe slice data manipulation. 126 array2 := reflect2.Type2(rtype).(*reflect2.UnsafeArrayType) 127 n := array2.Len() 128 129 return func(buf []byte, value any) []byte { 130 // Get raw value data. 131 ptr := eface_data(value) 132 133 for i := 0; i < n; i++ { 134 // Mangle data at each slice index. 135 e := array2.UnsafeGetIndex(ptr, i) 136 buf = mangle(buf, e) 137 buf = append(buf, ',') 138 } 139 140 if n > 0 { 141 // Drop final comma. 142 buf = buf[:len(buf)-1] 143 } 144 145 return buf 146 } 147 } 148 149 func iter_map_mangler(rtype reflect.Type, kmangle, emangle Mangler) Mangler { 150 if rtype == nil || kmangle == nil || emangle == nil { 151 panic("bad input") 152 } 153 154 // Get reflect2's type for later 155 // unsafe map data manipulation. 156 map2 := reflect2.Type2(rtype).(*reflect2.UnsafeMapType) 157 key2, elem2 := map2.Key(), map2.Elem() 158 159 return func(buf []byte, value any) []byte { 160 // Get raw value data. 161 ptr := eface_data(value) 162 ptr = indirect_ptr(ptr) 163 164 // Create iterator for map value. 165 iter := map2.UnsafeIterate(ptr) 166 167 // Check if empty map. 168 empty := !iter.HasNext() 169 170 for iter.HasNext() { 171 // Get key + elem data as ifaces. 172 kptr, eptr := iter.UnsafeNext() 173 key := key2.UnsafeIndirect(kptr) 174 elem := elem2.UnsafeIndirect(eptr) 175 176 // Mangle data for key + elem. 177 buf = kmangle(buf, key) 178 buf = append(buf, ':') 179 buf = emangle(buf, elem) 180 buf = append(buf, ',') 181 } 182 183 if !empty { 184 // Drop final comma. 185 buf = buf[:len(buf)-1] 186 } 187 188 return buf 189 } 190 } 191 192 func iter_struct_mangler(rtype reflect.Type, manglers []Mangler) Mangler { 193 if rtype == nil || len(manglers) != rtype.NumField() { 194 panic("bad input") 195 } 196 197 type field struct { 198 type2 reflect2.Type 199 field *reflect2.UnsafeStructField 200 mangle Mangler 201 } 202 203 // Get reflect2's type for later 204 // unsafe struct field data access. 205 struct2 := reflect2.Type2(rtype).(*reflect2.UnsafeStructType) 206 207 // Bundle together the fields and manglers. 208 fields := make([]field, rtype.NumField()) 209 for i := range fields { 210 fields[i].field = struct2.Field(i).(*reflect2.UnsafeStructField) 211 fields[i].type2 = fields[i].field.Type() 212 fields[i].mangle = manglers[i] 213 if fields[i].type2 == nil || 214 fields[i].field == nil || 215 fields[i].mangle == nil { 216 panic("bad input") 217 } 218 } 219 220 return func(buf []byte, value any) []byte { 221 // Get raw value data. 222 ptr := eface_data(value) 223 224 for i := range fields { 225 // Get struct field as iface via offset. 226 fptr := fields[i].field.UnsafeGet(ptr) 227 field := fields[i].type2.UnsafeIndirect(fptr) 228 229 // Mangle the struct field data. 230 buf = fields[i].mangle(buf, field) 231 buf = append(buf, ',') 232 } 233 234 if len(fields) > 0 { 235 // Drop final comma. 236 buf = buf[:len(buf)-1] 237 } 238 239 return buf 240 } 241 } 242 243 func indirect_ptr(p unsafe.Pointer) unsafe.Pointer { 244 return unsafe.Pointer(&p) 245 } 246 247 func eface_data(a any) unsafe.Pointer { 248 type eface struct{ _, data unsafe.Pointer } 249 return (*eface)(unsafe.Pointer(&a)).data 250 }