use std::collections::BTreeSet;
#[cfg(doc)]
use super::SyncDoc;
use super::{encode_hashes, BloomFilter, Capability};
use crate::storage::parse;
use crate::ChangeHash;
const SYNC_STATE_TYPE: u8 = 0x43;
#[derive(Debug, thiserror::Error)]
pub enum DecodeError {
#[error("{0:?}")]
Parse(String),
#[error("wrong type: expected one of {expected_one_of:?} but found {found}")]
WrongType { expected_one_of: Vec<u8>, found: u8 },
#[error("not enough input")]
NotEnoughInput,
}
impl From<parse::leb128::Error> for DecodeError {
fn from(_: parse::leb128::Error) -> Self {
Self::Parse("bad leb128 encoding".to_string())
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct State {
pub shared_heads: Vec<ChangeHash>,
pub last_sent_heads: Vec<ChangeHash>,
pub their_heads: Option<Vec<ChangeHash>>,
pub their_need: Option<Vec<ChangeHash>>,
pub their_have: Option<Vec<Have>>,
pub sent_hashes: BTreeSet<ChangeHash>,
pub in_flight: bool,
pub have_responded: bool,
pub their_capabilities: Option<Vec<Capability>>,
pub read_only: bool,
pub peer_read_only: bool,
pub needs_reset: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, serde::Serialize)]
pub struct Have {
pub last_sync: Vec<ChangeHash>,
pub bloom: BloomFilter,
}
impl State {
pub fn new() -> Self {
Default::default()
}
pub fn new_read_only() -> Self {
Self {
read_only: true,
..Default::default()
}
}
pub fn encode(&self) -> Vec<u8> {
let mut buf = vec![SYNC_STATE_TYPE];
encode_hashes(&mut buf, &self.shared_heads);
buf
}
pub fn decode(input: &[u8]) -> Result<Self, DecodeError> {
let input = parse::Input::new(input);
match Self::parse(input) {
Ok((_, state)) => Ok(state),
Err(parse::ParseError::Incomplete(_)) => Err(DecodeError::NotEnoughInput),
Err(parse::ParseError::Error(e)) => Err(e),
}
}
pub(crate) fn parse(input: parse::Input<'_>) -> parse::ParseResult<'_, Self, DecodeError> {
let (i, record_type) = parse::take1(input)?;
if record_type != SYNC_STATE_TYPE {
return Err(parse::ParseError::Error(DecodeError::WrongType {
expected_one_of: vec![SYNC_STATE_TYPE],
found: record_type,
}));
}
let (i, shared_heads) = parse::length_prefixed(parse::change_hash)(i)?;
Ok((
i,
Self {
shared_heads,
last_sent_heads: Vec::new(),
their_heads: None,
their_need: None,
their_have: Some(Vec::new()),
sent_hashes: BTreeSet::new(),
in_flight: false,
have_responded: false,
their_capabilities: None,
read_only: false,
peer_read_only: false,
needs_reset: false,
},
))
}
pub fn set_read_only(&mut self, read_only: bool) {
if self.read_only == read_only {
return;
}
if self.read_only && !read_only {
let their_capabilities = self.their_capabilities.take();
*self = Self {
their_capabilities,
read_only: false,
needs_reset: true,
..Default::default()
};
} else {
self.read_only = true;
self.in_flight = false;
self.have_responded = false;
}
}
pub fn is_peer_read_only(&self) -> bool {
self.peer_read_only
}
pub(crate) fn peer_supports_sync_reset(&self) -> bool {
self.their_capabilities
.as_ref()
.map(|caps| caps.contains(&Capability::SyncReset))
.unwrap_or(false)
}
pub(crate) fn send_doc(&self) -> bool {
self.their_heads == Some(vec![]) && self.supports_v2_messages()
}
pub(crate) fn their(&self) -> Option<(&[Have], &[ChangeHash])> {
let have = self.their_have.as_ref()?;
let need = self.their_need.as_ref()?;
Some((have.as_slice(), need.as_slice()))
}
pub(crate) fn supports_v2_messages(&self) -> bool {
self.their_capabilities
.as_ref()
.map(|caps| caps.contains(&Capability::MessageV2))
.unwrap_or(false)
}
}