blob: 8a605c52205fbe562c0f0249e7afd6dbb45cac7a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fidl_fuchsia_inspect::{Metric, MetricValue, Object, Property, PropertyValue};
pub trait ObjectUtil {
fn new(name: String) -> Self;
fn clone(&self) -> Self;
fn add_property(&mut self, prop: Property) -> Option<Property>;
fn get_property(&self, key: &str) -> Option<&Property>;
fn get_property_mut(&mut self, key: &str) -> Option<&mut Property>;
fn remove_property(&mut self, key: &str) -> Option<Property>;
fn add_metric(&mut self, metric: Metric) -> Option<Metric>;
fn get_metric(&self, key: &str) -> Option<&Metric>;
fn get_metric_mut(&mut self, key: &str) -> Option<&mut Metric>;
fn remove_metric(&mut self, key: &str) -> Option<Metric>;
}
impl ObjectUtil for Object {
/// Creates a new Object with the given name and no properties or metrics.
fn new(name: String) -> Object {
Object {
name,
properties: None,
metrics: None,
}
}
/// clone will create a copy of the given Object. This is necessary because
/// fidl-generated structs don't derive the Clone trait.
fn clone(&self) -> Object {
let name = self.name.clone();
let mut properties = None;
let mut metrics = None;
if let Some(ps) = &self.properties {
let mut pvec = Vec::new();
for p in ps {
pvec.push(Property {
key: p.key.clone(),
value: match &p.value {
PropertyValue::Str(s) => PropertyValue::Str(s.clone()),
PropertyValue::Bytes(b) => PropertyValue::Bytes(b.clone()),
},
});
}
properties = Some(pvec);
}
if let Some(ms) = &self.metrics {
let mut mvec = Vec::new();
for m in ms {
mvec.push(Metric {
key: m.key.clone(),
value: match m.value {
MetricValue::IntValue(n) => MetricValue::IntValue(n),
MetricValue::UintValue(n) => MetricValue::UintValue(n),
MetricValue::DoubleValue(n) => MetricValue::DoubleValue(n),
},
});
}
metrics = Some(mvec);
}
Object {
name,
properties,
metrics,
}
}
/// Adds the given property to the given Object. If a property with this key already exists, it is
/// replaced and the old value is returned.
fn add_property(&mut self, prop: Property) -> Option<Property> {
let properties = self.properties.get_or_insert(Vec::new());
if let Some(i) = properties
.iter()
.position(|old_prop| old_prop.key == prop.key)
{
properties.push(prop);
Some(properties.swap_remove(i))
} else {
properties.push(prop);
None
}
}
/// Gets a reference to the property with the given key on the given Object.
fn get_property(&self, key: &str) -> Option<&Property> {
if let Some(properties) = &self.properties {
if let Some(i) = properties.iter().position(|prop| prop.key == key) {
return Some(&properties[i]);
}
}
None
}
/// Gets a mutable reference to the property with the given key on the given Object.
fn get_property_mut(&mut self, key: &str) -> Option<&mut Property> {
if let Some(properties) = &mut self.properties {
if let Some(i) = properties.iter().position(|prop| prop.key == key) {
return Some(&mut properties[i]);
}
}
None
}
/// Removes the property with the given key from the given Object. Returns the removed value if it
/// existed.
fn remove_property(&mut self, key: &str) -> Option<Property> {
if let Some(properties) = &mut self.properties {
if let Some(i) = properties.iter().position(|prop| prop.key == key) {
return Some(properties.remove(i));
}
}
None
}
/// Adds the given metric to the given Object. If a metric with this key already exists, it is
/// replaced and the old value is returned.
fn add_metric(&mut self, metric: Metric) -> Option<Metric> {
let metrics = self.metrics.get_or_insert(Vec::new());
if let Some(i) = metrics
.iter()
.position(|old_metric| old_metric.key == metric.key)
{
metrics.push(metric);
Some(metrics.swap_remove(i))
} else {
metrics.push(metric);
None
}
}
/// Gets a reference to the metric with the given key on the given Object
fn get_metric(&self, key: &str) -> Option<&Metric> {
if let Some(metrics) = &self.metrics {
if let Some(i) = metrics.iter().position(|metric| metric.key == key) {
return Some(&metrics[i]);
}
}
None
}
/// Gets a mutable reference to the metric with the given key on the given Object.
fn get_metric_mut(&mut self, key: &str) -> Option<&mut Metric> {
if let Some(metrics) = &mut self.metrics {
if let Some(i) = metrics.iter().position(|metric| metric.key == key) {
return Some(&mut metrics[i]);
}
}
None
}
/// Removes the metric with the given key on the given Object. Returns the removed value if it
/// existed.
fn remove_metric(&mut self, key: &str) -> Option<Metric> {
if let Some(metrics) = &mut self.metrics {
if let Some(i) = metrics.iter().position(|metric| metric.key == key) {
return Some(metrics.remove(i));
}
}
None
}
}
pub trait PropertyValueUtil {
fn clone(&self) -> Self;
}
impl PropertyValueUtil for PropertyValue {
fn clone(&self) -> PropertyValue {
match &self {
PropertyValue::Str(s) => PropertyValue::Str(s.clone()),
PropertyValue::Bytes(b) => PropertyValue::Bytes(b.clone()),
}
}
}
pub trait MetricValueUtil {
fn clone(&self) -> Self;
}
impl MetricValueUtil for MetricValue {
fn clone(&self) -> MetricValue {
match &self {
MetricValue::IntValue(n) => MetricValue::IntValue(*n),
MetricValue::UintValue(n) => MetricValue::UintValue(*n),
MetricValue::DoubleValue(n) => MetricValue::DoubleValue(*n),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_test() {
assert_eq!(
Object::new("test".to_string()),
Object {
name: "test".to_string(),
properties: None,
metrics: None,
}
);
}
#[test]
fn clone_test() {
let original = Object {
name: "test".to_string(),
properties: Some(vec![
Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
},
Property {
key: "prop1".to_string(),
value: PropertyValue::Bytes(vec![0x00, 0x01, 0x02]),
},
]),
metrics: Some(vec![
Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
},
Metric {
key: "metric1".to_string(),
value: MetricValue::UintValue(1),
},
Metric {
key: "metric2".to_string(),
value: MetricValue::DoubleValue(2.0),
},
]),
};
let cloned = original.clone();
assert_eq!(original, cloned);
}
#[test]
fn add_property_test() {
let mut obj = Object::new("test".to_string());
obj.add_property(Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
});
assert_eq!(
obj.properties.as_ref().unwrap(),
&vec![Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
},]
);
obj.add_property(Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
});
assert_eq!(
obj.properties.unwrap(),
vec![
Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
},
Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
},
]
);
}
#[test]
fn get_property_test() {
let mut obj = Object::new("test".to_string());
obj.add_property(Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
});
obj.add_property(Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
});
assert!(obj.get_property("prop0").is_some());
assert_eq!(
obj.get_property("prop0").unwrap(),
&Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
}
);
assert!(obj.get_property("prop1").is_some());
assert_eq!(
obj.get_property("prop1").unwrap(),
&Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
}
);
}
#[test]
fn get_property_mut_test() {
let mut obj = Object::new("test".to_string());
obj.add_property(Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
});
assert!(obj.get_property_mut("prop0").is_some());
obj.get_property_mut("prop0").unwrap().key = "prop1".to_string();
assert_eq!(
obj.get_property("prop1").unwrap(),
&Property {
key: "prop1".to_string(),
value: PropertyValue::Str("string value".to_string()),
}
);
}
#[test]
fn remove_property_test() {
let mut obj = Object::new("test".to_string());
obj.add_property(Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
});
obj.add_property(Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
});
assert_eq!(None, obj.remove_property("prop-1"));
assert_eq!(
Some(Property {
key: "prop0".to_string(),
value: PropertyValue::Str("string value".to_string()),
}),
obj.remove_property("prop0")
);
assert_eq!(None, obj.remove_property("prop0"));
assert_eq!(
Some(Property {
key: "prop1".to_string(),
value: PropertyValue::Str("another string value".to_string()),
}),
obj.remove_property("prop1")
);
assert_eq!(None, obj.remove_property("prop1"));
}
#[test]
fn add_metric_test() {
let mut obj = Object::new("test".to_string());
obj.add_metric(Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
});
assert_eq!(
obj.metrics.as_ref().unwrap(),
&vec![Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
},]
);
obj.add_metric(Metric {
key: "metric1".to_string(),
value: MetricValue::DoubleValue(3.14),
});
assert_eq!(
obj.metrics.unwrap(),
vec![
Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
},
Metric {
key: "metric1".to_string(),
value: MetricValue::DoubleValue(3.14),
},
]
);
}
#[test]
fn get_metric_test() {
let mut obj = Object::new("test".to_string());
obj.add_metric(Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
});
obj.add_metric(Metric {
key: "metric1".to_string(),
value: MetricValue::DoubleValue(3.14),
});
assert!(obj.get_metric("metric0").is_some());
assert_eq!(
obj.get_metric("metric0").unwrap(),
&Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
}
);
assert!(obj.get_metric("metric1").is_some());
assert_eq!(
obj.get_metric("metric1").unwrap(),
&Metric {
key: "metric1".to_string(),
value: MetricValue::DoubleValue(3.14),
}
);
}
#[test]
fn get_metric_mut_test() {
let mut obj = Object::new("test".to_string());
obj.add_metric(Metric {
key: "metric0".to_string(),
value: MetricValue::IntValue(0),
});
assert!(obj.get_metric_mut("metric0").is_some());
obj.get_metric_mut("metric0").unwrap().key = "metric1".to_string();
assert_eq!(
obj.get_metric("metric1").unwrap(),
&Metric {
key: "metric1".to_string(),
value: MetricValue::IntValue(0),
}
);
}
#[test]
fn remove_metric_test() {
let mut obj = Object::new("test".to_string());
obj.add_metric(Metric {
key: "metric0".to_string(),
value: MetricValue::UintValue(0),
});
obj.add_metric(Metric {
key: "metric1".to_string(),
value: MetricValue::IntValue(-1),
});
assert_eq!(None, obj.remove_metric("metric-1"));
assert_eq!(
Some(Metric {
key: "metric0".to_string(),
value: MetricValue::UintValue(0),
}),
obj.remove_metric("metric0")
);
assert_eq!(None, obj.remove_metric("metric0"));
assert_eq!(
Some(Metric {
key: "metric1".to_string(),
value: MetricValue::IntValue(-1),
}),
obj.remove_metric("metric1")
);
assert_eq!(None, obj.remove_metric("metric1"));
}
}