bibliographix/
bib_manager.rs

1use crate::bibliography::bibliography_dict::BibliographyDictionary;
2use crate::bibliography::bibliography_entry::{BibliographyEntry, BibliographyEntryReference};
3use crate::bibliography::keys::K_KEY;
4use crate::bibliography::FromHashMap;
5use crate::references::anchor::BibListAnchor;
6use parking_lot::Mutex;
7use std::collections::HashMap;
8use std::io;
9use std::io::BufRead;
10use std::iter::FromIterator;
11use std::sync::Arc;
12use toml::Value;
13
14/// The root manager for that should be used for further reference operations that
15/// go beyond insertion.
16#[derive(Clone, Debug)]
17pub struct BibManager {
18    root_ref_anchor: Arc<Mutex<BibListAnchor>>,
19    entry_dictionary: Arc<Mutex<BibliographyDictionary>>,
20}
21
22impl BibManager {
23    /// Creates a new BibRefManager with an empty root anchor
24    pub fn new() -> Self {
25        Self {
26            root_ref_anchor: Arc::new(Mutex::new(BibListAnchor::new())),
27            entry_dictionary: Arc::new(Mutex::new(BibliographyDictionary::new())),
28        }
29    }
30
31    /// Returns the BibRefManagers root anchor that.
32    pub fn root_ref_anchor(&self) -> Arc<Mutex<BibListAnchor>> {
33        Arc::clone(&self.root_ref_anchor)
34    }
35
36    /// Creates a new child BibManager with a child anchor and the parents entry dict
37    pub fn create_child(&self) -> BibManager {
38        let anchor = self.root_ref_anchor.lock().create_anchor();
39        let entry_dict = Arc::clone(&self.entry_dictionary);
40
41        Self {
42            entry_dictionary: entry_dict,
43            root_ref_anchor: anchor,
44        }
45    }
46
47    /// Returns the reference to the entry dictionary
48    pub fn entry_dictionary(&self) -> Arc<Mutex<BibliographyDictionary>> {
49        Arc::clone(&self.entry_dictionary)
50    }
51
52    /// Assigns the corresponding bib entry to each bib reference
53    pub fn assign_entries_to_references(&self) {
54        let entry_dict = self.entry_dictionary.lock();
55        let mut root_anchor = self.root_ref_anchor.lock();
56        root_anchor.flatten();
57        let entries = root_anchor.references();
58        entries.iter().for_each(|e| {
59            if let Some(bib) = entry_dict.get(e.key()) {
60                e.anchor().lock().entry = Some(bib)
61            }
62        })
63    }
64
65    /// Returns the list of bibliography entries ordered by first referenced
66    pub fn get_entry_list_by_occurrence(&self) -> Vec<BibliographyEntryReference> {
67        let mut entries = Vec::new();
68        let mut inserted_keys = Vec::new();
69        let entry_dict = self.entry_dictionary.lock();
70
71        for bib_ref in self.root_ref_anchor.lock().references() {
72            if let Some(bib_entry) = entry_dict.get(bib_ref.key()) {
73                if !inserted_keys.contains(bib_ref.key()) {
74                    entries.push(bib_entry);
75                    inserted_keys.push(bib_ref.key().clone())
76                }
77            }
78        }
79
80        entries
81    }
82
83    /// Reads a toml bibliography file and inserts each entry into the dictionary
84    pub fn read_bib_file(&self, reader: &mut impl BufRead) -> io::Result<()> {
85        let mut contents = String::new();
86        reader.read_to_string(&mut contents)?;
87        let bib_content = contents.parse::<Value>()?;
88        let mut entry_dict = self.entry_dictionary.lock();
89
90        if let Some(table) = bib_content.as_table() {
91            let mut entries = table
92                .iter()
93                .filter_map(|(k, v)| {
94                    let entry_iter = v
95                        .as_table()?
96                        .iter()
97                        .filter_map(|(k, v)| Some((k.clone(), v.as_str()?.to_string())));
98
99                    let mut entry_map: HashMap<String, String> = HashMap::from_iter(entry_iter);
100
101                    entry_map.insert(K_KEY.to_string(), k.clone());
102
103                    Some(*BibliographyEntry::from_hash_map(&entry_map).ok()?)
104                })
105                .collect::<Vec<BibliographyEntry>>();
106
107            while let Some(entry) = entries.pop() {
108                entry_dict.insert(entry)
109            }
110        }
111
112        Ok(())
113    }
114}