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}
151impl PartialEq<str> for GID {
152    fn eq(&self, other: &str) -> bool {
153        match self {
154            GID::U64(_) => false,
155            GID::Str(id) => id == other,
156        }
157    }
158}
159
160impl PartialEq<String> for GID {
161    fn eq(&self, other: &String) -> bool {
162        match self {
163            GID::U64(_) => false,
164            GID::Str(id) => id == other,
165        }
166    }
167}
168
169impl PartialEq<u64> for GID {
170    fn eq(&self, other: &u64) -> bool {
171        match self {
172            GID::Str(_) => false,
173            GID::U64(id) => id == other,
174        }
175    }
176}
177
178impl Default for GID {
179    fn default() -> Self {
180        GID::U64(u64::MAX)
181    }
182}
183
184impl Display for GID {
185    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
186        match self {
187            GID::U64(v) => write!(f, "{}", v),
188            GID::Str(v) => write!(f, "{}", v),
189        }
190    }
191}
192
193impl GID {
194    pub fn dtype(&self) -> GidType {
195        match self {
196            GID::U64(_) => GidType::U64,
197            GID::Str(_) => GidType::Str,
198        }
199    }
200    pub fn into_str(self) -> Option<String> {
201        match self {
202            GID::Str(v) => Some(v),
203            _ => None,
204        }
205    }
206
207    pub fn into_u64(self) -> Option<u64> {
208        match self {
209            GID::U64(v) => Some(v),
210            _ => None,
211        }
212    }
213
214    pub fn as_str(&self) -> Option<&str> {
215        match self {
216            GID::Str(v) => Some(v.as_str()),
217            _ => None,
218        }
219    }
220
221    pub fn as_u64(&self) -> Option<u64> {
222        match self {
223            GID::U64(v) => Some(*v),
224            _ => None,
225        }
226    }
227
228    pub fn to_str(&'_ self) -> Cow<'_, str> {
229        match self {
230            GID::U64(v) => Cow::Owned(v.to_string()),
231            GID::Str(v) => Cow::Borrowed(v),
232        }
233    }
234
235    pub fn to_i64(&self) -> Option<i64> {
236        match self {
237            GID::U64(v) => v.to_i64(),
238            GID::Str(v) => parse_u64_strict(v)?.to_i64(),
239        }
240    }
241
242    pub fn to_u64(&self) -> Option<u64> {
243        match self {
244            GID::U64(v) => Some(*v),
245            GID::Str(v) => parse_u64_strict(v),
246        }
247    }
248
249    pub fn as_ref(&self) -> GidRef<'_> {
250        match self {
251            GID::U64(v) => GidRef::U64(*v),
252            GID::Str(v) => GidRef::Str(v),
253        }
254    }
255}
256
257impl From<u64> for GID {
258    fn from(id: u64) -> Self {
259        Self::U64(id)
260    }
261}
262
263impl From<&u64> for GID {
264    fn from(value: &u64) -> Self {
265        GID::U64(*value)
266    }
267}
268
269impl From<String> for GID {
270    fn from(id: String) -> Self {
271        Self::Str(id)
272    }
273}
274
275impl From<&str> for GID {
276    fn from(id: &str) -> Self {
277        Self::Str(id.to_string())
278    }
279}
280
281impl<'a> From<GidRef<'a>> for GID {
282    fn from(value: GidRef<'a>) -> Self {
283        match value {
284            GidRef::U64(v) => GID::U64(v),
285            GidRef::Str(v) => GID::Str(v.to_owned()),
286        }
287    }
288}
289
290#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
291pub enum GidRef<'a> {
292    U64(u64),
293    Str(&'a str),
294}
295
296#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
297pub enum GidType {
298    U64,
299    Str,
300}
301
302impl Display for GidType {
303    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
304        match self {
305            GidType::U64 => {
306                write!(f, "Numeric")
307            }
308            GidType::Str => {
309                write!(f, "String")
310            }
311        }
312    }
313}
314
315impl Display for GidRef<'_> {
316    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
317        match self {
318            GidRef::U64(v) => write!(f, "{}", v),
319            GidRef::Str(v) => write!(f, "{}", v),
320        }
321    }
322}
323
324impl<'a> From<&'a GID> for GidRef<'a> {
325    fn from(value: &'a GID) -> Self {
326        match value {
327            GID::U64(v) => GidRef::U64(*v),
328            GID::Str(v) => GidRef::Str(v),
329        }
330    }
331}
332
333impl<'a> From<&'a str> for GidRef<'a> {
334    fn from(value: &'a str) -> Self {
335        GidRef::Str(value)
336    }
337}
338
339impl<'a> GidRef<'a> {
340    pub fn dtype(self) -> GidType {
341        match self {
342            GidRef::U64(_) => GidType::U64,
343            GidRef::Str(_) => GidType::Str,
344        }
345    }
346    pub fn as_str(self) -> Option<&'a str> {
347        match self {
348            GidRef::Str(s) => Some(s),
349            _ => None,
350        }
351    }
352
353    pub fn as_u64(self) -> Option<u64> {
354        match self {
355            GidRef::U64(v) => Some(v),
356            _ => None,
357        }
358    }
359
360    pub fn to_owned(self) -> GID {
361        match self {
362            GidRef::U64(v) => GID::U64(v),
363            GidRef::Str(v) => GID::Str(v.to_owned()),
364        }
365    }
366
367    pub fn to_str(self) -> Cow<'a, str> {
368        match self {
369            GidRef::U64(v) => Cow::Owned(v.to_string()),
370            GidRef::Str(v) => Cow::Borrowed(v),
371        }
372    }
373
374    pub fn to_i64(self) -> Option<i64> {
375        match self {
376            GidRef::U64(v) => v.to_i64(),
377            GidRef::Str(v) => parse_u64_strict(v)?.to_i64(),
378        }
379    }
380
381    pub fn to_u64(self) -> Option<u64> {
382        match self {
383            GidRef::U64(v) => Some(v),
384            GidRef::Str(v) => parse_u64_strict(v),
385        }
386    }
387}
388
389#[cfg(test)]
390mod test {
391    use crate::core::entities::Multiple;
392
393    #[test]
394    fn empty_bit_multiple() {
395        let bm = super::Multiple::default();
396        let actual = bm.into_iter().collect::<Vec<_>>();
397        let expected: Vec<usize> = vec![];
398        assert_eq!(actual, expected);
399    }
400
401    #[test]
402    fn set_one() {
403        let bm: Multiple = [1].into_iter().collect();
404        let actual = bm.into_iter().collect::<Vec<_>>();
405        assert_eq!(actual, vec![1usize]);
406    }
407
408    #[test]
409    fn set_two() {
410        let bm: Multiple = [1, 67].into_iter().collect();
411
412        let actual = bm.into_iter().collect::<Vec<_>>();
413        assert_eq!(actual, vec![1usize, 67]);
414    }
415}
416
417impl LayerIds {
418    pub fn find(&self, layer_id: usize) -> Option<usize> {
419        match self {
420            LayerIds::All => Some(layer_id),
421            LayerIds::One(id) => {
422                if *id == layer_id {
423                    Some(layer_id)
424                } else {
425                    None
426                }
427            }
428            LayerIds::Multiple(ids) => ids.contains(layer_id).then_some(layer_id),
429            LayerIds::None => None,
430        }
431    }
432
433    pub fn intersect(&self, other: &LayerIds) -> LayerIds {
434        match (self, other) {
435            (LayerIds::None, _) => LayerIds::None,
436            (_, LayerIds::None) => LayerIds::None,
437            (LayerIds::All, other) => other.clone(),
438            (this, LayerIds::All) => this.clone(),
439            (LayerIds::One(id), other) => {
440                if other.contains(id) {
441                    LayerIds::One(*id)
442                } else {
443                    LayerIds::None
444                }
445            }
446            (LayerIds::Multiple(ids), other) => {
447                let ids: Vec<usize> = ids.iter().filter(|id| other.contains(id)).collect();
448                match ids.len() {
449                    0 => LayerIds::None,
450                    1 => LayerIds::One(ids[0]),
451                    _ => LayerIds::Multiple(ids.into()),
452                }
453            }
454        }
455    }
456
457    pub fn constrain_from_edge(&self, e: EdgeRef) -> Cow<'_, LayerIds> {
458        match e.layer() {
459            None => Cow::Borrowed(self),
460            Some(l) => self
461                .find(l)
462                .map(|id| Cow::Owned(LayerIds::One(id)))
463                .unwrap_or(Cow::Owned(LayerIds::None)),
464        }
465    }
466
467    pub fn contains(&self, layer_id: &usize) -> bool {
468        self.find(*layer_id).is_some()
469    }
470
471    pub fn is_none(&self) -> bool {
472        matches!(self, LayerIds::None)
473    }
474
475    pub fn is_single(&self) -> bool {
476        matches!(self, LayerIds::One(_))
477    }
478
479    pub fn iter(&self, num_layers: usize) -> impl Iterator<Item = usize> {
480        match self {
481            LayerIds::None => iter::empty().into_dyn_boxed(),
482            LayerIds::All => (0..num_layers).into_dyn_boxed(),
483            LayerIds::One(id) => iter::once(*id).into_dyn_boxed(),
484            LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
485        }
486    }
487}
488
489impl From<Vec<usize>> for LayerIds {
490    fn from(v: Vec<usize>) -> Self {
491        match v.len() {
492            0 => LayerIds::All,
493            1 => LayerIds::One(v[0]),
494            _ => LayerIds::Multiple(v.into()),
495        }
496    }
497}
498
499impl<const N: usize> From<[usize; N]> for LayerIds {
500    fn from(v: [usize; N]) -> Self {
501        match v.len() {
502            0 => LayerIds::All,
503            1 => LayerIds::One(v[0]),
504            _ => LayerIds::Multiple(v.into_iter().collect()),
505        }
506    }
507}
508
509impl From<usize> for LayerIds {
510    fn from(id: usize) -> Self {
511        LayerIds::One(id)
512    }
513}
514
515#[cfg(test)]
516mod tests {
517    use crate::core::entities::{EID, MAX_LAYER};
518    use proptest::{prop_assert, prop_assert_eq, proptest};
519
520    #[test]
521    fn test_elid_layer() {
522        proptest!(|(eid in 0..=usize::MAX, layer in 0..=MAX_LAYER)| {
523            let elid = EID(eid).with_layer(layer);
524            prop_assert_eq!(elid.layer(), layer);
525            prop_assert!(!elid.is_deletion());
526
527            let elid_deleted = elid.into_deletion();
528            prop_assert_eq!(elid_deleted.layer(), layer);
529            prop_assert_eq!(elid_deleted.edge, EID(eid));
530            prop_assert!(elid_deleted.is_deletion())
531        })
532    }
533
534    #[test]
535    fn test_elid_deletion() {
536        proptest!(|(eid in 0..=usize::MAX, layer in 0..=MAX_LAYER)| {
537            let elid = EID(eid).with_layer_deletion(layer);
538            prop_assert_eq!(elid.layer(), layer);
539            prop_assert!(elid.is_deletion());
540            prop_assert_eq!(elid, elid.into_deletion());
541            prop_assert_eq!(elid.edge.0, eid);
542        })
543    }
544}