aboutsummaryrefslogtreecommitdiffstats
path: root/atuin-client/src/import/mod.rs
diff options
context:
space:
mode:
authorConrad Ludgate <conradludgate@gmail.com>2022-05-09 07:46:52 +0100
committerGitHub <noreply@github.com>2022-05-09 07:46:52 +0100
commit1d030b9d32f539fd38f5ff3335234c5111c3303f (patch)
tree08619ad238362f66270919902c887c6357404bcd /atuin-client/src/import/mod.rs
parentBump clap from 3.1.15 to 3.1.16 (#392) (diff)
downloadatuin-1d030b9d32f539fd38f5ff3335234c5111c3303f.zip
Importer V3 (#395)
* start of importer refactor * fish * resh * zsh
Diffstat (limited to 'atuin-client/src/import/mod.rs')
-rw-r--r--atuin-client/src/import/mod.rs99
1 files changed, 85 insertions, 14 deletions
diff --git a/atuin-client/src/import/mod.rs b/atuin-client/src/import/mod.rs
index 8d4aa17f..07178d17 100644
--- a/atuin-client/src/import/mod.rs
+++ b/atuin-client/src/import/mod.rs
@@ -1,9 +1,8 @@
-use std::{
- io::{BufRead, BufReader, Read, Seek, SeekFrom},
- path::{Path, PathBuf},
-};
+use std::path::PathBuf;
-use eyre::Result;
+use async_trait::async_trait;
+use eyre::{bail, Result};
+use memchr::Memchr;
use crate::history::History;
@@ -12,16 +11,88 @@ pub mod fish;
pub mod resh;
pub mod zsh;
-// this could probably be sped up
-fn count_lines(buf: &mut BufReader<impl Read + Seek>) -> Result<usize> {
- let lines = buf.lines().count();
- buf.seek(SeekFrom::Start(0))?;
+#[async_trait]
+pub trait Importer: Sized {
+ const NAME: &'static str;
+ async fn new() -> Result<Self>;
+ async fn entries(&mut self) -> Result<usize>;
+ async fn load(self, loader: &mut impl Loader) -> Result<()>;
+}
- Ok(lines)
+#[async_trait]
+pub trait Loader: Sync + Send {
+ async fn push(&mut self, hist: History) -> eyre::Result<()>;
}
-pub trait Importer: IntoIterator<Item = Result<History>> + Sized {
- const NAME: &'static str;
- fn histpath() -> Result<PathBuf>;
- fn parse(path: impl AsRef<Path>) -> Result<Self>;
+fn unix_byte_lines(input: &[u8]) -> impl Iterator<Item = &[u8]> {
+ UnixByteLines {
+ iter: memchr::memchr_iter(b'\n', input),
+ bytes: input,
+ i: 0,
+ }
+}
+
+struct UnixByteLines<'a> {
+ iter: Memchr<'a>,
+ bytes: &'a [u8],
+ i: usize,
+}
+
+impl<'a> Iterator for UnixByteLines<'a> {
+ type Item = &'a [u8];
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let j = self.iter.next()?;
+ let out = &self.bytes[self.i..j];
+ self.i = j + 1;
+ Some(out)
+ }
+
+ fn count(self) -> usize
+ where
+ Self: Sized,
+ {
+ self.iter.count()
+ }
+}
+
+fn count_lines(input: &[u8]) -> usize {
+ unix_byte_lines(input).count()
+}
+
+fn get_histpath<D>(def: D) -> Result<PathBuf>
+where
+ D: FnOnce() -> Result<PathBuf>,
+{
+ if let Ok(p) = std::env::var("HISTFILE") {
+ is_file(PathBuf::from(p))
+ } else {
+ is_file(def()?)
+ }
+}
+
+fn is_file(p: PathBuf) -> Result<PathBuf> {
+ if p.is_file() {
+ Ok(p)
+ } else {
+ bail!("Could not find history file {:?}. Try setting $HISTFILE", p)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[derive(Default)]
+ pub struct TestLoader {
+ pub buf: Vec<History>,
+ }
+
+ #[async_trait]
+ impl Loader for TestLoader {
+ async fn push(&mut self, hist: History) -> Result<()> {
+ self.buf.push(hist);
+ Ok(())
+ }
+ }
}