use crate::{LabelId, RelTypeId, Value};
use std::collections::{BTreeMap, BTreeSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId(pub u64);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NodeRecord {
pub id: NodeId,
pub labels: BTreeSet<LabelId>,
pub properties: BTreeMap<String, Value>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProjectedNodeRecord {
pub id: NodeId,
pub labels: BTreeSet<LabelId>,
pub properties: BTreeMap<String, Value>,
}
#[doc(hidden)]
pub fn project_node_record(
node: NodeRecord,
required_properties: &BTreeSet<String>,
) -> ProjectedNodeRecord {
let properties = required_properties
.iter()
.filter_map(|property| {
node.properties
.get(property)
.cloned()
.map(|value| (property.clone(), value))
})
.collect();
ProjectedNodeRecord {
id: node.id,
labels: node.labels,
properties,
}
}
#[doc(hidden)]
pub fn project_node_record_ref(
node: &NodeRecord,
required_properties: &BTreeSet<String>,
) -> ProjectedNodeRecord {
ProjectedNodeRecord {
id: node.id,
labels: node.labels.clone(),
properties: required_properties
.iter()
.filter_map(|name| {
node.properties
.get(name)
.map(|value| (name.clone(), value.clone()))
})
.collect(),
}
}
#[doc(hidden)]
pub fn projected_node_allocation_bytes(
node: &NodeRecord,
required_properties: &BTreeSet<String>,
) -> usize {
std::mem::size_of::<ProjectedNodeRecord>()
.saturating_add(node.labels.len().saturating_mul(128))
.saturating_add(properties_allocation_bytes(
required_properties.iter().filter_map(|name| {
node.properties
.get(name)
.map(|value| (name.as_str(), value))
}),
))
}
#[doc(hidden)]
pub fn node_allocation_bytes(node: &NodeRecord) -> usize {
std::mem::size_of::<NodeRecord>()
.saturating_add(node.labels.len().saturating_mul(128))
.saturating_add(properties_allocation_bytes(
node.properties
.iter()
.map(|(name, value)| (name.as_str(), value)),
))
}
fn properties_allocation_bytes<'a>(
properties: impl Iterator<Item = (&'a str, &'a Value)>,
) -> usize {
let (count, payload) = properties.fold((0usize, 0usize), |(count, payload), (name, value)| {
(
count.saturating_add(1),
payload
.saturating_add(name.len())
.saturating_add(projected_value_allocation_bytes(value)),
)
});
if count == 0 {
return 0;
}
payload.saturating_add(property_container_allocation_bytes(count))
}
#[doc(hidden)]
pub fn property_container_allocation_bytes(count: usize) -> usize {
if count == 0 {
return 0;
}
let pair_bytes = std::mem::size_of::<(String, Value)>();
let node_bytes = pair_bytes
.saturating_mul(11)
.saturating_add(std::mem::size_of::<usize>().saturating_mul(12))
.saturating_add(32);
let nodes = if count <= 11 {
1
} else {
1usize.saturating_add((count - 1) / 5)
};
nodes
.saturating_mul(node_bytes)
.saturating_add(count.saturating_mul(2).max(4).saturating_mul(pair_bytes))
}
fn projected_value_allocation_bytes(value: &Value) -> usize {
std::mem::size_of::<Value>().saturating_add(match value {
Value::String(value) => value.len(),
Value::Binary(value) => value.len(),
Value::Vector(value) => value.encoded().len(),
Value::List(values) => values.iter().fold(32usize, |total, value| {
total.saturating_add(projected_value_allocation_bytes(value).saturating_mul(2))
}),
Value::Map(values) => {
properties_allocation_bytes(values.iter().map(|(key, value)| (key.as_str(), value)))
}
_ => 0,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RelId(pub u64);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RelRecord {
pub id: RelId,
pub source: NodeId,
pub target: NodeId,
pub rel_type: RelTypeId,
pub properties: BTreeMap<String, Value>,
}
#[doc(hidden)]
pub fn relationship_allocation_bytes(relationship: &RelRecord) -> usize {
std::mem::size_of::<RelRecord>().saturating_add(properties_allocation_bytes(
relationship
.properties
.iter()
.map(|(name, value)| (name.as_str(), value)),
))
}