#![doc = include_str!("../README.md")]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
use std::{
fs::File,
io::{BufRead, BufReader, Cursor, Read},
path::Path,
};
use serde::Deserialize;
mod error;
mod reader;
mod versions;
pub use error::Error;
pub use reader::Reader;
pub use versions::{Streamable, V1, V2, V3, Version, common, v1, v2, v3};
#[derive(Debug, Clone, PartialEq)]
pub struct Asciicast<V: Version> {
pub header: V::Header,
pub events: Vec<V::Event>,
}
impl<V: Version> Asciicast<V> {
pub fn from_reader<R: BufRead>(reader: R) -> Result<Self, Error> {
V::parse(reader)
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
V::parse(bytes)
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
V::parse(BufReader::new(File::open(path)?))
}
pub fn absolute_times(&self) -> impl Iterator<Item = (f64, &V::Event)> {
self.events.iter().scan(0.0_f64, |elapsed, event| {
let raw = V::event_time(event);
let absolute = if V::RELATIVE_TIMING {
*elapsed += raw;
*elapsed
} else {
raw
};
Some((absolute, event))
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum AsciicastVersioned {
V1(Asciicast<V1>),
V2(Asciicast<V2>),
V3(Asciicast<V3>),
}
impl AsciicastVersioned {
pub fn from_reader<R: BufRead>(mut reader: R) -> Result<Self, Error> {
#[derive(Deserialize)]
struct VersionProbe {
version: u8,
}
let mut first_line = String::new();
reader.read_line(&mut first_line)?;
let version = serde_json::from_str::<VersionProbe>(&first_line)
.ok()
.map(|probe| probe.version);
let combined = BufReader::new(Cursor::new(first_line.into_bytes()).chain(reader));
match version {
None | Some(1) => Asciicast::<V1>::from_reader(combined).map(Self::V1),
Some(2) => Asciicast::<V2>::from_reader(combined).map(Self::V2),
Some(3) => Asciicast::<V3>::from_reader(combined).map(Self::V3),
Some(other) => Err(Error::UnknownVersion(other)),
}
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
Self::from_reader(bytes)
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
Self::from_reader(BufReader::new(File::open(path)?))
}
}
pub mod prelude {
pub use crate::versions::{V1, V2, V3, Version};
pub use crate::{Asciicast, AsciicastVersioned, Error};
}