raphtory_core/entities/properties/
props.rs

1use crate::{
2    entities::properties::tprop::{IllegalPropType, TProp},
3    storage::{
4        lazy_vec::{IllegalSet, LazyVec},
5        timeindex::TimeIndexEntry,
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(
51        &mut self,
52        t: TimeIndexEntry,
53        prop_id: usize,
54        prop: Prop,
55    ) -> Result<(), TPropError> {
56        self.temporal_props.update(prop_id, |p| Ok(p.set(t, prop)?))
57    }
58
59    pub fn add_metadata(&mut self, prop_id: usize, prop: Prop) -> Result<(), MetadataError> {
60        Ok(self.metadata.set(prop_id, Some(prop))?)
61    }
62
63    pub fn update_metadata(&mut self, prop_id: usize, prop: Prop) -> Result<(), MetadataError> {
64        self.metadata.update(prop_id, |n| {
65            *n = Some(prop);
66            Ok(())
67        })
68    }
69
70    pub fn metadata(&self, prop_id: usize) -> Option<&Prop> {
71        let prop = self.metadata.get(prop_id)?;
72        prop.as_ref()
73    }
74
75    pub fn temporal_prop(&self, prop_id: usize) -> Option<&TProp> {
76        self.temporal_props.get(prop_id)
77    }
78
79    pub fn metadata_ids(&self) -> impl Iterator<Item = usize> + '_ {
80        self.metadata.filled_ids()
81    }
82
83    pub fn temporal_prop_ids(&self) -> impl Iterator<Item = usize> + Send + Sync + '_ {
84        self.temporal_props.filled_ids()
85    }
86}
87
88#[cfg(test)]
89mod test {
90    use super::*;
91    use raphtory_api::core::entities::properties::meta::PropMapper;
92    use std::{sync::Arc, thread};
93
94    #[test]
95    fn test_prop_mapper_concurrent() {
96        let values = [Prop::I64(1), Prop::U16(0), Prop::Bool(true), Prop::F64(0.0)];
97        let input_len = values.len();
98
99        let mapper = Arc::new(PropMapper::default());
100        let threads: Vec<_> = values
101            .into_iter()
102            .map(move |v| {
103                let mapper = mapper.clone();
104                thread::spawn(move || mapper.get_or_create_and_validate("test", v.dtype()))
105            })
106            .flat_map(|t| t.join())
107            .collect();
108
109        assert_eq!(threads.len(), input_len); // no errors
110        assert_eq!(threads.into_iter().flatten().count(), 1); // only one result (which ever was first)
111    }
112}