github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/transformation/type.go (about) 1 // go:generate stringer -type=Type 2 // Copyright (c) 2017 Uber Technologies, Inc. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 package transformation 23 24 import ( 25 "errors" 26 "fmt" 27 28 "github.com/m3db/m3/src/metrics/generated/proto/transformationpb" 29 ) 30 31 // Type defines a transformation function. 32 type Type int32 33 34 var errUnknownTransformationType = errors.New("unknown transformation type") 35 36 // Supported transformation types. 37 const ( 38 UnknownType Type = iota 39 Absolute 40 PerSecond 41 Increase 42 Add 43 Reset 44 ) 45 46 const ( 47 _minValidTransformationType = Absolute 48 _maxValidTransformationType = Reset 49 ) 50 51 // IsValid checks if the transformation type is valid. 52 func (t Type) IsValid() bool { 53 return t.IsUnaryTransform() || t.IsBinaryTransform() || t.IsUnaryMultiOutputTransform() 54 } 55 56 // IsUnaryTransform returns whether this is a unary transformation. 57 func (t Type) IsUnaryTransform() bool { 58 _, exists := unaryTransforms[t] 59 return exists 60 } 61 62 // IsBinaryTransform returns whether this is a binary transformation. 63 func (t Type) IsBinaryTransform() bool { 64 _, exists := binaryTransforms[t] 65 return exists 66 } 67 68 func (t Type) IsUnaryMultiOutputTransform() bool { 69 _, exists := unaryMultiOutputTransforms[t] 70 return exists 71 } 72 73 // NewOp returns a constructed operation that is allocated once and can be 74 // reused. 75 func (t Type) NewOp() (Op, error) { 76 var ( 77 err error 78 unary UnaryTransform 79 binary BinaryTransform 80 unaryMulti UnaryMultiOutputTransform 81 ) 82 switch { 83 case t.IsUnaryTransform(): 84 unary, err = t.UnaryTransform() 85 case t.IsBinaryTransform(): 86 binary, err = t.BinaryTransform() 87 case t.IsUnaryMultiOutputTransform(): 88 unaryMulti, err = t.UnaryMultiOutputTransform() 89 default: 90 err = errUnknownTransformationType 91 } 92 if err != nil { 93 return Op{}, err 94 } 95 return Op{ 96 opType: t, 97 unary: unary, 98 binary: binary, 99 unaryMulti: unaryMulti, 100 }, nil 101 } 102 103 // UnaryTransform returns the unary transformation function associated with 104 // the transformation type if applicable, or an error otherwise. 105 func (t Type) UnaryTransform() (UnaryTransform, error) { 106 tf, exists := unaryTransforms[t] 107 if !exists { 108 return nil, fmt.Errorf("%v is not a unary transfomration", t) 109 } 110 return tf(), nil 111 } 112 113 // MustUnaryTransform returns the unary transformation function associated with 114 // the transformation type if applicable, or panics otherwise. 115 func (t Type) MustUnaryTransform() UnaryTransform { 116 tf, err := t.UnaryTransform() 117 if err != nil { 118 panic(err) 119 } 120 return tf 121 } 122 123 // BinaryTransform returns the binary transformation function associated with 124 // the transformation type if applicable, or an error otherwise. 125 func (t Type) BinaryTransform() (BinaryTransform, error) { 126 tf, exists := binaryTransforms[t] 127 if !exists { 128 return nil, fmt.Errorf("%v is not a binary transfomration", t) 129 } 130 return tf(), nil 131 } 132 133 // MustBinaryTransform returns the binary transformation function associated with 134 // the transformation type if applicable, or an error otherwise. 135 func (t Type) MustBinaryTransform() BinaryTransform { 136 tf, err := t.BinaryTransform() 137 if err != nil { 138 panic(err) 139 } 140 return tf 141 } 142 143 // UnaryMultiOutputTransform returns the unary transformation function associated with 144 // the transformation type if applicable, or an error otherwise. 145 func (t Type) UnaryMultiOutputTransform() (UnaryMultiOutputTransform, error) { 146 tf, exists := unaryMultiOutputTransforms[t] 147 if !exists { 148 return nil, fmt.Errorf("%v is not a unary transfomration", t) 149 } 150 return tf(), nil 151 } 152 153 // MustUnaryMultiOutputTransform returns the unary transformation function associated with 154 // the transformation type if applicable, or panics otherwise. 155 func (t Type) MustUnaryMultiOutputTransform() UnaryMultiOutputTransform { 156 tf, err := t.UnaryMultiOutputTransform() 157 if err != nil { 158 panic(err) 159 } 160 return tf 161 } 162 163 // ToProto converts the transformation type to a protobuf message in place. 164 func (t Type) ToProto(pb *transformationpb.TransformationType) error { 165 if t < _minValidTransformationType || t > _maxValidTransformationType { 166 return errUnknownTransformationType 167 } 168 *pb = transformationpb.TransformationType(t) 169 return nil 170 } 171 172 // FromProto converts the protobuf message to a transformation type in place. 173 func (t *Type) FromProto(pb transformationpb.TransformationType) error { 174 *t = Type(pb) 175 if *t < _minValidTransformationType || *t > _maxValidTransformationType { 176 return errUnknownTransformationType 177 } 178 return nil 179 } 180 181 // UnmarshalText extracts this type from the textual representation 182 func (t *Type) UnmarshalText(text []byte) error { 183 parsed, err := ParseType(string(text)) 184 if err != nil { 185 return err 186 } 187 *t = parsed 188 return nil 189 } 190 191 // MarshalYAML marshals a Type. 192 func (t Type) MarshalYAML() (interface{}, error) { 193 return t.String(), nil 194 } 195 196 // UnmarshalYAML unmarshals text-encoded data into an transformation type. 197 func (t *Type) UnmarshalYAML(unmarshal func(interface{}) error) error { 198 var str string 199 if err := unmarshal(&str); err != nil { 200 return err 201 } 202 value, err := ParseType(str) 203 if err != nil { 204 return err 205 } 206 *t = value 207 return nil 208 } 209 210 // MarshalText serializes this type to its textual representation. 211 func (t Type) MarshalText() (text []byte, err error) { 212 if !t.IsValid() { 213 return nil, fmt.Errorf("invalid aggregation type %s", t.String()) 214 } 215 return []byte(t.String()), nil 216 } 217 218 // ParseType parses a transformation type. 219 func ParseType(str string) (Type, error) { 220 t, ok := typeStringMap[str] 221 if !ok { 222 return UnknownType, fmt.Errorf("invalid transformation type: %s", str) 223 } 224 return t, nil 225 } 226 227 // Op represents a transform operation. 228 type Op struct { 229 unary UnaryTransform 230 binary BinaryTransform 231 unaryMulti UnaryMultiOutputTransform 232 // opType determines which one of the above transformations are applied 233 opType Type 234 } 235 236 // Type returns the op type. 237 func (o Op) Type() Type { 238 return o.opType 239 } 240 241 // UnaryTransform returns the active unary transform if op is unary transform. 242 func (o Op) UnaryTransform() (UnaryTransform, bool) { 243 if !o.Type().IsUnaryTransform() { 244 return nil, false 245 } 246 return o.unary, true 247 } 248 249 // BinaryTransform returns the active binary transform if op is binary transform. 250 func (o Op) BinaryTransform() (BinaryTransform, bool) { 251 if !o.Type().IsBinaryTransform() { 252 return nil, false 253 } 254 return o.binary, true 255 } 256 257 // UnaryMultiOutputTransform returns the active unary multi transform if op is unary multi transform. 258 func (o Op) UnaryMultiOutputTransform() (UnaryMultiOutputTransform, bool) { 259 if !o.Type().IsUnaryMultiOutputTransform() { 260 return nil, false 261 } 262 return o.unaryMulti, true 263 } 264 265 var ( 266 unaryTransforms = map[Type]func() UnaryTransform{ 267 Absolute: transformAbsolute, 268 Add: transformAdd, 269 } 270 binaryTransforms = map[Type]func() BinaryTransform{ 271 PerSecond: transformPerSecond, 272 Increase: transformIncrease, 273 } 274 unaryMultiOutputTransforms = map[Type]func() UnaryMultiOutputTransform{ 275 Reset: transformReset, 276 } 277 typeStringMap map[string]Type 278 ) 279 280 func init() { 281 typeStringMap = make(map[string]Type) 282 for t := range unaryTransforms { 283 typeStringMap[t.String()] = t 284 } 285 for t := range binaryTransforms { 286 typeStringMap[t.String()] = t 287 } 288 for t := range unaryMultiOutputTransforms { 289 typeStringMap[t.String()] = t 290 } 291 }