Skip to main content

hara_native/lang/data/
pointer.rs

1use crate::core::Value;
2use crate::lang::data::{Keyword, Map, Metadata};
3use crate::lang::hash::JavaHash;
4use crate::lang::protocol::{HashType, IDisplay, IHash, IMetadata, IObjType, ObjType};
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::rc::Rc;
8
9/// An immutable, context-qualified reference descriptor.
10///
11/// Pointers deliberately contain no runtime, resolver, target, or dereferenced
12/// value. Resolution is owned by the active evaluator context.
13#[derive(Debug, Clone)]
14pub struct Pointer {
15    context: Keyword,
16    fields: Map<Value, Value>,
17    metadata: Option<Rc<Metadata>>,
18}
19
20impl Pointer {
21    pub fn new(context: Keyword, fields: Map<Value, Value>) -> Self {
22        Self {
23            context,
24            fields,
25            metadata: None,
26        }
27    }
28
29    pub fn context(&self) -> &Keyword {
30        &self.context
31    }
32
33    pub fn fields(&self) -> &Map<Value, Value> {
34        &self.fields
35    }
36
37    pub fn get(&self, key: &Value) -> Option<&Value> {
38        self.fields.get(key)
39    }
40
41    pub fn descriptor(&self) -> Map<Value, Value> {
42        self.fields.assoc_value(
43            Value::Keyword(Keyword::from("context")),
44            Value::Keyword(self.context.clone()),
45        )
46    }
47}
48
49impl PartialEq for Pointer {
50    fn eq(&self, other: &Self) -> bool {
51        self.context == other.context && self.fields == other.fields
52    }
53}
54
55impl Eq for Pointer {}
56
57impl IMetadata for Pointer {
58    type Metadata = Rc<Metadata>;
59
60    fn meta(&self) -> Option<&Self::Metadata> {
61        self.metadata.as_ref()
62    }
63
64    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
65        Self {
66            context: self.context.clone(),
67            fields: self.fields.clone(),
68            metadata,
69        }
70    }
71}
72
73impl IDisplay for Pointer {
74    fn display(&self) -> String {
75        format!("#ptr {}", Value::Map(self.descriptor()).display())
76    }
77}
78
79impl IObjType for Pointer {
80    fn obj_type(&self) -> ObjType {
81        ObjType::Pointer
82    }
83}
84
85impl IHash for Pointer {
86    fn hash_calc(&self, hash_type: HashType) -> u64 {
87        crate::lang::hash::compose_ordered(
88            "POINTER",
89            [
90                self.context.java_hash(hash_type),
91                self.fields.hash_calc(hash_type) as i64,
92            ],
93        ) as u64
94    }
95}
96
97impl crate::lang::hash::JavaHash for Pointer {
98    fn java_hash(&self, hash_type: HashType) -> i64 {
99        self.hash_calc(hash_type) as i64
100    }
101}
102
103impl Hash for Pointer {
104    fn hash<H: Hasher>(&self, state: &mut H) {
105        state.write_u64(self.hash_calc(crate::lang::hash::DEFAULT_HASH));
106    }
107}
108
109impl fmt::Display for Pointer {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        f.write_str(&self.display())
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn pointer_identity_is_structural_and_display_is_literal() {
121        let fields: Map<Value, Value> = vec![(
122            Value::Keyword(Keyword::from("id")),
123            Value::String("ROOT".into()),
124        )]
125        .into_iter()
126        .collect();
127        let left = Pointer::new(Keyword::from("kernel"), fields.clone());
128        let right = Pointer::new(Keyword::from("kernel"), fields);
129        assert_eq!(left, right);
130        assert_eq!(
131            left.hash_calc(HashType::Rapid),
132            right.hash_calc(HashType::Rapid)
133        );
134        assert!(left.display().starts_with("#ptr {"));
135        assert!(left.display().contains(":context :kernel"));
136        assert!(left.display().contains(":id \"ROOT\""));
137    }
138}