diff --git a/chain-server/src/server.rs b/chain-server/src/server.rs index ac771062d..f77b003ce 100644 --- a/chain-server/src/server.rs +++ b/chain-server/src/server.rs @@ -139,9 +139,10 @@ where // make sure that the evaluation terminated appropriatelly match cont_out.tag() { Tag::Cont(ContTag::Terminal) => { - // car_cdr the result to retrieve the chain result and the next callable - let (result, next_callable) = self.store.car_cdr(expr_out).map_err(|_e| { - Status::failed_precondition("Call didn't result in a cons-like expression") + // get the car/cdr of the result to retrieve the chain result and + // the next callable + let (result, next_callable) = self.store.fetch_cons(expr_out).ok_or_else(|| { + Status::failed_precondition("Call didn't result in a cons expression") })?; // retrieve (or compute if needed) the public params for proving diff --git a/src/cli/repl/meta_cmd.rs b/src/cli/repl/meta_cmd.rs index ad61339bb..194a408cf 100644 --- a/src/cli/repl/meta_cmd.rs +++ b/src/cli/repl/meta_cmd.rs @@ -398,7 +398,7 @@ where example: &["!(defpackage abc)"], run: |repl, args, _path| { // TODO: handle args - let (name, _args) = repl.store.car_cdr(args)?; + let (name, _args) = repl.store.car_cdr_simple(args)?; let name = match name.tag() { Tag::Expr(ExprTag::Str) => repl.state.borrow_mut().intern(repl.get_string(&name)?), Tag::Expr(ExprTag::Sym) => repl.get_symbol(&name)?.into(), @@ -419,7 +419,7 @@ where example: &[], run: |repl, args, _path| { // TODO: handle pkg - let (mut symbols, _pkg) = repl.store.car_cdr(args)?; + let (mut symbols, _pkg) = repl.store.car_cdr_simple(args)?; if symbols.tag() == &Tag::Expr(ExprTag::Sym) { let sym = SymbolRef::new(repl.get_symbol(&symbols)?); repl.state.borrow_mut().import(&[sym])?; @@ -427,7 +427,7 @@ where let mut symbols_vec = vec![]; loop { { - let (head, tail) = repl.store.car_cdr(&symbols)?; + let (head, tail) = repl.store.car_cdr_simple(&symbols)?; let sym = repl.get_symbol(&head)?; symbols_vec.push(SymbolRef::new(sym)); if tail.is_nil() { @@ -530,7 +530,7 @@ where } fn call(repl: &mut Repl, args: &Ptr, _path: &Utf8Path) -> Result<()> { - let (hash_expr, args) = repl.store.car_cdr(args)?; + let (hash_expr, args) = repl.store.car_cdr_simple(args)?; let hash = *repl.get_comm_hash(hash_expr)?; // check if the data is already available on the store before trying to // fetch it from the file system @@ -586,7 +586,10 @@ where let result = ev .get_result() .expect("evaluation result must have been set"); - let (_, comm) = repl.store.car_cdr(result)?; + let (_, comm) = repl + .store + .fetch_cons(result) + .ok_or_else(|| anyhow!("Chained function must return a cons expression"))?; let (Tag::Expr(ExprTag::Comm), RawPtr::Atom(hash)) = comm.parts() else { bail!("Second component of a chain must be a commitment") }; @@ -719,9 +722,9 @@ where " :description \"example protocol\")", ], run: |repl, args, _path| { - let (name, rest) = repl.store.car_cdr(args)?; - let (vars, rest) = repl.store.car_cdr(&rest)?; - let (body, props) = repl.store.car_cdr(&rest)?; + let (name, rest) = repl.store.car_cdr_simple(args)?; + let (vars, rest) = repl.store.car_cdr_simple(&rest)?; + let (body, props) = repl.store.car_cdr_simple(&rest)?; if !name.is_sym() { bail!( "Protocol name must be a symbol. Got {}", @@ -807,9 +810,9 @@ where .with_context(|| "evaluating protocol")?; let ptcl = &io[0]; - let (fun, rest) = repl.store.car_cdr(ptcl)?; + let (fun, rest) = repl.store.car_cdr_simple(ptcl)?; - let (car, rest) = repl.store.car_cdr(&rest)?; + let (car, rest) = repl.store.car_cdr_simple(&rest)?; let Some(backend) = repl.store.fetch_string(&car) else { bail!("Backend must be a string") }; @@ -819,7 +822,7 @@ where _ => bail!("Invalid value for backend"), }; - let (car, _) = repl.store.car_cdr(&rest)?; + let (car, _) = repl.store.car_cdr_simple(&rest)?; let (Tag::Expr(ExprTag::Num), RawPtr::Atom(rc_idx)) = car.parts() else { bail!("Reduction count must be a Num") }; @@ -945,8 +948,8 @@ where " '(13 . 17))", ], run: |repl, args, _path| { - let (ptcl, rest) = repl.store.car_cdr(args)?; - let (path, args) = repl.store.car_cdr(&rest)?; + let (ptcl, rest) = repl.store.car_cdr_simple(args)?; + let (path, args) = repl.store.car_cdr_simple(&rest)?; let path = get_path(repl, &path)?; diff --git a/src/cli/repl/mod.rs b/src/cli/repl/mod.rs index 95d93caa2..6aff3567b 100644 --- a/src/cli/repl/mod.rs +++ b/src/cli/repl/mod.rs @@ -135,7 +135,7 @@ impl + Serialize + DeserializeOwned> Repl } fn peek1(&self, args: &Ptr) -> Result { - let (first, rest) = self.store.car_cdr(args)?; + let (first, rest) = self.store.car_cdr_simple(args)?; if !rest.is_nil() { bail!("At most one argument is accepted") } @@ -143,8 +143,8 @@ impl + Serialize + DeserializeOwned> Repl } fn peek2(&self, args: &Ptr) -> Result<(Ptr, Ptr)> { - let (first, rest) = self.store.car_cdr(args)?; - let (second, rest) = self.store.car_cdr(&rest)?; + let (first, rest) = self.store.car_cdr_simple(args)?; + let (second, rest) = self.store.car_cdr_simple(&rest)?; if !rest.is_nil() { bail!("At most two arguments are accepted") } @@ -588,7 +588,7 @@ where } fn handle_meta(&mut self, expr_ptr: Ptr, file_path: &Utf8Path) -> Result<()> { - let (car, cdr) = self.store.car_cdr(&expr_ptr)?; + let (car, cdr) = self.store.car_cdr_simple(&expr_ptr)?; match &self.store.fetch_sym(&car) { Some(symbol) => { let cmdstr = symbol.name()?; diff --git a/src/coroutine/memoset/demo.rs b/src/coroutine/memoset/demo.rs index cbefb651a..e1a04d279 100644 --- a/src/coroutine/memoset/demo.rs +++ b/src/coroutine/memoset/demo.rs @@ -57,7 +57,7 @@ impl Query for DemoQuery { } fn from_ptr(_: &Self::RD, s: &Store, ptr: &Ptr) -> Option { - let (head, body) = s.car_cdr(ptr).expect("query should be cons"); + let (head, body) = s.car_cdr_simple(ptr).expect("query should be cons"); let sym = s.fetch_sym(&head).expect("head should be sym"); if sym == Symbol::sym(&["lurk", "user", "factorial"]) { diff --git a/src/coroutine/memoset/env.rs b/src/coroutine/memoset/env.rs index 843518e87..b92b808c4 100644 --- a/src/coroutine/memoset/env.rs +++ b/src/coroutine/memoset/env.rs @@ -57,11 +57,11 @@ impl Query for EnvQuery { } fn from_ptr(_: &Self::RD, s: &Store, ptr: &Ptr) -> Option { - let (head, body) = s.car_cdr(ptr).expect("query should be cons"); + let (head, body) = s.car_cdr_simple(ptr).expect("query should be cons"); let sym = s.fetch_sym(&head).expect("head should be sym"); if sym == Symbol::sym(&["lurk", "env", "lookup"]) { - let (var, env) = s.car_cdr(&body).expect("query body should be cons"); + let (var, env) = s.car_cdr_simple(&body).expect("query body should be cons"); Some(Self::Lookup(var, env)) } else { None diff --git a/src/coroutine/memoset/mod.rs b/src/coroutine/memoset/mod.rs index 93e4c9954..12897844a 100644 --- a/src/coroutine/memoset/mod.rs +++ b/src/coroutine/memoset/mod.rs @@ -377,9 +377,9 @@ impl> Scope, F> { Ok(Provenance::new(query, *result, dependencies)) } - fn provenance_from_kv(&self, kv: Ptr) -> Result { + fn provenance_from_kv(&self, kv: &Ptr) -> Result { let store = self.store.as_ref(); - let (query, result) = store.car_cdr(&kv).expect("kv missing"); + let (query, result) = store.car_cdr_simple(kv).expect("kv missing"); let query_dependencies = self.dependencies.get(&query); let dependencies = if let Some(deps) = query_dependencies { @@ -401,7 +401,7 @@ impl> Scope, F> { let s = self.store.as_ref(); let mut memoset = s.num(F::ZERO); for kv in self.toplevel_insertions.iter() { - let provenance = self.provenance_from_kv(*kv).unwrap(); + let provenance = self.provenance_from_kv(kv).unwrap(); memoset = self.memoset.acc_add(&memoset, provenance.to_ptr(s), s); } memoset @@ -411,7 +411,7 @@ impl> Scope, F> { let s = self.store.as_ref(); let mut transcript = Transcript::new(s); for kv in self.toplevel_insertions.iter() { - let provenance = self.provenance_from_kv(*kv).unwrap(); + let provenance = self.provenance_from_kv(kv).unwrap(); transcript.add(s, *provenance.to_ptr(s)); } transcript.acc @@ -754,7 +754,7 @@ impl> Scope, F> { let mut unique_keys: IndexMap> = Default::default(); let mut record_kv = |kv: &Ptr| { - let key = s.car_cdr(kv).unwrap().0; + let key = s.car_cdr_simple(kv).unwrap().0; let kv1 = kvs_by_key.entry(key).or_insert_with(|| { let index = Q::from_ptr(&self.runtime_data, s, &key) .expect("bad query") @@ -785,7 +785,7 @@ impl> Scope, F> { }); for kv in self.toplevel_insertions.iter() { - let provenance = self.provenance_from_kv(*kv).unwrap(); + let provenance = self.provenance_from_kv(kv).unwrap(); transcript.add(s, *provenance.to_ptr(s)); } @@ -804,7 +804,7 @@ impl> Scope, F> { // `unique_keys`. let kv = kvs_by_key.get(key).expect("kv missing"); let count = self.memoset.count(kv); - let provenance = self.provenance_from_kv(*kv).unwrap(); + let provenance = self.provenance_from_kv(kv).unwrap(); (provenance, count) } else { (Provenance::dummy(s), 0) @@ -1171,7 +1171,7 @@ impl CircuitScope, RD> { for (i, kv) in scope.toplevel_insertions.iter().enumerate() { let s = scope.store.as_ref(); let cs = ns!(cs, format!("toplevel_insertion-{i}")); - let (key, value) = s.car_cdr(kv).expect("kv missing"); + let (key, value) = s.car_cdr_simple(kv).expect("kv missing"); // NOTE: This is an unconstrained allocation, but when actually hooked up to Lurk reduction, it must be // constrained appropriately. let allocated_key = diff --git a/src/lem/coroutine/toplevel.rs b/src/lem/coroutine/toplevel.rs index 489a31011..27d227b26 100644 --- a/src/lem/coroutine/toplevel.rs +++ b/src/lem/coroutine/toplevel.rs @@ -119,7 +119,7 @@ impl Query for ToplevelQuery { ToplevelCircuitQuery { name, args } } fn from_ptr(toplevel: &Arc>, s: &Store, ptr: &Ptr) -> Option { - let (head, mut acc) = s.car_cdr(ptr).expect("query should be cons"); + let (head, mut acc) = s.car_cdr_simple(ptr).expect("query should be cons"); let name = s.fetch_sym(&head).expect("head should be sym"); let num_args = toplevel.get(&name).unwrap().func.input_params.len(); assert!(num_args > 0, "cannot yet make 0 argument queries"); @@ -127,7 +127,7 @@ impl Query for ToplevelQuery { let _p = PhantomData; if !acc.is_nil() { while args.len() < num_args - 1 { - let (arg, rest) = s.car_cdr(&acc).expect("can't find image for cons"); + let (arg, rest) = s.car_cdr_simple(&acc).expect("can't find image for cons"); args.push(arg); acc = rest; } diff --git a/src/lem/pointers.rs b/src/lem/pointers.rs index cd0d92f81..50b4cb3d1 100644 --- a/src/lem/pointers.rs +++ b/src/lem/pointers.rs @@ -91,6 +91,12 @@ impl Ptr { (tag, raw) } + #[inline] + pub fn into_parts(self) -> (Tag, RawPtr) { + let Ptr { tag, raw } = self; + (tag, raw) + } + #[inline] pub fn has_tag(&self, tag: &Tag) -> bool { self.tag() == tag diff --git a/src/lem/store.rs b/src/lem/store.rs index 63368f8c2..9fb3cb481 100644 --- a/src/lem/store.rs +++ b/src/lem/store.rs @@ -6,6 +6,7 @@ use elsa::{ sync::{FrozenMap, FrozenVec}, }; use indexmap::IndexSet; +use match_opt::match_opt; use neptune::Poseidon; use nom::{sequence::preceded, Parser}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; @@ -342,6 +343,11 @@ impl Store { .and_then(|idx| self.fetch_f_by_idx(idx)) } + #[inline] + pub fn expect_f(&self, idx: usize) -> &F { + self.fetch_f_by_idx(idx).expect("Index missing from f_elts") + } + #[inline] pub fn fetch_raw_ptrs(&self, idx: usize) -> Option<&[RawPtr; N]> { macro_rules! fetch { @@ -359,6 +365,12 @@ impl Store { } } + #[inline] + pub fn expect_raw_ptrs(&self, idx: usize) -> &[RawPtr; N] { + self.fetch_raw_ptrs::(idx) + .expect("Index missing from store") + } + #[inline] pub fn fetch_ptrs(&self, idx: usize) -> Option<[Ptr; P]> { assert_eq!(P * 2, N); @@ -366,17 +378,6 @@ impl Store { self.raw_ptrs_to_ptrs(raw_ptrs) } - #[inline] - pub fn expect_f(&self, idx: usize) -> &F { - self.fetch_f_by_idx(idx).expect("Index missing from f_elts") - } - - #[inline] - pub fn expect_raw_ptrs(&self, idx: usize) -> &[RawPtr; N] { - self.fetch_raw_ptrs::(idx) - .expect("Index missing from store") - } - #[inline] pub fn expect_ptrs(&self, idx: usize) -> [Ptr; P] { self.fetch_ptrs::(idx) @@ -391,8 +392,7 @@ impl Store { #[inline] pub fn fetch_tag(&self, ptr: &RawPtr) -> Option { - let idx = ptr.get_atom()?; - Tag::pos(idx) + ptr.get_atom().and_then(Tag::pos) } #[inline] @@ -402,18 +402,20 @@ impl Store { #[inline] pub fn push_binding(&self, sym: Ptr, val: Ptr, env: Ptr) -> Ptr { - assert_eq!(*sym.tag(), Tag::Expr(Sym)); - assert_eq!(*env.tag(), Tag::Expr(Env)); - let raw = - self.intern_raw_ptrs::<4>([*sym.raw(), self.tag(*val.tag()), *val.raw(), *env.raw()]); + let (sym_tag, sym_raw) = sym.into_parts(); + let (val_tag, val_raw) = val.into_parts(); + let (env_tag, env_raw) = env.into_parts(); + assert_eq!(sym_tag, Tag::Expr(Sym)); + assert_eq!(env_tag, Tag::Expr(Env)); + let raw = self.intern_raw_ptrs([sym_raw, self.tag(val_tag), val_raw, env_raw]); Ptr::new(Tag::Expr(Env), raw) } #[inline] pub fn pop_binding(&self, env: Ptr) -> Option<[Ptr; 3]> { - assert_eq!(*env.tag(), Tag::Expr(Env)); + assert_eq!(env.tag(), &Tag::Expr(Env)); let idx = env.get_index2()?; - let [sym_pay, val_tag, val_pay, env_pay] = self.fetch_raw_ptrs::<4>(idx)?; + let [sym_pay, val_tag, val_pay, env_pay] = self.fetch_raw_ptrs(idx)?; let val_tag = self.fetch_tag(val_tag)?; let sym = Ptr::new(Tag::Expr(Sym), *sym_pay); let val = Ptr::new(val_tag, *val_pay); @@ -423,29 +425,26 @@ impl Store { #[inline] pub fn intern_provenance(&self, query: Ptr, val: Ptr, deps: Ptr) -> Ptr { - assert_eq!(*query.tag(), Tag::Expr(Cons)); + let (query_tag, query_raw) = query.into_parts(); + let (val_tag, val_raw) = val.into_parts(); + let (deps_tag, deps_raw) = deps.into_parts(); + assert_eq!(query_tag, Tag::Expr(Cons)); // TODO: Deps must be a single Prov or a list (later, an N-ary tuple), but we discard the type tag. This is // arguably okay, but it means that in order to recover the preimage we will need to know the expected arity // based on the query. - assert!(matches!(*deps.tag(), Tag::Expr(Prov | Cons | Nil))); - let raw = self.intern_raw_ptrs::<4>([ - *query.raw(), - self.tag(*val.tag()), - *val.raw(), - *deps.raw(), - ]); + assert!(matches!(deps_tag, Tag::Expr(Prov | Cons | Nil))); + let raw = self.intern_raw_ptrs([query_raw, self.tag(val_tag), val_raw, deps_raw]); Ptr::new(Tag::Expr(Prov), raw) } #[inline] pub fn deconstruct_provenance(&self, prov: Ptr) -> Option<[Ptr; 3]> { - assert_eq!(*prov.tag(), Tag::Expr(Prov)); + assert_eq!(prov.tag(), &Tag::Expr(Prov)); let idx = prov.get_index2()?; let [query_pay, val_tag, val_pay, deps_pay] = self.fetch_raw_ptrs::<4>(idx)?; let val_tag = self.fetch_tag(val_tag)?; let query = Ptr::new(Tag::Expr(Cons), *query_pay); let val = Ptr::new(val_tag, *val_pay); - let deps = Ptr::new(Tag::Expr(Cons), *deps_pay); Some([query, val, deps]) } @@ -462,10 +461,7 @@ impl Store { #[inline] pub fn fetch_num(&self, ptr: &Ptr) -> Option<&F> { - match ptr.tag() { - Tag::Expr(Num) => self.fetch_f(ptr), - _ => None, - } + match_opt!(ptr.tag(), Tag::Expr(Num) => self.fetch_f(ptr)?) } #[inline] @@ -480,10 +476,7 @@ impl Store { #[inline] pub fn fetch_u64(&self, ptr: &Ptr) -> Option { - match ptr.tag() { - Tag::Expr(U64) => self.fetch_f(ptr).and_then(F::to_u64), - _ => None, - } + match_opt!(ptr.tag(), Tag::Expr(U64) => self.fetch_f(ptr).and_then(F::to_u64)?) } #[inline] @@ -493,10 +486,7 @@ impl Store { #[inline] pub fn fetch_char(&self, ptr: &Ptr) -> Option { - match ptr.tag() { - Tag::Expr(Char) => self.fetch_f(ptr).and_then(F::to_char), - _ => None, - } + match_opt!(ptr.tag(), Tag::Expr(Char) => self.fetch_f(ptr).and_then(F::to_char)?) } #[inline] @@ -514,8 +504,8 @@ impl Store { Ptr::new(tag, self.raw_zero()) } - pub fn is_zero(&self, ptr: &RawPtr) -> bool { - match ptr { + pub fn is_zero(&self, raw: &RawPtr) -> bool { + match raw { RawPtr::Atom(idx) => self.fetch_f_by_idx(*idx) == Some(&F::ZERO), _ => false, } @@ -530,7 +520,8 @@ impl Store { /// such pointer will result on the same original `ZPtr` #[inline] pub fn opaque(&self, z: ZPtr) -> Ptr { - self.intern_atom(*z.tag(), *z.value()) + let crate::z_ptr::ZPtr(tag, value) = z; + self.intern_atom(tag, value) } pub fn intern_string(&self, s: &str) -> Ptr { @@ -675,20 +666,14 @@ impl Store { } } + #[inline] pub fn fetch_sym(&self, ptr: &Ptr) -> Option { - if ptr.tag() == &Tag::Expr(Sym) { - self.fetch_symbol(ptr) - } else { - None - } + match_opt!(ptr.tag(), Tag::Expr(Sym) => self.fetch_symbol(ptr)?) } + #[inline] pub fn fetch_key(&self, ptr: &Ptr) -> Option { - if ptr.tag() == &Tag::Expr(Key) { - self.fetch_symbol(ptr) - } else { - None - } + match_opt!(ptr.tag(), Tag::Expr(Key) => self.fetch_symbol(ptr)?) } #[inline] @@ -771,31 +756,12 @@ impl Store { Ptr::new(Tag::Cont(Terminal), RawPtr::Atom(self.hash8zeros_idx)) } - /// Returns the pair of pointers used to construct the provided `RawPtr` - fn decons_hash4_raw(&self, raw: &RawPtr) -> Result<(Ptr, Ptr)> { - let Some(idx) = raw.get_hash4() else { - bail!("not a hash4 raw pointer") - }; - match self.fetch_raw_ptrs(idx) { - Some([car_tag, car, cdr_tag, cdr]) => { - let car_ptr = self.raw_to_ptr(car_tag, *car).context("Not a pointer")?; - let cdr_ptr = self.raw_to_ptr(cdr_tag, *cdr).context("Not a pointer")?; - Ok((car_ptr, cdr_ptr)) - } - None => bail!("couldn't fetch raw ptrs"), - } - } - - /// Simpler version of `car_cdr` that doesn't deconstruct strings - pub fn car_cdr_simple(&self, ptr: &Ptr) -> Result<(Ptr, Ptr)> { - match ptr.tag() { - Tag::Expr(Nil) => { - let nil = self.intern_nil(); - Ok((nil, nil)) - } - Tag::Expr(Cons) => self.decons_hash4_raw(ptr.raw()), - _ => bail!("invalid pointer to extract car/cdr (simple) from"), - } + /// Function specialized on deconstructing `Cons` pointers into their car/cdr + pub fn fetch_cons(&self, ptr: &Ptr) -> Option<(Ptr, Ptr)> { + match_opt!((ptr.tag(), ptr.raw()), (Tag::Expr(Cons), RawPtr::Hash4(idx)) => { + let [car, cdr] = fetch_ptrs!(self, 2, *idx)?; + (car, cdr) + }) } /// Deconstruct a cons-like pointer such that: @@ -804,20 +770,42 @@ impl Store { /// * If applied on the empty string, returns `(nil, "")` /// * If applied on a string `"abc..."`, returns `('a', "bc...")` pub fn car_cdr(&self, ptr: &Ptr) -> Result<(Ptr, Ptr)> { - match ptr.tag() { - Tag::Expr(Nil | Cons) => self.car_cdr_simple(ptr), - Tag::Expr(Str) => { - if self.is_zero(ptr.raw()) { + match (ptr.tag(), ptr.raw()) { + (Tag::Expr(Nil), _) => { + let nil = self.intern_nil(); + Ok((nil, nil)) + } + (Tag::Expr(Str), RawPtr::Atom(idx)) => { + if self.fetch_f_by_idx(*idx) == Some(&F::ZERO) { let empty_str = Ptr::new(Tag::Expr(Str), self.raw_zero()); Ok((self.intern_nil(), empty_str)) } else { - self.decons_hash4_raw(ptr.raw()) + bail!("Invalid empty string pointer") } } + (Tag::Expr(Cons | Str), RawPtr::Hash4(idx)) => { + let [car, cdr] = fetch_ptrs!(self, 2, *idx).context("couldn't fetch car/cdr")?; + Ok((car, cdr)) + } _ => bail!("invalid pointer to extract car/cdr from"), } } + /// Simpler version of `car_cdr` that doesn't deconstruct strings + pub fn car_cdr_simple(&self, ptr: &Ptr) -> Result<(Ptr, Ptr)> { + match (ptr.tag(), ptr.raw()) { + (Tag::Expr(Nil), _) => { + let nil = self.intern_nil(); + Ok((nil, nil)) + } + (Tag::Expr(Cons), RawPtr::Hash4(idx)) => { + let [car, cdr] = fetch_ptrs!(self, 2, *idx).context("couldn't fetch car/cdr")?; + Ok((car, cdr)) + } + _ => bail!("invalid pointer to extract car/cdr (simple) from"), + } + } + /// Interns a sequence of pointers as a cons-list. The terminating element /// defaults to `nil` if `last` is `None` fn intern_list>(&self, elts: I, last: Option) -> Ptr @@ -900,10 +888,10 @@ impl Store { /// Fetches an environment pub fn fetch_env(&self, ptr: &Ptr) -> Option> { - if *ptr.tag() != Tag::Expr(Env) { + if ptr.tag() != &Tag::Expr(Env) { return None; } - if *ptr == self.intern_empty_env() { + if ptr == &self.intern_empty_env() { return Some(vec![]); } let mut idx = ptr.raw().get_hash4()?; @@ -922,7 +910,7 @@ impl Store { /// Fetches a provenance pub fn fetch_provenance(&self, ptr: &Ptr) -> Option<(Ptr, Ptr, Ptr)> { - if *ptr.tag() != Tag::Expr(Prov) { + if ptr.tag() != &Tag::Expr(Prov) { return None; } @@ -1495,6 +1483,8 @@ mod tests { let nil = store.intern_nil(); let (car, cdr) = store.car_cdr(&nil).unwrap(); assert_eq!((&car, &cdr), (&nil, &nil)); + let (car, cdr) = store.car_cdr_simple(&nil).unwrap(); + assert_eq!((&car, &cdr), (&nil, &nil)); // regular cons let one = store.num_u64(1); @@ -1502,6 +1492,8 @@ mod tests { let one_a = store.cons(one, a); let (car, cdr) = store.car_cdr(&one_a).unwrap(); assert_eq!((&one, &a), (&car, &cdr)); + let (car, cdr) = store.car_cdr_simple(&one_a).unwrap(); + assert_eq!((&one, &a), (&car, &cdr)); // string let abc = store.intern_string("abc");