lsm_engine 0.1.9

A rust implementation of a key-value store using LSM trees
use serde::{Deserialize, Serialize};
#[macro_use]
use thiserror::Error;
use std::fs::File;
use serde::export::TryFrom;
use std::io::{SeekFrom, Seek, BufReader, BufRead, Write};


pub(crate) type Result<T> = std::result::Result<T, KvError>;


#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct KVPair {
    pub key: String,
    pub value: String,
}


impl TryFrom<String> for KVPair {
    type Error = KvError;

    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
        let kv_pair = serde_json::from_str::<KVPair>(&value)?;
        Ok(kv_pair)
    }
}


#[derive(Error, Debug)]
pub enum KvError {
    #[error(transparent)]
    JsonError(#[from] serde_json::error::Error),

    #[error(transparent)]
    FileIOError(#[from] std::io::Error),

}

pub trait KVFileIterator {
    fn file_as_mut(&mut self) -> &mut File;
    fn seek(&mut self, pos: u64) -> Result<()> {
        self.file_as_mut().seek(SeekFrom::Start(pos))?;
        Ok(())
    }


    fn reset(&mut self) -> Result<()> {
        self.seek(0)?;
        Ok(())
    }

    fn tell(&mut self) -> Result<u64> {
        let offset = self.file_as_mut().seek(SeekFrom::Current(0))?;
        return Ok(offset);
    }
}

pub trait KVFileReader: KVFileIterator {
    fn read(&mut self) -> Box<dyn Iterator<Item=Result<KVPair>> + '_> {
        let reader = BufReader::new(self.file_as_mut());

        return Box::new(reader.lines().map(|string| {
            KVPair::try_from(string?)
        }));
    }

    fn read_from_start(&mut self) -> Result<Box<dyn Iterator<Item=Result<KVPair>> + '_>> {
        self.seek(0)?;
        let reader = BufReader::new(self.file_as_mut());
        return Ok(Box::new(reader.lines().map(|string| {
            KVPair::try_from(string?)
        })));
    }
}

pub trait KVFileWriter: KVFileIterator {
    fn persist(&mut self, kv: KVPair) -> Result<u64> {
        let current_offset = self.tell()?;
        serde_json::to_writer(self.file_as_mut(), &kv)?;
        self.file_as_mut().write(b"\n")?;
        return Ok(current_offset);
    }
}