haste_pointer/
lib.rs

1use haste_reflect::MetaValue;
2pub struct Pointer<'a> {
3    value: Option<&'a dyn MetaValue>,
4    path: String,
5}
6
7pub enum Key {
8    Field(String),
9    Index(usize),
10}
11
12fn path_descend(path: &str, key: &str) -> String {
13    format!("{}/{}", path, key)
14}
15
16impl<'a> Pointer<'a> {
17    pub fn path(&self) -> &str {
18        self.path.as_str()
19    }
20    pub fn value(&self) -> Option<&'a dyn MetaValue> {
21        self.value
22    }
23    pub fn root(value: &'a dyn MetaValue) -> Self {
24        Pointer {
25            value: Some(value),
26            path: "".to_string(),
27        }
28    }
29
30    pub fn descend(&self, key: &Key) -> Pointer<'a> {
31        match key {
32            Key::Field(field) => Self {
33                path: path_descend(self.path.as_str(), field),
34                value: self.value.and_then(|v| v.get_field(field)),
35            },
36            Key::Index(index) => Self {
37                path: path_descend(self.path.as_str(), index.to_string().as_str()),
38                value: self.value.and_then(|v| v.get_index(*index)),
39            },
40        }
41    }
42}
43
44#[cfg(test)]
45mod test {
46    use super::*;
47    use haste_fhir_model::r4::generated::{
48        resources::Patient, types::FHIRString, types::HumanName,
49    };
50
51    #[test]
52    fn test_pointer_descend() {
53        let patient = Patient {
54            id: Some("patient-1".to_string()),
55            name: Some(vec![Box::new(HumanName {
56                family: Some(Box::new(FHIRString {
57                    value: Some("Doe".to_string()),
58                    ..Default::default()
59                })),
60                ..Default::default()
61            })]),
62            ..Default::default()
63        };
64
65        let pointer = Pointer::root(&patient);
66        let pointer = pointer.descend(&Key::Field("name".to_string()));
67        assert_eq!(pointer.path(), "/name");
68        let pointer = pointer.descend(&Key::Index(0));
69        assert_eq!(pointer.path(), "/name/0");
70        let pointer = pointer
71            .descend(&Key::Field("family".to_string()))
72            .descend(&Key::Field("value".to_string()));
73
74        assert_eq!(pointer.path(), "/name/0/family/value");
75        assert_eq!(
76            pointer
77                .value()
78                .and_then(|v| v.as_any().downcast_ref::<String>()),
79            Some(&"Doe".to_string())
80        );
81    }
82}