mirror of
https://github.com/urbit/ares.git
synced 2024-11-23 00:25:49 +03:00
hoon, jets: add +mas
This commit is contained in:
parent
15656c1fe2
commit
a90b23d263
@ -147,6 +147,17 @@
|
|||||||
* $(a (div a 2))
|
* $(a (div a 2))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ mas :: axis within head/tail
|
||||||
|
~/ %mas
|
||||||
|
|= a=@
|
||||||
|
~> %sham.%mas
|
||||||
|
^- @
|
||||||
|
?- a
|
||||||
|
?(%2 %3) 1
|
||||||
|
?(%0 %1) !!
|
||||||
|
* (add (mod a 2) (mul $(a (div a 2)) 2))
|
||||||
|
==
|
||||||
|
::
|
||||||
:: List logic
|
:: List logic
|
||||||
::
|
::
|
||||||
++ flop :: reverse
|
++ flop :: reverse
|
||||||
|
4
rust/ares/Cargo.lock
generated
4
rust/ares/Cargo.lock
generated
@ -230,9 +230,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
|
@ -12,7 +12,7 @@ ibig = { path = "../ibig-rs" }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ares_macros = { path = "../ares_macros" }
|
ares_macros = { path = "../ares_macros" }
|
||||||
bitvec = "1.0.0"
|
bitvec = "1.0.0"
|
||||||
either = "1.6.1"
|
either = "1.9.0"
|
||||||
libc = "0.2.126"
|
libc = "0.2.126"
|
||||||
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
|
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
|
||||||
memmap = "0.7.0"
|
memmap = "0.7.0"
|
||||||
|
@ -9,6 +9,7 @@ use crate::mem::NockStack;
|
|||||||
use crate::newt::Newt;
|
use crate::newt::Newt;
|
||||||
use crate::noun::{self, Noun, Slots};
|
use crate::noun::{self, Noun, Slots};
|
||||||
use ares_macros::tas;
|
use ares_macros::tas;
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ pub fn get_jet(jet_name: Noun) -> Option<Jet> {
|
|||||||
tas!(b"rev") => Some(jet_rev),
|
tas!(b"rev") => Some(jet_rev),
|
||||||
//
|
//
|
||||||
tas!(b"cap") => Some(jet_cap),
|
tas!(b"cap") => Some(jet_cap),
|
||||||
|
tas!(b"mas") => Some(jet_mas),
|
||||||
//
|
//
|
||||||
tas!(b"mink") => Some(jet_mink),
|
tas!(b"mink") => Some(jet_mink),
|
||||||
_ => {
|
_ => {
|
||||||
@ -91,8 +93,10 @@ pub fn get_jet_test_mode(_jet_name: Noun) -> bool {
|
|||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::noun::{Atom, Noun, D};
|
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D};
|
||||||
|
use crate::noun::Error::NotRepresentable;
|
||||||
use bitvec::prelude::{BitSlice, Lsb0};
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
|
use ibig::UBig;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
pub fn slot(noun: Noun, axis: u64) -> Result {
|
pub fn slot(noun: Noun, axis: u64) -> Result {
|
||||||
@ -151,6 +155,58 @@ pub mod util {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Subtraction */
|
||||||
|
pub fn sub(stack: &mut NockStack, a: Atom, b: Atom) -> noun::Result<Atom> {
|
||||||
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
|
let a_small = a.data();
|
||||||
|
let b_small = b.data();
|
||||||
|
|
||||||
|
if a_small < b_small {
|
||||||
|
Err(NotRepresentable)
|
||||||
|
} else {
|
||||||
|
Ok(Atom::new(stack, a_small - b_small))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let a_big = a.as_ubig(stack);
|
||||||
|
let b_big = b.as_ubig(stack);
|
||||||
|
|
||||||
|
if a_big < b_big {
|
||||||
|
Err(NotRepresentable)
|
||||||
|
} else {
|
||||||
|
let a_big = a.as_ubig(stack);
|
||||||
|
let b_big = b.as_ubig(stack);
|
||||||
|
let res = UBig::sub_stack(stack, a_big, b_big);
|
||||||
|
Ok(Atom::from_ubig(stack, &res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Binary exponent */
|
||||||
|
pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
|
||||||
|
unsafe {
|
||||||
|
if arg < 63 {
|
||||||
|
DirectAtom::new_unchecked(1 << arg).as_atom()
|
||||||
|
} else {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
|
||||||
|
dest.set(arg, true);
|
||||||
|
atom.normalize_as_atom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Binary OR */
|
||||||
|
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
|
||||||
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
|
||||||
|
let a_bit = a.as_bitslice();
|
||||||
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
|
*dest |= b.as_bitslice();
|
||||||
|
atom.normalize_as_atom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Measure the number of bloqs in an atom */
|
/** Measure the number of bloqs in an atom */
|
||||||
pub fn met(bloq: usize, a: Atom) -> usize {
|
pub fn met(bloq: usize, a: Atom) -> usize {
|
||||||
if unsafe { a.as_noun().raw_equals(D(0)) } {
|
if unsafe { a.as_noun().raw_equals(D(0)) } {
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
*/
|
*/
|
||||||
use crate::jets;
|
use crate::jets;
|
||||||
use crate::jets::JetErr::*;
|
use crate::jets::JetErr::*;
|
||||||
use crate::jets::util::{bite, chop, met, slot};
|
use crate::jets::util::*;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::mug::mug;
|
use crate::mug::mug;
|
||||||
use crate::newt::Newt;
|
use crate::newt::Newt;
|
||||||
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES};
|
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D, DIRECT_MAX, NO, T, YES};
|
||||||
use either::Either::*;
|
use either::{Left, Right};
|
||||||
use ibig::ops::DivRem;
|
use ibig::ops::DivRem;
|
||||||
use ibig::UBig;
|
use ibig::UBig;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
@ -96,24 +96,7 @@ pub fn jet_sub(
|
|||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
Ok(sub(stack, a, b)?.as_noun())
|
||||||
if a.data() < b.data() {
|
|
||||||
Err(Deterministic)
|
|
||||||
} else {
|
|
||||||
Ok(unsafe { DirectAtom::new_unchecked(a.data() - b.data()) }.as_noun())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let a_int = a.as_ubig(stack);
|
|
||||||
let b_int = b.as_ubig(stack);
|
|
||||||
if a_int < b_int {
|
|
||||||
Err(Deterministic)
|
|
||||||
} else {
|
|
||||||
let a_big = a.as_ubig(stack);
|
|
||||||
let b_big = b.as_ubig(stack);
|
|
||||||
let res = UBig::sub_stack(stack, a_big, b_big);
|
|
||||||
Ok(Atom::from_ubig(stack, &res).as_noun())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_mul(
|
pub fn jet_mul(
|
||||||
@ -329,16 +312,7 @@ pub fn jet_bex(
|
|||||||
subject: Noun,
|
subject: Noun,
|
||||||
) -> jets::Result {
|
) -> jets::Result {
|
||||||
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
||||||
|
Ok(bex(stack, arg).as_noun())
|
||||||
if arg < 63 {
|
|
||||||
Ok(unsafe { DirectAtom::new_unchecked(1 << arg) }.as_noun())
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
|
|
||||||
dest.set(arg, true);
|
|
||||||
Ok(atom.normalize_as_atom().as_noun())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_lsh(
|
pub fn jet_lsh(
|
||||||
@ -410,15 +384,7 @@ pub fn jet_con(
|
|||||||
let a = slot(arg, 2)?.as_atom()?;
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
let b = slot(arg, 3)?.as_atom()?;
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
let new_size = cmp::max(a.size(), b.size());
|
Ok(con(stack, a, b).as_noun())
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
|
|
||||||
let a_bit = a.as_bitslice();
|
|
||||||
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
|
||||||
*dest |= b.as_bitslice();
|
|
||||||
Ok(atom.normalize_as_atom().as_noun())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jet_dis(
|
pub fn jet_dis(
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*/
|
*/
|
||||||
use crate::jets;
|
use crate::jets;
|
||||||
use crate::jets::JetErr::*;
|
use crate::jets::JetErr::*;
|
||||||
use crate::jets::util::{met, slot};
|
use crate::jets::util::*;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::newt::Newt;
|
use crate::newt::Newt;
|
||||||
use crate::noun::{Noun, D};
|
use crate::noun::{Noun, D};
|
||||||
@ -12,7 +12,7 @@ crate::gdb!();
|
|||||||
pub fn jet_cap(
|
pub fn jet_cap(
|
||||||
_stack: &mut NockStack,
|
_stack: &mut NockStack,
|
||||||
_newt: &mut Option<&mut Newt>,
|
_newt: &mut Option<&mut Newt>,
|
||||||
subject: Noun,
|
subject: Noun
|
||||||
) -> jets::Result {
|
) -> jets::Result {
|
||||||
let arg = slot(subject, 6)?;
|
let arg = slot(subject, 6)?;
|
||||||
let tom = arg.as_atom()?;
|
let tom = arg.as_atom()?;
|
||||||
@ -29,6 +29,26 @@ pub fn jet_cap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn jet_mas(
|
||||||
|
stack: &mut NockStack,
|
||||||
|
_newt: &mut Option<&mut Newt>,
|
||||||
|
subject: Noun
|
||||||
|
) -> jets::Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let tom = arg.as_atom()?;
|
||||||
|
let met = met(0, tom);
|
||||||
|
|
||||||
|
if met < 2 {
|
||||||
|
Err(Deterministic)
|
||||||
|
} else {
|
||||||
|
let c = bex(stack, met - 1);
|
||||||
|
let d = bex(stack, met - 2);
|
||||||
|
let e = sub(stack, tom, c)?;
|
||||||
|
|
||||||
|
Ok(con(stack, e, d).as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -51,4 +71,20 @@ mod tests {
|
|||||||
assert_jet(s, jet_cap, D(7), D(3));
|
assert_jet(s, jet_cap, D(7), D(3));
|
||||||
assert_jet(s, jet_cap, D(8), D(2));
|
assert_jet(s, jet_cap, D(8), D(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mas() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
|
||||||
|
assert_jet_err(s, jet_mas, D(0), JetErr::Deterministic);
|
||||||
|
assert_jet_err(s, jet_mas, D(1), JetErr::Deterministic);
|
||||||
|
|
||||||
|
assert_jet(s, jet_mas, D(2), D(1));
|
||||||
|
assert_jet(s, jet_mas, D(3), D(1));
|
||||||
|
assert_jet(s, jet_mas, D(4), D(2));
|
||||||
|
assert_jet(s, jet_mas, D(5), D(3));
|
||||||
|
assert_jet(s, jet_mas, D(6), D(2));
|
||||||
|
assert_jet(s, jet_mas, D(7), D(3));
|
||||||
|
assert_jet(s, jet_mas, D(8), D(4));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::mem::{word_size_of, NockStack};
|
use crate::mem::{word_size_of, NockStack};
|
||||||
use bitvec::prelude::{BitSlice, Lsb0};
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
use either::Either;
|
use either::{Either, Left, Right};
|
||||||
use ibig::{Stack, UBig};
|
use ibig::{Stack, UBig};
|
||||||
use intmap::IntMap;
|
use intmap::IntMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -61,8 +61,8 @@ pub fn acyclic_noun(noun: Noun) -> bool {
|
|||||||
|
|
||||||
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
||||||
match noun.as_either_atom_cell() {
|
match noun.as_either_atom_cell() {
|
||||||
Either::Left(_atom) => true,
|
Left(_atom) => true,
|
||||||
Either::Right(cell) => {
|
Right(cell) => {
|
||||||
if seen.get(cell.0).is_some() {
|
if seen.get(cell.0).is_some() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@ -669,9 +669,9 @@ impl Atom {
|
|||||||
|
|
||||||
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
|
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
|
||||||
if self.is_indirect() {
|
if self.is_indirect() {
|
||||||
unsafe { Either::Right(self.indirect) }
|
unsafe { Right(self.indirect) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Left(self.direct) }
|
unsafe { Left(self.direct) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,22 +717,22 @@ impl Atom {
|
|||||||
|
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(_direct) => 1,
|
Left(_direct) => 1,
|
||||||
Either::Right(indirect) => indirect.size(),
|
Right(indirect) => indirect.size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bit_size(&self) -> usize {
|
pub fn bit_size(&self) -> usize {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(direct) => direct.bit_size(),
|
Left(direct) => direct.bit_size(),
|
||||||
Either::Right(indirect) => indirect.bit_size(),
|
Right(indirect) => indirect.bit_size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_pointer(&self) -> *const u64 {
|
pub fn data_pointer(&self) -> *const u64 {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(_direct) => (self as *const Atom) as *const u64,
|
Left(_direct) => (self as *const Atom) as *const u64,
|
||||||
Either::Right(indirect) => indirect.data_pointer(),
|
Right(indirect) => indirect.data_pointer(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,8 +787,8 @@ impl Allocated {
|
|||||||
|
|
||||||
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
|
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
|
Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
|
||||||
Either::Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
|
Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,9 +802,9 @@ impl Allocated {
|
|||||||
|
|
||||||
pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
|
pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
|
||||||
if self.is_indirect() {
|
if self.is_indirect() {
|
||||||
unsafe { Either::Left(self.indirect) }
|
unsafe { Left(self.indirect) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Right(self.cell) }
|
unsafe { Right(self.cell) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,17 +905,17 @@ impl Noun {
|
|||||||
|
|
||||||
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
|
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
|
||||||
if self.is_cell() {
|
if self.is_cell() {
|
||||||
unsafe { Either::Right(self.cell) }
|
unsafe { Right(self.cell) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Left(self.atom) }
|
unsafe { Left(self.atom) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
|
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
|
||||||
if self.is_direct() {
|
if self.is_direct() {
|
||||||
unsafe { Either::Left(self.direct) }
|
unsafe { Left(self.direct) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Right(self.allocated) }
|
unsafe { Right(self.allocated) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,8 +1013,8 @@ impl Noun {
|
|||||||
if allocated.get_metadata() & (1 << 32) == 0 {
|
if allocated.get_metadata() & (1 << 32) == 0 {
|
||||||
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
|
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
|
||||||
match allocated.as_either() {
|
match allocated.as_either() {
|
||||||
Either::Left(indirect) => indirect.size() + 2,
|
Left(indirect) => indirect.size() + 2,
|
||||||
Either::Right(cell) => {
|
Right(cell) => {
|
||||||
word_size_of::<CellMemory>()
|
word_size_of::<CellMemory>()
|
||||||
+ cell.head().mass_wind(inside)
|
+ cell.head().mass_wind(inside)
|
||||||
+ cell.tail().mass_wind(inside)
|
+ cell.tail().mass_wind(inside)
|
||||||
@ -1036,7 +1036,7 @@ impl Noun {
|
|||||||
if let Ok(allocated) = self.as_allocated() {
|
if let Ok(allocated) = self.as_allocated() {
|
||||||
if inside(allocated.to_raw_pointer()) {
|
if inside(allocated.to_raw_pointer()) {
|
||||||
allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
|
allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
|
||||||
if let Either::Right(cell) = allocated.as_either() {
|
if let Right(cell) = allocated.as_either() {
|
||||||
cell.head().mass_unwind(inside);
|
cell.head().mass_unwind(inside);
|
||||||
cell.tail().mass_unwind(inside);
|
cell.tail().mass_unwind(inside);
|
||||||
}
|
}
|
||||||
@ -1077,8 +1077,8 @@ impl Slots for Noun {}
|
|||||||
impl private::RawSlots for Noun {
|
impl private::RawSlots for Noun {
|
||||||
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
|
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
|
||||||
match self.as_either_atom_cell() {
|
match self.as_either_atom_cell() {
|
||||||
Either::Right(cell) => cell.raw_slot(axis),
|
Right(cell) => cell.raw_slot(axis),
|
||||||
Either::Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
|
Left(_atom) => Err(Error::NotCell), // Axis tried to descend through atom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user