prometheus_parser/types/expression.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
// (C) Copyright 2019-2020 Hewlett Packard Enterprise Development LP
use std::fmt;
use super::function::Function;
use super::group::Group;
use super::operator::Operator;
use super::return_value::{LabelSetOp, ReturnKind, ReturnValue};
use super::selector::Selector;
/// A root expression node.
///
/// These are all valid root expression types.
#[derive(PartialEq, Clone)]
pub enum Expression {
/// A single scalar float
Float(f64),
/// A single scalar string.
///
/// Prometheus' docs claim strings aren't currently implemented, but they're
/// valid as function arguments.
String(String),
/// A metric selector
Selector(Selector),
/// A grouped expression wrapped in parentheses
Group(Group),
/// A function call
Function(Function),
/// A binary operator expression
Operator(Operator),
}
// For handling groups when testing
impl Expression {
/// Wraps this Expression in a Group, consuming this Expression but returning
/// an owned Group.
pub fn group(self) -> Expression {
Group::new(self).wrap()
}
/// Determines a predicted `ReturnValue` for this Expression. A `ReturnValue`
/// includes a predicted data type and a set of label operations that may
/// affect which labels are returned.
pub fn return_value(&self) -> ReturnValue {
match self {
Expression::Float(_) => ReturnValue {
kind: ReturnKind::Scalar,
label_ops: vec![LabelSetOp::clear(self.clone(), None)],
},
Expression::String(_) => ReturnValue {
kind: ReturnKind::String,
label_ops: vec![LabelSetOp::clear(self.clone(), None)],
},
Expression::Selector(s) => s.return_value(),
Expression::Group(g) => g.return_value(),
Expression::Function(f) => f.return_value(),
Expression::Operator(o) => o.return_value(),
}
}
/// If this Expression is a Float, returns its value. Otherwise, returns None.
pub fn as_f64(&self) -> Option<f64> {
if let Expression::Float(f) = self {
Some(*f)
} else {
None
}
}
/// If this Expression is a String, returns its value. Otherwise, returns
/// None.
pub fn as_str(&self) -> Option<&str> {
if let Expression::String(s) = self {
Some(s.as_str())
} else {
None
}
}
}
impl fmt::Debug for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// don't bother formatting the Expression enum itself, this just creates
// tons of whitespace if we pretty-print
// this makes the output significantly more readable, if a bit misleading
// there's gotta be a better way to pass through flags...
if f.alternate() {
match self {
Expression::Float(val) => write!(f, "{:#?}", val),
Expression::String(val) => write!(f, "{:#?}", val),
Expression::Selector(val) => write!(f, "{:#?}", val),
Expression::Group(val) => write!(f, "{:#?}", val),
Expression::Function(val) => write!(f, "{:#?}", val),
Expression::Operator(val) => write!(f, "{:#?}", val),
}
} else {
match self {
Expression::Float(val) => write!(f, "{:?}", val),
Expression::String(val) => write!(f, "{:?}", val),
Expression::Selector(val) => write!(f, "{:?}", val),
Expression::Group(val) => write!(f, "{:?}", val),
Expression::Function(val) => write!(f, "{:?}", val),
Expression::Operator(val) => write!(f, "{:?}", val),
}
}
}
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expression::Float(val) => write!(f, "{}", val),
Expression::String(val) => write!(f, "{}", val),
Expression::Selector(val) => write!(f, "{}", val),
Expression::Group(val) => write!(f, "{}", val),
Expression::Function(val) => write!(f, "{}", val),
Expression::Operator(val) => write!(f, "{}", val),
}
}
}
pub type BExpression = Box<Expression>;