noodles_fasta/
repository.rs1mod adapter;
4pub mod adapters;
5
6pub use self::adapter::Adapter;
7
8use std::{
9 collections::HashMap,
10 fmt, io,
11 sync::{Arc, RwLock},
12};
13
14use super::record::Sequence;
15
16struct AdapterCache {
17 adapter: Box<dyn Adapter>,
18 cache: HashMap<Vec<u8>, Sequence>,
19}
20
21pub struct Repository(Arc<RwLock<AdapterCache>>);
23
24impl Repository {
25 pub fn new<A>(adapter: A) -> Self
27 where
28 A: Adapter + 'static,
29 {
30 Self(Arc::new(RwLock::new(AdapterCache {
31 adapter: Box::new(adapter),
32 cache: HashMap::new(),
33 })))
34 }
35
36 pub fn get(&self, name: &[u8]) -> Option<io::Result<Sequence>> {
38 {
39 let lock = self.0.read().unwrap();
40
41 if let Some(sequence) = lock.cache.get(name) {
42 return Some(Ok(sequence.clone()));
43 }
44 }
45
46 let mut lock = self.0.write().unwrap();
47
48 let record = match lock.adapter.get(name)? {
49 Ok(record) => record,
50 Err(e) => return Some(Err(e)),
51 };
52
53 lock.cache
54 .entry(name.into())
55 .or_insert_with(|| record.sequence().clone());
56
57 Some(Ok(record.sequence().clone()))
58 }
59
60 pub fn len(&self) -> usize {
62 self.0.read().unwrap().cache.len()
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.0.read().unwrap().cache.is_empty()
68 }
69
70 pub fn clear(&self) {
72 self.0.write().unwrap().cache.clear();
73 }
74}
75
76impl Clone for Repository {
77 fn clone(&self) -> Self {
78 Self(self.0.clone())
79 }
80}
81
82impl fmt::Debug for Repository {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 f.debug_struct("Repository")
85 .field("cache", &self.0.read().unwrap().cache)
86 .finish()
87 }
88}
89
90impl Default for Repository {
91 fn default() -> Self {
92 Self::new(adapters::Empty::new())
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::{
100 record::{Definition, Sequence},
101 Record,
102 };
103
104 #[test]
105 fn test_get() -> io::Result<()> {
106 let sq0 = Record::new(
107 Definition::new("sq0", None),
108 Sequence::from(b"ACGT".to_vec()),
109 );
110 let repository = Repository::new(vec![sq0.clone()]);
111
112 assert_eq!(
113 repository.get(b"sq0").transpose()?,
114 Some(sq0.sequence().clone())
115 );
116 assert_eq!(repository.get(b"sq1").transpose()?, None);
117
118 Ok(())
119 }
120}