Skip to main content

raphtory_api/core/entities/
mod.rs

1use super::input::input_node::parse_u64_strict;
2use crate::iter::IntoDynBoxed;
3use bytemuck::{Pod, Zeroable};
4use itertools::Itertools;
5use num_traits::ToPrimitive;
6use serde::{Deserialize, Serialize};
7use std::{
8    borrow::Cow,
9    fmt::{Debug, Display, Formatter},
10    iter,
11};
12
13pub mod edges;
14pub mod layers;
15pub mod properties;
16
17use crate::core::entities::properties::prop::PropType;
18pub use layers::*;
19
20// The only reason this is public is because the physical IDs of the nodes don’t move.
21#[repr(transparent)]
22#[derive(
23    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
24)]
25pub struct VID(pub usize);
26
27impl Default for VID {
28    fn default() -> Self {
29        VID(usize::MAX)
30    }
31}
32
33impl VID {
34    pub fn index(&self) -> usize {
35        self.0
36    }
37
38    pub fn as_u64(&self) -> u64 {
39        self.0 as u64
40    }
41
42    /// check if the VID points to a node
43    #[inline]
44    pub fn is_initialised(&self) -> bool {
45        self.0 != usize::MAX
46    }
47
48    #[inline]
49    /// either return `self` if it is initialised, otherwise run the `init` closure
50    pub fn or_init(self, init: impl FnOnce() -> VID) -> Self {
51        if self.is_initialised() {
52            self
53        } else {
54            init()
55        }
56    }
57
58    #[inline]
59    /// either return `Some(self)` if it is initialised, otherwise, run the `init` closure
60    pub fn or_maybe_init(self, init: impl FnOnce() -> Option<VID>) -> Option<Self> {
61        if self.is_initialised() {
62            Some(self)
63        } else {
64            init()
65        }
66    }
67
68    #[inline]
69    /// return `Some(self)` if initialised, otherwise, `None`
70    pub fn into_option(self) -> Option<Self> {
71        self.is_initialised().then_some(self)
72    }
73}
74
75impl From<usize> for VID {
76    fn from(id: usize) -> Self {
77        VID(id)
78    }
79}
80
81impl From<VID> for usize {
82    fn from(id: VID) -> Self {
83        id.0
84    }
85}
86
87#[repr(transparent)]
88#[derive(
89    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
90)]
91pub struct EID(pub usize);
92
93impl Default for EID {
94    fn default() -> Self {
95        EID(usize::MAX)
96    }
97}
98
99impl EID {
100    pub fn index(&self) -> usize {
101        self.0
102    }
103
104    pub fn as_u64(self) -> u64 {
105        self.0 as u64
106    }
107
108    pub fn with_layer(self, layer: LayerId) -> ELID {
109        ELID::new(self, layer)
110    }
111
112    pub fn with_layer_deletion(self, layer: LayerId) -> ELID {
113        ELID::new_deletion(self, layer)
114    }
115}
116
117impl From<EID> for usize {
118    fn from(id: EID) -> Self {
119        id.0
120    }
121}
122
123impl From<usize> for EID {
124    fn from(id: usize) -> Self {
125        EID(id)
126    }
127}
128
129impl EID {
130    pub fn from_u64(id: u64) -> Self {
131        EID(id as usize)
132    }
133}
134
135impl From<ELID> for EID {
136    fn from(elid: ELID) -> Self {
137        elid.eid()
138    }
139}
140
141#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
142pub struct ELID {
143    edge_and_deletion: EDID,
144    layer: LayerId,
145}
146
147/// Edge id with deletion flag
148#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
149pub struct EDID(pub usize);
150
151impl Debug for EDID {
152    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
153        f.debug_struct("EDID")
154            .field("edge", &self.eid())
155            .field("deletion", &self.is_deletion())
156            .finish()
157    }
158}
159
160impl EDID {
161    pub fn new(edge: EID) -> Self {
162        EDID(edge.0)
163    }
164
165    pub fn new_deletion(edge: EID) -> Self {
166        EDID(edge.0 | DELETION_FLAG)
167    }
168
169    pub fn eid(&self) -> EID {
170        EID(self.0 & !DELETION_FLAG)
171    }
172
173    pub fn is_deletion(&self) -> bool {
174        self.0 & DELETION_FLAG != 0
175    }
176
177    pub fn into_deletion(mut self) -> Self {
178        self.0 = self.0 | DELETION_FLAG;
179        self
180    }
181}
182
183impl Debug for ELID {
184    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185        f.debug_struct("ELID")
186            .field("edge", &self.edge_and_deletion)
187            .field("layer", &self.layer())
188            .field("deletion", &self.is_deletion())
189            .finish()
190    }
191}
192
193const DELETION_FLAG: usize = 1usize.reverse_bits();
194pub const MAX_EID: usize = usize::MAX & !DELETION_FLAG;
195
196impl ELID {
197    pub fn new(edge: EID, layer: LayerId) -> Self {
198        ELID {
199            edge_and_deletion: EDID::new(edge),
200            layer,
201        }
202    }
203
204    pub fn new_flagged(edge_and_deletion: EDID, layer: LayerId) -> Self {
205        ELID {
206            edge_and_deletion,
207            layer,
208        }
209    }
210
211    pub fn new_deletion(edge: EID, layer: LayerId) -> Self {
212        ELID {
213            edge_and_deletion: EDID::new_deletion(edge),
214            layer,
215        }
216    }
217
218    pub fn layer(&self) -> LayerId {
219        self.layer
220    }
221
222    pub fn eid(&self) -> EID {
223        self.edge_and_deletion.eid()
224    }
225
226    pub fn eid_and_flag(&self) -> EDID {
227        self.edge_and_deletion
228    }
229
230    pub fn is_deletion(&self) -> bool {
231        self.edge_and_deletion.is_deletion()
232    }
233
234    pub fn into_deletion(mut self) -> Self {
235        self.edge_and_deletion = self.edge_and_deletion.into_deletion();
236        self
237    }
238}
239
240#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
241pub enum GID {
242    U64(u64),
243    Str(String),
244}
245
246impl PartialEq<str> for GID {
247    fn eq(&self, other: &str) -> bool {
248        match self {
249            GID::U64(_) => false,
250            GID::Str(id) => id == other,
251        }
252    }
253}
254
255impl PartialEq<String> for GID {
256    fn eq(&self, other: &String) -> bool {
257        match self {
258            GID::U64(_) => false,
259            GID::Str(id) => id == other,
260        }
261    }
262}
263
264impl PartialEq<u64> for GID {
265    fn eq(&self, other: &u64) -> bool {
266        match self {
267            GID::Str(_) => false,
268            GID::U64(id) => id == other,
269        }
270    }
271}
272
273impl Default for GID {
274    fn default() -> Self {
275        GID::U64(u64::MAX)
276    }
277}
278
279impl Display for GID {
280    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
281        match self {
282            GID::U64(v) => write!(f, "{}", v),
283            GID::Str(v) => write!(f, "{}", v),
284        }
285    }
286}
287
288impl GID {
289    pub fn dtype(&self) -> GidType {
290        match self {
291            GID::U64(_) => GidType::U64,
292            GID::Str(_) => GidType::Str,
293        }
294    }
295    pub fn into_str(self) -> Option<String> {
296        match self {
297            GID::Str(v) => Some(v),
298            _ => None,
299        }
300    }
301
302    pub fn into_u64(self) -> Option<u64> {
303        match self {
304            GID::U64(v) => Some(v),
305            _ => None,
306        }
307    }
308
309    pub fn as_str(&self) -> Option<&str> {
310        match self {
311            GID::Str(v) => Some(v.as_str()),
312            _ => None,
313        }
314    }
315
316    pub fn as_u64(&self) -> Option<u64> {
317        match self {
318            GID::U64(v) => Some(*v),
319            _ => None,
320        }
321    }
322
323    pub fn to_str(&self) -> Cow<'_, str> {
324        match self {
325            GID::U64(v) => Cow::Owned(v.to_string()),
326            GID::Str(v) => Cow::Borrowed(v),
327        }
328    }
329
330    pub fn to_i64(&self) -> Option<i64> {
331        match self {
332            GID::U64(v) => v.to_i64(),
333            GID::Str(v) => parse_u64_strict(v)?.to_i64(),
334        }
335    }
336
337    pub fn to_u64(&self) -> Option<u64> {
338        match self {
339            GID::U64(v) => Some(*v),
340            GID::Str(v) => parse_u64_strict(v),
341        }
342    }
343
344    pub fn as_ref(&self) -> GidRef<'_> {
345        match self {
346            GID::U64(v) => GidRef::U64(*v),
347            GID::Str(v) => GidRef::Str(v),
348        }
349    }
350}
351
352impl From<u64> for GID {
353    fn from(id: u64) -> Self {
354        Self::U64(id)
355    }
356}
357
358impl From<&u64> for GID {
359    fn from(value: &u64) -> Self {
360        GID::U64(*value)
361    }
362}
363
364impl From<String> for GID {
365    fn from(id: String) -> Self {
366        Self::Str(id)
367    }
368}
369
370impl From<&str> for GID {
371    fn from(id: &str) -> Self {
372        Self::Str(id.to_string())
373    }
374}
375
376impl<'a> From<GidRef<'a>> for GID {
377    fn from(value: GidRef<'a>) -> Self {
378        match value {
379            GidRef::U64(v) => GID::U64(v),
380            GidRef::Str(v) => GID::Str(v.to_owned()),
381        }
382    }
383}
384
385#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
386pub enum GidRef<'a> {
387    U64(u64),
388    Str(&'a str),
389}
390
391#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
392pub enum GidCow<'a> {
393    U64(u64),
394    Str(Cow<'a, str>),
395}
396
397impl<'a> From<GidRef<'a>> for GidCow<'a> {
398    fn from(value: GidRef<'a>) -> Self {
399        match value {
400            GidRef::U64(v) => Self::U64(v),
401            GidRef::Str(v) => Self::Str(Cow::Borrowed(v)),
402        }
403    }
404}
405
406impl<'a> GidCow<'a> {
407    pub fn as_ref<'b>(&'b self) -> GidRef<'b>
408    where
409        'a: 'b,
410    {
411        match self {
412            GidCow::U64(v) => GidRef::U64(*v),
413            GidCow::Str(v) => GidRef::Str(v),
414        }
415    }
416
417    pub fn into_owned(self) -> GID {
418        match self {
419            GidCow::U64(v) => GID::U64(v),
420            GidCow::Str(v) => GID::Str(v.into_owned()),
421        }
422    }
423}
424
425#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
426pub enum GidType {
427    U64,
428    Str,
429}
430
431impl Display for GidType {
432    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
433        match self {
434            GidType::U64 => {
435                write!(f, "Numeric")
436            }
437            GidType::Str => {
438                write!(f, "String")
439            }
440        }
441    }
442}
443
444impl GidType {
445    pub fn from_prop_type(prop_type: &PropType) -> Option<Self> {
446        match prop_type {
447            PropType::Str => Some(GidType::Str),
448            PropType::U64 | PropType::U32 | PropType::I64 | PropType::I32 => Some(GidType::U64),
449            _ => None,
450        }
451    }
452}
453
454impl Display for GidRef<'_> {
455    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
456        match self {
457            GidRef::U64(v) => write!(f, "{v}"),
458            GidRef::Str(v) => write!(f, "{v}"),
459        }
460    }
461}
462
463impl<'a> From<&'a GID> for GidRef<'a> {
464    fn from(value: &'a GID) -> Self {
465        match value {
466            GID::U64(v) => GidRef::U64(*v),
467            GID::Str(v) => GidRef::Str(v),
468        }
469    }
470}
471
472impl<'a> From<&'a str> for GidRef<'a> {
473    fn from(value: &'a str) -> Self {
474        GidRef::Str(value)
475    }
476}
477
478impl From<u64> for GidRef<'_> {
479    fn from(value: u64) -> Self {
480        GidRef::U64(value)
481    }
482}
483
484impl<'a> GidRef<'a> {
485    pub fn dtype(self) -> GidType {
486        match self {
487            GidRef::U64(_) => GidType::U64,
488            GidRef::Str(_) => GidType::Str,
489        }
490    }
491    pub fn as_str(self) -> Option<&'a str> {
492        match self {
493            GidRef::Str(s) => Some(s),
494            _ => None,
495        }
496    }
497
498    pub fn as_u64(self) -> Option<u64> {
499        match self {
500            GidRef::U64(v) => Some(v),
501            _ => None,
502        }
503    }
504
505    pub fn to_owned(self) -> GID {
506        match self {
507            GidRef::U64(v) => GID::U64(v),
508            GidRef::Str(v) => GID::Str(v.to_owned()),
509        }
510    }
511
512    pub fn to_str(self) -> Cow<'a, str> {
513        match self {
514            GidRef::U64(v) => Cow::Owned(v.to_string()),
515            GidRef::Str(v) => Cow::Borrowed(v),
516        }
517    }
518
519    pub fn to_i64(self) -> Option<i64> {
520        match self {
521            GidRef::U64(v) => v.to_i64(),
522            GidRef::Str(v) => parse_u64_strict(v)?.to_i64(),
523        }
524    }
525
526    pub fn to_u64(self) -> Option<u64> {
527        match self {
528            GidRef::U64(v) => Some(v),
529            GidRef::Str(v) => parse_u64_strict(v),
530        }
531    }
532}
533
534#[cfg(test)]
535mod test {
536    use crate::core::entities::{LayerId, Multiple};
537
538    #[test]
539    fn empty_bit_multiple() {
540        let bm = super::Multiple::default();
541        let actual = bm.into_iter().collect::<Vec<_>>();
542        let expected: Vec<LayerId> = vec![];
543        assert_eq!(actual, expected);
544    }
545
546    #[test]
547    fn set_one() {
548        let bm: Multiple = [1].into_iter().collect();
549        let actual = bm.into_iter().collect::<Vec<_>>();
550        assert_eq!(actual, vec![1usize]);
551    }
552
553    #[test]
554    fn set_two() {
555        let bm: Multiple = [1, 67].into_iter().collect();
556
557        let actual = bm.into_iter().collect::<Vec<_>>();
558        assert_eq!(actual, vec![1usize, 67]);
559    }
560}
561
562impl LayerIds {
563    pub fn intersect(&self, other: &LayerIds) -> LayerIds {
564        match (self, other) {
565            (LayerIds::None, _) => LayerIds::None,
566            (_, LayerIds::None) => LayerIds::None,
567            (LayerIds::All, other) => other.clone(),
568            (this, LayerIds::All) => this.clone(),
569            (LayerIds::One(id), other) => {
570                if other.contains(id) {
571                    LayerIds::One(*id)
572                } else {
573                    LayerIds::None
574                }
575            }
576            (LayerIds::Multiple(ids), other) => {
577                let ids: Vec<_> = ids.iter().filter(|id| other.contains(id)).collect();
578                match ids.len() {
579                    0 => LayerIds::None,
580                    1 => LayerIds::One(ids[0]),
581                    _ => LayerIds::Multiple(ids.into()),
582                }
583            }
584        }
585    }
586
587    pub fn union(&self, other: &LayerIds) -> LayerIds {
588        match (self, other) {
589            (LayerIds::All, _) | (_, LayerIds::All) => LayerIds::All,
590            (LayerIds::None, o) | (o, LayerIds::None) => o.clone(),
591            (LayerIds::One(id), LayerIds::One(other_id)) => {
592                if id == other_id {
593                    LayerIds::One(*id)
594                } else {
595                    LayerIds::Multiple([*id.min(other_id), *id.max(other_id)].into_iter().collect())
596                }
597            }
598            (LayerIds::Multiple(ids), LayerIds::Multiple(other_ids)) => {
599                LayerIds::Multiple(ids.iter().merge(other_ids.iter()).dedup().collect())
600            }
601            (LayerIds::One(id), LayerIds::Multiple(ids))
602            | (LayerIds::Multiple(ids), LayerIds::One(id)) => {
603                if ids.contains(*id) {
604                    LayerIds::Multiple(ids.clone())
605                } else {
606                    LayerIds::Multiple(ids.iter().merge(iter::once(*id)).collect())
607                }
608            }
609        }
610    }
611
612    pub fn contains(&self, layer_id: &LayerId) -> bool {
613        match self {
614            LayerIds::All => true,
615            LayerIds::One(id) => id == layer_id,
616            LayerIds::Multiple(ids) => ids.contains(*layer_id),
617            LayerIds::None => false,
618        }
619    }
620
621    pub fn is_none(&self) -> bool {
622        matches!(self, LayerIds::None)
623    }
624
625    pub fn is_single(&self) -> bool {
626        matches!(self, LayerIds::One(_))
627    }
628
629    pub fn is_all(&self) -> bool {
630        matches!(self, LayerIds::All)
631    }
632
633    pub fn iter(&self, num_layers: usize) -> impl Iterator<Item = LayerId> + use<'_> {
634        match self {
635            LayerIds::None => iter::empty().into_dyn_boxed(),
636            LayerIds::All => (0..num_layers).map(LayerId).into_dyn_boxed(),
637            LayerIds::One(id) => iter::once(*id).into_dyn_boxed(),
638            LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
639        }
640    }
641
642    pub fn into_iter(self, num_layers: usize) -> impl Iterator<Item = LayerId> {
643        match self {
644            LayerIds::None => iter::empty().into_dyn_boxed(),
645            LayerIds::All => (0..num_layers).map(LayerId).into_dyn_boxed(),
646            LayerIds::One(id) => iter::once(id).into_dyn_boxed(),
647            LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
648        }
649    }
650}
651
652impl From<Vec<usize>> for LayerIds {
653    fn from(v: Vec<usize>) -> Self {
654        match v.len() {
655            0 => LayerIds::All,
656            1 => LayerIds::One(LayerId(v[0])),
657            _ => LayerIds::Multiple(v.into()),
658        }
659    }
660}
661
662impl From<Vec<LayerId>> for LayerIds {
663    fn from(v: Vec<LayerId>) -> Self {
664        match v.len() {
665            0 => LayerIds::All,
666            1 => LayerIds::One(v[0]),
667            _ => LayerIds::Multiple(v.into()),
668        }
669    }
670}
671
672impl<const N: usize> From<[usize; N]> for LayerIds {
673    fn from(v: [usize; N]) -> Self {
674        match v.len() {
675            0 => LayerIds::All,
676            1 => LayerIds::One(LayerId(v[0])),
677            _ => LayerIds::Multiple(v.into_iter().collect()),
678        }
679    }
680}
681
682impl<const N: usize> From<[LayerId; N]> for LayerIds {
683    fn from(v: [LayerId; N]) -> Self {
684        match v.len() {
685            0 => LayerIds::All,
686            1 => LayerIds::One(v[0]),
687            _ => LayerIds::Multiple(v.into_iter().collect()),
688        }
689    }
690}
691
692impl From<usize> for LayerIds {
693    fn from(id: usize) -> Self {
694        LayerIds::One(LayerId(id))
695    }
696}
697
698impl From<LayerId> for LayerIds {
699    fn from(id: LayerId) -> Self {
700        LayerIds::One(id)
701    }
702}
703
704#[cfg(test)]
705mod tests {
706    use std::hash::{Hash, Hasher};
707
708    use super::*;
709    use crate::core::entities::{LayerId, EID, MAX_EID};
710    use proptest::{prelude::*, prop_assert, prop_assert_eq, prop_oneof, proptest};
711
712    #[test]
713    fn test_elid_layer_proptest() {
714        proptest!(|(eid in 0..=MAX_EID, layer in 0..=usize::MAX)| {
715            let elid = EID(eid).with_layer(LayerId(layer));
716            prop_assert_eq!(elid.layer(), LayerId(layer));
717            prop_assert!(!elid.is_deletion());
718
719            let elid_deleted = elid.into_deletion();
720            prop_assert_eq!(elid_deleted.layer(), LayerId(layer));
721            prop_assert_eq!(elid_deleted.eid(), EID(eid));
722            prop_assert!(elid_deleted.is_deletion())
723        })
724    }
725
726    #[test]
727    fn test_elid_deletion_proptest() {
728        proptest!(|(eid in 0..=MAX_EID, layer in 0..=usize::MAX)| {
729            let elid = EID(eid).with_layer_deletion(LayerId(layer));
730            prop_assert_eq!(elid.layer(), LayerId(layer));
731            prop_assert!(elid.is_deletion());
732            prop_assert_eq!(elid, elid.into_deletion());
733            prop_assert_eq!(elid.eid().0, eid);
734        })
735    }
736
737    #[test]
738    fn gid_and_gid_ref_hash_to_the_same_thing() {
739        proptest!(|(gid in prop_oneof![any::<u64>().prop_map(GID::U64), ".*".prop_map(GID::Str)])| {
740            let gid_ref: GidRef<'_> = (&gid).into();
741            let mut gid_hasher = std::collections::hash_map::DefaultHasher::new();
742            let mut gid_ref_hasher = std::collections::hash_map::DefaultHasher::new();
743            gid.hash(&mut gid_hasher);
744            gid_ref.hash(&mut gid_ref_hasher);
745            prop_assert_eq!(gid_hasher.finish(), gid_ref_hasher.finish());
746        })
747    }
748}