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 edges::edge_ref::EdgeRef;
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
17pub use layers::*;
18
19// The only reason this is public is because the physical IDs of the nodes don’t move.
20#[repr(transparent)]
21#[derive(
22    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
23)]
24pub struct VID(pub usize);
25
26impl Default for VID {
27    fn default() -> Self {
28        VID(usize::MAX)
29    }
30}
31
32impl VID {
33    pub fn index(&self) -> usize {
34        self.0
35    }
36
37    pub fn as_u64(&self) -> u64 {
38        self.0 as u64
39    }
40}
41
42impl From<usize> for VID {
43    fn from(id: usize) -> Self {
44        VID(id)
45    }
46}
47
48impl From<VID> for usize {
49    fn from(id: VID) -> Self {
50        id.0
51    }
52}
53
54#[repr(transparent)]
55#[derive(
56    Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
57)]
58pub struct EID(pub usize);
59
60impl Default for EID {
61    fn default() -> Self {
62        EID(usize::MAX)
63    }
64}
65
66impl EID {
67    pub fn as_u64(self) -> u64 {
68        self.0 as u64
69    }
70
71    pub fn with_layer(self, layer: usize) -> ELID {
72        ELID::new(self, layer)
73    }
74
75    pub fn with_layer_deletion(self, layer: usize) -> ELID {
76        ELID::new_deletion(self, layer)
77    }
78}
79
80impl From<EID> for usize {
81    fn from(id: EID) -> Self {
82        id.0
83    }
84}
85
86impl From<usize> for EID {
87    fn from(id: usize) -> Self {
88        EID(id)
89    }
90}
91
92impl EID {
93    pub fn from_u64(id: u64) -> Self {
94        EID(id as usize)
95    }
96}
97
98#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
99pub struct ELID {
100    pub edge: EID,
101    layer_and_deletion: usize,
102}
103
104impl Debug for ELID {
105    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106        f.debug_struct("ELID")
107            .field("edge", &self.edge)
108            .field("layer", &self.layer())
109            .field("deletion", &self.is_deletion())
110            .finish()
111    }
112}
113
114const LAYER_FLAG: usize = 1usize.reverse_bits();
115pub const MAX_LAYER: usize = usize::MAX & !LAYER_FLAG;
116
117impl ELID {
118    pub fn new(edge: EID, layer: usize) -> Self {
119        ELID {
120            edge,
121            layer_and_deletion: layer,
122        }
123    }
124
125    pub fn new_deletion(edge: EID, layer: usize) -> Self {
126        ELID {
127            edge,
128            layer_and_deletion: layer | LAYER_FLAG,
129        }
130    }
131
132    pub fn layer(&self) -> usize {
133        self.layer_and_deletion & !LAYER_FLAG
134    }
135
136    pub fn is_deletion(&self) -> bool {
137        self.layer_and_deletion & LAYER_FLAG != 0
138    }
139
140    pub fn into_deletion(mut self) -> Self {
141        self.layer_and_deletion = self.layer_and_deletion | LAYER_FLAG;
142        self
143    }
144}
145
146#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
147pub enum GID {
148    U64(u64),
149    Str(String),
150}
151
152impl PartialEq<str> for GID {
153    fn eq(&self, other: &str) -> bool {
154        match self {
155            GID::U64(_) => false,
156            GID::Str(id) => id == other,
157        }
158    }
159}
160
161impl PartialEq<String> for GID {
162    fn eq(&self, other: &String) -> bool {
163        match self {
164            GID::U64(_) => false,
165            GID::Str(id) => id == other,
166        }
167    }
168}
169
170impl PartialEq<u64> for GID {
171    fn eq(&self, other: &u64) -> bool {
172        match self {
173            GID::Str(_) => false,
174            GID::U64(id) => id == other,
175        }
176    }
177}
178
179impl Default for GID {
180    fn default() -> Self {
181        GID::U64(u64::MAX)
182    }
183}
184
185impl Display for GID {
186    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187        match self {
188            GID::U64(v) => write!(f, "{}", v),
189            GID::Str(v) => write!(f, "{}", v),
190        }
191    }
192}
193
194impl GID {
195    pub fn dtype(&self) -> GidType {
196        match self {
197            GID::U64(_) => GidType::U64,
198            GID::Str(_) => GidType::Str,
199        }
200    }
201    pub fn into_str(self) -> Option<String> {
202        match self {
203            GID::Str(v) => Some(v),
204            _ => None,
205        }
206    }
207
208    pub fn into_u64(self) -> Option<u64> {
209        match self {
210            GID::U64(v) => Some(v),
211            _ => None,
212        }
213    }
214
215    pub fn as_str(&self) -> Option<&str> {
216        match self {
217            GID::Str(v) => Some(v.as_str()),
218            _ => None,
219        }
220    }
221
222    pub fn as_u64(&self) -> Option<u64> {
223        match self {
224            GID::U64(v) => Some(*v),
225            _ => None,
226        }
227    }
228
229    pub fn to_str(&'_ self) -> Cow<'_, str> {
230        match self {
231            GID::U64(v) => Cow::Owned(v.to_string()),
232            GID::Str(v) => Cow::Borrowed(v),
233        }
234    }
235
236    pub fn to_i64(&self) -> Option<i64> {
237        match self {
238            GID::U64(v) => v.to_i64(),
239            GID::Str(v) => parse_u64_strict(v)?.to_i64(),
240        }
241    }
242
243    pub fn to_u64(&self) -> Option<u64> {
244        match self {
245            GID::U64(v) => Some(*v),
246            GID::Str(v) => parse_u64_strict(v),
247        }
248    }
249
250    pub fn as_ref(&self) -> GidRef<'_> {
251        match self {
252            GID::U64(v) => GidRef::U64(*v),
253            GID::Str(v) => GidRef::Str(v),
254        }
255    }
256}
257
258impl From<u64> for GID {
259    fn from(id: u64) -> Self {
260        Self::U64(id)
261    }
262}
263
264impl From<&u64> for GID {
265    fn from(value: &u64) -> Self {
266        GID::U64(*value)
267    }
268}
269
270impl From<String> for GID {
271    fn from(id: String) -> Self {
272        Self::Str(id)
273    }
274}
275
276impl From<&str> for GID {
277    fn from(id: &str) -> Self {
278        Self::Str(id.to_string())
279    }
280}
281
282impl<'a> From<GidRef<'a>> for GID {
283    fn from(value: GidRef<'a>) -> Self {
284        match value {
285            GidRef::U64(v) => GID::U64(v),
286            GidRef::Str(v) => GID::Str(v.to_owned()),
287        }
288    }
289}
290
291#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
292pub enum GidRef<'a> {
293    U64(u64),
294    Str(&'a str),
295}
296
297#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
298pub enum GidType {
299    U64,
300    Str,
301}
302
303impl Display for GidType {
304    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
305        match self {
306            GidType::U64 => {
307                write!(f, "Numeric")
308            }
309            GidType::Str => {
310                write!(f, "String")
311            }
312        }
313    }
314}
315
316impl Display for GidRef<'_> {
317    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
318        match self {
319            GidRef::U64(v) => write!(f, "{}", v),
320            GidRef::Str(v) => write!(f, "{}", v),
321        }
322    }
323}
324
325impl<'a> From<&'a GID> for GidRef<'a> {
326    fn from(value: &'a GID) -> Self {
327        match value {
328            GID::U64(v) => GidRef::U64(*v),
329            GID::Str(v) => GidRef::Str(v),
330        }
331    }
332}
333
334impl<'a> From<&'a str> for GidRef<'a> {
335    fn from(value: &'a str) -> Self {
336        GidRef::Str(value)
337    }
338}
339
340impl<'a> GidRef<'a> {
341    pub fn dtype(self) -> GidType {
342        match self {
343            GidRef::U64(_) => GidType::U64,
344            GidRef::Str(_) => GidType::Str,
345        }
346    }
347    pub fn as_str(self) -> Option<&'a str> {
348        match self {
349            GidRef::Str(s) => Some(s),
350            _ => None,
351        }
352    }
353
354    pub fn as_u64(self) -> Option<u64> {
355        match self {
356            GidRef::U64(v) => Some(v),
357            _ => None,
358        }
359    }
360
361    pub fn to_owned(self) -> GID {
362        match self {
363            GidRef::U64(v) => GID::U64(v),
364            GidRef::Str(v) => GID::Str(v.to_owned()),
365        }
366    }
367
368    pub fn to_str(self) -> Cow<'a, str> {
369        match self {
370            GidRef::U64(v) => Cow::Owned(v.to_string()),
371            GidRef::Str(v) => Cow::Borrowed(v),
372        }
373    }
374
375    pub fn to_i64(self) -> Option<i64> {
376        match self {
377            GidRef::U64(v) => v.to_i64(),
378            GidRef::Str(v) => parse_u64_strict(v)?.to_i64(),
379        }
380    }
381
382    pub fn to_u64(self) -> Option<u64> {
383        match self {
384            GidRef::U64(v) => Some(v),
385            GidRef::Str(v) => parse_u64_strict(v),
386        }
387    }
388}
389
390#[cfg(test)]
391mod test {
392    use crate::core::entities::Multiple;
393
394    #[test]
395    fn empty_bit_multiple() {
396        let bm = super::Multiple::default();
397        let actual = bm.into_iter().collect::<Vec<_>>();
398        let expected: Vec<usize> = vec![];
399        assert_eq!(actual, expected);
400    }
401
402    #[test]
403    fn set_one() {
404        let bm: Multiple = [1].into_iter().collect();
405        let actual = bm.into_iter().collect::<Vec<_>>();
406        assert_eq!(actual, vec![1usize]);
407    }
408
409    #[test]
410    fn set_two() {
411        let bm: Multiple = [1, 67].into_iter().collect();
412
413        let actual = bm.into_iter().collect::<Vec<_>>();
414        assert_eq!(actual, vec![1usize, 67]);
415    }
416}
417
418impl LayerIds {
419    pub fn find(&self, layer_id: usize) -> Option<usize> {
420        match self {
421            LayerIds::All => Some(layer_id),
422            LayerIds::One(id) => {
423                if *id == layer_id {
424                    Some(layer_id)
425                } else {
426                    None
427                }
428            }
429            LayerIds::Multiple(ids) => ids.contains(layer_id).then_some(layer_id),
430            LayerIds::None => None,
431        }
432    }
433
434    pub fn intersect(&self, other: &LayerIds) -> LayerIds {
435        match (self, other) {
436            (LayerIds::None, _) => LayerIds::None,
437            (_, LayerIds::None) => LayerIds::None,
438            (LayerIds::All, other) => other.clone(),
439            (this, LayerIds::All) => this.clone(),
440            (LayerIds::One(id), other) => {
441                if other.contains(id) {
442                    LayerIds::One(*id)
443                } else {
444                    LayerIds::None
445                }
446            }
447            (LayerIds::Multiple(ids), other) => {
448                let ids: Vec<usize> = ids.iter().filter(|id| other.contains(id)).collect();
449                match ids.len() {
450                    0 => LayerIds::None,
451                    1 => LayerIds::One(ids[0]),
452                    _ => LayerIds::Multiple(ids.into()),
453                }
454            }
455        }
456    }
457
458    pub fn constrain_from_edge(&self, e: EdgeRef) -> Cow<'_, LayerIds> {
459        match e.layer() {
460            None => Cow::Borrowed(self),
461            Some(l) => self
462                .find(l)
463                .map(|id| Cow::Owned(LayerIds::One(id)))
464                .unwrap_or(Cow::Owned(LayerIds::None)),
465        }
466    }
467
468    pub fn contains(&self, layer_id: &usize) -> bool {
469        self.find(*layer_id).is_some()
470    }
471
472    pub fn is_none(&self) -> bool {
473        matches!(self, LayerIds::None)
474    }
475
476    pub fn is_single(&self) -> bool {
477        matches!(self, LayerIds::One(_))
478    }
479
480    pub fn iter(&self, num_layers: usize) -> impl Iterator<Item = usize> {
481        match self {
482            LayerIds::None => iter::empty().into_dyn_boxed(),
483            LayerIds::All => (0..num_layers).into_dyn_boxed(),
484            LayerIds::One(id) => iter::once(*id).into_dyn_boxed(),
485            LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
486        }
487    }
488}
489
490impl From<Vec<usize>> for LayerIds {
491    fn from(v: Vec<usize>) -> Self {
492        match v.len() {
493            0 => LayerIds::All,
494            1 => LayerIds::One(v[0]),
495            _ => LayerIds::Multiple(v.into()),
496        }
497    }
498}
499
500impl<const N: usize> From<[usize; N]> for LayerIds {
501    fn from(v: [usize; N]) -> Self {
502        match v.len() {
503            0 => LayerIds::All,
504            1 => LayerIds::One(v[0]),
505            _ => LayerIds::Multiple(v.into_iter().collect()),
506        }
507    }
508}
509
510impl From<usize> for LayerIds {
511    fn from(id: usize) -> Self {
512        LayerIds::One(id)
513    }
514}
515
516#[cfg(test)]
517mod tests {
518    use crate::core::entities::{EID, MAX_LAYER};
519    use proptest::{prop_assert, prop_assert_eq, proptest};
520
521    #[test]
522    fn test_elid_layer() {
523        proptest!(|(eid in 0..=usize::MAX, layer in 0..=MAX_LAYER)| {
524            let elid = EID(eid).with_layer(layer);
525            prop_assert_eq!(elid.layer(), layer);
526            prop_assert!(!elid.is_deletion());
527
528            let elid_deleted = elid.into_deletion();
529            prop_assert_eq!(elid_deleted.layer(), layer);
530            prop_assert_eq!(elid_deleted.edge, EID(eid));
531            prop_assert!(elid_deleted.is_deletion())
532        })
533    }
534
535    #[test]
536    fn test_elid_deletion() {
537        proptest!(|(eid in 0..=usize::MAX, layer in 0..=MAX_LAYER)| {
538            let elid = EID(eid).with_layer_deletion(layer);
539            prop_assert_eq!(elid.layer(), layer);
540            prop_assert!(elid.is_deletion());
541            prop_assert_eq!(elid, elid.into_deletion());
542            prop_assert_eq!(elid.edge.0, eid);
543        })
544    }
545}