expressionorlist.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package config
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "slices"
  7. "strings"
  8. )
  9. var (
  10. ErrExpressionOrListMustBeStringOrObject = errors.New("config: this must be a string or an object")
  11. ErrExpressionEmpty = errors.New("config: this expression is empty")
  12. ErrExpressionCantHaveBoth = errors.New("config: expression block can't contain multiple expression types")
  13. )
  14. type ExpressionOrList struct {
  15. Expression string `json:"-" yaml:"-"`
  16. All []string `json:"all,omitempty" yaml:"all,omitempty"`
  17. Any []string `json:"any,omitempty" yaml:"any,omitempty"`
  18. }
  19. func (eol ExpressionOrList) String() string {
  20. switch {
  21. case len(eol.Expression) != 0:
  22. return eol.Expression
  23. case len(eol.All) != 0:
  24. var sb strings.Builder
  25. for i, pred := range eol.All {
  26. if i != 0 {
  27. fmt.Fprintf(&sb, " && ")
  28. }
  29. fmt.Fprintf(&sb, "( %s )", pred)
  30. }
  31. return sb.String()
  32. case len(eol.Any) != 0:
  33. var sb strings.Builder
  34. for i, pred := range eol.Any {
  35. if i != 0 {
  36. fmt.Fprintf(&sb, " || ")
  37. }
  38. fmt.Fprintf(&sb, "( %s )", pred)
  39. }
  40. return sb.String()
  41. }
  42. panic("this should not happen")
  43. }
  44. func (eol ExpressionOrList) Equal(rhs *ExpressionOrList) bool {
  45. if eol.Expression != rhs.Expression {
  46. return false
  47. }
  48. if !slices.Equal(eol.All, rhs.All) {
  49. return false
  50. }
  51. if !slices.Equal(eol.Any, rhs.Any) {
  52. return false
  53. }
  54. return true
  55. }
  56. func (eol *ExpressionOrList) MarshalYAML() (any, error) {
  57. switch {
  58. case len(eol.All) == 1 && len(eol.Any) == 0:
  59. eol.Expression = eol.All[0]
  60. eol.All = nil
  61. case len(eol.Any) == 1 && len(eol.All) == 0:
  62. eol.Expression = eol.Any[0]
  63. eol.Any = nil
  64. }
  65. if eol.Expression != "" {
  66. return eol.Expression, nil
  67. }
  68. type RawExpressionOrList ExpressionOrList
  69. return RawExpressionOrList(*eol), nil
  70. }
  71. func (eol *ExpressionOrList) MarshalJSON() ([]byte, error) {
  72. switch {
  73. case len(eol.All) == 1 && len(eol.Any) == 0:
  74. eol.Expression = eol.All[0]
  75. eol.All = nil
  76. case len(eol.Any) == 1 && len(eol.All) == 0:
  77. eol.Expression = eol.Any[0]
  78. eol.Any = nil
  79. }
  80. if eol.Expression != "" {
  81. return json.Marshal(string(eol.Expression))
  82. }
  83. type RawExpressionOrList ExpressionOrList
  84. val := RawExpressionOrList(*eol)
  85. return json.Marshal(val)
  86. }
  87. func (eol *ExpressionOrList) UnmarshalJSON(data []byte) error {
  88. switch string(data[0]) {
  89. case `"`: // string
  90. return json.Unmarshal(data, &eol.Expression)
  91. case "{": // object
  92. type RawExpressionOrList ExpressionOrList
  93. var val RawExpressionOrList
  94. if err := json.Unmarshal(data, &val); err != nil {
  95. return err
  96. }
  97. eol.All = val.All
  98. eol.Any = val.Any
  99. return nil
  100. }
  101. return ErrExpressionOrListMustBeStringOrObject
  102. }
  103. func (eol *ExpressionOrList) Valid() error {
  104. if eol.Expression == "" && len(eol.All) == 0 && len(eol.Any) == 0 {
  105. return ErrExpressionEmpty
  106. }
  107. if len(eol.All) != 0 && len(eol.Any) != 0 {
  108. return ErrExpressionCantHaveBoth
  109. }
  110. return nil
  111. }