summaryrefslogtreecommitdiffstats
path: root/third_party/rust/glean/src/private/object.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/glean/src/private/object.rs')
-rw-r--r--third_party/rust/glean/src/private/object.rs192
1 files changed, 192 insertions, 0 deletions
diff --git a/third_party/rust/glean/src/private/object.rs b/third_party/rust/glean/src/private/object.rs
new file mode 100644
index 0000000000..f7403ec889
--- /dev/null
+++ b/third_party/rust/glean/src/private/object.rs
@@ -0,0 +1,192 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+use std::marker::PhantomData;
+
+use glean_core::metrics::JsonValue;
+use glean_core::traits;
+
+use crate::ErrorType;
+
+// We need to wrap the glean-core type: otherwise if we try to implement
+// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
+// only traits defined in the current crate can be implemented for arbitrary
+// types.
+
+/// Developer-facing API for recording object metrics.
+///
+/// Instances of this class type are automatically generated by the parsers
+/// at build time, allowing developers to record values that were previously
+/// registered in the metrics.yaml file.
+#[derive(Clone)]
+pub struct ObjectMetric<K> {
+ pub(crate) inner: glean_core::metrics::ObjectMetric,
+ object_type: PhantomData<K>,
+}
+
+impl<K: traits::ObjectSerialize> ObjectMetric<K> {
+ /// The public constructor used by automatically generated metrics.
+ pub fn new(meta: glean_core::CommonMetricData) -> Self {
+ let inner = glean_core::metrics::ObjectMetric::new(meta);
+ Self {
+ inner,
+ object_type: PhantomData,
+ }
+ }
+
+ /// Sets to the specified structure.
+ ///
+ /// # Arguments
+ ///
+ /// * `object` - the object to set.
+ pub fn set(&self, object: K) {
+ let obj = object
+ .into_serialized_object()
+ .expect("failed to serialize object. This should be impossible.");
+ self.inner.set(obj);
+ }
+
+ /// Sets to the specified structure.
+ ///
+ /// Parses the passed JSON string.
+ /// If it can't be parsed into a valid object it records an invalid value error.
+ ///
+ /// # Arguments
+ ///
+ /// * `object` - JSON representation of the object to set.
+ pub fn set_string(&self, object: String) {
+ let data = match K::from_str(&object) {
+ Ok(data) => data,
+ Err(_) => {
+ self.inner.record_schema_error();
+ return;
+ }
+ };
+ self.set(data)
+ }
+
+ /// **Test-only API (exported for FFI purposes).**
+ ///
+ /// Gets the currently stored value as JSON-encoded string.
+ ///
+ /// This doesn't clear the stored value.
+ pub fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<JsonValue> {
+ let ping_name = ping_name.into().map(|s| s.to_string());
+ self.inner.test_get_value(ping_name)
+ }
+
+ /// **Exported for test purposes.**
+ ///
+ /// Gets the number of recorded errors for the given metric and error type.
+ ///
+ /// # Arguments
+ ///
+ /// * `error` - The type of error
+ ///
+ /// # Returns
+ ///
+ /// The number of errors reported.
+ pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
+ self.inner.test_get_num_recorded_errors(error)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::common_test::{lock_test, new_glean};
+ use crate::CommonMetricData;
+
+ use serde_json::json;
+
+ #[test]
+ fn simple_array() {
+ let _lock = lock_test();
+ let _t = new_glean(None, true);
+
+ type SimpleArray = Vec<i64>;
+
+ let metric: ObjectMetric<SimpleArray> = ObjectMetric::new(CommonMetricData {
+ name: "object".into(),
+ category: "test".into(),
+ send_in_pings: vec!["test1".into()],
+ ..Default::default()
+ });
+
+ let arr = SimpleArray::from([1, 2, 3]);
+ metric.set(arr);
+
+ let data = metric.test_get_value(None).expect("no object recorded");
+ let expected = json!([1, 2, 3]);
+ assert_eq!(expected, data);
+ }
+
+ #[test]
+ fn complex_nested_object() {
+ let _lock = lock_test();
+ let _t = new_glean(None, true);
+
+ type BalloonsObject = Vec<BalloonsObjectItem>;
+
+ #[derive(
+ Debug, Hash, Eq, PartialEq, traits::__serde::Deserialize, traits::__serde::Serialize,
+ )]
+ #[serde(crate = "traits::__serde")]
+ #[serde(deny_unknown_fields)]
+ struct BalloonsObjectItem {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ colour: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ diameter: Option<i64>,
+ }
+
+ let metric: ObjectMetric<BalloonsObject> = ObjectMetric::new(CommonMetricData {
+ name: "object".into(),
+ category: "test".into(),
+ send_in_pings: vec!["test1".into()],
+ ..Default::default()
+ });
+
+ let balloons = BalloonsObject::from([
+ BalloonsObjectItem {
+ colour: Some("red".to_string()),
+ diameter: Some(5),
+ },
+ BalloonsObjectItem {
+ colour: Some("green".to_string()),
+ diameter: None,
+ },
+ ]);
+ metric.set(balloons);
+
+ let data = metric.test_get_value(None).expect("no object recorded");
+ let expected = json!([
+ { "colour": "red", "diameter": 5 },
+ { "colour": "green" },
+ ]);
+ assert_eq!(expected, data);
+ }
+
+ #[test]
+ fn set_string_api() {
+ let _lock = lock_test();
+ let _t = new_glean(None, true);
+
+ type SimpleArray = Vec<i64>;
+
+ let metric: ObjectMetric<SimpleArray> = ObjectMetric::new(CommonMetricData {
+ name: "object".into(),
+ category: "test".into(),
+ send_in_pings: vec!["test1".into()],
+ ..Default::default()
+ });
+
+ let arr_str = String::from("[1, 2, 3]");
+ metric.set_string(arr_str);
+
+ let data = metric.test_get_value(None).expect("no object recorded");
+ let expected = json!([1, 2, 3]);
+ assert_eq!(expected, data);
+ }
+}