use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ComplexRecord {
pub fields: Vec<ComplexField>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ComplexField {
pub name: String,
pub value: FieldValue,
}
impl ComplexRecord {
pub fn field(&self, name: &str) -> Option<&FieldValue> {
self.fields
.iter()
.find(|field| field.name == name)
.map(|field| &field.value)
}
pub fn scalar(&self) -> Option<&FieldValue> {
for preferred in ["Value", "FileName"] {
if let Some(value) = self.field(preferred) {
return Some(value);
}
}
self.fields
.iter()
.find(|field| !matches!(field.value, FieldValue::Binary(_)))
.map(|field| &field.value)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FieldValue {
Null,
Boolean(bool),
Integer(i64),
Float(f64),
Currency(i64),
DateTime(f64),
Decimal(i128),
Text(String),
Binary(Vec<u8>),
Guid([u8; 16]),
Complex(Vec<ComplexRecord>),
}
impl FieldValue {
pub fn family(&self) -> &'static str {
match self {
Self::Null => "null",
Self::Boolean(_) => "boolean",
Self::Integer(_) => "integer",
Self::Float(_) => "float",
Self::Currency(_) => "currency",
Self::DateTime(_) => "date/time",
Self::Decimal(_) => "decimal",
Self::Text(_) => "text",
Self::Binary(_) => "binary",
Self::Guid(_) => "guid",
Self::Complex(_) => "complex",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn family_names_cover_every_variant() {
let cases: [(FieldValue, &str); 11] = [
(FieldValue::Null, "null"),
(FieldValue::Boolean(true), "boolean"),
(FieldValue::Integer(1), "integer"),
(FieldValue::Float(1.0), "float"),
(FieldValue::Currency(1), "currency"),
(FieldValue::DateTime(1.0), "date/time"),
(FieldValue::Decimal(1), "decimal"),
(FieldValue::Text("t".into()), "text"),
(FieldValue::Binary(vec![]), "binary"),
(FieldValue::Guid([0; 16]), "guid"),
(FieldValue::Complex(vec![]), "complex"),
];
for (value, family) in cases {
assert_eq!(value.family(), family, "family of {value:?}");
}
}
}