aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-10-27 08:07:09 -0400
committerJesse Luehrs <doy@tozt.net>2019-10-27 08:07:09 -0400
commit17fc6b3eda370f99fee48420532ada8b497ecd8c (patch)
treecf8067dc80e700bf3056e22e86942e13e4fd3795
parent9739318498f8b78788923986d77a7b436d6af12a (diff)
downloadttyrec-17fc6b3eda370f99fee48420532ada8b497ecd8c.tar.gz
ttyrec-17fc6b3eda370f99fee48420532ada8b497ecd8c.zip
docs
-rw-r--r--src/creator.rs17
-rw-r--r--src/error.rs8
-rw-r--r--src/frame.rs13
-rw-r--r--src/lib.rs6
-rw-r--r--src/parser.rs14
-rw-r--r--src/reader.rs8
-rw-r--r--src/writer.rs23
7 files changed, 89 insertions, 0 deletions
diff --git a/src/creator.rs b/src/creator.rs
index fb228dd..c0f9b76 100644
--- a/src/creator.rs
+++ b/src/creator.rs
@@ -1,17 +1,34 @@
+/// Creates ttyrec frames.
+///
+/// A ttyrec file is a stream of concatenated frames. This struct creates
+/// `Frame` objects, which can be serialized to bytes using their `try_from`
+/// implementation, and then a ttyrec file can be generated by concatenating
+/// those byte strings.
#[derive(Debug, Clone)]
pub struct Creator {
base_time: Option<std::time::Instant>,
}
impl Creator {
+ /// Creates a new `Creator` instance.
pub fn new() -> Self {
Default::default()
}
+ /// Returns a new `Frame` object containing the given data.
+ ///
+ /// Equivalent to calling `frame_at` and passing
+ /// `std::time::Instant::now()` as the `cur_time` parameter.
pub fn frame(&mut self, data: &[u8]) -> crate::frame::Frame {
self.frame_at(std::time::Instant::now(), data)
}
+ /// Returns a new `Frame` object containing the given data at the given
+ /// time.
+ ///
+ /// Note that this is not guaranteed to do the correct thing unless the
+ /// `cur_time` parameters given in each `frame_at` call are
+ /// non-decreasing.
pub fn frame_at(
&mut self,
cur_time: std::time::Instant,
diff --git a/src/error.rs b/src/error.rs
index aa315e6..975889b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,18 +1,26 @@
+/// Errors potentially returned by this crate.
#[derive(Debug, snafu::Snafu)]
#[snafu(visibility(pub))]
pub enum Error {
+ /// eof
#[snafu(display("eof"))]
EOF,
+ /// failed to create ttyrec frame: got N bytes of data but ttyrec frames
+ /// can be at most M bytes
#[snafu(display("failed to create ttyrec frame: got {} bytes of data, but ttyrec frames can be at most {} bytes", input, u32::max_value()))]
FrameTooBig { input: usize },
+ /// failed to create ttyrec frame: got N seconds but ttyrec frames can be
+ /// at most M seconds
#[snafu(display("failed to create ttyrec frame: got {} seconds, but ttyrecs can be at most {} seconds", input, u32::max_value()))]
FrameTooLong { input: u64 },
+ /// failed to read from file
#[snafu(display("failed to read from file: {}", source))]
ReadFile { source: tokio::io::Error },
+ /// failed to write to file
#[snafu(display("failed to write to file: {}", source))]
WriteFile { source: tokio::io::Error },
}
diff --git a/src/frame.rs b/src/frame.rs
index 7558470..17c6c5a 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -1,6 +1,19 @@
+/// Represents a single ttyrec frame.
+///
+/// Ttyrec files are a raw concatenation of frames. Note that the `time` field
+/// in each frame is the time since the start of the entire file, and it is
+/// invalid for the `time` fields in a ttyrec file to be decreasing.
+///
+/// Frame objects are typically created via the `Creator`, `Parser`, or
+/// `Reader` classes.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Frame {
+ /// Amount of time passed since the start of the ttyrec file.
+ ///
+ /// Note that this is *not* the amount of time since the previous frame.
pub time: std::time::Duration,
+
+ /// Bytes emitted at the given time.
pub data: Vec<u8>,
}
diff --git a/src/lib.rs b/src/lib.rs
index 7324edd..1de8daa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,9 @@
+//! This crate contains helpers for reading and writing
+//! [ttyrec](https://en.wikipedia.org/wiki/Ttyrec) files.
+//!
+//! `Parser` and `Creator` can be used to read and write files manually, and
+//! `Reader` and `Writer` are helpers to provide a nicer API for asynchronous
+//! applications using `tokio`.
mod creator;
pub use creator::Creator;
mod error;
diff --git a/src/parser.rs b/src/parser.rs
index d3c3861..a473931 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -18,6 +18,13 @@ impl Header {
}
}
+/// Parses ttyrec streams.
+///
+/// Designed to be able to be used in a streaming/asynchronous fashion. As you
+/// read bytes from the ttyrec stream (whether from a file or whatever else),
+/// call the `add_bytes` method to add them to the internal buffer. At any
+/// point, you can call `next_frame` to then return the next complete frame if
+/// one has been read.
#[derive(Debug, Clone)]
pub struct Parser {
reading: std::collections::VecDeque<u8>,
@@ -25,14 +32,21 @@ pub struct Parser {
}
impl Parser {
+ /// Create a new `Parser`.
pub fn new() -> Self {
Default::default()
}
+ /// Add more bytes to the internal buffer.
pub fn add_bytes(&mut self, bytes: &[u8]) {
self.reading.extend(bytes.iter());
}
+ /// Try to read a frame from the internal buffer.
+ ///
+ /// If a complete frame is found, the bytes for that frame will be removed
+ /// from the internal buffer and the frame object will be returned. If a
+ /// complete frame is not found, this method will return `None`.
pub fn next_frame(&mut self) -> Option<crate::frame::Frame> {
let header = if let Some(header) = &self.read_state {
header
diff --git a/src/reader.rs b/src/reader.rs
index 4d122f9..fd87cd5 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -1,5 +1,6 @@
use snafu::ResultExt as _;
+/// Reads ttyrec frames from a `tokio::io::AsyncRead` instance.
pub struct Reader<R> {
reader: R,
parser: crate::parser::Parser,
@@ -8,6 +9,7 @@ pub struct Reader<R> {
}
impl<R: tokio::io::AsyncRead> Reader<R> {
+ /// Creates a new `Reader` from a `tokio::io::AsyncRead` instance.
pub fn new(reader: R) -> Self {
Self {
reader,
@@ -17,6 +19,12 @@ impl<R: tokio::io::AsyncRead> Reader<R> {
}
}
+ /// Polls to see if a new frame can be read.
+ ///
+ /// Returns `Ok(Async::Ready(Some(frame)))` if a frame is available,
+ /// `Ok(Async::Ready(None))` if the underlying reader is done, and
+ /// `Ok(Async::NotReady)` if not enough bytes have been read for a full
+ /// frame.
pub fn poll_read(
&mut self,
) -> futures::Poll<Option<crate::frame::Frame>, crate::error::Error> {
diff --git a/src/writer.rs b/src/writer.rs
index 109aba9..8f79737 100644
--- a/src/writer.rs
+++ b/src/writer.rs
@@ -1,5 +1,6 @@
use snafu::ResultExt as _;
+/// Writes ttyrec frames to a `tokio::io::AsyncWrite` instance.
pub struct Writer<W> {
writer: W,
creator: crate::creator::Creator,
@@ -7,6 +8,7 @@ pub struct Writer<W> {
}
impl<W: tokio::io::AsyncWrite> Writer<W> {
+ /// Creates a new `Writer` from a `tokio::io::AsyncWrite` instance.
pub fn new(writer: W) -> Self {
Self {
writer,
@@ -15,10 +17,22 @@ impl<W: tokio::io::AsyncWrite> Writer<W> {
}
}
+ /// Generates a new ttyrec frame with the given data.
+ ///
+ /// Equivalent to calling `frame_at` and passing
+ /// `std::time::Instant::now()` as the `time` parameter.
pub fn frame(&mut self, data: &[u8]) -> crate::error::Result<()> {
self.frame_at(std::time::Instant::now(), data)
}
+ /// Generates a new ttyrec frame with the given data at the given time.
+ ///
+ /// The frame data will be stored on this object until written out by
+ /// calls to `poll_write`.
+ ///
+ /// Note that this is not guaranteed to do the correct thing unless the
+ /// `cur_time` parameters given in each `frame_at` call are
+ /// non-decreasing.
pub fn frame_at(
&mut self,
time: std::time::Instant,
@@ -30,6 +44,11 @@ impl<W: tokio::io::AsyncWrite> Writer<W> {
Ok(())
}
+ /// Attempt to write serialized ttyrec frames to the underlying writer.
+ ///
+ /// Writes data from the previous calls to `frame` and `frame_at`. Returns
+ /// `Ok(Async::Ready(()))` if all bytes were written, and
+ /// `Ok(Async::NotReady)` otherwise.
pub fn poll_write(&mut self) -> futures::Poll<(), crate::error::Error> {
loop {
if self.to_write.is_empty() {
@@ -54,6 +73,10 @@ impl<W: tokio::io::AsyncWrite> Writer<W> {
}
}
+ /// Returns `true` if there are still bytes that need to be written.
+ ///
+ /// It is only necessary to call `poll_write` if this method returns
+ /// `true`.
pub fn needs_write(&self) -> bool {
!self.to_write.is_empty()
}