#[cfg(feature = "minimal")]
use grovedb_merk::{
merk::NodeType,
tree::{
kv::{
ValueDefinedCostType,
ValueDefinedCostType::{LayeredValueDefinedCost, SpecializedValueDefinedCost},
KV,
},
TreeNode,
},
};
#[cfg(any(feature = "minimal", feature = "verify"))]
use grovedb_merk::{
tree_type::{MaybeTree, TreeType},
TreeFeatureType,
TreeFeatureType::{
BasicMerkNode, BigSummedMerkNode, CountedMerkNode, CountedSummedMerkNode, SummedMerkNode,
},
};
#[cfg(feature = "minimal")]
use grovedb_version::{check_grovedb_v0, version::GroveVersion};
#[cfg(feature = "minimal")]
use integer_encoding::VarInt;
#[cfg(feature = "minimal")]
use crate::element::{
BIG_SUM_TREE_COST_SIZE, COUNT_SUM_TREE_COST_SIZE, COUNT_TREE_COST_SIZE, SUM_ITEM_COST_SIZE,
SUM_TREE_COST_SIZE, TREE_COST_SIZE,
};
#[cfg(feature = "minimal")]
use crate::reference_path::path_from_reference_path_type;
#[cfg(any(feature = "minimal", feature = "verify"))]
use crate::reference_path::ReferencePathType;
#[cfg(any(feature = "minimal", feature = "verify"))]
use crate::{Element, ElementFlags, Error};
impl Element {
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn sum_value_or_default(&self) -> i64 {
match self {
Element::SumItem(sum_value, _) | Element::SumTree(_, sum_value, _) => *sum_value,
_ => 0,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn count_value_or_default(&self) -> u64 {
match self {
Element::CountTree(_, count_value, _) => *count_value,
_ => 1,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn count_sum_value_or_default(&self) -> (u64, i64) {
match self {
Element::SumItem(sum_value, _) | Element::SumTree(_, sum_value, _) => (1, *sum_value),
Element::CountTree(_, count_value, _) => (*count_value, 0),
Element::CountSumTree(_, count_value, sum_value, _) => (*count_value, *sum_value),
_ => (1, 0),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn big_sum_value_or_default(&self) -> i128 {
match self {
Element::SumItem(sum_value, _) | Element::SumTree(_, sum_value, _) => {
*sum_value as i128
}
Element::BigSumTree(_, sum_value, _) => *sum_value,
_ => 0,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn as_sum_item_value(&self) -> Result<i64, Error> {
match self {
Element::SumItem(value, _) => Ok(*value),
_ => Err(Error::WrongElementType("expected a sum item")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn into_sum_item_value(self) -> Result<i64, Error> {
match self {
Element::SumItem(value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected a sum item")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn as_sum_tree_value(&self) -> Result<i64, Error> {
match self {
Element::SumTree(_, value, _) => Ok(*value),
_ => Err(Error::WrongElementType("expected a sum tree")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn into_sum_tree_value(self) -> Result<i64, Error> {
match self {
Element::SumTree(_, value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected a sum tree")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn as_item_bytes(&self) -> Result<&[u8], Error> {
match self {
Element::Item(value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected an item")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn into_item_bytes(self) -> Result<Vec<u8>, Error> {
match self {
Element::Item(value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected an item")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn into_reference_path_type(self) -> Result<ReferencePathType, Error> {
match self {
Element::Reference(value, ..) => Ok(value),
_ => Err(Error::WrongElementType("expected a reference")),
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_sum_tree(&self) -> bool {
matches!(self, Element::SumTree(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn root_key_and_tree_type_owned(self) -> Option<(Option<Vec<u8>>, TreeType)> {
match self {
Element::Tree(root_key, _) => Some((root_key, TreeType::NormalTree)),
Element::SumTree(root_key, ..) => Some((root_key, TreeType::SumTree)),
Element::BigSumTree(root_key, ..) => Some((root_key, TreeType::BigSumTree)),
Element::CountTree(root_key, ..) => Some((root_key, TreeType::CountTree)),
Element::CountSumTree(root_key, ..) => Some((root_key, TreeType::CountSumTree)),
_ => None,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn root_key_and_tree_type(&self) -> Option<(&Option<Vec<u8>>, TreeType)> {
match self {
Element::Tree(root_key, _) => Some((root_key, TreeType::NormalTree)),
Element::SumTree(root_key, ..) => Some((root_key, TreeType::SumTree)),
Element::BigSumTree(root_key, ..) => Some((root_key, TreeType::BigSumTree)),
Element::CountTree(root_key, ..) => Some((root_key, TreeType::CountTree)),
Element::CountSumTree(root_key, ..) => Some((root_key, TreeType::CountSumTree)),
_ => None,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn tree_flags_and_type(&self) -> Option<(&Option<ElementFlags>, TreeType)> {
match self {
Element::Tree(_, flags) => Some((flags, TreeType::NormalTree)),
Element::SumTree(_, _, flags) => Some((flags, TreeType::SumTree)),
Element::BigSumTree(_, _, flags) => Some((flags, TreeType::BigSumTree)),
Element::CountTree(_, _, flags) => Some((flags, TreeType::CountTree)),
Element::CountSumTree(.., flags) => Some((flags, TreeType::CountSumTree)),
_ => None,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn tree_type(&self) -> Option<TreeType> {
match self {
Element::Tree(..) => Some(TreeType::NormalTree),
Element::SumTree(..) => Some(TreeType::SumTree),
Element::BigSumTree(..) => Some(TreeType::BigSumTree),
Element::CountTree(..) => Some(TreeType::CountTree),
Element::CountSumTree(..) => Some(TreeType::CountSumTree),
_ => None,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn tree_feature_type(&self) -> Option<TreeFeatureType> {
match self {
Element::Tree(..) => Some(BasicMerkNode),
Element::SumTree(_, value, _) => Some(SummedMerkNode(*value)),
Element::BigSumTree(_, value, _) => Some(BigSummedMerkNode(*value)),
Element::CountTree(_, value, _) => Some(CountedMerkNode(*value)),
Element::CountSumTree(_, count, sum, _) => Some(CountedSummedMerkNode(*count, *sum)),
_ => None,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn maybe_tree_type(&self) -> MaybeTree {
match self {
Element::Tree(..) => MaybeTree::Tree(TreeType::NormalTree),
Element::SumTree(..) => MaybeTree::Tree(TreeType::SumTree),
Element::BigSumTree(..) => MaybeTree::Tree(TreeType::BigSumTree),
Element::CountTree(..) => MaybeTree::Tree(TreeType::CountTree),
Element::CountSumTree(..) => MaybeTree::Tree(TreeType::CountSumTree),
_ => MaybeTree::NotTree,
}
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_big_sum_tree(&self) -> bool {
matches!(self, Element::BigSumTree(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_basic_tree(&self) -> bool {
matches!(self, Element::Tree(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_any_tree(&self) -> bool {
matches!(
self,
Element::SumTree(..)
| Element::Tree(..)
| Element::BigSumTree(..)
| Element::CountTree(..)
| Element::CountSumTree(..)
)
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_reference(&self) -> bool {
matches!(self, Element::Reference(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_any_item(&self) -> bool {
matches!(self, Element::Item(..) | Element::SumItem(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_basic_item(&self) -> bool {
matches!(self, Element::Item(..))
}
#[cfg(any(feature = "minimal", feature = "verify"))]
pub fn is_sum_item(&self) -> bool {
matches!(self, Element::SumItem(..))
}
#[cfg(feature = "minimal")]
pub fn get_feature_type(&self, parent_tree_type: TreeType) -> Result<TreeFeatureType, Error> {
match parent_tree_type {
TreeType::NormalTree => Ok(BasicMerkNode),
TreeType::SumTree => Ok(SummedMerkNode(self.sum_value_or_default())),
TreeType::BigSumTree => Ok(BigSummedMerkNode(self.big_sum_value_or_default())),
TreeType::CountTree => Ok(CountedMerkNode(self.count_value_or_default())),
TreeType::CountSumTree => {
let v = self.count_sum_value_or_default();
Ok(CountedSummedMerkNode(v.0, v.1))
}
}
}
#[cfg(feature = "minimal")]
pub fn get_flags(&self) -> &Option<ElementFlags> {
match self {
Element::Tree(_, flags)
| Element::Item(_, flags)
| Element::Reference(_, _, flags)
| Element::SumTree(.., flags)
| Element::BigSumTree(.., flags)
| Element::CountTree(.., flags)
| Element::SumItem(_, flags)
| Element::CountSumTree(.., flags) => flags,
}
}
#[cfg(feature = "minimal")]
pub fn get_flags_owned(self) -> Option<ElementFlags> {
match self {
Element::Tree(_, flags)
| Element::Item(_, flags)
| Element::Reference(_, _, flags)
| Element::SumTree(.., flags)
| Element::BigSumTree(.., flags)
| Element::CountTree(.., flags)
| Element::SumItem(_, flags)
| Element::CountSumTree(.., flags) => flags,
}
}
#[cfg(feature = "minimal")]
pub fn get_flags_mut(&mut self) -> &mut Option<ElementFlags> {
match self {
Element::Tree(_, flags)
| Element::Item(_, flags)
| Element::Reference(_, _, flags)
| Element::SumTree(.., flags)
| Element::BigSumTree(.., flags)
| Element::CountTree(.., flags)
| Element::SumItem(_, flags)
| Element::CountSumTree(.., flags) => flags,
}
}
#[cfg(feature = "minimal")]
pub fn set_flags(&mut self, new_flags: Option<ElementFlags>) {
match self {
Element::Tree(_, flags)
| Element::Item(_, flags)
| Element::Reference(_, _, flags)
| Element::SumTree(.., flags)
| Element::BigSumTree(.., flags)
| Element::CountTree(.., flags)
| Element::SumItem(_, flags)
| Element::CountSumTree(.., flags) => *flags = new_flags,
}
}
#[cfg(feature = "minimal")]
pub fn required_item_space(
len: u32,
flag_len: u32,
grove_version: &GroveVersion,
) -> Result<u32, Error> {
check_grovedb_v0!(
"required_item_space",
grove_version.grovedb_versions.element.required_item_space
);
Ok(len + len.required_space() as u32 + flag_len + flag_len.required_space() as u32 + 1)
}
#[cfg(feature = "minimal")]
pub(crate) fn convert_if_reference_to_absolute_reference(
self,
path: &[&[u8]],
key: Option<&[u8]>,
) -> Result<Element, Error> {
Ok(match &self {
Element::Reference(reference_path_type, ..) => match reference_path_type {
ReferencePathType::AbsolutePathReference(..) => self,
_ => {
let absolute_path =
path_from_reference_path_type(reference_path_type.clone(), path, key)?;
Element::Reference(
ReferencePathType::AbsolutePathReference(absolute_path),
None,
None,
)
}
},
_ => self,
})
}
#[cfg(feature = "minimal")]
pub fn specialized_costs_for_key_value(
key: &[u8],
value: &[u8],
node_type: NodeType,
grove_version: &GroveVersion,
) -> Result<u32, Error> {
check_grovedb_v0!(
"specialized_costs_for_key_value",
grove_version
.grovedb_versions
.element
.specialized_costs_for_key_value
);
let element = Element::deserialize(value, grove_version)?;
let cost = match element {
Element::Tree(_, flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = TREE_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::layered_value_byte_cost_size_for_key_and_value_lengths(
key_len, value_len, node_type,
)
}
Element::SumTree(_, _sum_value, flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = SUM_TREE_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::layered_value_byte_cost_size_for_key_and_value_lengths(
key_len, value_len, node_type,
)
}
Element::BigSumTree(_, _sum_value, flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = BIG_SUM_TREE_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::layered_value_byte_cost_size_for_key_and_value_lengths(
key_len, value_len, node_type,
)
}
Element::CountTree(_, _count_value, flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = COUNT_TREE_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::layered_value_byte_cost_size_for_key_and_value_lengths(
key_len, value_len, node_type,
)
}
Element::CountSumTree(.., flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = COUNT_SUM_TREE_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::layered_value_byte_cost_size_for_key_and_value_lengths(
key_len, value_len, node_type,
)
}
Element::SumItem(.., flags) => {
let flags_len = flags.map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
let value_len = SUM_ITEM_COST_SIZE + flags_len;
let key_len = key.len() as u32;
KV::node_value_byte_cost_size(key_len, value_len, node_type)
}
_ => KV::node_value_byte_cost_size(key.len() as u32, value.len() as u32, node_type),
};
Ok(cost)
}
#[cfg(feature = "minimal")]
pub fn get_specialized_cost(&self, grove_version: &GroveVersion) -> Result<u32, Error> {
check_grovedb_v0!(
"get_specialized_cost",
grove_version.grovedb_versions.element.get_specialized_cost
);
match self {
Element::Tree(..) => Ok(TREE_COST_SIZE),
Element::SumTree(..) => Ok(SUM_TREE_COST_SIZE),
Element::BigSumTree(..) => Ok(BIG_SUM_TREE_COST_SIZE),
Element::SumItem(..) => Ok(SUM_ITEM_COST_SIZE),
Element::CountTree(..) => Ok(COUNT_TREE_COST_SIZE),
Element::CountSumTree(..) => Ok(COUNT_SUM_TREE_COST_SIZE),
_ => Err(Error::CorruptedCodeExecution(
"trying to get tree cost from non tree element",
)),
}
}
#[cfg(feature = "minimal")]
pub fn value_defined_cost(&self, grove_version: &GroveVersion) -> Option<ValueDefinedCostType> {
let value_cost = self.get_specialized_cost(grove_version).ok()?;
let cost = value_cost
+ self.get_flags().as_ref().map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
match self {
Element::Tree(..) => Some(LayeredValueDefinedCost(cost)),
Element::SumTree(..) => Some(LayeredValueDefinedCost(cost)),
Element::BigSumTree(..) => Some(LayeredValueDefinedCost(cost)),
Element::CountTree(..) => Some(LayeredValueDefinedCost(cost)),
Element::CountSumTree(..) => Some(LayeredValueDefinedCost(cost)),
Element::SumItem(..) => Some(SpecializedValueDefinedCost(cost)),
_ => None,
}
}
#[cfg(feature = "minimal")]
pub fn value_defined_cost_for_serialized_value(
value: &[u8],
grove_version: &GroveVersion,
) -> Option<ValueDefinedCostType> {
let element = Element::deserialize(value, grove_version).ok()?;
element.value_defined_cost(grove_version)
}
}
#[cfg(feature = "minimal")]
pub fn raw_decode(bytes: &[u8], grove_version: &GroveVersion) -> Result<Element, Error> {
let tree = TreeNode::decode_raw(
bytes,
vec![],
Some(Element::value_defined_cost_for_serialized_value),
grove_version,
)
.map_err(|e| Error::CorruptedData(e.to_string()))?;
let element: Element = Element::deserialize(tree.value_as_slice(), grove_version)?;
Ok(element)
}