use crate::event::Event;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Clone)]
pub struct TrajectoryHandle {
source: TrajectorySource,
}
#[derive(Clone)]
pub enum TrajectorySource {
File(PathBuf),
InMemory(Arc<Vec<Event>>),
}
impl std::fmt::Debug for TrajectoryHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.source {
TrajectorySource::File(p) => write!(f, "TrajectoryHandle::File({})", p.display()),
TrajectorySource::InMemory(v) => {
write!(f, "TrajectoryHandle::InMemory(len={})", v.len())
}
}
}
}
impl TrajectoryHandle {
pub fn from_path(path: impl Into<PathBuf>) -> Self {
Self {
source: TrajectorySource::File(path.into()),
}
}
pub fn in_memory(events: Vec<Event>) -> Self {
Self {
source: TrajectorySource::InMemory(Arc::new(events)),
}
}
pub fn source(&self) -> &TrajectorySource {
&self.source
}
pub fn path(&self) -> Option<&std::path::Path> {
match &self.source {
TrajectorySource::File(p) => Some(p),
TrajectorySource::InMemory(_) => None,
}
}
pub fn summarize(&self) -> TrajectorySummary {
match &self.source {
TrajectorySource::File(p) => TrajectorySummary {
event_count: None,
path: Some(p.clone()),
in_memory: false,
},
TrajectorySource::InMemory(v) => TrajectorySummary {
event_count: Some(v.len()),
path: None,
in_memory: true,
},
}
}
pub fn in_memory_events(&self) -> Option<&Arc<Vec<Event>>> {
match &self.source {
TrajectorySource::InMemory(v) => Some(v),
TrajectorySource::File(_) => None,
}
}
}
impl Serialize for TrajectoryHandle {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
match &self.source {
TrajectorySource::File(p) => {
let mut m = s.serialize_map(Some(2))?;
m.serialize_entry("type", "file")?;
m.serialize_entry("path", p)?;
m.end()
}
TrajectorySource::InMemory(_) => Err(serde::ser::Error::custom(
"in-memory TrajectoryHandle cannot be serialized; materialize to a file first",
)),
}
}
}
impl<'de> Deserialize<'de> for TrajectoryHandle {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
struct Wire {
#[serde(rename = "type")]
kind: String,
path: Option<PathBuf>,
}
let w = Wire::deserialize(d)?;
match w.kind.as_str() {
"file" => {
let p = w
.path
.ok_or_else(|| serde::de::Error::custom("file trajectory missing `path`"))?;
Ok(TrajectoryHandle::from_path(p))
}
other => Err(serde::de::Error::custom(format!(
"unknown trajectory source `{other}`"
))),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrajectorySummary {
pub event_count: Option<usize>,
pub path: Option<PathBuf>,
pub in_memory: bool,
}
#[derive(Debug, thiserror::Error)]
pub enum TrajectoryError {
#[error("trajectory I/O: {0}")]
Io(#[from] std::io::Error),
#[error("trajectory JSON decode: {0}")]
Decode(#[from] serde_json::Error),
#[error("payload sidecar missing: {0}")]
PayloadNotFound(String),
#[error("unsupported trajectory source for this operation")]
Unsupported,
}