use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use crate::types::VertexId;
use crate::value::Value;
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct Tag {
pub name: String,
pub properties: HashMap<Arc<str>, Value>,
}
impl std::hash::Hash for Tag {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
let mut pairs: Vec<_> = self.properties.iter().collect();
pairs.sort_by_key(|&(k, _)| k);
for (k, v) in pairs {
k.hash(state);
v.hash(state);
}
}
}
impl Tag {
pub fn new(name: String, properties: HashMap<std::sync::Arc<str>, Value>) -> Self {
Self { name, properties }
}
pub fn estimated_size(&self) -> usize {
let mut size = std::mem::size_of::<Self>();
size += std::mem::size_of::<String>() + self.name.capacity();
size += self.properties.capacity()
* (8 + std::mem::size_of::<String>() + std::mem::size_of::<Value>());
for (k, v) in &self.properties {
size += k.len();
size += v.estimated_size();
}
size
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct Vertex {
pub vid: VertexId,
pub tag: Tag,
}
impl std::hash::Hash for Vertex {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.vid.hash(state);
self.tag.hash(state);
}
}
impl Vertex {
pub fn new(vid: VertexId, tag: Tag) -> Self {
Self { vid, tag }
}
pub fn vid(&self) -> &VertexId {
&self.vid
}
pub fn tag(&self) -> &Tag {
&self.tag
}
pub fn tag_name(&self) -> &str {
&self.tag.name
}
pub fn properties(&self) -> &HashMap<Arc<str>, Value> {
&self.tag.properties
}
pub fn get_property(&self, prop_name: &str) -> Option<&Value> {
self.tag.properties.get(prop_name)
}
pub fn property_value(&self, property: &str) -> Option<Value> {
self.tag.properties.get(property).cloned()
}
pub fn has_properties(&self) -> bool {
!self.tag.properties.is_empty()
}
fn cmp_properties(
a: &HashMap<Arc<str>, Value>,
b: &HashMap<Arc<str>, Value>,
) -> std::cmp::Ordering {
match a.len().cmp(&b.len()) {
std::cmp::Ordering::Equal => {
let mut a_sorted: Vec<_> = a.iter().collect();
let mut b_sorted: Vec<_> = b.iter().collect();
a_sorted.sort_by_key(|(k1, _)| *k1);
b_sorted.sort_by_key(|(k1, _)| *k1);
for ((k1, v1), (k2, v2)) in a_sorted.iter().zip(b_sorted.iter()) {
match k1.cmp(k2) {
std::cmp::Ordering::Equal => match v1.cmp(v2) {
std::cmp::Ordering::Equal => continue,
ord => return ord,
},
ord => return ord,
}
}
std::cmp::Ordering::Equal
}
ord => ord,
}
}
}
impl Ord for Vertex {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.vid.cmp(&other.vid).then_with(|| {
self.tag
.name
.cmp(&other.tag.name)
.then_with(|| Vertex::cmp_properties(&self.tag.properties, &other.tag.properties))
})
}
}
impl PartialOrd for Vertex {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Vertex {
pub fn estimated_size(&self) -> usize {
let mut size = std::mem::size_of::<Self>();
size += self.vid.len();
size += self.tag.estimated_size();
size
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Edge {
pub src: VertexId,
pub dst: VertexId,
pub edge_type: String,
pub ranking: i64,
pub props: HashMap<Arc<str>, Value>,
}
impl Edge {
pub fn properties(&self) -> &HashMap<Arc<str>, Value> {
&self.props
}
pub fn src(&self) -> &VertexId {
&self.src
}
pub fn dst(&self) -> &VertexId {
&self.dst
}
pub fn edge_type(&self) -> &str {
&self.edge_type
}
pub fn ranking(&self) -> i64 {
self.ranking
}
pub fn get_all_properties(&self) -> &HashMap<Arc<str>, Value> {
&self.props
}
pub fn get_property(&self, name: &str) -> Option<&Value> {
self.props.get(name)
}
pub fn set_property(&mut self, name: Arc<str>, value: Value) {
self.props.insert(name, value);
}
pub fn remove_property(&mut self, name: &str) -> Option<Value> {
self.props.remove(name)
}
pub fn has_property(&self, name: &str) -> bool {
self.props.contains_key(name)
}
pub fn property_count(&self) -> usize {
self.props.len()
}
pub fn has_properties(&self) -> bool {
!self.props.is_empty()
}
pub fn new_empty(src: VertexId, dst: VertexId, edge_type: String, ranking: i64) -> Self {
Self {
src,
dst,
edge_type,
ranking,
props: HashMap::new(),
}
}
pub fn debug_string(&self) -> String {
format!(
"Edge({:?} -> {:?}, type: {}, ranking: {})",
self.src, self.dst, self.edge_type, self.ranking
)
}
pub fn estimated_size(&self) -> usize {
let mut size = std::mem::size_of::<Self>();
size += self.src.len();
size += self.dst.len();
size += std::mem::size_of::<String>() + self.edge_type.capacity();
size += self.props.capacity()
* (8 + std::mem::size_of::<Arc<str>>() + std::mem::size_of::<Value>());
for (k, v) in &self.props {
size += k.len();
size += v.estimated_size();
}
size
}
}
impl std::hash::Hash for Edge {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.src.hash(state);
self.dst.hash(state);
self.edge_type.hash(state);
self.ranking.hash(state);
let mut pairs: Vec<_> = self.props.iter().collect();
pairs.sort_by_key(|&(k, _)| k);
for (k, v) in pairs {
k.hash(state);
v.hash(state);
}
}
}
impl Edge {
pub fn new(
src: VertexId,
dst: VertexId,
edge_type: String,
ranking: i64,
props: HashMap<Arc<str>, Value>,
) -> Self {
Self {
src,
dst,
edge_type,
ranking,
props,
}
}
}
impl Edge {
fn cmp_properties(
a: &HashMap<Arc<str>, Value>,
b: &HashMap<Arc<str>, Value>,
) -> std::cmp::Ordering {
match a.len().cmp(&b.len()) {
std::cmp::Ordering::Equal => {
let mut a_sorted: Vec<_> = a.iter().collect();
let mut b_sorted: Vec<_> = b.iter().collect();
a_sorted.sort_by_key(|(k1, _)| *k1);
b_sorted.sort_by_key(|(k1, _)| *k1);
for ((k1, v1), (k2, v2)) in a_sorted.iter().zip(b_sorted.iter()) {
match k1.cmp(k2) {
std::cmp::Ordering::Equal => match v1.cmp(v2) {
std::cmp::Ordering::Equal => continue,
ord => return ord,
},
ord => return ord,
}
}
std::cmp::Ordering::Equal
}
ord => ord,
}
}
}
impl Ord for Edge {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.src
.cmp(&other.src)
.then_with(|| self.dst.cmp(&other.dst))
.then_with(|| self.edge_type.cmp(&other.edge_type))
.then_with(|| self.ranking.cmp(&other.ranking))
.then_with(|| Edge::cmp_properties(&self.props, &other.props))
}
}
impl PartialOrd for Edge {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EdgeDeleteKey {
pub src: VertexId,
pub dst: VertexId,
pub edge_type: String,
pub ranking: i64,
}
impl EdgeDeleteKey {
pub fn new(src: VertexId, dst: VertexId, edge_type: String, ranking: i64) -> Self {
Self {
src,
dst,
edge_type,
ranking,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EdgeHeader {
pub src: VertexId,
pub dst: VertexId,
pub edge_type: String,
pub ranking: i64,
}
impl EdgeHeader {
pub fn new(src: VertexId, dst: VertexId, edge_type: String, ranking: i64) -> Self {
Self {
src,
dst,
edge_type,
ranking,
}
}
pub fn from_edge(edge: &Edge) -> Self {
Self {
src: edge.src,
dst: edge.dst,
edge_type: edge.edge_type.clone(),
ranking: edge.ranking,
}
}
pub fn src(&self) -> &VertexId {
&self.src
}
pub fn dst(&self) -> &VertexId {
&self.dst
}
pub fn edge_type(&self) -> &str {
&self.edge_type
}
pub fn ranking(&self) -> i64 {
self.ranking
}
pub fn estimated_size(&self) -> usize {
std::mem::size_of::<Self>()
+ self.src.len()
+ self.dst.len()
+ std::mem::size_of::<String>()
+ self.edge_type.capacity()
}
}
impl std::hash::Hash for EdgeHeader {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.src.hash(state);
self.dst.hash(state);
self.edge_type.hash(state);
self.ranking.hash(state);
}
}
impl Ord for EdgeHeader {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.src
.cmp(&other.src)
.then_with(|| self.dst.cmp(&other.dst))
.then_with(|| self.edge_type.cmp(&other.edge_type))
.then_with(|| self.ranking.cmp(&other.ranking))
}
}
impl PartialOrd for EdgeHeader {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Step {
pub dst: Box<Vertex>,
pub edge: Box<Edge>,
}
impl std::hash::Hash for Step {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.dst.hash(state);
self.edge.hash(state);
}
}
impl Ord for Step {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.dst.cmp(&other.dst) {
std::cmp::Ordering::Equal => self.edge.cmp(&other.edge),
ord => ord,
}
}
}
impl PartialOrd for Step {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Step {
pub fn new(dst: Vertex, edge_type: String, _edge_name: String, ranking: i64) -> Self {
let edge = Edge::new_empty(VertexId::new(), VertexId::new(), edge_type, ranking);
Self {
dst: Box::new(dst),
edge: Box::new(edge),
}
}
pub fn new_with_edge(dst: Vertex, edge: Edge) -> Self {
Self {
dst: Box::new(dst),
edge: Box::new(edge),
}
}
pub fn src_vid(&self) -> &VertexId {
&self.edge.src
}
pub fn dst_vid(&self) -> &VertexId {
&self.dst.vid
}
pub fn ranking(&self) -> i64 {
self.edge.ranking
}
pub fn estimated_size(&self) -> usize {
let mut size = std::mem::size_of::<Self>();
size += std::mem::size_of::<Box<Vertex>>() + self.dst.estimated_size();
size += std::mem::size_of::<Box<Edge>>() + self.edge.estimated_size();
size
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Path {
pub src: Box<Vertex>,
pub steps: Vec<Step>,
}
impl Ord for Path {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.src
.cmp(&other.src)
.then_with(|| self.steps.len().cmp(&other.steps.len()))
.then_with(|| self.cmp_steps(other))
}
}
impl Path {
fn cmp_steps(&self, other: &Self) -> std::cmp::Ordering {
for (step1, step2) in self.steps.iter().zip(other.steps.iter()) {
let step_cmp = step1.cmp(step2);
if step_cmp != std::cmp::Ordering::Equal {
return step_cmp;
}
}
std::cmp::Ordering::Equal
}
}
impl PartialOrd for Path {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::hash::Hash for Path {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.src.hash(state);
for step in &self.steps {
step.hash(state);
}
}
}
impl Path {
pub fn new(src: Vertex) -> Self {
Self {
src: Box::new(src),
steps: Vec::new(),
}
}
pub fn estimated_size(&self) -> usize {
let mut size = std::mem::size_of::<Self>();
size += std::mem::size_of::<Box<Vertex>>() + self.src.as_ref().estimated_size();
size += self.steps.capacity() * std::mem::size_of::<Step>();
for step in &self.steps {
size += step.estimated_size();
}
size
}
pub fn add_step(&mut self, step: Step) {
self.steps.push(step);
}
pub fn edges(&self) -> Vec<&Edge> {
self.steps.iter().map(|step| step.edge.as_ref()).collect()
}
pub fn len(&self) -> usize {
self.steps.len()
}
pub fn length(&self) -> usize {
self.steps.len()
}
pub fn steps(&self) -> &[Step] {
&self.steps
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
pub fn has_duplicate_edges(&self) -> bool {
let mut seen_edges: std::collections::HashSet<(VertexId, VertexId, String)> =
std::collections::HashSet::new();
for step in &self.steps {
let edge_key = (step.edge.src, step.edge.dst, step.edge.edge_type.clone());
if !seen_edges.insert(edge_key) {
return true;
}
}
false
}
pub fn reverse(&mut self) {
if self.steps.is_empty() {
return;
}
let mut vertices = Vec::with_capacity(self.steps.len() + 1);
vertices.push((*self.src).clone());
for step in &self.steps {
vertices.push((*step.dst).clone());
}
let mut reversed_steps = Vec::with_capacity(self.steps.len());
for i in (0..self.steps.len()).rev() {
let mut edge = (*self.steps[i].edge).clone();
std::mem::swap(&mut edge.src, &mut edge.dst);
reversed_steps.push(Step {
dst: Box::new(vertices[i].clone()),
edge: Box::new(edge),
});
}
self.src = Box::new(vertices[vertices.len() - 1].clone());
self.steps = reversed_steps;
}
pub fn append_reverse(&mut self, other: Path) {
if other.steps.is_empty() {
return;
}
let mut other_steps: Vec<Step> = other.steps.into_iter().rev().collect();
for step in &mut other_steps {
std::mem::swap(&mut step.edge.src, &mut step.edge.dst);
}
self.steps.extend(other_steps);
}
}
impl Default for Path {
fn default() -> Self {
Self {
src: Box::new(Vertex::default()),
steps: Vec::new(),
}
}
}