Skip to content

Commit 59808fa

Browse files
committed
Created base Var type
1 parent fa1c880 commit 59808fa

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

src/var.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//use crate::namespace::Namespace;
2+
use crate::symbol::Symbol;
3+
use crate::persistent_list_map::PersistentListMap;
4+
use crate::value::{Value,ToValue};
5+
use crate::ifn::IFn;
6+
//use crate::ifn::IFn;
7+
use crate::protocols;
8+
// @TODO change to protocols::iterable;
9+
use crate::iterable::Iterable;
10+
use std::rc::Rc;
11+
use std::cell::RefCell;
12+
use crate::protocol::Protocol;
13+
use crate::protocol::ProtocolCastable;
14+
15+
pub struct Var {
16+
// Normally in Clojure, this references an actual Namespace. However, hard
17+
// references are more expensive, logically, in Rust, not to mention it
18+
// makes this harder to reason about -- its much easier to deal with data
19+
// (even partially mutable data), rather than something intertwined with the
20+
// living system in some way by referencing and interacting with another
21+
// piece
22+
pub ns : Symbol,
23+
pub sym: Symbol,
24+
// Another decision we will have to make; meta can be any IPersistentMap,
25+
// but as we know, rust is not so friendly for passing around trait objects,
26+
// and so we avoid them. For now, we will use a PersistentListMap, but I
27+
// believe this is actually a perfect time to use our Protocols, since our Protocols
28+
// allow us to we
29+
// don't need to be extending any Rust values with these protocols [see note on Protocols
30+
// in design document, once they arrive] (and if
31+
// we do, perhaps this is time to think on how we're going to represent Rust
32+
// types generically with Values anyways)
33+
//
34+
// Other note; all values here except the meta and `root` should be
35+
// immutable, is there value in expressing this mixed mutability in someway
36+
// without just wrapping these in RefCells?
37+
meta: RefCell<protocols::IPersistentMap>,
38+
pub root: RefCell<Rc<Value>>,
39+
}
40+
macro_rules! var{
41+
($ns:expr, $sym:expr) => {
42+
Var::intern(sym!($ns),sym!($sym))
43+
}
44+
}
45+
impl Var {
46+
// Note; not quite the same as Clojure's intern, because this does not directly reference the living
47+
// Its possible we should call this create or something instead, and basically not use intern at all
48+
pub fn intern(ns: Symbol,sym: Symbol) -> Var {
49+
let empty_meta = PersistentListMap::Empty.to_rc_value();
50+
Var {
51+
ns,
52+
sym,
53+
meta: RefCell::new(empty_meta.as_protocol::<protocols::IPersistentMap>()),
54+
// What do if unbound? Why does unbound exist?
55+
root: RefCell::new(Value::Nil.to_rc_value())
56+
}
57+
}
58+
pub fn deref(&self) -> Rc<Value> {
59+
self.root.borrow().clone()
60+
}
61+
pub fn bind_root(&self,root: Rc<Value>){
62+
self.root.replace(root);
63+
}
64+
// @TODO swap out Iterable for ISeq
65+
// Also, this cannot return a Condition until we decide how we want to represent Conditions
66+
// in a function that returns a Protocol'ed value -- let's handle that next, as we add Conditions
67+
pub fn alter_meta(&self,alter: protocols::IFn,args: Iterable) -> protocols::IPersistentMap {
68+
self.meta.replace_with(|meta| {
69+
// @TODO add proper prepending
70+
let mut new_args = vec![Rc::clone(&meta.unwrap())];
71+
new_args.extend_from_slice(&args.iter().collect::<Vec<Rc<Value>>>());
72+
73+
let maybe_updated_meta = Rc::new(alter.invoke(new_args)).try_as_protocol::<protocols::IPersistentMap>();
74+
if let Some(updated_meta) = maybe_updated_meta {
75+
updated_meta
76+
}
77+
else {
78+
meta.clone()
79+
}
80+
})
81+
}
82+
}
83+
84+
#[cfg(test)]
85+
mod tests {
86+
use crate::var::Var;
87+
use crate::symbol::Symbol;
88+
use std::rc::Rc;
89+
use crate::value::Value;
90+
91+
#[test]
92+
fn deref(){
93+
let a = sym!("clojure");
94+
assert!(a == Symbol::intern("clojure"));
95+
96+
let v = var!("clojure.core","+");
97+
v.bind_root(Rc::new(Value::I32(12)));
98+
99+
assert!(*v.deref() == Value::I32(12));
100+
101+
v.bind_root(Rc::new(Value::I32(25)));
102+
103+
assert!(*v.deref() == Value::I32(25));
104+
}
105+
}

0 commit comments

Comments
 (0)