haste_pointer/
lib.rs

1use haste_reflect::MetaValue;
2use std::sync::Arc;
3
4#[derive(Clone)]
5struct ChildPointer<U>(*const U);
6
7unsafe impl<U> Send for ChildPointer<U> {}
8unsafe impl<U> Sync for ChildPointer<U> {}
9
10#[derive(Clone)]
11pub struct Pointer<T: MetaValue, U: MetaValue> {
12    root: Arc<T>,
13    value: ChildPointer<U>,
14    path: String,
15}
16
17pub enum Key {
18    Field(String),
19    Index(usize),
20}
21
22fn path_descend(path: &str, key: &str) -> String {
23    format!("{}/{}", path, key)
24}
25
26impl<'a, Root: MetaValue, U: MetaValue> Pointer<Root, U> {
27    pub fn new(value: Arc<Root>) -> Pointer<Root, Root> {
28        Pointer {
29            value: ChildPointer(&*value.as_ref() as *const Root),
30            root: value,
31            path: "".to_string(),
32        }
33    }
34
35    pub fn root(&self) -> Pointer<Root, Root> {
36        Pointer {
37            value: ChildPointer(&*self.root.as_ref() as *const Root),
38            root: self.root.clone(),
39            path: "".to_string(),
40        }
41    }
42
43    pub fn path(&self) -> &str {
44        self.path.as_str()
45    }
46
47    pub fn value(&self) -> Option<&U> {
48        let p = unsafe { (*self.value.0).as_any().downcast_ref::<U>() };
49
50        p
51    }
52
53    pub fn descend<Child: MetaValue>(&'a self, key: &Key) -> Option<Pointer<Root, Child>> {
54        match key {
55            Key::Field(field) => self.value().and_then(|v| {
56                v.get_field(field)
57                    .and_then(|v| v.as_any().downcast_ref::<Child>())
58                    .map(|child| Pointer {
59                        root: self.root.clone(),
60                        value: ChildPointer(&*child as *const Child),
61                        path: path_descend(self.path.as_str(), field.as_str()),
62                    })
63            }),
64            Key::Index(index) => self.value().and_then(|v| {
65                v.get_index(*index)
66                    .and_then(|v| v.as_any().downcast_ref::<Child>())
67                    .map(|child| Pointer {
68                        root: self.root.clone(),
69                        value: ChildPointer(&*child as *const Child),
70                        path: path_descend(self.path.as_str(), index.to_string().as_str()),
71                    })
72            }),
73        }
74    }
75}
76
77#[cfg(test)]
78mod test {
79    use super::*;
80    use haste_fhir_model::r4::generated::{
81        resources::Patient, types::FHIRString, types::HumanName,
82    };
83
84    #[test]
85    fn test_pointer_descend() {
86        let patient = Arc::new(Patient {
87            id: Some("patient-1".to_string()),
88            name: Some(vec![Box::new(HumanName {
89                family: Some(Box::new(FHIRString {
90                    value: Some("Doe".to_string()),
91                    ..Default::default()
92                })),
93                ..Default::default()
94            })]),
95            ..Default::default()
96        });
97
98        let pointer = Pointer::<Patient, Patient>::new(patient);
99        let pointer = pointer
100            .descend::<Vec<Box<HumanName>>>(&Key::Field("name".to_string()))
101            .unwrap();
102        assert_eq!(pointer.path(), "/name");
103        let pointer = pointer.descend::<Box<HumanName>>(&Key::Index(0)).unwrap();
104        assert_eq!(pointer.path(), "/name/0");
105        let pointer = pointer
106            .descend::<Box<FHIRString>>(&Key::Field("family".to_string()))
107            .unwrap();
108        let pointer = pointer
109            .descend::<String>(&Key::Field("value".to_string()))
110            .unwrap();
111
112        assert_eq!(pointer.path(), "/name/0/family/value");
113        assert_eq!(pointer.value(), Some(&"Doe".to_string()));
114    }
115}