Skip to content

Instantly share code, notes, and snippets.

@fxdave
Last active April 13, 2020 22:17
Show Gist options
  • Select an option

  • Save fxdave/4b4e363322e6141add00b6bb09d8eb04 to your computer and use it in GitHub Desktop.

Select an option

Save fxdave/4b4e363322e6141add00b6bb09d8eb04 to your computer and use it in GitHub Desktop.
Bulky Cached Rust File Repository
mod seri {
pub trait Deserialize {
fn deserialize(atoms: Vec<String>) -> Option<Self>
where
Self: Sized;
}
}
mod db {
use super::seri::Deserialize;
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
pub trait GenericDB {
fn find_one<D: Deserialize>(
&self,
query: impl Fn(D) -> Option<D>,
) -> Result<Option<D>, Box<dyn Error>>;
}
pub struct DB {
path: PathBuf,
}
impl DB {
pub fn new(path: &Path) -> DB {
DB {
path: path.to_owned(),
}
}
}
impl GenericDB for DB {
fn find_one<D: Deserialize>(
&self,
query: impl Fn(D) -> Option<D>,
) -> Result<Option<D>, Box<dyn Error>> {
let mut lines = BufReader::new(File::open(&self.path)?).lines();
let result: Option<D> = lines.find_map(|raw_user_res| {
raw_user_res
.ok()
.and_then(|raw_user| {
Some(raw_user.split(";").map(|atom| atom.to_owned()).collect())
})
.and_then(|atoms| D::deserialize(atoms))
.and_then(&query)
});
Ok(result)
}
}
}
mod model {
use std::error::Error;
pub trait ModelInterface: Clone {}
pub trait RepositoryInterface<M: ModelInterface> {
fn find_by_name(&mut self, name: &'static str) -> Result<Option<M>, Box<dyn Error>>;
}
}
mod cache {
pub trait Cache<T> {
fn get(&self, key: &'static str) -> Option<T>;
fn set(&mut self, key: &'static str, val: &T);
}
}
mod model_cache {
use super::cache::Cache;
use super::model::{ModelInterface, RepositoryInterface};
use std::error::Error;
use std::collections::HashMap;
pub struct ModelCacher<M> {
storage: HashMap<&'static str, M>,
}
impl<M: ModelInterface> ModelCacher<M> {
pub fn new() -> ModelCacher<M> {
ModelCacher {
storage: HashMap::new(),
}
}
}
impl<M: ModelInterface> Cache<M> for ModelCacher<M> {
fn get(&self, key: &'static str) -> Option<M> {
match self.storage.get(key) {
Some(el) => {
println!("Loaded from cache.");
Some(el.clone())
}
None => {
println!("Cache key missmatch.");
None
}
}
}
fn set(&mut self, key: &'static str, val: &M) {
self.storage.insert(key, val.clone());
}
}
pub struct CachedRepository<M: ModelInterface, R: RepositoryInterface<M>> {
pub repo: R,
pub cache: ModelCacher<M>,
}
impl<M: ModelInterface, R: RepositoryInterface<M>> CachedRepository<M, R> {
pub fn new(repo: R, cache: ModelCacher<M>) -> CachedRepository<M, R> {
CachedRepository { repo, cache }
}
}
impl<M: ModelInterface, R: RepositoryInterface<M>> RepositoryInterface<M>
for CachedRepository<M, R>
{
fn find_by_name(&mut self, name: &'static str) -> Result<Option<M>, Box<dyn Error>> {
let cached = self.cache.get(name);
match cached {
Some(val) => Ok(Some(val)),
None => {
let find = self.repo.find_by_name(name);
match find {
Ok(Some(val)) => {
self.cache.set(name, &val);
Ok(Some(val))
}
_ => find,
}
}
}
}
}
}
mod user {
use super::model::{ModelInterface, RepositoryInterface};
use super::seri::Deserialize;
#[derive(Debug, Clone)]
pub struct Model {
pub id: i32,
pub name: String,
pub email: String,
}
impl ModelInterface for Model {}
impl Deserialize for Model {
fn deserialize(atoms: Vec<String>) -> Option<Self> {
Some(Self {
id: atoms.get(0)?.parse().ok()?,
email: atoms.get(1)?.to_owned(),
name: atoms.get(2)?.to_owned(),
})
}
}
use super::db::{GenericDB, DB};
use std::error::Error;
use std::path::Path;
pub struct Repository {}
impl Repository {
pub fn new() -> Repository {
Repository {}
}
}
impl RepositoryInterface<Model> for Repository {
fn find_by_name(&mut self, name: &'static str) -> Result<Option<Model>, Box<dyn Error>> {
let userdb = DB::new(Path::new("./users.txt"));
userdb.find_one(
|user: Model| {
if user.name == name {
Some(user)
} else {
None
}
},
)
}
}
}
use model::RepositoryInterface;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut cached_user_repository = model_cache::CachedRepository::new(
user::Repository::new(),
model_cache::ModelCacher::new(),
);
match cached_user_repository.find_by_name("Nice")? {
Some(u) => println!("{:?}", u), // Cache key missmatch. Model { id: 3, name: "Nice", email: "lol@lol.hu" }
None => println!("User not found"),
}
match cached_user_repository.find_by_name("Asd")? {
Some(u) => println!("{:?}", u), // Cache key missmatch. Model { id: 1, name: "Asd", email: "lol@lol.hu" }
None => println!("User not found"),
}
match cached_user_repository.find_by_name("Nice")? {
Some(u) => println!("{:?}", u), // Loaded from cache. Model { id: 3, name: "Nice", email: "lol@lol.hu" }
None => println!("User not found"),
}
Ok(())
}
1;lol@lol.hu;Asd
2;lol@lol.hu;Lol
3;lol@lol.hu;Nice
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment