use std::hash::Hash as StdHash;
use crate::identity::Author;
use crate::logs::{LogHeights, LogId, LogRanges, SeqNum, compare};
#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, StdHash)]
pub struct Cursor<A, L> {
name: String,
state: LogHeights<A, L>,
}
impl<A, L> Cursor<A, L>
where
A: Author,
L: LogId,
{
pub fn new(name: impl AsRef<str>, state: LogHeights<A, L>) -> Self {
Self {
name: name.as_ref().to_string(),
state,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn state(&self) -> &LogHeights<A, L> {
&self.state
}
pub fn log_height(&self, author: &A, log_id: &L) -> Option<&SeqNum> {
self.state.get(author).and_then(|logs| logs.get(log_id))
}
pub fn compare(&self, other: &LogHeights<A, L>) -> LogRanges<A, L> {
compare(other, &self.state)
}
pub fn advance(&mut self, author: A, log_id: L, log_height: SeqNum) {
if let Some(current_log_height) = self.log_height(&author, &log_id)
&& current_log_height >= &log_height
{
return;
}
self.state
.entry(author)
.or_default()
.insert(log_id, log_height);
}
}
#[cfg(test)]
mod tests {
use crate::logs::LogHeights;
use crate::{SigningKey, VerifyingKey};
use super::Cursor;
#[test]
fn advance_log_height() {
let author_1 = SigningKey::generate().verifying_key();
let author_2 = SigningKey::generate().verifying_key();
let mut cursor = Cursor::<VerifyingKey, u64>::new("test", LogHeights::default());
assert_eq!(cursor.name(), "test");
assert!(cursor.log_height(&author_1, &0).is_none());
assert!(cursor.log_height(&author_2, &0).is_none());
cursor.advance(author_1, 0, 23);
assert_eq!(cursor.log_height(&author_1, &0), Some(&23));
assert!(cursor.log_height(&author_2, &0).is_none());
cursor.advance(author_2, 0, 10);
cursor.advance(author_2, 1, 2);
assert_eq!(cursor.log_height(&author_1, &0), Some(&23));
assert_eq!(cursor.log_height(&author_2, &0), Some(&10));
assert_eq!(cursor.log_height(&author_2, &1), Some(&2));
}
#[test]
fn strict_monotonic_incremental() {
let author = SigningKey::generate().verifying_key();
let mut cursor = Cursor::<VerifyingKey, u64>::new("test", LogHeights::default());
cursor.advance(author, 0, 10);
cursor.advance(author, 0, 5);
assert_eq!(cursor.log_height(&author, &0), Some(&10));
}
#[test]
fn compare() {
let author = SigningKey::generate().verifying_key();
let log_id_1 = 1;
let log_id_2 = 2;
let mut cursor_1 = Cursor::<VerifyingKey, u64>::new("one", LogHeights::default());
let mut cursor_2 = Cursor::<VerifyingKey, u64>::new("two", LogHeights::default());
cursor_1.advance(author, log_id_1, 121);
cursor_1.advance(author, log_id_2, 13);
cursor_2.advance(author, log_id_1, 287);
let ranges = cursor_1.compare(cursor_2.state());
assert_eq!(
ranges.get(&author).unwrap().get(&log_id_1).unwrap(),
&(Some(121), Some(287))
);
assert!(ranges.get(&author).unwrap().get(&log_id_2).is_none());
let ranges = cursor_2.compare(cursor_1.state());
assert!(ranges.get(&author).unwrap().get(&log_id_1).is_none());
assert_eq!(
ranges.get(&author).unwrap().get(&log_id_2).unwrap(),
&(None, Some(13))
);
}
}