Skip to main content

moddef_core/
measurand.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Measurand queries (spec §22, §26.1). A query selects points by their
4//! semantic tuple; unspecified qualifiers are wildcards, base_quantity is
5//! required. Mirrors go/client measurandMatches and moddef-ts measurand.ts.
6
7use crate::schema;
8
9/// Semantic point selector. Build with [`MeasurandQuery::base`] and narrow
10/// with the qualifier builders.
11#[derive(Clone, Copy, Debug)]
12pub struct MeasurandQuery<'a> {
13    pub base_quantity: &'a str,
14    pub direction: Option<schema::Direction>,
15    pub phase_ref: Option<schema::PhaseRef>,
16    pub aggregation: Option<schema::Aggregation>,
17    pub location: Option<schema::MeasurementLocation>,
18    pub accumulation: Option<schema::Accumulation>,
19}
20
21impl<'a> MeasurandQuery<'a> {
22    /// Query by base quantity only (all qualifiers wildcard).
23    pub fn base(base_quantity: &'a str) -> Self {
24        MeasurandQuery {
25            base_quantity,
26            direction: None,
27            phase_ref: None,
28            aggregation: None,
29            location: None,
30            accumulation: None,
31        }
32    }
33
34    pub fn direction(mut self, d: schema::Direction) -> Self {
35        self.direction = Some(d);
36        self
37    }
38
39    pub fn phase(mut self, p: schema::PhaseRef) -> Self {
40        self.phase_ref = Some(p);
41        self
42    }
43
44    pub fn aggregation(mut self, a: schema::Aggregation) -> Self {
45        self.aggregation = Some(a);
46        self
47    }
48
49    pub fn location(mut self, l: schema::MeasurementLocation) -> Self {
50        self.location = Some(l);
51        self
52    }
53
54    pub fn accumulation(mut self, a: schema::Accumulation) -> Self {
55        self.accumulation = Some(a);
56        self
57    }
58}
59
60/// Does the point's measurand tuple satisfy the query? `None` and
61/// `*_UNSPECIFIED` qualifiers are wildcards.
62pub fn measurand_matches(m: Option<&schema::MeasurandRef>, q: &MeasurandQuery<'_>) -> bool {
63    let Some(m) = m else { return false };
64    if m.base_quantity != q.base_quantity {
65        return false;
66    }
67    if let Some(d) = q.direction {
68        if d != schema::Direction::Unspecified && m.direction() != d {
69            return false;
70        }
71    }
72    if let Some(p) = q.phase_ref {
73        if p != schema::PhaseRef::Unspecified && m.phase_ref() != p {
74            return false;
75        }
76    }
77    if let Some(a) = q.aggregation {
78        if a != schema::Aggregation::Unspecified && m.aggregation() != a {
79            return false;
80        }
81    }
82    if let Some(l) = q.location {
83        if l != schema::MeasurementLocation::LocationUnspecified && m.location() != l {
84            return false;
85        }
86    }
87    if let Some(a) = q.accumulation {
88        if a != schema::Accumulation::Unspecified && m.accumulation() != a {
89            return false;
90        }
91    }
92    true
93}