Skip to main content

raphtory_core/entities/properties/
props.rs

1use crate::{
2    entities::properties::tprop::{IllegalPropType, TProp},
3    storage::{
4        lazy_vec::{IllegalSet, LazyVec},
5        timeindex::EventTime,
6    },
7};
8use raphtory_api::core::entities::properties::prop::Prop;
9use serde::{Deserialize, Serialize};
10use std::fmt::Debug;
11use thiserror::Error;
12
13#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
14pub struct Props {
15    // properties
16    pub(crate) metadata: LazyVec<Option<Prop>>,
17    pub(crate) temporal_props: LazyVec<TProp>,
18}
19
20#[derive(Error, Debug)]
21pub enum TPropError {
22    #[error(transparent)]
23    IllegalSet(#[from] IllegalSet<TProp>),
24    #[error(transparent)]
25    IllegalPropType(#[from] IllegalPropType),
26}
27
28#[derive(Error, Debug)]
29pub enum MetadataError {
30    #[error("Attempted to change value of metadata, old: {old}, new: {new}")]
31    IllegalUpdate { old: Prop, new: Prop },
32}
33
34impl From<IllegalSet<Option<Prop>>> for MetadataError {
35    fn from(value: IllegalSet<Option<Prop>>) -> Self {
36        let old = value.previous_value.unwrap_or(Prop::str("NONE"));
37        let new = value.new_value.unwrap_or(Prop::str("NONE"));
38        MetadataError::IllegalUpdate { old, new }
39    }
40}
41
42impl Props {
43    pub fn new() -> Self {
44        Self {
45            metadata: Default::default(),
46            temporal_props: Default::default(),
47        }
48    }
49
50    pub fn add_prop(&mut self, t: EventTime, prop_id: usize, prop: Prop) -> Result<(), TPropError> {
51        self.temporal_props.update(prop_id, |p| Ok(p.set(t, prop)?))
52    }
53
54    pub fn add_metadata(&mut self, prop_id: usize, prop: Prop) -> Result<(), MetadataError> {
55        Ok(self.metadata.set(prop_id, Some(prop))?)
56    }
57
58    pub fn update_metadata(&mut self, prop_id: usize, prop: Prop) -> Result<(), MetadataError> {
59        self.metadata.update(prop_id, |n| {
60            *n = Some(prop);
61            Ok(())
62        })
63    }
64
65    pub fn metadata(&self, prop_id: usize) -> Option<&Prop> {
66        let prop = self.metadata.get(prop_id)?;
67        prop.as_ref()
68    }
69
70    pub fn temporal_prop(&self, prop_id: usize) -> Option<&TProp> {
71        self.temporal_props.get(prop_id)
72    }
73
74    pub fn metadata_ids(&self) -> impl Iterator<Item = usize> + '_ {
75        self.metadata.filled_ids()
76    }
77
78    pub fn temporal_prop_ids(&self) -> impl Iterator<Item = usize> + Send + Sync + '_ {
79        self.temporal_props.filled_ids()
80    }
81}
82
83#[cfg(test)]
84mod test {
85    use super::*;
86    use raphtory_api::core::entities::properties::meta::PropMapper;
87    use std::{sync::Arc, thread};
88
89    #[test]
90    fn test_prop_mapper_concurrent() {
91        let values = [Prop::I64(1), Prop::U16(0), Prop::Bool(true), Prop::F64(0.0)];
92        let input_len = values.len();
93
94        let mapper = Arc::new(PropMapper::default());
95        let threads: Vec<_> = values
96            .into_iter()
97            .map(move |v| {
98                let mapper = mapper.clone();
99                thread::spawn(move || mapper.get_or_create_and_validate("test", v.dtype()))
100            })
101            .flat_map(|t| t.join())
102            .collect();
103
104        assert_eq!(threads.len(), input_len); // no errors
105        assert_eq!(threads.into_iter().flatten().count(), 1); // only one result (which ever was first)
106    }
107}