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}