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>;