compare.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package ottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
  4. import (
  5. "bytes"
  6. "time"
  7. "go.uber.org/zap"
  8. "golang.org/x/exp/constraints"
  9. )
  10. // The functions in this file implement a general-purpose comparison of two
  11. // values of type any, which for the purposes of OTTL mean values that are one of
  12. // int, float, string, bool, or pointers to those, or []byte, or nil.
  13. // invalidComparison returns false for everything except NE (where it returns true to indicate that the
  14. // objects were definitely not equivalent).
  15. // It also gives us an opportunity to log something.
  16. func (p *Parser[K]) invalidComparison(msg string, op compareOp) bool {
  17. p.telemetrySettings.Logger.Debug(msg, zap.Any("op", op))
  18. return op == NE
  19. }
  20. // comparePrimitives implements a generic comparison helper for all Ordered types (derived from Float, Int, or string).
  21. // According to benchmarks, it's faster than explicit comparison functions for these types.
  22. func comparePrimitives[T constraints.Ordered](a T, b T, op compareOp) bool {
  23. switch op {
  24. case EQ:
  25. return a == b
  26. case NE:
  27. return a != b
  28. case LT:
  29. return a < b
  30. case LTE:
  31. return a <= b
  32. case GTE:
  33. return a >= b
  34. case GT:
  35. return a > b
  36. default:
  37. return false
  38. }
  39. }
  40. func compareBools(a bool, b bool, op compareOp) bool {
  41. switch op {
  42. case EQ:
  43. return a == b
  44. case NE:
  45. return a != b
  46. case LT:
  47. return !a && b
  48. case LTE:
  49. return !a || b
  50. case GTE:
  51. return a || !b
  52. case GT:
  53. return a && !b
  54. default:
  55. return false
  56. }
  57. }
  58. func compareBytes(a []byte, b []byte, op compareOp) bool {
  59. switch op {
  60. case EQ:
  61. return bytes.Equal(a, b)
  62. case NE:
  63. return !bytes.Equal(a, b)
  64. case LT:
  65. return bytes.Compare(a, b) < 0
  66. case LTE:
  67. return bytes.Compare(a, b) <= 0
  68. case GTE:
  69. return bytes.Compare(a, b) >= 0
  70. case GT:
  71. return bytes.Compare(a, b) > 0
  72. default:
  73. return false
  74. }
  75. }
  76. func (p *Parser[K]) compareBool(a bool, b any, op compareOp) bool {
  77. switch v := b.(type) {
  78. case bool:
  79. return compareBools(a, v, op)
  80. default:
  81. return p.invalidComparison("bool to non-bool", op)
  82. }
  83. }
  84. func (p *Parser[K]) compareString(a string, b any, op compareOp) bool {
  85. switch v := b.(type) {
  86. case string:
  87. return comparePrimitives(a, v, op)
  88. default:
  89. return p.invalidComparison("string to non-string", op)
  90. }
  91. }
  92. func (p *Parser[K]) compareByte(a []byte, b any, op compareOp) bool {
  93. switch v := b.(type) {
  94. case nil:
  95. return op == NE
  96. case []byte:
  97. if v == nil {
  98. return op == NE
  99. }
  100. return compareBytes(a, v, op)
  101. default:
  102. return p.invalidComparison("Bytes to non-Bytes", op)
  103. }
  104. }
  105. func (p *Parser[K]) compareInt64(a int64, b any, op compareOp) bool {
  106. switch v := b.(type) {
  107. case int64:
  108. return comparePrimitives(a, v, op)
  109. case float64:
  110. return comparePrimitives(float64(a), v, op)
  111. default:
  112. return p.invalidComparison("int to non-numeric value", op)
  113. }
  114. }
  115. func (p *Parser[K]) compareFloat64(a float64, b any, op compareOp) bool {
  116. switch v := b.(type) {
  117. case int64:
  118. return comparePrimitives(a, float64(v), op)
  119. case float64:
  120. return comparePrimitives(a, v, op)
  121. default:
  122. return p.invalidComparison("float to non-numeric value", op)
  123. }
  124. }
  125. func (p *Parser[K]) compareDuration(a time.Duration, b any, op compareOp) bool {
  126. switch v := b.(type) {
  127. case time.Duration:
  128. ansecs := a.Nanoseconds()
  129. vnsecs := v.Nanoseconds()
  130. return comparePrimitives(ansecs, vnsecs, op)
  131. default:
  132. return p.invalidComparison("cannot compare invalid duration", op)
  133. }
  134. }
  135. func (p *Parser[K]) compareTime(a time.Time, b any, op compareOp) bool {
  136. switch v := b.(type) {
  137. case time.Time:
  138. switch op {
  139. case EQ:
  140. return a.Equal(v)
  141. case NE:
  142. return !a.Equal(v)
  143. case LT:
  144. return a.Before(v)
  145. case LTE:
  146. return a.Before(v) || a.Equal(v)
  147. case GTE:
  148. return a.After(v) || a.Equal(v)
  149. case GT:
  150. return a.After(v)
  151. default:
  152. return p.invalidComparison("invalid comparison operator", op)
  153. }
  154. default:
  155. return p.invalidComparison("time to non-time value", op)
  156. }
  157. }
  158. // a and b are the return values from a Getter; we try to compare them
  159. // according to the given operator.
  160. func (p *Parser[K]) compare(a any, b any, op compareOp) bool {
  161. // nils are equal to each other and never equal to anything else,
  162. // so if they're both nil, report equality.
  163. if a == nil && b == nil {
  164. return op == EQ || op == LTE || op == GTE
  165. }
  166. // Anything else, we switch on the left side first.
  167. switch v := a.(type) {
  168. case nil:
  169. // If a was nil, it means b wasn't and inequalities don't apply,
  170. // so let's swap and give it the chance to get evaluated.
  171. return p.compare(b, nil, op)
  172. case bool:
  173. return p.compareBool(v, b, op)
  174. case int64:
  175. return p.compareInt64(v, b, op)
  176. case float64:
  177. return p.compareFloat64(v, b, op)
  178. case string:
  179. return p.compareString(v, b, op)
  180. case []byte:
  181. if v == nil {
  182. return p.compare(b, nil, op)
  183. }
  184. return p.compareByte(v, b, op)
  185. case time.Duration:
  186. return p.compareDuration(v, b, op)
  187. case time.Time:
  188. return p.compareTime(v, b, op)
  189. default:
  190. // If we don't know what type it is, we can't do inequalities yet. So we can fall back to the old behavior where we just
  191. // use Go's standard equality.
  192. switch op {
  193. case EQ:
  194. return a == b
  195. case NE:
  196. return a != b
  197. default:
  198. return p.invalidComparison("unsupported type for inequality on left", op)
  199. }
  200. }
  201. }