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  }