raphtory_storage/graph/
graph.rs

1use super::{
2    edges::{edge_entry::EdgeStorageEntry, unlocked::UnlockedEdges},
3    nodes::node_entry::NodeStorageEntry,
4};
5use crate::graph::{
6    edges::edges::{EdgesStorage, EdgesStorageRef},
7    locked::LockedGraph,
8    nodes::{nodes::NodesStorage, nodes_ref::NodesStorageEntry},
9};
10use raphtory_api::core::entities::{properties::meta::Meta, LayerIds, LayerVariants, EID, VID};
11use raphtory_core::entities::{
12    graph::tgraph::TemporalGraph, nodes::node_ref::NodeRef, properties::graph_meta::GraphMeta,
13};
14use serde::{Deserialize, Serialize};
15use std::{fmt::Debug, iter, sync::Arc};
16use thiserror::Error;
17
18#[cfg(feature = "storage")]
19use crate::disk::{
20    storage_interface::{
21        edges::DiskEdges, edges_ref::DiskEdgesRef, node::DiskNode, nodes::DiskNodesOwned,
22        nodes_ref::DiskNodesRef,
23    },
24    DiskGraphStorage,
25};
26use crate::mutation::MutationError;
27
28#[derive(Clone, Debug, Serialize, Deserialize)]
29pub enum GraphStorage {
30    Mem(LockedGraph),
31    Unlocked(Arc<TemporalGraph>),
32    #[cfg(feature = "storage")]
33    Disk(Arc<DiskGraphStorage>),
34}
35
36#[derive(Error, Debug)]
37pub enum Immutable {
38    #[error("The graph is locked and cannot be mutated")]
39    ReadLockedImmutable,
40    #[cfg(feature = "storage")]
41    #[error("DiskGraph cannot be mutated")]
42    DiskGraphImmutable,
43}
44
45impl From<TemporalGraph> for GraphStorage {
46    fn from(value: TemporalGraph) -> Self {
47        Self::Unlocked(Arc::new(value))
48    }
49}
50
51impl Default for GraphStorage {
52    fn default() -> Self {
53        GraphStorage::Unlocked(Arc::new(TemporalGraph::default()))
54    }
55}
56
57impl std::fmt::Display for GraphStorage {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "Graph(num_nodes={}, num_edges={})",
62            self.unfiltered_num_nodes(),
63            self.unfiltered_num_edges(),
64        )
65    }
66}
67
68impl GraphStorage {
69    /// Check if two storage instances point at the same underlying storage
70    pub fn ptr_eq(&self, other: &Self) -> bool {
71        match self {
72            GraphStorage::Mem(LockedGraph {
73                graph: this_graph, ..
74            })
75            | GraphStorage::Unlocked(this_graph) => match other {
76                GraphStorage::Mem(LockedGraph {
77                    graph: other_graph, ..
78                })
79                | GraphStorage::Unlocked(other_graph) => Arc::ptr_eq(this_graph, other_graph),
80                #[cfg(feature = "storage")]
81                _ => false,
82            },
83            #[cfg(feature = "storage")]
84            GraphStorage::Disk(this_graph) => match other {
85                GraphStorage::Disk(other_graph) => Arc::ptr_eq(this_graph, other_graph),
86                _ => false,
87            },
88        }
89    }
90
91    pub fn mutable(&self) -> Result<&Arc<TemporalGraph>, MutationError> {
92        match self {
93            GraphStorage::Mem(_) => Err(Immutable::ReadLockedImmutable)?,
94            GraphStorage::Unlocked(graph) => Ok(graph),
95            #[cfg(feature = "storage")]
96            GraphStorage::Disk(_) => Err(Immutable::DiskGraphImmutable)?,
97        }
98    }
99
100    #[inline(always)]
101    pub fn is_immutable(&self) -> bool {
102        match self {
103            GraphStorage::Mem(_) => true,
104            GraphStorage::Unlocked(_) => false,
105            #[cfg(feature = "storage")]
106            GraphStorage::Disk(_) => true,
107        }
108    }
109
110    #[inline(always)]
111    pub fn lock(&self) -> Self {
112        match self {
113            GraphStorage::Unlocked(storage) => {
114                let locked = LockedGraph::new(storage.clone());
115                GraphStorage::Mem(locked)
116            }
117            _ => self.clone(),
118        }
119    }
120
121    #[inline(always)]
122    pub fn nodes(&self) -> NodesStorageEntry {
123        match self {
124            GraphStorage::Mem(storage) => NodesStorageEntry::Mem(&storage.nodes),
125            GraphStorage::Unlocked(storage) => {
126                NodesStorageEntry::Unlocked(storage.storage.nodes.read_lock())
127            }
128            #[cfg(feature = "storage")]
129            GraphStorage::Disk(storage) => {
130                NodesStorageEntry::Disk(DiskNodesRef::new(&storage.inner))
131            }
132        }
133    }
134
135    #[inline(always)]
136    pub fn internalise_node(&self, v: NodeRef) -> Option<VID> {
137        match v {
138            NodeRef::Internal(vid) => Some(vid),
139            node_ref => match self {
140                GraphStorage::Mem(locked) => locked.graph.resolve_node_ref(node_ref),
141                GraphStorage::Unlocked(unlocked) => unlocked.resolve_node_ref(node_ref),
142                #[cfg(feature = "storage")]
143                GraphStorage::Disk(storage) => match v {
144                    NodeRef::External(id) => storage.inner.find_node(id),
145                    _ => unreachable!("VID is handled above!"),
146                },
147            },
148        }
149    }
150
151    #[inline(always)]
152    pub fn unfiltered_num_nodes(&self) -> usize {
153        match self {
154            GraphStorage::Mem(storage) => storage.nodes.len(),
155            GraphStorage::Unlocked(storage) => storage.internal_num_nodes(),
156            #[cfg(feature = "storage")]
157            GraphStorage::Disk(storage) => storage.inner.num_nodes(),
158        }
159    }
160
161    #[inline(always)]
162    pub fn unfiltered_num_edges(&self) -> usize {
163        match self {
164            GraphStorage::Mem(storage) => storage.edges.len(),
165            GraphStorage::Unlocked(storage) => storage.storage.edges_len(),
166            #[cfg(feature = "storage")]
167            GraphStorage::Disk(storage) => storage.inner.count_edges(),
168        }
169    }
170
171    #[inline(always)]
172    pub fn unfiltered_num_layers(&self) -> usize {
173        match self {
174            GraphStorage::Mem(storage) => storage.graph.num_layers(),
175            GraphStorage::Unlocked(storage) => storage.num_layers(),
176            #[cfg(feature = "storage")]
177            GraphStorage::Disk(storage) => storage.inner.layers().len(),
178        }
179    }
180
181    #[inline(always)]
182    pub fn core_nodes(&self) -> NodesStorage {
183        match self {
184            GraphStorage::Mem(storage) => NodesStorage::Mem(storage.nodes.clone()),
185            GraphStorage::Unlocked(storage) => {
186                NodesStorage::Mem(LockedGraph::new(storage.clone()).nodes.clone())
187            }
188            #[cfg(feature = "storage")]
189            GraphStorage::Disk(storage) => {
190                NodesStorage::Disk(DiskNodesOwned::new(storage.inner.clone()))
191            }
192        }
193    }
194
195    #[inline(always)]
196    pub fn core_node<'a>(&'a self, vid: VID) -> NodeStorageEntry<'a> {
197        match self {
198            GraphStorage::Mem(storage) => NodeStorageEntry::Mem(storage.nodes.get_entry(vid)),
199            GraphStorage::Unlocked(storage) => {
200                NodeStorageEntry::Unlocked(storage.storage.get_node(vid))
201            }
202            #[cfg(feature = "storage")]
203            GraphStorage::Disk(storage) => {
204                NodeStorageEntry::Disk(DiskNode::new(&storage.inner, vid))
205            }
206        }
207    }
208
209    #[inline(always)]
210    pub fn edges(&self) -> EdgesStorageRef {
211        match self {
212            GraphStorage::Mem(storage) => EdgesStorageRef::Mem(&storage.edges),
213            GraphStorage::Unlocked(storage) => {
214                EdgesStorageRef::Unlocked(UnlockedEdges(&storage.storage))
215            }
216            #[cfg(feature = "storage")]
217            GraphStorage::Disk(storage) => EdgesStorageRef::Disk(DiskEdgesRef::new(&storage.inner)),
218        }
219    }
220
221    #[inline(always)]
222    pub fn owned_edges(&self) -> EdgesStorage {
223        match self {
224            GraphStorage::Mem(storage) => EdgesStorage::Mem(storage.edges.clone()),
225            GraphStorage::Unlocked(storage) => {
226                GraphStorage::Mem(LockedGraph::new(storage.clone())).owned_edges()
227            }
228            #[cfg(feature = "storage")]
229            GraphStorage::Disk(storage) => EdgesStorage::Disk(DiskEdges::new(storage)),
230        }
231    }
232
233    #[inline(always)]
234    pub fn edge_entry(&self, eid: EID) -> EdgeStorageEntry {
235        match self {
236            GraphStorage::Mem(storage) => EdgeStorageEntry::Mem(storage.edges.get_mem(eid)),
237            GraphStorage::Unlocked(storage) => {
238                EdgeStorageEntry::Unlocked(storage.storage.edge_entry(eid))
239            }
240            #[cfg(feature = "storage")]
241            GraphStorage::Disk(storage) => EdgeStorageEntry::Disk(storage.inner.edge(eid)),
242        }
243    }
244
245    pub fn layer_ids_iter(&self, layer_ids: &LayerIds) -> impl Iterator<Item = usize> {
246        match layer_ids {
247            LayerIds::None => LayerVariants::None(iter::empty()),
248            LayerIds::All => LayerVariants::All(0..self.unfiltered_num_layers()),
249            LayerIds::One(id) => LayerVariants::One(iter::once(*id)),
250            LayerIds::Multiple(ids) => LayerVariants::Multiple(ids.into_iter()),
251        }
252    }
253    //
254    // pub fn into_nodes_iter<'graph, G: GraphViewOps<'graph>>(
255    //     self,
256    //     view: G,
257    //     node_list: NodeList,
258    //     type_filter: Option<Arc<[bool]>>,
259    // ) -> BoxedLIter<'graph, VID> {
260    //     node_list
261    //         .into_iter()
262    //         .filter(move |&vid| {
263    //             let node = self.node_entry(vid);
264    //             type_filter
265    //                 .as_ref()
266    //                 .map_or(true, |type_filter| type_filter[node.node_type_id()])
267    //                 && view.filter_node(node.as_ref())
268    //         })
269    //         .into_dyn_boxed()
270    // }
271    //
272    // pub fn nodes_par<'a, 'graph: 'a, G: GraphViewOps<'graph>>(
273    //     &'a self,
274    //     view: &'a G,
275    //     type_filter: Option<&'a Arc<[bool]>>,
276    // ) -> impl ParallelIterator<Item = VID> + 'a {
277    //     let nodes = self.nodes();
278    //     view.node_list().into_par_iter().filter(move |&vid| {
279    //         let node = nodes.node(vid);
280    //         type_filter.map_or(true, |type_filter| type_filter[node.node_type_id()])
281    //             && view.filter_node(node)
282    //     })
283    // }
284    //
285    // pub fn into_nodes_par<'graph, G: GraphViewOps<'graph>>(
286    //     self,
287    //     view: G,
288    //     node_list: NodeList,
289    //     type_filter: Option<Arc<[bool]>>,
290    // ) -> impl ParallelIterator<Item = VID> + 'graph {
291    //     node_list.into_par_iter().filter(move |&vid| {
292    //         let node = self.node_entry(vid);
293    //         type_filter
294    //             .as_ref()
295    //             .map_or(true, |type_filter| type_filter[node.node_type_id()])
296    //             && view.filter_node(node.as_ref())
297    //     })
298    // }
299    //
300    // pub fn edges_iter<'graph, G: GraphViewOps<'graph>>(
301    //     &'graph self,
302    //     view: &'graph G,
303    // ) -> impl Iterator<Item = EdgeRef> + Send + 'graph {
304    //     let iter = self.edges().iter(view.layer_ids());
305    //
306    //     let filtered = match view.filter_state() {
307    //         FilterState::Neither => FilterVariants::Neither(iter),
308    //         FilterState::Both => {
309    //             let nodes = self.nodes();
310    //             FilterVariants::Both(iter.filter(move |e| {
311    //                 view.filter_edge(e.as_ref(), view.layer_ids())
312    //                     && view.filter_node(nodes.node(e.src()))
313    //                     && view.filter_node(nodes.node(e.dst()))
314    //             }))
315    //         }
316    //         FilterState::Nodes => {
317    //             let nodes = self.nodes();
318    //             FilterVariants::Nodes(iter.filter(move |e| {
319    //                 view.filter_node(nodes.node(e.src())) && view.filter_node(nodes.node(e.dst()))
320    //             }))
321    //         }
322    //         FilterState::Edges | FilterState::BothIndependent => FilterVariants::Edges(
323    //             iter.filter(|e| view.filter_edge(e.as_ref(), view.layer_ids())),
324    //         ),
325    //     };
326    //     filtered.map(|e| e.out_ref())
327    // }
328    //
329    // pub fn into_edges_iter<'graph, G: GraphViewOps<'graph>>(
330    //     self,
331    //     view: G,
332    // ) -> impl Iterator<Item = EdgeRef> + Send + 'graph {
333    //     match view.node_list() {
334    //         NodeList::List { elems } => {
335    //             return elems
336    //                 .into_iter()
337    //                 .flat_map(move |v| {
338    //                     self.clone()
339    //                         .into_node_edges_iter(v, Direction::OUT, view.clone())
340    //                 })
341    //                 .into_dyn_boxed()
342    //         }
343    //         _ => {}
344    //     }
345    //     let edges = self.owned_edges();
346    //     let nodes = self.owned_nodes();
347    //
348    //     match edges {
349    //         EdgesStorage::Mem(edges) => {
350    //             let iter = (0..edges.len()).map(EID);
351    //             let filtered = match view.filter_state() {
352    //                 FilterState::Neither => {
353    //                     FilterVariants::Neither(iter.map(move |eid| edges.get_mem(eid).out_ref()))
354    //                 }
355    //                 FilterState::Both => FilterVariants::Both(iter.filter_map(move |e| {
356    //                     let e = EdgeStorageRef::Mem(edges.get_mem(e));
357    //                     (view.filter_edge(e, view.layer_ids())
358    //                         && view.filter_node(nodes.node_entry(e.src()))
359    //                         && view.filter_node(nodes.node_entry(e.dst())))
360    //                     .then(|| e.out_ref())
361    //                 })),
362    //                 FilterState::Nodes => FilterVariants::Nodes(iter.filter_map(move |e| {
363    //                     let e = EdgeStorageRef::Mem(edges.get_mem(e));
364    //                     (view.filter_node(nodes.node_entry(e.src()))
365    //                         && view.filter_node(nodes.node_entry(e.dst())))
366    //                     .then(|| e.out_ref())
367    //                 })),
368    //                 FilterState::Edges | FilterState::BothIndependent => {
369    //                     FilterVariants::Edges(iter.filter_map(move |e| {
370    //                         let e = EdgeStorageRef::Mem(edges.get_mem(e));
371    //                         view.filter_edge(e, view.layer_ids()).then(|| e.out_ref())
372    //                     }))
373    //                 }
374    //             };
375    //             filtered.into_dyn_boxed()
376    //         }
377    //         #[cfg(feature = "storage")]
378    //         EdgesStorage::Disk(edges) => {
379    //             let edges_clone = edges.clone();
380    //             let iter = edges_clone.into_iter_refs(view.layer_ids().clone());
381    //             let filtered = match view.filter_state() {
382    //                 FilterState::Neither => FilterVariants::Neither(iter),
383    //                 FilterState::Both => FilterVariants::Both(iter.filter_map(move |e| {
384    //                     let edge = EdgeStorageRef::Disk(edges.get(e.pid()));
385    //                     if !view.filter_edge(edge, view.layer_ids()) {
386    //                         return None;
387    //                     }
388    //                     let src = nodes.node_entry(e.src());
389    //                     if !view.filter_node(src) {
390    //                         return None;
391    //                     }
392    //                     let dst = nodes.node_entry(e.dst());
393    //                     if !view.filter_node(dst) {
394    //                         return None;
395    //                     }
396    //                     Some(e)
397    //                 })),
398    //                 FilterState::Nodes => FilterVariants::Nodes(iter.filter_map(move |e| {
399    //                     let src = nodes.node_entry(e.src());
400    //                     if !view.filter_node(src) {
401    //                         return None;
402    //                     }
403    //                     let dst = nodes.node_entry(e.dst());
404    //                     if !view.filter_node(dst) {
405    //                         return None;
406    //                     }
407    //                     Some(e)
408    //                 })),
409    //                 FilterState::Edges | FilterState::BothIndependent => {
410    //                     FilterVariants::Edges(iter.filter_map(move |e| {
411    //                         let edge = EdgeStorageRef::Disk(edges.get(e.pid()));
412    //                         if !view.filter_edge(edge, view.layer_ids()) {
413    //                             return None;
414    //                         }
415    //                         Some(e)
416    //                     }))
417    //                 }
418    //             };
419    //             filtered.into_dyn_boxed()
420    //         }
421    //     }
422    // }
423    //
424    // pub fn edges_par<'graph, G: GraphViewOps<'graph>>(
425    //     &'graph self,
426    //     view: &'graph G,
427    // ) -> impl ParallelIterator<Item = EdgeRef> + 'graph {
428    //     self.edges()
429    //         .par_iter(view.layer_ids())
430    //         .filter(|edge| match view.filter_state() {
431    //             FilterState::Neither => true,
432    //             FilterState::Both => {
433    //                 let src = self.node_entry(edge.src());
434    //                 let dst = self.node_entry(edge.dst());
435    //                 view.filter_edge(edge.as_ref(), view.layer_ids())
436    //                     && view.filter_node(src.as_ref())
437    //                     && view.filter_node(dst.as_ref())
438    //             }
439    //             FilterState::Nodes => {
440    //                 let src = self.node_entry(edge.src());
441    //                 let dst = self.node_entry(edge.dst());
442    //                 view.filter_node(src.as_ref()) && view.filter_node(dst.as_ref())
443    //             }
444    //             FilterState::Edges | FilterState::BothIndependent => {
445    //                 view.filter_edge(edge.as_ref(), view.layer_ids())
446    //             }
447    //         })
448    //         .map(|e| e.out_ref())
449    // }
450    //
451    // pub fn into_edges_par<'graph, G: GraphViewOps<'graph>>(
452    //     self,
453    //     view: G,
454    // ) -> impl ParallelIterator<Item = EdgeRef> + 'graph {
455    //     let edges = self.owned_edges();
456    //     let nodes = self.owned_nodes();
457    //
458    //     match edges {
459    //         EdgesStorage::Mem(edges) => {
460    //             let iter = (0..edges.len()).into_par_iter().map(EID);
461    //             let filtered = match view.filter_state() {
462    //                 FilterState::Neither => FilterVariants::Neither(
463    //                     iter.map(move |eid| edges.get_mem(eid).as_edge_ref()),
464    //                 ),
465    //                 FilterState::Both => FilterVariants::Both(iter.filter_map(move |e| {
466    //                     let e = EdgeStorageRef::Mem(edges.get_mem(e));
467    //                     (view.filter_edge(e, view.layer_ids())
468    //                         && view.filter_node(nodes.node_entry(e.src()))
469    //                         && view.filter_node(nodes.node_entry(e.dst())))
470    //                     .then(|| e.out_ref())
471    //                 })),
472    //                 FilterState::Nodes => FilterVariants::Nodes(iter.filter_map(move |e| {
473    //                     let e = EdgeStorageRef::Mem(edges.get_mem(e));
474    //                     (view.filter_node(nodes.node_entry(e.src()))
475    //                         && view.filter_node(nodes.node_entry(e.dst())))
476    //                     .then(|| e.out_ref())
477    //                 })),
478    //                 FilterState::Edges | FilterState::BothIndependent => {
479    //                     FilterVariants::Edges(iter.filter_map(move |e| {
480    //                         let e = EdgeStorageRef::Mem(edges.get_mem(e));
481    //                         view.filter_edge(e, view.layer_ids()).then(|| e.out_ref())
482    //                     }))
483    //                 }
484    //             };
485    //             #[cfg(feature = "storage")]
486    //             {
487    //                 StorageVariants::Mem(filtered)
488    //             }
489    //             #[cfg(not(feature = "storage"))]
490    //             {
491    //                 filtered
492    //             }
493    //         }
494    //         #[cfg(feature = "storage")]
495    //         EdgesStorage::Disk(edges) => {
496    //             let edges_clone = edges.clone();
497    //             let iter = edges_clone.into_par_iter_refs(view.layer_ids().clone());
498    //             let filtered = match view.filter_state() {
499    //                 FilterState::Neither => FilterVariants::Neither(
500    //                     iter.map(move |eid| EdgeStorageRef::Disk(edges.get(eid)).out_ref()),
501    //                 ),
502    //                 FilterState::Both => FilterVariants::Both(iter.filter_map(move |eid| {
503    //                     let e = EdgeStorageRef::Disk(edges.get(eid));
504    //                     if !view.filter_edge(e, view.layer_ids()) {
505    //                         return None;
506    //                     }
507    //                     let src = nodes.node_entry(e.src());
508    //                     if !view.filter_node(src) {
509    //                         return None;
510    //                     }
511    //                     let dst = nodes.node_entry(e.dst());
512    //                     if !view.filter_node(dst) {
513    //                         return None;
514    //                     }
515    //                     Some(e.out_ref())
516    //                 })),
517    //                 FilterState::Nodes => FilterVariants::Nodes(iter.filter_map(move |eid| {
518    //                     let e = EdgeStorageRef::Disk(edges.get(eid));
519    //                     let src = nodes.node_entry(e.src());
520    //                     if !view.filter_node(src) {
521    //                         return None;
522    //                     }
523    //                     let dst = nodes.node_entry(e.dst());
524    //                     if !view.filter_node(dst) {
525    //                         return None;
526    //                     }
527    //                     Some(e.out_ref())
528    //                 })),
529    //                 FilterState::Edges | FilterState::BothIndependent => {
530    //                     FilterVariants::Edges(iter.filter_map(move |eid| {
531    //                         let e = EdgeStorageRef::Disk(edges.get(eid));
532    //                         if !view.filter_edge(e, view.layer_ids()) {
533    //                             return None;
534    //                         }
535    //                         Some(e.out_ref())
536    //                     }))
537    //                 }
538    //             };
539    //             StorageVariants::Disk(filtered)
540    //         }
541    //     }
542    // }
543    //
544    // pub fn node_neighbours_iter<'a, 'graph: 'a, G: GraphViewOps<'graph>>(
545    //     &'a self,
546    //     node: VID,
547    //     dir: Direction,
548    //     view: &'a G,
549    // ) -> impl Iterator<Item = VID> + Send + 'a {
550    //     self.node_edges_iter(node, dir, view)
551    //         .map(|e| e.remote())
552    //         .dedup()
553    // }
554    //
555    // pub fn into_node_neighbours_iter<'graph, G: GraphViewOps<'graph>>(
556    //     self,
557    //     node: VID,
558    //     dir: Direction,
559    //     view: G,
560    // ) -> impl Iterator<Item = VID> + 'graph {
561    //     self.into_node_edges_iter(node, dir, view)
562    //         .map(|e| e.remote())
563    //         .dedup()
564    // }
565    //
566    // #[inline]
567    // pub fn node_degree<'graph, G: GraphViewOps<'graph>>(
568    //     &self,
569    //     node: VID,
570    //     dir: Direction,
571    //     view: &G,
572    // ) -> usize {
573    //     if matches!(view.filter_state(), FilterState::Neither) {
574    //         self.node_entry(node).degree(view.layer_ids(), dir)
575    //     } else {
576    //         self.node_neighbours_iter(node, dir, view).count()
577    //     }
578    // }
579    //
580    // pub fn node_edges_iter<'a, 'graph: 'a, G: GraphViewOps<'graph>>(
581    //     &'a self,
582    //     node: VID,
583    //     dir: Direction,
584    //     view: &'a G,
585    // ) -> impl Iterator<Item = EdgeRef> + 'a {
586    //     let source = self.node_entry(node);
587    //     let layers = view.layer_ids();
588    //     let iter = source.into_edges_iter(layers, dir);
589    //     match view.filter_state() {
590    //         FilterState::Neither => FilterVariants::Neither(iter),
591    //         FilterState::Both => FilterVariants::Both(iter.filter(|&e| {
592    //             view.filter_edge(self.edge_entry(e.pid()).as_ref(), view.layer_ids())
593    //                 && view.filter_node(self.node_entry(e.remote()).as_ref())
594    //         })),
595    //         FilterState::Nodes => FilterVariants::Nodes(
596    //             iter.filter(|e| view.filter_node(self.node_entry(e.remote()).as_ref())),
597    //         ),
598    //         FilterState::Edges | FilterState::BothIndependent => {
599    //             FilterVariants::Edges(iter.filter(|&e| {
600    //                 view.filter_edge(self.edge_entry(e.pid()).as_ref(), view.layer_ids())
601    //             }))
602    //         }
603    //     }
604    // }
605    //
606    // pub fn into_node_edges_iter<'graph, G: GraphViewOps<'graph>>(
607    //     self,
608    //     node: VID,
609    //     dir: Direction,
610    //     view: G,
611    // ) -> impl Iterator<Item = EdgeRef> + 'graph {
612    //     let layers = view.layer_ids().clone();
613    //     let local = self.owned_node(node);
614    //     let iter = local.into_edges_iter(layers, dir);
615    //
616    //     match view.filter_state() {
617    //         FilterState::Neither => FilterVariants::Neither(iter),
618    //         FilterState::Both => FilterVariants::Both(iter.filter(move |&e| {
619    //             view.filter_edge(self.edge_entry(e.pid()).as_ref(), view.layer_ids())
620    //                 && view.filter_node(self.node_entry(e.remote()).as_ref())
621    //         })),
622    //         FilterState::Nodes => FilterVariants::Nodes(
623    //             iter.filter(move |e| view.filter_node(self.node_entry(e.remote()).as_ref())),
624    //         ),
625    //         FilterState::Edges | FilterState::BothIndependent => {
626    //             FilterVariants::Edges(iter.filter(move |&e| {
627    //                 view.filter_edge(self.edge_entry(e.pid()).as_ref(), view.layer_ids())
628    //             }))
629    //         }
630    //     }
631    // }
632
633    pub fn node_meta(&self) -> &Meta {
634        match self {
635            GraphStorage::Mem(storage) => &storage.graph.node_meta,
636            GraphStorage::Unlocked(storage) => &storage.node_meta,
637            #[cfg(feature = "storage")]
638            GraphStorage::Disk(storage) => storage.node_meta(),
639        }
640    }
641
642    pub fn edge_meta(&self) -> &Meta {
643        match self {
644            GraphStorage::Mem(storage) => &storage.graph.edge_meta,
645            GraphStorage::Unlocked(storage) => &storage.edge_meta,
646            #[cfg(feature = "storage")]
647            GraphStorage::Disk(storage) => storage.edge_meta(),
648        }
649    }
650
651    pub fn graph_meta(&self) -> &GraphMeta {
652        match self {
653            GraphStorage::Mem(storage) => &storage.graph.graph_meta,
654            GraphStorage::Unlocked(storage) => &storage.graph_meta,
655            #[cfg(feature = "storage")]
656            GraphStorage::Disk(storage) => storage.graph_meta(),
657        }
658    }
659}