use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use std::collections::VecDeque;
use std::io::Write;
use libsail::collection::{Indexable, Iterable};
use libsail::index::Reader;
use crate::cli::{FormatArg, ReadArgs};
use crate::input::{Backend, Inputs, Needs, dispatch};
use crate::output::{emit, write_framed, writer};
#[derive(Args)]
pub struct TailArgs {
#[arg(default_value = "-")]
pub input: PathBuf,
#[arg(short = 'n', long, default_value_t = 10)]
pub count: usize,
#[arg(long, value_enum)]
pub format: Option<FormatArg>,
#[arg(short, long)]
pub output: Option<PathBuf>,
#[command(flatten)]
pub read: ReadArgs,
}
impl TailArgs {
pub fn run(self) -> Result<()> {
let inputs = Inputs::plan(
std::slice::from_ref(&self.input),
self.format,
self.read,
Needs::Count,
)?;
let entry = &inputs.entries()[0];
let out = writer(self.output.as_deref())?;
let count = self.count;
match inputs.backend() {
Backend::Stream | Backend::Indexed => {
let mut reader = Reader::new(entry.reader()?, inputs.format());
let mut last: VecDeque<Vec<u8>> = VecDeque::new();
let mut out = out;
while reader.advance()? {
if count == 0 {
continue;
}
if last.len() == count {
last.pop_front();
}
last.push_back(reader.record().to_vec());
}
for record in &last {
write_framed(inputs.format(), record, &mut out)?;
}
out.flush()?;
Ok(())
}
Backend::Memory => {
dispatch!(inputs.format(), entry, |collection, _size, _name, write| {
let skip = collection.len().saturating_sub(count);
emit(collection.skip(skip).iter(), write, out)
})
}
}
}
}