github.com/GuanceCloud/cliutils@v1.1.21/point/any.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package point 7 8 import ( 9 "fmt" 10 "reflect" 11 12 proto "github.com/gogo/protobuf/proto" 13 types "github.com/gogo/protobuf/types" 14 ) 15 16 var ( 17 // EnableMixedArrayField and EnableDictField used to allow mix-typed array and dict/map 18 // value in point field. 19 // 20 // Currently, GuanceDB backend do NOT support mix-typed array and dict. 21 EnableMixedArrayField = false 22 EnableDictField = false 23 ) 24 25 const ( 26 ArrayFieldType = "type.googleapis.com/point.Array" 27 DictFieldType = "type.googleapis.com/point.Map" 28 ) 29 30 // MustAnyRaw get underlying wrapped value, and panic if any error. 31 func MustAnyRaw(x *types.Any) any { 32 res, err := AnyRaw(x) 33 if err != nil { 34 panic(err.Error()) 35 } 36 37 return res 38 } 39 40 // AnyRaw get underlying wrapped value within types.Any. 41 func AnyRaw(x *types.Any) (any, error) { 42 if x == nil { 43 return nil, fmt.Errorf("nil value") 44 } 45 46 switch x.TypeUrl { 47 case ArrayFieldType: 48 var arr Array 49 if err := proto.Unmarshal(x.Value, &arr); err != nil { 50 return nil, err 51 } 52 53 if err := checkMixTypedArray(&arr); err != nil { 54 return nil, err 55 } 56 57 var res []any 58 for _, v := range arr.Arr { 59 switch v.GetX().(type) { 60 case *BasicTypes_I: 61 res = append(res, v.GetI()) 62 case *BasicTypes_U: 63 res = append(res, v.GetU()) 64 case *BasicTypes_F: 65 res = append(res, v.GetF()) 66 case *BasicTypes_B: 67 res = append(res, v.GetB()) 68 case *BasicTypes_D: 69 res = append(res, v.GetD()) 70 case *BasicTypes_S: 71 res = append(res, v.GetS()) 72 default: // pass 73 return nil, fmt.Errorf("unknown type %q within array", reflect.TypeOf(v.GetX()).String()) 74 } 75 } 76 77 return res, nil 78 79 case DictFieldType: 80 if !EnableDictField { 81 return nil, fmt.Errorf("dict/map field value not allowed") 82 } 83 84 var m Map 85 if err := proto.Unmarshal(x.Value, &m); err != nil { 86 return nil, err 87 } 88 89 res := map[string]any{} 90 for k, v := range m.Map { 91 switch v.GetX().(type) { 92 case *BasicTypes_I: 93 res[k] = v.GetI() 94 case *BasicTypes_U: 95 res[k] = v.GetU() 96 case *BasicTypes_F: 97 res[k] = v.GetF() 98 case *BasicTypes_B: 99 res[k] = v.GetB() 100 case *BasicTypes_D: 101 res[k] = v.GetD() 102 case *BasicTypes_S: 103 res[k] = v.GetS() 104 default: 105 return nil, fmt.Errorf("unknown type %q within map", reflect.TypeOf(v.GetX()).String()) 106 } 107 } 108 109 return res, nil 110 111 default: 112 return nil, fmt.Errorf("unknown type %q", x.TypeUrl) 113 } 114 } 115 116 // MustNewAnyArray wrapped mix-basic-typed list into types.Any, and panic if any error. 117 func MustNewAnyArray(a ...any) *types.Any { 118 if x, err := NewAnyArray(a...); err != nil { 119 panic(err.Error()) 120 } else { 121 return x 122 } 123 } 124 125 // NewAnyArray wrapped mix-basic-typed list into types.Any. 126 func NewAnyArray(a ...any) (*types.Any, error) { 127 x, err := NewArray(a...) 128 if err != nil { 129 return nil, err 130 } 131 132 return types.MarshalAny(x) 133 } 134 135 // MustNewIntArray wrapped signed int list into types.Any, and panic if any error. 136 func MustNewIntArray[T int8 | int16 | int | int32 | int64](i ...T) *types.Any { 137 if x, err := NewIntArray(i...); err != nil { 138 panic(err) 139 } else { 140 return x 141 } 142 } 143 144 // NewIntArray wrapped signed int list into types.Any. 145 func NewIntArray[T int8 | int16 | int | int32 | int64](i ...T) (*types.Any, error) { 146 arr := &Array{ 147 Arr: make([]*BasicTypes, 0, len(i)), 148 } 149 150 for _, v := range i { 151 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{int64(v)}}) 152 } 153 154 return types.MarshalAny(arr) 155 } 156 157 // MustNewUintArray wrapped unsigned int list into types.Any, and panic if any error. 158 func MustNewUintArray[T uint16 | uint | uint32 | uint64](i ...T) *types.Any { 159 if x, err := NewUintArray(i...); err != nil { 160 panic(err) 161 } else { 162 return x 163 } 164 } 165 166 // NewUintArray wrapped unsigned int list into types.Any. 167 func NewUintArray[T uint16 | uint | uint32 | uint64](i ...T) (*types.Any, error) { 168 arr := &Array{ 169 Arr: make([]*BasicTypes, 0, len(i)), 170 } 171 172 for _, v := range i { 173 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{uint64(v)}}) 174 } 175 176 return types.MarshalAny(arr) 177 } 178 179 // MustNewFloatArray wrapped float list into types.Any, and panic if any error. 180 func MustNewFloatArray[T float32 | float64](f ...T) *types.Any { 181 if x, err := NewFloatArray(f...); err != nil { 182 panic(err) 183 } else { 184 return x 185 } 186 } 187 188 // NewFloatArray wrapped float list into types.Any. 189 func NewFloatArray[T float32 | float64](f ...T) (*types.Any, error) { 190 arr := &Array{ 191 Arr: make([]*BasicTypes, 0, len(f)), 192 } 193 194 for _, v := range f { 195 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_F{float64(v)}}) 196 } 197 198 return types.MarshalAny(arr) 199 } 200 201 // MustNewBoolArray wrapped boolean list into types.Any, and panic if any error. 202 func MustNewBoolArray(b ...bool) *types.Any { 203 if x, err := NewBoolArray(b...); err != nil { 204 panic(err) 205 } else { 206 return x 207 } 208 } 209 210 // NewBoolArray wrapped boolean list into types.Any. 211 func NewBoolArray(b ...bool) (*types.Any, error) { 212 arr := &Array{ 213 Arr: make([]*BasicTypes, 0, len(b)), 214 } 215 216 for _, v := range b { 217 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_B{v}}) 218 } 219 220 return types.MarshalAny(arr) 221 } 222 223 // NewBytesArray wrapped string list into types.Any. 224 func NewBytesArray(bytes ...[]byte) (*types.Any, error) { 225 arr := &Array{ 226 Arr: make([]*BasicTypes, 0, len(bytes)), 227 } 228 229 for _, b := range bytes { 230 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_D{b}}) 231 } 232 233 return types.MarshalAny(arr) 234 } 235 236 // MustNewBytesArray wrapped string list into types.Any, and panic if any error. 237 func MustNewBytesArray(bytes ...[]byte) *types.Any { 238 if x, err := NewBytesArray(bytes...); err != nil { 239 panic(err) 240 } else { 241 return x 242 } 243 } 244 245 // MustNewStringArray wrapped string list into types.Any, and panic if any error. 246 func MustNewStringArray(s ...string) *types.Any { 247 if x, err := NewStringArray(s...); err != nil { 248 panic(err) 249 } else { 250 return x 251 } 252 } 253 254 // NewStringArray wrapped string list into types.Any. 255 func NewStringArray(s ...string) (*types.Any, error) { 256 arr := &Array{ 257 Arr: make([]*BasicTypes, 0, len(s)), 258 } 259 260 for _, v := range s { 261 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_S{v}}) 262 } 263 264 return types.MarshalAny(arr) 265 } 266 267 // NewArray create array value that can be used in point field. 268 // The types within ents can be mixed basic types. 269 func NewArray(ents ...any) (arr *Array, err error) { 270 arr = &Array{ 271 Arr: make([]*BasicTypes, 0, len(ents)), 272 } 273 274 for idx, v := range ents { 275 switch x := v.(type) { 276 case int8: 277 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{int64(x)}}) 278 case uint8: 279 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{uint64(x)}}) 280 case int16: 281 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{int64(x)}}) 282 case uint16: 283 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{uint64(x)}}) 284 case int32: 285 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{int64(x)}}) 286 case uint32: 287 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{uint64(x)}}) 288 case int: 289 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{int64(x)}}) 290 case uint: 291 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{uint64(x)}}) 292 case int64: 293 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_I{x}}) 294 case uint64: 295 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_U{x}}) 296 case float64: 297 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_F{x}}) 298 case float32: 299 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_F{float64(x)}}) 300 case string: 301 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_S{x}}) 302 case []byte: 303 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_D{x}}) 304 case bool: 305 arr.Arr = append(arr.Arr, &BasicTypes{X: &BasicTypes_B{x}}) 306 default: 307 if x == nil { 308 // gogoproto any do not support nil value. 309 return nil, fmt.Errorf("got nil(index: %d) within array", idx) 310 } else { 311 return nil, fmt.Errorf("unknown element type %q(index: %d) within array", 312 reflect.TypeOf(v).String(), idx) 313 } 314 } 315 } 316 317 if err := checkMixTypedArray(arr); err != nil { 318 return nil, err 319 } 320 321 return arr, nil 322 } 323 324 func checkMixTypedArray(arr *Array) error { 325 if !EnableMixedArrayField && len(arr.Arr) > 1 { // check if array elements are same type 326 firstElemType := reflect.TypeOf(arr.Arr[0].X).String() 327 for idx, elem := range arr.Arr[1:] { 328 if et := reflect.TypeOf(elem.X).String(); et != firstElemType { 329 return fmt.Errorf("mixed type elements found in array([0]: %s <> [%d]: %s)", 330 firstElemType, idx+1, et) 331 } 332 } 333 } 334 335 return nil 336 } 337 338 // MustNewMap create map value that can be used in point field, and panic if any error. 339 func MustNewMap(ents map[string]any) *Map { 340 x, err := NewMap(ents) 341 if err != nil { 342 panic(err.Error()) 343 } 344 345 return x 346 } 347 348 // NewMap create map value that can be used in point field. 349 func NewMap(ents map[string]any) (dict *Map, err error) { 350 if !EnableDictField { 351 return nil, fmt.Errorf("dict/map field value not allowed") 352 } 353 354 dict = &Map{ 355 Map: map[string]*BasicTypes{}, 356 } 357 358 for k, v := range ents { 359 switch x := v.(type) { 360 case int8: 361 dict.Map[k] = &BasicTypes{X: &BasicTypes_I{int64(x)}} 362 case uint8: 363 dict.Map[k] = &BasicTypes{X: &BasicTypes_U{uint64(x)}} 364 case int16: 365 dict.Map[k] = &BasicTypes{X: &BasicTypes_I{int64(x)}} 366 case uint16: 367 dict.Map[k] = &BasicTypes{X: &BasicTypes_U{uint64(x)}} 368 case int32: 369 dict.Map[k] = &BasicTypes{X: &BasicTypes_I{int64(x)}} 370 case uint32: 371 dict.Map[k] = &BasicTypes{X: &BasicTypes_U{uint64(x)}} 372 case int: 373 dict.Map[k] = &BasicTypes{X: &BasicTypes_I{int64(x)}} 374 case uint: 375 dict.Map[k] = &BasicTypes{X: &BasicTypes_U{uint64(x)}} 376 case int64: 377 dict.Map[k] = &BasicTypes{X: &BasicTypes_I{x}} 378 case uint64: 379 dict.Map[k] = &BasicTypes{X: &BasicTypes_U{x}} 380 case float64: 381 dict.Map[k] = &BasicTypes{X: &BasicTypes_F{x}} 382 case float32: 383 dict.Map[k] = &BasicTypes{X: &BasicTypes_F{float64(x)}} 384 case string: 385 dict.Map[k] = &BasicTypes{X: &BasicTypes_S{x}} 386 case []byte: 387 dict.Map[k] = &BasicTypes{X: &BasicTypes_D{x}} 388 case bool: 389 dict.Map[k] = &BasicTypes{X: &BasicTypes_B{x}} 390 case nil: 391 dict.Map[k] = nil 392 default: // value ignored 393 return nil, fmt.Errorf("unknown type %q within map", reflect.TypeOf(v).String()) 394 } 395 } 396 397 return dict, nil 398 } 399 400 // NewAny create types.Any based on exist proto message. 401 func NewAny(x proto.Message) (*types.Any, error) { 402 return types.MarshalAny(x) 403 } 404 405 // MustNewAny create anypb based on exist proto message, and panic if any error. 406 func MustNewAny(x proto.Message) *types.Any { 407 if a, err := types.MarshalAny(x); err != nil { 408 panic(err.Error()) 409 } else { 410 return a 411 } 412 }