use serde::{Deserialize, Serialize};
use std::fmt;
use crate::core::v_latest::model::merkle_tree::node::vnode::VNodeData as VNodeImplV0_25_0;
use crate::error::OxenError;
use crate::model::{MerkleHash, MerkleTreeNodeIdType, MerkleTreeNodeType, TMerkleTreeNode};
pub trait TVNode {
fn node_type(&self) -> &MerkleTreeNodeType;
fn hash(&self) -> &MerkleHash;
fn num_entries(&self) -> u64;
fn set_num_entries(&mut self, _: u64);
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq)]
pub enum EVNode {
V0_25_0(VNodeImplV0_25_0),
}
pub struct VNodeOpts {
pub hash: MerkleHash,
pub num_entries: u64,
}
#[derive(Deserialize, Serialize, Clone, Eq, PartialEq)]
pub struct VNode {
pub node: EVNode,
}
impl VNode {
pub fn new(vnode_opts: VNodeOpts) -> Result<VNode, OxenError> {
Ok(Self {
node: EVNode::V0_25_0(VNodeImplV0_25_0 {
hash: vnode_opts.hash,
node_type: MerkleTreeNodeType::VNode,
num_entries: vnode_opts.num_entries,
}),
})
}
#[inline(always)]
pub fn deserialize(data: &[u8]) -> Result<VNode, rmp_serde::decode::Error> {
rmp_serde::from_slice(data)
}
pub fn get_opts(&self) -> VNodeOpts {
match &self.node {
EVNode::V0_25_0(vnode) => VNodeOpts {
hash: vnode.hash,
num_entries: vnode.num_entries,
},
}
}
fn node(&self) -> &dyn TVNode {
match self.node {
EVNode::V0_25_0(ref vnode) => vnode,
}
}
fn mut_node(&mut self) -> &mut dyn TVNode {
match self.node {
EVNode::V0_25_0(ref mut vnode) => vnode,
}
}
pub fn hash(&self) -> &MerkleHash {
self.node().hash()
}
pub fn num_entries(&self) -> u64 {
self.node().num_entries()
}
pub fn set_num_entries(&mut self, num_entries: u64) {
self.mut_node().set_num_entries(num_entries);
}
}
impl Default for VNode {
fn default() -> Self {
VNode {
node: EVNode::V0_25_0(VNodeImplV0_25_0 {
node_type: MerkleTreeNodeType::VNode,
hash: MerkleHash::new(0),
num_entries: 0,
}),
}
}
}
impl MerkleTreeNodeIdType for VNode {
fn node_type(&self) -> MerkleTreeNodeType {
*self.node().node_type()
}
fn hash(&self) -> MerkleHash {
*self.node().hash()
}
}
impl fmt::Debug for VNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VNode({})", self.hash())
}
}
impl fmt::Display for VNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "")
}
}
impl TMerkleTreeNode for VNode {}
#[cfg(test)]
mod on_disk_format {
use super::*;
use crate::model::merkle_tree::node::commit_node::{CommitNode, ECommitNode};
use crate::model::merkle_tree::node::dir_node::{DirNode, EDirNode};
#[test]
fn latest_nodes_are_name_tagged_and_round_trip() {
let vnode_bytes = rmp_serde::to_vec(&VNode::default()).unwrap();
let dir_bytes = rmp_serde::to_vec(&DirNode::default()).unwrap();
let commit_bytes = rmp_serde::to_vec(&CommitNode::default()).unwrap();
for bytes in [&vnode_bytes, &dir_bytes, &commit_bytes] {
assert!(
bytes.windows(7).any(|w| w == b"V0_25_0"),
"node must be tagged by variant name, not ordinal: {bytes:02x?}"
);
}
assert!(matches!(
VNode::deserialize(&vnode_bytes).unwrap().node,
EVNode::V0_25_0(_)
));
assert!(matches!(
DirNode::deserialize(&dir_bytes).unwrap().node,
EDirNode::V0_25_0(_)
));
assert!(matches!(
CommitNode::deserialize(&commit_bytes).unwrap().node,
ECommitNode::V0_25_0(_)
));
}
}