use std::sync::Arc;
use crate::column::{Scalar, Value};
use crate::error::{PondError, Result};
use crate::query::EventKey;
use crate::series::{ColumnDef, ColumnKind};
#[derive(Debug)]
pub(crate) struct LiveSchema {
pub(crate) columns: Vec<ColumnDef>,
}
impl LiveSchema {
pub(crate) fn new(columns: Vec<ColumnDef>) -> Arc<Self> {
Arc::new(Self { columns })
}
pub(crate) fn value_index(&self, name: &str) -> Option<usize> {
self.columns[1..].iter().position(|c| c.name == name)
}
pub(crate) fn values(&self) -> &[ColumnDef] {
&self.columns[1..]
}
}
#[derive(Debug)]
struct EventData {
key: EventKey,
values: Vec<Option<Value>>,
}
#[derive(Debug, Clone)]
pub struct LiveEvent {
data: Arc<EventData>,
schema: Arc<LiveSchema>,
}
impl PartialEq for LiveEvent {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
|| (self.data.key == other.data.key && self.data.values == other.data.values)
}
}
impl LiveEvent {
pub(crate) fn new(schema: Arc<LiveSchema>, key: EventKey, values: Vec<Option<Value>>) -> Self {
Self {
data: Arc::new(EventData { key, values }),
schema,
}
}
pub(crate) fn is_shared(&self) -> bool {
Arc::strong_count(&self.data) > 1
}
pub(crate) fn into_parts(self) -> (EventKey, Vec<Option<Value>>) {
match Arc::try_unwrap(self.data) {
Ok(data) => (data.key, data.values),
Err(shared) => (shared.key.clone(), shared.values.clone()),
}
}
pub fn key(&self) -> &EventKey {
&self.data.key
}
pub fn begin(&self) -> i64 {
self.data.key.begin()
}
pub fn end(&self) -> i64 {
self.data.key.end()
}
pub fn values(&self) -> &[Option<Value>] {
&self.data.values
}
pub fn schema(&self) -> &[ColumnDef] {
&self.schema.columns
}
pub fn value(&self, name: &str) -> Result<Option<&Value>> {
let i = self.index(name)?;
Ok(self.data.values[i].as_ref())
}
pub fn number(&self, name: &str) -> Result<Option<f64>> {
match self.typed(name, ColumnKind::Number)? {
Some(Value::Number(v)) => Ok(Some(*v)),
_ => Ok(None),
}
}
pub fn string(&self, name: &str) -> Result<Option<&str>> {
match self.typed(name, ColumnKind::String)? {
Some(Value::String(v)) => Ok(Some(v)),
_ => Ok(None),
}
}
pub fn boolean(&self, name: &str) -> Result<Option<bool>> {
match self.typed(name, ColumnKind::Boolean)? {
Some(Value::Boolean(v)) => Ok(Some(*v)),
_ => Ok(None),
}
}
pub fn array(&self, name: &str) -> Result<Option<&[Scalar]>> {
match self.typed(name, ColumnKind::Array)? {
Some(Value::Array(v)) => Ok(Some(v)),
_ => Ok(None),
}
}
fn index(&self, name: &str) -> Result<usize> {
self.schema
.value_index(name)
.ok_or_else(|| PondError::UnknownColumn {
call: "LiveEvent",
column: name.to_string(),
available: self
.schema
.values()
.iter()
.map(|c| c.name.clone())
.collect(),
})
}
fn typed(&self, name: &str, want: ColumnKind) -> Result<Option<&Value>> {
let i = self.index(name)?;
let kind = self.schema.values()[i].kind;
if kind != want {
return Err(PondError::WrongKind {
call: "LiveEvent",
column: name.to_string(),
kind: kind.as_str(),
reason: format!("this is a {} column, not {}", kind.as_str(), want.as_str()),
});
}
Ok(self.data.values[i].as_ref())
}
}