1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/*! Checklists used for verifying an Entry. */ use std::collections::HashMap; use Hash; use validator::ValidatorChecklist; /// A single item within a checklist. Used by [`Checklist`]. Complete /// by passing to a schema along with the appropriate Document /// /// [`Checklist`]: ./struct.Checklist.html pub struct ChecklistItem { items: Vec<usize>, done: bool } impl ChecklistItem { fn new(items: Vec<usize>) -> Self { ChecklistItem { items, done: false } } pub fn done(&self) -> bool { self.done } pub(crate) fn get_list(&self) -> &Vec<usize> { &self.items } pub(crate) fn iter(&self) -> ::std::slice::Iter<usize> { self.items.iter() } pub(crate) fn mark_done(&mut self) { self.done = true; } } /// A Checklist for validating an Entry. /// /// The checklist can be iterated over, yielding a series of hashes and their associated /// [`ChecklistItem`]. Passing an item to a schema along with the document referred to by the hash /// allows it to be checked off the list. When all items have been checked off, calling /// [`complete`] will return the contained data. This may be a Vec<u8> from encoding an Entry, an /// Entry that was decoded, or nothihng if the purpose was purely validation. /// /// # Examples /// /// Assuming there is a HashMap containing all documents, a function to encode and verify an /// entry could be: /// /// ``` /// # use fog_pack::{Schema, Entry, Hash, Document}; /// # use std::collections::HashMap; /// # /// fn encode_entry(e: Entry, schema: &mut Schema, db: &HashMap<Hash, Document>) -> /// Result<Vec<u8>, ()> /// { /// let mut checklist = schema.encode_entry(e).or(Err(()))?; /// // Fetch each document for verification, and fail if we don't have one /// for (h, item) in checklist.iter_mut() { /// if let Some(doc) = db.get(h) { /// schema.check_item(doc, item); /// } /// else { /// return Err(()); /// } /// } /// checklist.complete() /// } /// ``` /// /// [`ChecklistItem`]: ./struct.ChecklistItem.html /// [`complete`]: #method.complete /// [`Entry`]: ../struct.Entry.html pub struct Checklist<T> { list: HashMap<Hash, ChecklistItem>, data: T, } impl<T> Checklist<T> { pub(crate) fn new(checklist: ValidatorChecklist, data: T) -> Self { let mut list = HashMap::with_capacity(checklist.len()); for v in checklist.to_map().drain() { list.insert(v.0, ChecklistItem::new(v.1)); } Self { list, data, } } /// Check to see if the checklist is ready for completion. pub fn is_complete(&self) -> bool { self.list.values().all(|x| x.done()) } /// Complete the checklist and return the encoded Entry as a byte vector. Fails if the /// checklist was not completed. pub fn complete(self) -> Result<T, ()> { if self.is_complete() { Ok(self.data) } else { Err(()) } } /// Iterate over the checklist, yielding tuples of type `(&Hash, &ChecklistItem)`. pub fn iter(&self) -> ::std::collections::hash_map::Iter<Hash, ChecklistItem> { self.list.iter() } /// Mutably iterate over the checklist, yielding tuples of type `(&Hash, &mut ChecklistItem)`. pub fn iter_mut(&mut self) -> ::std::collections::hash_map::IterMut<Hash, ChecklistItem> { self.list.iter_mut() } /// Fetch a specific checklist item by hash. pub fn get(&self, h: &Hash) -> Option<&ChecklistItem> { self.list.get(h) } /// Mutably fetch a specific checklist item by hash. pub fn get_mut(&mut self, h: &Hash) -> Option<&mut ChecklistItem> { self.list.get_mut(h) } }