use std::fmt;
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Symbol(pub String);
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Symbol").field(&self.0).finish()
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for Symbol {
fn from(s: &str) -> Self {
Symbol(s.to_string())
}
}
impl From<String> for Symbol {
fn from(s: String) -> Self {
Symbol(s)
}
}
#[derive(Clone, PartialEq)]
pub struct RangeValue {
pub lower: Option<f64>,
pub upper: Option<f64>,
}
impl fmt::Debug for RangeValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RangeValue")
.field("lower", &self.lower)
.field("upper", &self.upper)
.finish()
}
}
impl fmt::Display for RangeValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self.lower, self.upper) {
(Some(lower), Some(upper)) => write!(f, "{}..{}", lower, upper),
(Some(lower), None) => write!(f, "{}..", lower),
(None, Some(upper)) => write!(f, "..{}", upper),
(None, None) => write!(f, ".."),
}
}
}
#[derive(Clone, PartialEq)]
pub enum Value {
VInteger(i64),
VDecimal(f64),
VBoolean(bool),
VString(String),
VSymbol(String),
VTaggedString {
tag: String,
content: String,
},
VArray(Vec<Value>),
VMap(std::collections::HashMap<String, Value>),
VRange(RangeValue),
VMeasurement {
unit: String,
value: f64,
},
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::VInteger(i) => f.debug_tuple("VInteger").field(i).finish(),
Value::VDecimal(d) => f.debug_tuple("VDecimal").field(d).finish(),
Value::VBoolean(b) => f.debug_tuple("VBoolean").field(b).finish(),
Value::VString(s) => f.debug_tuple("VString").field(s).finish(),
Value::VSymbol(s) => f.debug_tuple("VSymbol").field(s).finish(),
Value::VTaggedString { tag, content } => f
.debug_struct("VTaggedString")
.field("tag", tag)
.field("content", content)
.finish(),
Value::VArray(arr) => f.debug_list().entries(arr).finish(),
Value::VMap(map) => f.debug_map().entries(map.iter()).finish(),
Value::VRange(r) => f.debug_tuple("VRange").field(r).finish(),
Value::VMeasurement { unit, value } => f
.debug_struct("VMeasurement")
.field("unit", unit)
.field("value", value)
.finish(),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::VInteger(i) => write!(f, "{}", i),
Value::VDecimal(d) => write!(f, "{}", d),
Value::VBoolean(b) => write!(f, "{}", b),
Value::VString(s) => write!(f, "\"{}\"", s),
Value::VSymbol(s) => write!(f, "{}", s),
Value::VTaggedString { tag, content } => write!(f, "{}:{}", tag, content),
Value::VArray(arr) => {
write!(f, "[")?;
for (i, item) in arr.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
Value::VMap(map) => {
write!(f, "{{")?;
let mut first = true;
for (k, v) in map.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
write!(f, "{}: {}", k, v)?;
}
write!(f, "}}")
}
Value::VRange(r) => write!(f, "{}", r),
Value::VMeasurement { unit, value } => write!(f, "{}{}", value, unit),
}
}
}
pub type PropertyRecord = std::collections::HashMap<String, Value>;
#[derive(Clone, PartialEq)]
pub struct Subject {
pub identity: Symbol,
pub labels: std::collections::HashSet<String>,
pub properties: PropertyRecord,
}
impl fmt::Debug for Subject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Subject")
.field("identity", &self.identity)
.field("labels", &self.labels)
.field("properties", &self.properties)
.finish()
}
}
impl fmt::Display for Subject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.identity)?;
if !self.labels.is_empty() {
write!(f, ":")?;
let mut labels_vec: Vec<_> = self.labels.iter().collect();
labels_vec.sort();
for (i, label) in labels_vec.iter().enumerate() {
if i > 0 {
write!(f, "::")?;
}
write!(f, "{}", label)?;
}
}
if !self.properties.is_empty() {
write!(f, " {{")?;
let mut props_vec: Vec<_> = self.properties.iter().collect();
props_vec.sort_by_key(|(k, _)| *k);
for (i, (key, value)) in props_vec.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", key, value)?;
}
write!(f, "}}")?;
}
Ok(())
}
}
impl Subject {
pub fn from_id(identity: impl Into<String>) -> Subject {
Subject {
identity: Symbol(identity.into()),
labels: std::collections::HashSet::new(),
properties: std::collections::HashMap::new(),
}
}
pub fn build(identity: impl Into<String>) -> SubjectBuilder {
SubjectBuilder {
identity: Symbol(identity.into()),
labels: std::collections::HashSet::new(),
properties: PropertyRecord::new(),
}
}
}
pub struct SubjectBuilder {
identity: Symbol,
labels: std::collections::HashSet<String>,
properties: PropertyRecord,
}
impl SubjectBuilder {
pub fn label(mut self, label: impl Into<String>) -> Self {
self.labels.insert(label.into());
self
}
pub fn property(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
self.properties.insert(key.into(), value.into());
self
}
pub fn done(self) -> Subject {
Subject {
identity: self.identity,
labels: self.labels,
properties: self.properties,
}
}
}
impl From<SubjectBuilder> for Subject {
fn from(builder: SubjectBuilder) -> Self {
builder.done()
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::VInteger(v)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::VInteger(v as i64)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::VDecimal(v)
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::VBoolean(v)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::VString(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::VString(v.to_string())
}
}