use crate::ids::ShardId;
use crate::store::NodeStore;
use crate::tree::{Hash, Node};
use super::SyncError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TargetNodeSummary {
Leaf,
Internal(Vec<(Vec<u8>, Hash)>),
}
impl TargetNodeSummary {
#[must_use]
pub fn from_node(node: &Node) -> Self {
match node {
Node::Leaf(_) => Self::Leaf,
Node::Internal(internal) => Self::Internal(internal.children().to_vec()),
}
}
#[must_use]
pub fn child_hash(&self, separator: &[u8]) -> Option<Hash> {
let Self::Internal(children) = self else {
return None;
};
children
.iter()
.find(|(target_separator, _hash)| target_separator.as_slice() == separator)
.map(|(_separator, hash)| *hash)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TargetNodeRequest {
pub shard_id: ShardId,
pub hash: Hash,
}
impl TargetNodeRequest {
#[must_use]
pub const fn new(shard_id: ShardId, hash: Hash) -> Self {
Self { shard_id, hash }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TargetNodeResponse {
pub shard_id: ShardId,
pub hash: Hash,
pub summary: Option<TargetNodeSummary>,
}
impl TargetNodeResponse {
#[must_use]
pub const fn missing(shard_id: ShardId, hash: Hash) -> Self {
Self {
shard_id,
hash,
summary: None,
}
}
#[must_use]
pub fn present(shard_id: ShardId, hash: Hash, node: &Node) -> Self {
Self {
shard_id,
hash,
summary: Some(TargetNodeSummary::from_node(node)),
}
}
pub fn from_store<T>(request: TargetNodeRequest, target_store: &T) -> Result<Self, SyncError>
where
T: NodeStore + ?Sized,
{
let node = target_store
.get(&request.hash)
.map_err(|_error| SyncError::TargetStoreRead { hash: request.hash })?;
Ok(node.map_or_else(
|| Self::missing(request.shard_id, request.hash),
|node| Self::present(request.shard_id, request.hash, &node),
))
}
}
pub trait TargetNodeReader {
fn read_target_node(&self, hash: Hash) -> Result<Option<TargetNodeSummary>, SyncError>;
}
impl<T> TargetNodeReader for T
where
T: NodeStore + ?Sized,
{
fn read_target_node(&self, hash: Hash) -> Result<Option<TargetNodeSummary>, SyncError> {
self.get(&hash)
.map_err(|_error| SyncError::TargetStoreRead { hash })
.map(|node| node.as_deref().map(TargetNodeSummary::from_node))
}
}