relay_profiling/
measurements.rs

1use serde::{Deserialize, Serialize};
2
3use crate::utils::deserialize_number_from_string;
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct LegacyMeasurement {
7    unit: MeasurementUnit,
8    values: Vec<LegacyMeasurementValue>,
9}
10
11#[derive(Debug, Serialize, Deserialize, Clone)]
12pub struct ChunkMeasurement {
13    unit: MeasurementUnit,
14    values: Vec<ChunkMeasurementValue>,
15}
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
18pub struct LegacyMeasurementValue {
19    // nanoseconds elapsed since the start of the profile
20    #[serde(deserialize_with = "deserialize_number_from_string")]
21    elapsed_since_start_ns: u64,
22
23    // Android 6.8.0 sends a string instead of a float64 so we need to accept both
24    #[serde(deserialize_with = "deserialize_number_from_string")]
25    value: f64,
26}
27
28#[derive(Debug, Serialize, Deserialize, Clone)]
29pub struct ChunkMeasurementValue {
30    // UNIX timestamp in seconds as a float
31    timestamp: f64,
32
33    #[serde(deserialize_with = "deserialize_number_from_string")]
34    value: f64,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39pub enum MeasurementUnit {
40    #[serde(alias = "ns")]
41    Nanosecond,
42    #[serde(alias = "hz")]
43    Hertz,
44    Byte,
45    Percent,
46    #[serde(alias = "nj")]
47    Nanojoule,
48}
49
50#[cfg(test)]
51mod tests {
52    use super::{ChunkMeasurementValue, LegacyMeasurementValue};
53
54    #[test]
55    fn test_roundtrip() {
56        let raw_value = r#"{"elapsed_since_start_ns":1234567890,"value":1234.56789}"#;
57        let parsed_value = serde_json::from_str::<LegacyMeasurementValue>(raw_value);
58        assert!(parsed_value.is_ok());
59        let value = parsed_value.unwrap();
60        let encoded_value = serde_json::to_string(&value).unwrap();
61        assert_eq!(encoded_value, raw_value);
62    }
63
64    #[test]
65    fn test_value_as_float() {
66        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":1234.56789}"#;
67        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
68        assert!(measurement.is_ok());
69        assert_eq!(measurement.unwrap().value, 1234.56789);
70    }
71
72    #[test]
73    fn test_value_as_string() {
74        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":"1234.56789"}"#;
75        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
76        assert!(measurement.is_ok());
77        assert_eq!(measurement.unwrap().value, 1234.56789);
78    }
79
80    #[test]
81    fn test_value_as_string_scientific_notation() {
82        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":"1e3"}"#;
83        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
84        assert!(measurement.is_ok());
85        assert_eq!(measurement.unwrap().value, 1e3f64);
86    }
87
88    #[test]
89    fn test_value_as_string_infinity() {
90        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":"+Infinity"}"#;
91        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
92        assert!(measurement.is_ok());
93        assert_eq!(measurement.unwrap().value, f64::INFINITY);
94    }
95
96    #[test]
97    fn test_value_as_float_scientific_notation() {
98        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":1e3}"#;
99        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
100        assert!(measurement.is_ok());
101        assert_eq!(measurement.unwrap().value, 1e3f64);
102    }
103
104    #[test]
105    fn test_value_as_float_infinity() {
106        let measurement_json = r#"{"elapsed_since_start_ns":1234567890,"value":+Infinity}"#;
107        let measurement = serde_json::from_str::<LegacyMeasurementValue>(measurement_json);
108        assert!(measurement.is_err());
109    }
110
111    #[test]
112    fn test_with_timestamp_only() {
113        let measurement_json = r#"{"timestamp":1717161756.408,"value":10.3}"#;
114        let measurement = serde_json::from_str::<ChunkMeasurementValue>(measurement_json);
115        assert!(measurement.is_ok());
116        assert_eq!(measurement.unwrap().value, 10.3);
117    }
118}