Sword OOM round 2: PANIC! in alloc_would_oom_ (#286)

* Revert "fix build error in assert_no_alloc (#284)"

This reverts commit 14124d804e.

* Revert "NockStack: explicitly catch OOM (#283)"

This reverts commit bd27200ef3.

* Panic instead of Result for OOM

* panic_any, don't use expect

* Buh-bye to PMA + guard

* fix tests

---------

Co-authored-by: Chris Allen <cma@bitemyapp.com>
This commit is contained in:
Edward Amsden 2024-11-26 19:18:39 -06:00 committed by GitHub
parent 14124d804e
commit f9915a75ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 2350 additions and 3014 deletions

View File

@ -173,7 +173,6 @@ pub struct AllocDisabler;
#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled
impl AllocDisabler {
#[allow(unused_variables)]
fn check(&self, layout: Layout) {
let forbid_count = ALLOC_FORBID_COUNT.with(|f| f.get());
let permit_count = ALLOC_PERMIT_COUNT.with(|p| p.get());

View File

@ -1,20 +1,16 @@
//! Addition and subtraction operators.
use crate::{
add,
arch::word::Word,
buffer::Buffer,
helper_macros,
ibig::IBig,
memory::Stack,
primitive::{PrimitiveSigned, PrimitiveUnsigned},
sign::Sign::*,
ubig::{Repr::*, UBig},
};
use core::{
mem,
ops::{Add, AddAssign, Sub, SubAssign},
};
use crate::arch::word::Word;
use crate::buffer::Buffer;
use crate::ibig::IBig;
use crate::memory::Stack;
use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
use crate::sign::Sign::*;
use crate::ubig::Repr::*;
use crate::ubig::UBig;
use crate::{add, helper_macros};
use core::mem;
use core::ops::{Add, AddAssign, Sub, SubAssign};
impl Add<UBig> for UBig {
type Output = UBig;
@ -531,58 +527,58 @@ impl UBig {
// given at least 2 words of extra capacity. However, this supports UBigs which have already
// been expanded through other operations.
#[inline]
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
pub fn add_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1)?,
(Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0)?,
(Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1)?,
(Small(word0), Small(word1)) => UBig::add_word_stack(stack, word0, word1),
(Small(word0), Large(buffer1)) => UBig::add_large_word_stack(stack, buffer1, word0),
(Large(buffer0), Small(word1)) => UBig::add_large_word_stack(stack, buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::add_large_stack(stack, buffer0, &buffer1)?
UBig::add_large_stack(stack, buffer0, &buffer1)
} else {
UBig::add_large_stack(stack, buffer1, &buffer0)?
UBig::add_large_stack(stack, buffer1, &buffer0)
}
}
};
Ok(ubig)
ubig
}
/// Add two `Word`s.
#[inline]
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
fn add_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
let (res, overflow) = a.overflowing_add(b);
let ubig = if overflow {
let mut buffer = Buffer::allocate_stack(stack, 2)?;
let mut buffer = Buffer::allocate_stack(stack, 2);
buffer.push(res);
buffer.push(1);
buffer.into()
} else {
UBig::from_word(res)
};
Ok(ubig)
ubig
}
/// Add a large number to a `Word`.
fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> Result<UBig, S::AllocError> {
fn add_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: Word) -> UBig {
debug_assert!(buffer.len() >= 2);
if add::add_word_in_place(&mut buffer, rhs) {
buffer.push_may_reallocate_stack(stack, 1)?;
buffer.push_may_reallocate_stack(stack, 1);
}
Ok(buffer.into())
buffer.into()
}
/// Add two large numbers.
fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> Result<UBig, S::AllocError> {
fn add_large_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, rhs: &[Word]) -> UBig {
let n = buffer.len().min(rhs.len());
let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
if rhs.len() > n {
buffer.ensure_capacity_stack(stack, rhs.len())?;
buffer.ensure_capacity_stack(stack, rhs.len());
buffer.extend(&rhs[n..]);
}
if overflow && add::add_one_in_place(&mut buffer[n..]) {
buffer.push_may_reallocate_stack(stack, 1)?;
buffer.push_may_reallocate_stack(stack, 1);
}
Ok(buffer.into())
buffer.into()
}
/// Add two `Word`s.

View File

@ -1,13 +1,14 @@
//! Word buffer.
use crate::{arch::word::Word, memory, memory::Stack, ubig::UBig};
use crate::arch::word::Word;
use crate::memory;
use crate::memory::Stack;
use crate::ubig::UBig;
use alloc::vec::Vec;
use core::{
iter,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
use core::iter;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
/// Buffer for Words.
///
@ -21,14 +22,14 @@ use core::{
pub(crate) struct Buffer(ManuallyDrop<Vec<Word>>);
impl Buffer {
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Result<Buffer, S::AllocError> {
pub(crate) fn allocate_stack<S: Stack>(stack: &mut S, num_words: usize) -> Buffer {
if num_words > Buffer::MAX_CAPACITY {
UBig::panic_number_too_large();
}
let capacity = Buffer::default_capacity(num_words);
unsafe {
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity))?;
Ok(Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity))))
let ptr = stack.alloc_layout(memory::array_layout::<Word>(capacity));
Buffer(ManuallyDrop::new(Vec::from_raw_parts(ptr, 0, capacity)))
}
}
@ -44,11 +45,9 @@ impl Buffer {
)))
}
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
pub(crate) fn ensure_capacity_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
if num_words > self.capacity() {
self.reallocate_stack(stack, num_words)
} else {
Ok(())
}
}
@ -71,12 +70,11 @@ impl Buffer {
// }
}
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) -> Result<(), S::AllocError> {
fn reallocate_stack<S: Stack>(&mut self, stack: &mut S, num_words: usize) {
assert!(num_words >= self.len());
let mut new_buffer = Buffer::allocate_stack(stack, num_words)?;
let mut new_buffer = Buffer::allocate_stack(stack, num_words);
new_buffer.clone_from(self);
*self = new_buffer;
Ok(())
}
/// Change capacity to store `num_words` plus some extra space for future growth.
@ -109,10 +107,9 @@ impl Buffer {
}
#[inline]
pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) -> Result<(), S::AllocError> {
self.ensure_capacity_stack(stack, self.len() + 1)?;
pub(crate) fn push_may_reallocate_stack<S: Stack>(&mut self, stack: &mut S, word: Word) {
self.ensure_capacity_stack(stack, self.len() + 1);
self.push(word);
Ok(())
}
/// Append a Word and reallocate if necessary.

View File

@ -1,15 +1,14 @@
//! Conversions between types.
use crate::{
arch::word::Word,
buffer::Buffer,
error::OutOfBoundsError,
ibig::IBig,
memory::Stack,
primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES},
sign::Sign::*,
ubig::{Repr::*, UBig},
};
use crate::arch::word::Word;
use crate::buffer::Buffer;
use crate::error::OutOfBoundsError;
use crate::ibig::IBig;
use crate::memory::Stack;
use crate::primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES};
use crate::sign::Sign::*;
use crate::ubig::Repr::*;
use crate::ubig::UBig;
use alloc::vec::Vec;
use core::convert::{TryFrom, TryInto};
@ -31,19 +30,19 @@ impl Default for IBig {
impl UBig {
#[inline]
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
pub fn from_le_bytes_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
let ubig = if bytes.len() <= WORD_BYTES {
// fast path
UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
} else {
UBig::from_le_bytes_large_stack(stack, bytes)?
UBig::from_le_bytes_large_stack(stack, bytes)
};
Ok(ubig)
ubig
}
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> Result<UBig, S::AllocError> {
fn from_le_bytes_large_stack<S: Stack>(stack: &mut S, bytes: &[u8]) -> UBig {
debug_assert!(bytes.len() > WORD_BYTES);
let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1)?;
let mut buffer = Buffer::allocate_stack(stack, (bytes.len() - 1) / WORD_BYTES + 1);
let mut chunks = bytes.chunks_exact(WORD_BYTES);
for chunk in &mut chunks {
buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
@ -51,7 +50,7 @@ impl UBig {
if !chunks.remainder().is_empty() {
buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
}
Ok(buffer.into())
buffer.into()
}
/// Construct from little-endian bytes.
@ -553,7 +552,7 @@ impl TryFrom<&IBig> for UBig {
impl UBig {
#[inline]
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> Result<UBig, S::AllocError>
pub(crate) fn from_unsigned_stack<S: Stack, T>(stack: &mut S, x: T) -> UBig
where
T: PrimitiveUnsigned,
{
@ -561,10 +560,10 @@ impl UBig {
Ok(w) => UBig::from_word(w),
Err(_) => {
let repr = x.to_le_bytes();
UBig::from_le_bytes_stack(stack, repr.as_ref())?
UBig::from_le_bytes_stack(stack, repr.as_ref())
}
};
Ok(ubig)
ubig
}
/// Convert an unsigned primitive to [UBig].

View File

@ -1,23 +1,19 @@
//! Division operators.
use crate::{
arch::word::Word,
buffer::Buffer,
div, helper_macros,
ibig::IBig,
memory::{MemoryAllocation, Stack},
ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid},
primitive::{PrimitiveSigned, PrimitiveUnsigned},
shift,
sign::Sign::*,
ubig::{Repr::*, UBig},
};
use core::{
convert::TryFrom,
fmt::Debug,
mem,
ops::{Div, DivAssign, Rem, RemAssign},
};
use crate::arch::word::Word;
use crate::buffer::Buffer;
use crate::ibig::IBig;
use crate::memory::{MemoryAllocation, Stack};
use crate::ops::{Abs, DivEuclid, DivRem, DivRemEuclid, RemEuclid};
use crate::primitive::{PrimitiveSigned, PrimitiveUnsigned};
use crate::sign::Sign::*;
use crate::ubig::Repr::*;
use crate::ubig::UBig;
use crate::{div, helper_macros, shift};
use core::convert::TryFrom;
use core::fmt::Debug;
use core::mem;
use core::ops::{Div, DivAssign, Rem, RemAssign};
impl Div<UBig> for UBig {
type Output = UBig;
@ -1279,71 +1275,71 @@ impl_div_ibig_signed!(isize);
impl UBig {
#[inline]
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
pub fn div_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_word(word0, word1),
(Small(_), Large(_)) => UBig::from_word(0),
(Large(buffer0), Small(word1)) => UBig::div_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::div_large_stack(stack, buffer0, buffer1)?
UBig::div_large_stack(stack, buffer0, buffer1)
} else {
UBig::from_word(0)
}
}
};
Ok(ubig_tuple)
ubig_tuple
}
#[inline]
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
pub fn rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::rem_word(word0, word1),
(Small(word0), Large(_)) => UBig::from_word(word0),
(Large(buffer0), Small(word1)) => UBig::rem_large_word(&buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::rem_large_stack(stack, buffer0, buffer1)?
UBig::rem_large_stack(stack, buffer0, buffer1)
} else {
buffer0.into()
}
}
};
Ok(ubig_tuple)
ubig_tuple
}
#[inline]
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<(UBig, UBig), S::AllocError> {
pub fn div_rem_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> (UBig, UBig) {
let ubig_tuple = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::div_rem_word(word0, word1),
(Small(word0), Large(_)) => (UBig::from_word(0), UBig::from_word(word0)),
(Large(buffer0), Small(word1)) => UBig::div_rem_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => {
if buffer0.len() >= buffer1.len() {
UBig::div_rem_large_stack(stack, buffer0, buffer1)?
UBig::div_rem_large_stack(stack, buffer0, buffer1)
} else {
(UBig::from_word(0), buffer0.into())
}
}
};
Ok(ubig_tuple)
ubig_tuple
}
/// `lhs / rhs`
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
fn div_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
let _shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
lhs.erase_front(rhs.len());
Ok(lhs.into())
lhs.into()
}
/// `lhs % rhs`
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> Result<UBig, S::AllocError> {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
fn rem_large_stack<S: Stack>(stack: &mut S, mut lhs: Buffer, mut rhs: Buffer) -> UBig {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0);
Ok(rhs.into())
rhs.into()
}
/// `(lhs / rhs, lhs % rhs)`
@ -1351,33 +1347,33 @@ impl UBig {
stack: &mut S,
mut lhs: Buffer,
mut rhs: Buffer,
) -> Result<(UBig, UBig), S::AllocError> {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs)?;
) -> (UBig, UBig) {
let shift = UBig::div_rem_in_lhs_stack(stack, &mut lhs, &mut rhs);
let n = rhs.len();
rhs.copy_from_slice(&lhs[..n]);
let low_bits = shift::shr_in_place(&mut rhs, shift);
debug_assert!(low_bits == 0);
lhs.erase_front(n);
Ok((lhs.into(), rhs.into()))
(lhs.into(), rhs.into())
}
/// lhs = (lhs / rhs, lhs % rhs)
///
/// Returns shift.
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> Result<u32, S::AllocError> {
fn div_rem_in_lhs_stack<S: Stack>(stack: &mut S, lhs: &mut Buffer, rhs: &mut Buffer) -> u32 {
let (shift, fast_div_rhs_top) = div::normalize_large(rhs);
let lhs_carry = shift::shl_in_place(lhs, shift);
if lhs_carry != 0 {
lhs.push_may_reallocate_stack(stack, lhs_carry)?;
lhs.push_may_reallocate_stack(stack, lhs_carry);
}
let mut allocation =
MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()))?;
MemoryAllocation::new_stack(stack, div::memory_requirement_exact(lhs.len(), rhs.len()));
let mut memory = allocation.memory();
let overflow = div::div_rem_in_place(lhs, rhs, fast_div_rhs_top, &mut memory);
if overflow {
lhs.push_may_reallocate(1);
}
Ok(shift)
shift
}
/// `lhs / rhs`

View File

@ -1,7 +1,8 @@
//! Memory allocation.
use alloc::alloc::Layout;
use core::{marker::PhantomData, mem, slice};
use core::marker::PhantomData;
use core::{mem, slice};
/// Chunk of memory directly allocated from the global allocator.
pub(crate) struct MemoryAllocation {
@ -10,10 +11,8 @@ pub(crate) struct MemoryAllocation {
}
pub trait Stack: Sized {
// type AllocError: Debug;
// no-std bites me in the keister again
type AllocError;
unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<*mut u64, Self::AllocError>;
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64;
}
/// Chunk of memory.
@ -27,7 +26,7 @@ pub(crate) struct Memory<'a> {
}
impl MemoryAllocation {
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> Result<MemoryAllocation, S::AllocError> {
pub(crate) fn new_stack<S: Stack>(stack: &mut S, layout: Layout) -> MemoryAllocation {
let start = if layout.size() == 0 {
// We should use layout.dangling(), but that is unstable.
layout.align() as *mut u8
@ -36,7 +35,7 @@ impl MemoryAllocation {
} else {
// Safe because size is non-zero.
let ptr = unsafe {
let ep = stack.alloc_layout(layout)?;
let ep = stack.alloc_layout(layout);
ep as *mut u8
};
if ptr.is_null() {
@ -45,7 +44,7 @@ impl MemoryAllocation {
ptr
};
Ok(MemoryAllocation { layout, start })
MemoryAllocation { layout, start }
}
/// Allocate memory.

View File

@ -1,20 +1,16 @@
//! Multiplication operators.
use crate::{
arch::word::Word,
buffer::Buffer,
helper_macros,
ibig::IBig,
memory::{MemoryAllocation, Stack},
mul,
primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned},
sign::Sign::{self, *},
ubig::{Repr::*, UBig},
};
use core::{
mem,
ops::{Mul, MulAssign},
};
use crate::arch::word::Word;
use crate::buffer::Buffer;
use crate::ibig::IBig;
use crate::memory::{MemoryAllocation, Stack};
use crate::primitive::{extend_word, PrimitiveSigned, PrimitiveUnsigned};
use crate::sign::Sign::{self, *};
use crate::ubig::Repr::*;
use crate::ubig::UBig;
use crate::{helper_macros, mul};
use core::mem;
use core::ops::{Mul, MulAssign};
use static_assertions::const_assert;
impl Mul<UBig> for UBig {
@ -300,52 +296,52 @@ impl_mul_ibig_primitive!(isize);
impl UBig {
#[inline]
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> Result<UBig, S::AllocError> {
pub fn mul_stack<S: Stack>(stack: &mut S, lhs: UBig, rhs: UBig) -> UBig {
let res = match (lhs.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1)?,
(Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0)?,
(Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1)?,
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1)?,
(Small(word0), Small(word1)) => UBig::mul_word_stack(stack, word0, word1),
(Small(word0), Large(buffer1)) => UBig::mul_large_word_stack(stack, buffer1, word0),
(Large(buffer0), Small(word1)) => UBig::mul_large_word_stack(stack, buffer0, word1),
(Large(buffer0), Large(buffer1)) => UBig::mul_large_stack(stack, &buffer0, &buffer1),
};
Ok(res)
res
}
#[inline]
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> Result<UBig, S::AllocError> {
fn mul_word_stack<S: Stack>(stack: &mut S, a: Word, b: Word) -> UBig {
UBig::from_unsigned_stack(stack, extend_word(a) * extend_word(b))
}
fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> Result<UBig, S::AllocError> {
fn mul_large_word_stack<S: Stack>(stack: &mut S, mut buffer: Buffer, a: Word) -> UBig {
match a {
0 => Ok(UBig::from_word(0)),
1 => Ok(buffer.into()),
0 => UBig::from_word(0),
1 => buffer.into(),
_ => {
let carry = mul::mul_word_in_place(&mut buffer, a);
if carry != 0 {
buffer.push_may_reallocate_stack(stack, carry)?;
buffer.push_may_reallocate_stack(stack, carry);
}
Ok(buffer.into())
buffer.into()
}
}
}
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> Result<UBig, S::AllocError> {
pub fn mul_large_stack<S: Stack>(stack: &mut S, lhs: &[Word], rhs: &[Word]) -> UBig {
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
// This may be 1 too large.
const_assert!(Buffer::MAX_CAPACITY - UBig::MAX_LEN >= 1);
let res_len = lhs.len() + rhs.len();
let mut buffer = Buffer::allocate_stack(stack, res_len)?;
let mut buffer = Buffer::allocate_stack(stack, res_len);
buffer.push_zeros(res_len);
let mut allocation = MemoryAllocation::new_stack(
stack,
mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())),
)?;
);
let mut memory = allocation.memory();
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
assert!(overflow == 0);
Ok(buffer.into())
buffer.into()
}
/// Multiply two `Word`s.

View File

@ -17,7 +17,7 @@ fn main() -> io::Result<()> {
let jammed_input = unsafe {
let in_map = memmap::Mmap::map(&f)?;
let word_len = (in_len + 7) >> 3;
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize).expect("Out of memory condition on IndirectAtom allocation in main()");
let (mut atom, dest) = IndirectAtom::new_raw_mut(&mut stack, word_len as usize);
write_bytes(dest.add(word_len as usize - 1), 0, 8);
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
mem::drop(in_map);
@ -45,7 +45,7 @@ fn main() -> io::Result<()> {
let nuw = SystemTime::now();
let jammed_output = jam(&mut stack, input).expect("Out of memory condition on jam in main()");
let jammed_output = jam(&mut stack, input);
match nuw.elapsed() {
Ok(elapse) => {

View File

@ -1,5 +1,5 @@
use crate::interpreter::Context;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Atom, IndirectAtom};
use std::fmt::Arguments;
use std::io::{Result, Write};
@ -14,27 +14,26 @@ struct NockWriter<'s, 'b> {
const INITIAL_CAPACITY_BYTES: usize = 256;
impl<'s, 'b> NockWriter<'s, 'b> {
unsafe fn new(stack: &'s mut NockStack) -> AllocResult<Self> {
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES)?;
Ok(NockWriter {
unsafe fn new(stack: &'s mut NockStack) -> Self {
let (indirect, buffer) = IndirectAtom::new_raw_mut_bytes(stack, INITIAL_CAPACITY_BYTES);
NockWriter {
stack,
buffer,
indirect,
cursor: 0,
})
}
}
unsafe fn finalize(mut self) -> Atom {
self.indirect.normalize_as_atom()
}
unsafe fn expand(&mut self) -> AllocResult<()> {
unsafe fn expand(&mut self) {
let sz = self.buffer.len();
let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2)?;
let (new_indirect, new_buffer) = IndirectAtom::new_raw_mut_bytes(self.stack, sz * 2);
new_buffer[0..sz].copy_from_slice(self.buffer);
self.buffer = new_buffer;
self.indirect = new_indirect;
Ok(())
}
}
@ -42,7 +41,7 @@ impl Write for NockWriter<'_, '_> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let sz = buf.len();
while (self.buffer.len() - self.cursor) < sz {
unsafe { self.expand()? };
unsafe { self.expand() };
}
self.buffer[self.cursor..self.cursor + sz].copy_from_slice(buf);
self.cursor += sz;
@ -55,14 +54,14 @@ impl Write for NockWriter<'_, '_> {
}
pub fn nock_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<Atom> {
let mut nw = unsafe { NockWriter::new(&mut context.stack)? };
let mut nw = unsafe { NockWriter::new(&mut context.stack) };
nw.write_fmt(fmt)?;
Ok(unsafe { nw.finalize() })
}
pub fn flog_fmt(context: &mut Context, fmt: Arguments<'_>) -> Result<()> {
let cord = nock_fmt(context, fmt)?;
context.slogger.flog(&mut context.stack, cord.as_noun())?;
context.slogger.flog(&mut context.stack, cord.as_noun());
Ok(())
}

View File

@ -1,4 +1,4 @@
use crate::mem::{AllocResult, NockStack, Preserve};
use crate::mem::{NockStack, Preserve};
use crate::mug::mug_u32;
use crate::noun::Noun;
use crate::unifying_equality::unifying_equality;
@ -59,45 +59,45 @@ impl<T: Copy> MutStem<T> {
pub struct MutHamt<T: Copy>(*mut MutStem<T>);
impl<T: Copy> MutHamt<T> {
pub fn new(stack: &mut NockStack) -> AllocResult<MutHamt<T>> {
pub fn new(stack: &mut NockStack) -> MutHamt<T> {
unsafe {
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?;
let new_stem = stack.struct_alloc::<MutStem<T>>(1);
(*new_stem).bitmap = 0;
(*new_stem).typemap = 0;
Ok(MutHamt(new_stem))
MutHamt(new_stem)
}
}
pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> {
pub fn lookup(self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
let mut stem = self.0;
let mut mug = mug_u32(stack, *n)?;
let mut mug = mug_u32(stack, *n);
unsafe {
'lookup: loop {
let chunk = mug & 0x1f;
mug >>= 5;
match (*stem).entry(chunk) {
None => {
break Ok(None);
break None;
}
Some(Left(next_stem)) => {
stem = next_stem;
}
Some(Right(leaf)) => {
for pair in leaf.to_mut_slice().iter_mut() {
if unifying_equality(stack, n, &mut pair.0)? {
break 'lookup Ok(Some(pair.1));
if unifying_equality(stack, n, &mut pair.0) {
break 'lookup Some(pair.1);
}
}
break Ok(None);
break None;
}
}
}
}
}
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<()> {
pub fn insert(self, stack: &mut NockStack, n: &mut Noun, t: T) {
let mut stem = self.0;
let mut mug = mug_u32(stack, *n)?;
let mut mug = mug_u32(stack, *n);
let mut depth = 0u8;
unsafe {
'insert: loop {
@ -105,7 +105,7 @@ impl<T: Copy> MutHamt<T> {
mug >>= 5;
match (*stem).entry(chunk) {
None => {
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1)?;
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1);
*new_leaf_buffer = (*n, t);
(*stem).bitmap |= chunk_to_bit(chunk);
(*stem).typemap &= !chunk_to_bit(chunk);
@ -124,13 +124,13 @@ impl<T: Copy> MutHamt<T> {
}
Some(Right(leaf)) => {
for pair in leaf.to_mut_slice().iter_mut() {
if unifying_equality(stack, n, &mut pair.0)? {
if unifying_equality(stack, n, &mut pair.0) {
pair.1 = t;
break 'insert;
}
}
if depth >= 5 {
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1)?;
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(leaf.len + 1);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
*new_leaf_buffer.add(leaf.len) = (*n, t);
(*stem).buffer[chunk as usize] = MutEntry {
@ -142,8 +142,8 @@ impl<T: Copy> MutHamt<T> {
break;
} else {
assert!(leaf.len == 1);
let new_stem = stack.struct_alloc::<MutStem<T>>(1)?;
let leaf_mug = mug_u32(stack, (*leaf.buffer).0)?;
let new_stem = stack.struct_alloc::<MutStem<T>>(1);
let leaf_mug = mug_u32(stack, (*leaf.buffer).0);
let leaf_chunk = (leaf_mug >> ((depth + 1) * 5)) & 0x1f;
(*new_stem).bitmap = chunk_to_bit(leaf_chunk);
(*new_stem).typemap = 0;
@ -158,7 +158,6 @@ impl<T: Copy> MutHamt<T> {
}
}
}
Ok(())
}
}
@ -283,15 +282,15 @@ impl<T: Copy + Preserve> Hamt<T> {
unsafe { (*self.0).bitmap == 0 }
}
// Make a new, empty HAMT
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
pub fn new(stack: &mut NockStack) -> Self {
unsafe {
let stem_ptr = stack.struct_alloc::<Stem<T>>(1)?;
let stem_ptr = stack.struct_alloc::<Stem<T>>(1);
*stem_ptr = Stem {
bitmap: 0,
typemap: 0,
buffer: null_mut(),
};
Ok(Hamt(stem_ptr))
Hamt(stem_ptr)
}
}
@ -306,15 +305,15 @@ impl<T: Copy + Preserve> Hamt<T> {
* A mutable reference is required so that unifying equality can unify the key with a key entry
* in the HAMT
*/
pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> AllocResult<Option<T>> {
pub fn lookup(&self, stack: &mut NockStack, n: &mut Noun) -> Option<T> {
let mut stem = unsafe { *self.0 };
let mut mug = mug_u32(stack, *n)?;
let mut mug = mug_u32(stack, *n);
'lookup: loop {
let chunk = mug & 0x1F; // 5 bits
mug >>= 5;
match stem.entry(chunk) {
None => {
break Ok(None);
break None;
}
Some((Left(next_stem), _idx)) => {
stem = next_stem;
@ -322,11 +321,11 @@ impl<T: Copy + Preserve> Hamt<T> {
}
Some((Right(leaf), _idx)) => {
for pair in unsafe { leaf.to_mut_slice().iter_mut() } {
if unsafe { unifying_equality(stack, n, &mut pair.0)? } {
break 'lookup Ok(Some(pair.1));
if unsafe { unifying_equality(stack, n, &mut pair.0) } {
break 'lookup Some(pair.1);
}
}
break Ok(None);
break None;
}
}
}
@ -335,11 +334,11 @@ impl<T: Copy + Preserve> Hamt<T> {
// XX a delete function requires a stack, do we need one?
/// Make a new HAMT with the value inserted or replaced at the key.
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> AllocResult<Hamt<T>> {
let mut mug = mug_u32(stack, *n)?;
pub fn insert(&self, stack: &mut NockStack, n: &mut Noun, t: T) -> Hamt<T> {
let mut mug = mug_u32(stack, *n);
let mut depth = 0u8;
let mut stem = unsafe { *self.0 };
let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) }?;
let stem_ret = unsafe { stack.struct_alloc::<Stem<T>>(1) };
let mut dest = stem_ret;
unsafe {
'insert: loop {
@ -348,10 +347,10 @@ impl<T: Copy + Preserve> Hamt<T> {
match stem.entry(chunk) {
// No entry found at mug chunk index; add Leaf to current Stem
None => {
let new_leaf_buffer = stack.struct_alloc(1)?;
let new_leaf_buffer = stack.struct_alloc(1);
*new_leaf_buffer = (*n, t);
let split = stem.hypothetical_index(chunk);
let new_buffer = stack.struct_alloc(stem.size() + 1)?;
let new_buffer = stack.struct_alloc(stem.size() + 1);
if split > 0 {
copy_nonoverlapping(stem.buffer, new_buffer, split);
}
@ -373,11 +372,11 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap & !chunk_to_bit(chunk),
buffer: new_buffer,
};
break Ok(Hamt(stem_ret));
break Hamt(stem_ret);
}
// Stem found at mug chunk index; insert into found Stem
Some((Left(next_stem), idx)) => {
let new_buffer = stack.struct_alloc(stem.size())?;
let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*dest = Stem {
bitmap: stem.bitmap,
@ -393,11 +392,11 @@ impl<T: Copy + Preserve> Hamt<T> {
Some((Right(leaf), idx)) => {
// Override existing value for key, if one exists
for (ldx, pair) in leaf.to_mut_slice().iter_mut().enumerate() {
if unifying_equality(stack, n, &mut pair.0)? {
let new_leaf_buffer = stack.struct_alloc(leaf.len)?;
if unifying_equality(stack, n, &mut pair.0) {
let new_leaf_buffer = stack.struct_alloc(leaf.len);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
(*new_leaf_buffer.add(ldx)).1 = t;
let new_buffer = stack.struct_alloc(stem.size())?;
let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*new_buffer.add(idx) = Entry {
leaf: Leaf {
@ -410,16 +409,16 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap,
buffer: new_buffer,
};
break 'insert Ok(Hamt(stem_ret));
break 'insert Hamt(stem_ret);
}
}
// No existing pair in this Leaf matches the key, and we've maxxed out the
// Hamt depth; add the the key-value pair to the list of pairs for this Leaf
if depth >= 5 {
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1)?;
let new_leaf_buffer = stack.struct_alloc(leaf.len + 1);
copy_nonoverlapping(leaf.buffer, new_leaf_buffer, leaf.len);
*new_leaf_buffer.add(leaf.len) = (*n, t);
let new_buffer = stack.struct_alloc(stem.size())?;
let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*new_buffer.add(idx) = Entry {
leaf: Leaf {
@ -432,7 +431,7 @@ impl<T: Copy + Preserve> Hamt<T> {
typemap: stem.typemap,
buffer: new_buffer,
};
break 'insert Ok(Hamt(stem_ret));
break 'insert Hamt(stem_ret);
// No existing pair in this Leaf matches the key, but we haven't maxxed out
// the Hamt depth yet. If we haven't hit the depth limit yet, we shouldn't
// be making a linked list of pairs. Turn the Leaf into a Stem and insert
@ -442,18 +441,18 @@ impl<T: Copy + Preserve> Hamt<T> {
// Make a fake node pointing to the old leaf and "insert into it" the
// next time around
assert!(leaf.len == 1);
let fake_buffer = stack.struct_alloc(1)?;
let fake_buffer = stack.struct_alloc(1);
*fake_buffer = Entry { leaf };
// Get the mug chunk for the Noun at the *next* level so that we can
// build a fake stem for it
let fake_mug = mug_u32(stack, (*leaf.buffer).0)?;
let fake_mug = mug_u32(stack, (*leaf.buffer).0);
let fake_chunk = (fake_mug >> ((depth + 1) * 5)) & 0x1F;
let next_stem = Stem {
bitmap: chunk_to_bit(fake_chunk),
typemap: 0,
buffer: fake_buffer,
};
let new_buffer = stack.struct_alloc(stem.size())?;
let new_buffer = stack.struct_alloc(stem.size());
copy_nonoverlapping(stem.buffer, new_buffer, stem.size());
*dest = Stem {
bitmap: stem.bitmap,
@ -518,13 +517,13 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
}
}
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
let res = if stack.is_in_frame(self.0) {
let dest_stem = stack.struct_alloc_in_previous_frame(1)?;
unsafe fn preserve(&mut self, stack: &mut NockStack) {
if stack.is_in_frame(self.0) {
let dest_stem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(self.0, dest_stem, 1);
self.0 = dest_stem;
if stack.is_in_frame((*dest_stem).buffer) {
let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size())?;
let dest_buffer = stack.struct_alloc_in_previous_frame((*dest_stem).size());
copy_nonoverlapping((*dest_stem).buffer, dest_buffer, (*dest_stem).size());
(*dest_stem).buffer = dest_buffer;
// Here we're using the Rust stack since the array is a fixed
@ -557,7 +556,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
Some((Left(next_stem), idx)) => {
if stack.is_in_frame(next_stem.buffer) {
let dest_buffer =
stack.struct_alloc_in_previous_frame(next_stem.size())?;
stack.struct_alloc_in_previous_frame(next_stem.size());
copy_nonoverlapping(
next_stem.buffer,
dest_buffer,
@ -583,15 +582,15 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
Some((Right(leaf), idx)) => {
if stack.is_in_frame(leaf.buffer) {
let dest_buffer =
stack.struct_alloc_in_previous_frame(leaf.len)?;
stack.struct_alloc_in_previous_frame(leaf.len);
copy_nonoverlapping(leaf.buffer, dest_buffer, leaf.len);
let new_leaf = Leaf {
len: leaf.len,
buffer: dest_buffer,
};
for pair in new_leaf.to_mut_slice().iter_mut() {
pair.0.preserve(stack)?;
pair.1.preserve(stack)?;
pair.0.preserve(stack);
pair.1.preserve(stack);
}
*stem.buffer.add(idx) = Entry { leaf: new_leaf };
}
@ -602,8 +601,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
}
}
}
};
Ok(res)
}
}
}
@ -709,10 +707,10 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
hamt = hamt.insert(&mut stack, &mut D(0), D(1)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(2), D(3)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(4), D(5)).unwrap();
let mut hamt = Hamt::<Noun>::new(&mut stack);
hamt = hamt.insert(&mut stack, &mut D(0), D(1));
hamt = hamt.insert(&mut stack, &mut D(2), D(3));
hamt = hamt.insert(&mut stack, &mut D(4), D(5));
let mut iter = hamt.iter();
let three = cdr(&mut iter);
let one = cdr(&mut iter);
@ -730,10 +728,10 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut hs = HashSet::new();
for n in 0..100 {
hamt = hamt.insert(&mut stack, &mut D(n), D(n)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(n), D(n));
hs.insert((n, n));
}
let mut iter = hamt.iter();
@ -748,21 +746,17 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut hamt = Hamt::<Noun>::new(&mut stack);
let mut n = D(0);
let t = D(1);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let lu = hamt
.lookup(&mut stack, &mut n)
.expect("lookup failed due to OOM");
hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt.lookup(&mut stack, &mut n);
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 1);
let mut n = D(2);
let t = D(3);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
let lu = hamt
.lookup(&mut stack, &mut D(2))
.expect("lookup failed due to OOM");
hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt.lookup(&mut stack, &mut D(2));
let lu_value = unsafe { lu.expect("lookup failed").as_raw() };
assert_eq!(lu_value, 3);
}
@ -772,38 +766,32 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut hamt = Hamt::<Noun>::new(&mut stack);
// 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut n = D(0);
let t = D(0);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
hamt = hamt.insert(&mut stack, &mut n, t);
let mut n = D(87699370);
let t = D(87699370);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
hamt = hamt.insert(&mut stack, &mut n, t);
let mut n = D(317365951);
let t = D(317365951);
hamt = hamt.insert(&mut stack, &mut n, t).unwrap();
hamt = hamt.insert(&mut stack, &mut n, t);
let lu = hamt
.lookup(&mut stack, &mut D(0))
.expect("lookup failed due to OOM");
let lu = hamt.lookup(&mut stack, &mut D(0));
let lu_value = unsafe { lu.expect("0 lookup failed").as_raw() };
assert_eq!(lu_value, 0);
let lu = hamt
.lookup(&mut stack, &mut D(87699370))
.expect("lookup failed due to OOM");
let lu = hamt.lookup(&mut stack, &mut D(87699370));
let lu_value = unsafe { lu.expect("87699370 lookup failed").as_raw() };
assert_eq!(lu_value, 87699370);
let lu = hamt
.lookup(&mut stack, &mut D(317365951))
.expect("lookup failed due to OOM");
let lu = hamt.lookup(&mut stack, &mut D(317365951));
let lu_value = unsafe { lu.expect("317365951 lookup failed").as_raw() };
assert_eq!(lu_value, 317365951);
}
@ -813,13 +801,13 @@ mod test {
let size = 1 << 27;
let top_slots = 100;
let mut stack = NockStack::new(size, top_slots);
let mut hamt = Hamt::<Noun>::new(&mut stack).unwrap();
let mut hamt = Hamt::<Noun>::new(&mut stack);
// 3-way collision
// x: 0 y: 87699370 x_hash: 2046756072 y_hash: 2046756072
// x: 0 z: 317365951 x_hash: 2046756072 z_hash: 2046756072
let mut hs = HashSet::new();
for x in &[0, 87699370, 317365951] {
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x)).unwrap();
hamt = hamt.insert(&mut stack, &mut D(*x), D(*x));
hs.insert((*x, *x));
}
for x in hamt.iter() {

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,10 @@ pub mod tree;
use crate::flog;
use crate::interpreter::{Context, Error, Mote};
use crate::jets::bits::*;
use crate::jets::cold::Cold;
use crate::jets::form::*;
use crate::jets::hash::*;
use crate::jets::hot::{Hot, URBIT_HOT_STATE};
use crate::jets::list::*;
use crate::jets::lock::aes::*;
use crate::jets::lock::ed::*;
@ -32,36 +34,31 @@ use crate::jets::serial::*;
use crate::jets::sort::*;
use crate::jets::tree::*;
use crate::mem::{AllocResult, NockStack, Preserve};
use crate::jets::warm::Warm;
use crate::mem::{NockStack, Preserve};
use crate::noun::{self, Noun, Slots, D};
use sword_macros::tas;
crate::gdb!();
/// Return Err if the computation crashed or should punt to Nock
pub type Result<T> = std::result::Result<T, JetErr>;
pub type Jet = fn(&mut Context, Noun) -> Result<Noun>;
pub type Result = std::result::Result<Noun, JetErr>;
pub type Jet = fn(&mut Context, Noun) -> Result;
/**
* Only return a deterministic error if the Nock would have deterministically
* crashed.
*/
#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug)]
pub enum JetErr {
Punt, // Retry with the raw nock
Fail(Error), // Error; do not retry
}
impl From<crate::mem::AllocationError> for JetErr {
fn from(_err: crate::mem::AllocationError) -> Self {
JetErr::Fail(Error::NonDeterministic(Mote::Meme, D(0)))
}
}
impl Preserve for JetErr {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self {
JetErr::Punt => Ok(()),
JetErr::Punt => {}
JetErr::Fail(ref mut err) => err.preserve(stack),
}
}
@ -235,7 +232,7 @@ pub mod util {
bits_to_word(checked_left_shift(bloq, step)?)
}
pub fn slot(noun: Noun, axis: u64) -> Result<Noun> {
pub fn slot(noun: Noun, axis: u64) -> Result {
noun.slot(axis).map_err(|_e| BAIL_EXIT)
}
@ -291,7 +288,7 @@ pub mod util {
}
pub fn kick(context: &mut Context, core: Noun, axis: Noun) -> result::Result<Noun, JetErr> {
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)])?;
let formula: Noun = T(&mut context.stack, &[D(9), axis, D(0), D(1)]);
interpret(context, core, formula).map_err(JetErr::Fail)
}
@ -299,44 +296,41 @@ pub mod util {
let core: Noun = T(
&mut context.stack,
&[gate.as_cell()?.head(), sample, gate.as_cell()?.tail().as_cell()?.tail()],
)?;
);
kick(context, core, D(2))
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::hamt::Hamt;
use crate::interpreter::Slogger;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Atom, Noun, D, T};
use crate::unifying_equality::test::unifying_equality;
use crate::unifying_equality::unifying_equality;
use assert_no_alloc::assert_no_alloc;
use ibig::UBig;
struct TestSlogger {}
impl Slogger for TestSlogger {
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) -> AllocResult<()> {
fn slog(&mut self, _stack: &mut NockStack, _pri: u64, _noun: Noun) {
eprintln!("Jet slogged.");
Ok(())
}
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) -> AllocResult<()> {
fn flog(&mut self, _stack: &mut NockStack, _cord: Noun) {
eprintln!("Jet flogged.");
Ok(())
}
}
pub fn init_context() -> Result<Context> {
pub fn init_context() -> Context {
let mut stack = NockStack::new(8 << 10 << 10, 0);
let cold = cold::Cold::new(&mut stack)?;
let warm = warm::Warm::new(&mut stack)?;
let hot = hot::Hot::init(&mut stack, hot::URBIT_HOT_STATE)?;
let cache = Hamt::<Noun>::new(&mut stack)?;
let cold = Cold::new(&mut stack);
let warm = Warm::new(&mut stack);
let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
let cache = Hamt::<Noun>::new(&mut stack);
let slogger = std::boxed::Box::pin(TestSlogger {});
Ok(Context {
Context {
stack,
slogger,
cold,
@ -345,12 +339,12 @@ pub mod util {
cache,
scry_stack: D(0),
trace_info: None,
})
}
}
#[allow(non_snake_case)]
pub fn A(stack: &mut NockStack, ubig: &UBig) -> AllocResult<Noun> {
Ok(Atom::from_ubig(stack, ubig)?.as_noun())
pub fn A(stack: &mut NockStack, ubig: &UBig) -> Noun {
Atom::from_ubig(stack, ubig).as_noun()
}
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
@ -358,92 +352,28 @@ pub mod util {
assert!(eq, "got: {}, need: {}", a, b);
}
pub fn assert_jet(
context: &mut Context,
jet: Jet,
sam: Noun,
res: Noun,
) -> AllocResult<()> {
pub fn assert_jet(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
assert_jet_door(context, jet, sam, D(0), res)
}
pub type AssertJetFn = fn(
&mut Context,
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
Noun,
);
pub fn assert_jet_panicky(context: &mut Context, jet: Jet, sam: Noun, res: Noun) {
assert_jet(context, jet, sam, res).expect("assert_jet failed");
}
pub fn assert_jet_door(
context: &mut Context,
jet: Jet,
sam: Noun,
pay: Noun,
res: Noun,
) -> AllocResult<()> {
let sam = T(&mut context.stack, &[D(0), sam, pay])?;
pub fn assert_jet_door(context: &mut Context, jet: Jet, sam: Noun, pay: Noun, res: Noun) {
let sam = T(&mut context.stack, &[D(0), sam, pay]);
let jet_res = assert_no_alloc(|| jet(context, sam).unwrap());
assert_noun_eq(&mut context.stack, jet_res, res);
Ok(())
}
pub type AssertJetDoorFn = fn(
&mut Context,
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
Noun,
Noun,
);
pub fn assert_jet_door_panicky(
context: &mut Context,
jet: Jet,
sam: Noun,
pay: Noun,
res: Noun,
) {
assert_jet_door(context, jet, sam, pay, res).expect("assert_jet_door failed");
pub fn assert_jet_ubig(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
let res = A(&mut context.stack, &res);
assert_jet(context, jet, sam, res);
}
pub fn assert_jet_ubig(
context: &mut Context,
jet: Jet,
sam: Noun,
res: UBig,
) -> AllocResult<()> {
let res = A(&mut context.stack, &res)?;
assert_jet(context, jet, sam, res)
pub fn assert_nary_jet_ubig(context: &mut Context, jet: Jet, sam: &[Noun], res: UBig) {
let sam = T(&mut context.stack, sam);
assert_jet_ubig(context, jet, sam, res);
}
pub type AssertJetUBigFn = fn(
&mut Context,
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
UBig,
);
pub fn assert_jet_ubig_panicky(context: &mut Context, jet: Jet, sam: Noun, res: UBig) {
assert_jet_ubig(context, jet, sam, res).expect("assert_jet_ubig failed");
}
pub fn assert_nary_jet_ubig(
context: &mut Context,
jet: Jet,
sam: &[Noun],
res: UBig,
) -> AllocResult<()> {
let sam = T(&mut context.stack, sam)?;
assert_jet_ubig(context, jet, sam, res)
}
pub fn assert_jet_err(
context: &mut Context,
jet: Jet,
sam: Noun,
err: JetErr,
) -> AllocResult<()> {
let sam = T(&mut context.stack, &[D(0), sam, D(0)])?;
pub fn assert_jet_err(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
let jet_res = jet(context, sam);
assert!(
jet_res.is_err(),
@ -453,10 +383,10 @@ pub mod util {
&jet_res
);
let jet_err = jet_res.unwrap_err();
match (jet_err.clone(), err.clone()) {
match (jet_err, err) {
(JetErr::Punt, JetErr::Punt) => {}
(JetErr::Fail(actual_err), JetErr::Fail(expected_err)) => {
match (actual_err.clone(), expected_err.clone()) {
match (actual_err, expected_err) {
(Error::ScryBlocked(mut actual), Error::ScryBlocked(mut expected))
| (Error::ScryCrashed(mut actual), Error::ScryCrashed(mut expected))
| (
@ -485,22 +415,11 @@ pub mod util {
sam, err, jet_err
);
}
};
Ok(())
}
pub type AssertJetErrFn = fn(
&mut Context,
fn(&mut Context, Noun) -> core::result::Result<Noun, JetErr>,
Noun,
JetErr,
);
pub fn assert_jet_err_panicky(context: &mut Context, jet: Jet, sam: Noun, err: JetErr) {
assert_jet_err(context, jet, sam, err).expect("assert_jet failed");
}
}
pub fn assert_jet_size(context: &mut Context, jet: Jet, sam: Noun, siz: usize) {
let sam = T(&mut context.stack, &[D(0), sam, D(0)]).unwrap();
let sam = T(&mut context.stack, &[D(0), sam, D(0)]);
let res = assert_no_alloc(|| jet(context, sam).unwrap());
assert!(res.is_atom(), "jet result not atom");
let res_siz = res.atom().unwrap().size();
@ -514,7 +433,7 @@ pub mod util {
res: UBig,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
assert_nary_jet_ubig(context, jet, &sam, res).unwrap();
assert_nary_jet_ubig(context, jet, &sam, res);
}
pub fn assert_common_jet_noun(
@ -524,8 +443,8 @@ pub mod util {
res: Noun,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap();
assert_jet(context, jet, sam, res).unwrap();
let sam = T(&mut context.stack, &sam);
assert_jet(context, jet, sam, res);
}
pub fn assert_common_jet_err(
@ -535,8 +454,8 @@ pub mod util {
err: JetErr,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap();
assert_jet_err(context, jet, sam, err).unwrap();
let sam = T(&mut context.stack, &sam);
assert_jet_err(context, jet, sam, err);
}
pub fn assert_common_jet_size(
@ -546,7 +465,7 @@ pub mod util {
siz: usize,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut context.stack)).collect();
let sam = T(&mut context.stack, &sam).unwrap();
let sam = T(&mut context.stack, &sam);
assert_jet_size(context, jet, sam, siz)
}
}

View File

@ -14,12 +14,12 @@ crate::gdb!();
* Bit arithmetic
*/
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
Ok(util::bex(&mut context.stack, arg)?.as_noun())
Ok(util::bex(&mut context.stack, arg).as_noun())
}
pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_can(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?;
@ -27,7 +27,7 @@ pub fn jet_can(context: &mut Context, subject: Noun) -> Result<Noun> {
util::can(&mut context.stack, bloq, original_list)
}
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?;
let a = slot(arg, 6)?.as_atom()?;
@ -41,7 +41,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
} else {
unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_len);
chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?;
chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?;
Ok(new_indirect.normalize_as_atom().as_noun())
@ -49,7 +49,7 @@ pub fn jet_cat(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?;
let start = slot(arg, 12)?.as_direct()?.data() as usize;
@ -62,14 +62,14 @@ pub fn jet_cut(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_indirect = unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, run)?);
chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?;
new_indirect.normalize_as_atom()
};
Ok(new_indirect.as_noun())
}
pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sew(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let bloq = bloq(slot(sam, 2)?)?;
let e = slot(sam, 7)?.as_atom()?;
@ -90,12 +90,12 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
unsafe {
let (mut dest_indirect, dest) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, new_len)?);
chop(bloq, 0, len_e, 0, dest, e.as_bitslice())?;
let (_, lead) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
chop(bloq, 0, min(step, len_d), 0, lead, donor.as_bitslice())?;
@ -104,7 +104,7 @@ pub fn jet_sew(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_end(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?;
@ -116,14 +116,14 @@ pub fn jet_end(context: &mut Context, subject: Noun) -> Result<Noun> {
} else {
unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, step)?);
chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?;
Ok(new_indirect.normalize_as_atom().as_noun())
}
}
}
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?;
@ -131,7 +131,7 @@ pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result<Noun> {
util::lsh(&mut context.stack, bloq, step, a)
}
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?;
@ -139,14 +139,14 @@ pub fn jet_met(_context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(D(util::met(bloq, a) as u64))
}
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let bloq = bloq(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?;
Ok(util::rap(&mut context.stack, bloq, original_list)?.as_noun())
}
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?;
let original_list = slot(arg, 3)?;
@ -169,7 +169,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
} else {
unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?)?;
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bite_to_word(bloq, len)?);
let mut pos = 0;
let mut list = original_list;
loop {
@ -189,7 +189,7 @@ pub fn jet_rep(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data();
@ -207,7 +207,7 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
let src = dat.as_bitslice();
let (mut output, dest) =
unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize)? };
unsafe { IndirectAtom::new_raw_mut_bitslice(&mut context.stack, bits as usize) };
let len = len as usize;
let total_len = len << boz;
@ -219,14 +219,14 @@ pub fn jet_rev(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(unsafe { output.normalize_as_atom() }.as_noun())
}
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?;
let atom = slot(arg, 3)?.as_atom()?;
util::rip(&mut context.stack, bloq, step, atom)
}
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let (bloq, step) = bite(slot(arg, 2)?)?;
let a = slot(arg, 3)?.as_atom()?;
@ -238,13 +238,13 @@ pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
chop(bloq, step, len - step, 0, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun())
}
}
pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let a = slot(sam, 1)?.as_atom()?;
Ok(D(util::met(0, a) as u64))
@ -254,15 +254,15 @@ pub fn jet_xeb(_context: &mut Context, subject: Noun) -> Result<Noun> {
* Bit logic
*/
pub fn jet_con(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_con(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::con(&mut context.stack, a, b)?.as_noun())
Ok(util::con(&mut context.stack, a, b).as_noun())
}
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
@ -270,7 +270,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = cmp::max(a.size(), b.size());
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest &= b.as_bitslice();
@ -278,7 +278,7 @@ pub fn jet_dis(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
@ -286,7 +286,7 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
let new_size = cmp::max(a.size(), b.size());
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size)?;
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(&mut context.stack, new_size);
let a_bit = a.as_bitslice();
dest[..a_bit.len()].copy_from_bitslice(a_bit);
*dest ^= b.as_bitslice();
@ -297,26 +297,25 @@ pub fn jet_mix(context: &mut Context, subject: Noun) -> Result<Noun> {
pub mod util {
use crate::jets::util::*;
use crate::jets::{JetErr, Result};
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
use std::cmp;
use std::result;
/// Binary exponent
pub fn bex(stack: &mut NockStack, arg: usize) -> AllocResult<Atom> {
pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
unsafe {
let res = if arg < 63 {
if arg < 63 {
DirectAtom::new_unchecked(1 << arg).as_atom()
} else {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3)?;
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
dest.set(arg, true);
atom.normalize_as_atom()
};
Ok(res)
}
}
}
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result<Noun> {
pub fn lsh(stack: &mut NockStack, bloq: usize, step: usize, a: Atom) -> Result {
let len = met(bloq, a);
if len == 0 {
return Ok(D(0));
@ -324,13 +323,13 @@ pub mod util {
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size)?;
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
Ok(atom.normalize_as_atom().as_noun())
}
}
pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result<Noun> {
pub fn can(stack: &mut NockStack, bloq: usize, original_list: Noun) -> Result {
let mut len = 0usize;
let mut list = original_list;
loop {
@ -351,7 +350,7 @@ pub mod util {
} else {
unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?;
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
let mut pos = 0;
let mut list = original_list;
loop {
@ -385,32 +384,32 @@ pub mod util {
}
}
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result<Noun> {
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result {
let len = (met(bloq, atom) + step - 1) / step;
let mut list = D(0);
for i in (0..len).rev() {
let new_atom = unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq)?;
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq);
chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?;
new_indirect.normalize_as_atom()
};
list = Cell::new(stack, new_atom.as_noun(), list)?.as_noun();
list = Cell::new(stack, new_atom.as_noun(), list).as_noun();
}
Ok(list)
}
/// Binary OR
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> {
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 (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())
atom.normalize_as_atom()
}
}
@ -433,11 +432,11 @@ pub mod util {
}
if len == 0 {
Ok(Atom::new(stack, 0)?)
Ok(Atom::new(stack, 0))
} else {
unsafe {
let (mut new_indirect, new_slice) =
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?)?;
IndirectAtom::new_raw_mut_bitslice(stack, bite_to_word(bloq, len)?);
let mut pos = 0;
let mut list = original_list;
@ -476,7 +475,6 @@ pub mod util {
let s = &mut init_stack();
let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210))
.unwrap()
.as_atom()
.unwrap();
assert_eq!(met(0, a), 128);
@ -507,15 +505,8 @@ mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::mem::NockStack;
use crate::noun::{Noun, D};
use crate::noun::{Noun, D, T};
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -547,7 +538,7 @@ mod tests {
#[test]
fn test_bex() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet(c, jet_bex, D(0), D(1));
assert_jet(c, jet_bex, D(5), D(32));
@ -562,7 +553,7 @@ mod tests {
#[test]
fn test_can() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
let bloq0 = D(0);
@ -607,7 +598,7 @@ mod tests {
#[test]
fn test_cat() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
let bloq0 = D(0);
@ -639,7 +630,7 @@ mod tests {
#[test]
fn test_cut() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (_a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let run = T(&mut c.stack, &[D(0), D(0)]);
@ -662,7 +653,7 @@ mod tests {
#[test]
fn test_end() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a24]);
@ -685,7 +676,7 @@ mod tests {
#[test]
fn test_lsh() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (_, a24, _a63, a96, a128) = atoms(&mut c.stack);
assert_common_jet_noun(c, jet_lsh, &[atom_0, atom_24], D(0x10eca86));
@ -718,7 +709,7 @@ mod tests {
#[test]
fn test_met() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, _a63, _a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]);
@ -733,7 +724,7 @@ mod tests {
#[test]
fn test_rap() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let bloq0 = D(0);
let bloq2 = D(2);
@ -763,7 +754,7 @@ mod tests {
#[test]
fn test_rep() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(0)]);
@ -776,7 +767,7 @@ mod tests {
#[test]
fn test_rev() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (_a0, a24, _a63, a96, _a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(60), a24]);
@ -791,7 +782,7 @@ mod tests {
#[test]
fn test_rip() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (_a0, _a24, _a63, _a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[D(0), D(0)]);
@ -814,7 +805,7 @@ mod tests {
#[test]
fn test_rsh() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, _a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a24]);
@ -840,7 +831,7 @@ mod tests {
#[test]
fn test_sew() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
// 0xfaceb00c15deadbeef123456
@ -885,7 +876,7 @@ mod tests {
#[test]
fn test_con() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]);
@ -906,7 +897,7 @@ mod tests {
#[test]
fn test_dis() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]);
@ -926,7 +917,7 @@ mod tests {
#[test]
fn test_mix() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let sam = T(&mut c.stack, &[a0, a0]);
@ -948,7 +939,7 @@ mod tests {
#[test]
fn test_xeb() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
assert_jet(c, jet_xeb, a0, D(0));

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ use crate::noun::Noun;
crate::gdb!();
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result {
let aura = slot(subject, 12)?.as_direct()?;
let atom = slot(subject, 13)?.as_atom()?;
util::scow(&mut context.stack, aura, atom)
@ -17,7 +17,7 @@ pub mod util {
use crate::jets;
use crate::jets::JetErr;
use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, Noun, D, T};
use crate::noun::{Atom, Cell, DirectAtom, D, T};
use num_traits::identities::Zero;
use sword_macros::tas;
@ -25,11 +25,11 @@ pub mod util {
stack: &mut NockStack,
aura: DirectAtom, // XX: technically this should be Atom?
atom: Atom,
) -> jets::Result<Noun> {
) -> jets::Result {
match aura.data() {
tas!(b"ud") => {
if atom.as_bitslice().first_one().is_none() {
return Ok(T(stack, &[D(b'0' as u64), D(0)])?);
return Ok(T(stack, &[D(b'0' as u64), D(0)]));
}
let mut root = D(0);
@ -38,15 +38,15 @@ pub mod util {
let mut n = atom.as_direct()?.data();
while n != 0 {
root = T(stack, &[D(b'0' as u64 + (n % 10)), root])?;
root = T(stack, &[D(b'0' as u64 + (n % 10)), root]);
n /= 10;
lent += 1;
}
} else {
let mut n = atom.as_indirect()?.as_ubig(stack)?;
let mut n = atom.as_indirect()?.as_ubig(stack);
while !n.is_zero() {
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root])?;
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root]);
n /= 10u64;
lent += 1;
}
@ -58,7 +58,7 @@ pub mod util {
while lent > 2 {
if lent % 3 == 0 {
let (cell, memory) = Cell::new_raw_mut(stack)?;
let (cell, memory) = Cell::new_raw_mut(stack);
(*memory).head = D(b'.' as u64);
(*memory).tail = list.tail();
(*(list.to_raw_pointer_mut())).tail = cell.as_noun();
@ -79,18 +79,11 @@ pub mod util {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
use crate::jets::JetErr;
use crate::noun::{Noun, D};
use crate::noun::{Noun, D, T};
use ibig::ubig;
use sword_macros::tas;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
// Rust can't handle implicit conversions from u8 to u64
#[allow(non_snake_case)]
@ -100,7 +93,7 @@ mod tests {
#[test]
fn test_scow() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let aura = D(tas!(b"ud"));
let sam = T(&mut c.stack, &[aura, D(0)]);

View File

@ -8,22 +8,18 @@ use crate::noun::Noun;
crate::gdb!();
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
Ok(mug(&mut context.stack, arg)?.as_noun())
Ok(mug(&mut context.stack, arg).as_noun())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_jet, init_context, A};
use crate::mem::NockStack;
use crate::noun::{Noun, D};
use crate::noun::{Noun, D, T};
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -51,7 +47,7 @@ mod tests {
#[test]
fn test_mug() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
assert_jet(c, jet_mug, a0, D(0x79ff04e8));

View File

@ -1,5 +1,4 @@
use crate::jets::*;
use crate::mem::AllocResult;
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun, D, T};
use either::Either::{self, Left, Right};
use std::ptr::{copy_nonoverlapping, null_mut};
@ -1505,7 +1504,7 @@ pub const URBIT_HOT_STATE: &[HotEntry] = &[
pub struct Hot(*mut HotMem);
impl Hot {
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> AllocResult<Self> {
pub fn init(stack: &mut NockStack, constant_hot_state: &[HotEntry]) -> Self {
unsafe {
let mut next = Hot(null_mut());
for (htap, axe, jet) in constant_hot_state {
@ -1513,10 +1512,10 @@ impl Hot {
for i in *htap {
match i {
Left(tas) => {
let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)?
let chum = IndirectAtom::new_raw_bytes_ref(stack, tas)
.normalize_as_atom()
.as_noun();
a_path = T(stack, &[chum, a_path])?;
a_path = T(stack, &[chum, a_path]);
}
Right((tas, ver)) => {
let chum = T(
@ -1525,13 +1524,13 @@ impl Hot {
DirectAtom::new_panic(*tas).as_atom().as_noun(),
DirectAtom::new_panic(*ver).as_atom().as_noun(),
],
)?;
a_path = T(stack, &[chum, a_path])?;
);
a_path = T(stack, &[chum, a_path]);
}
};
}
let axis = DirectAtom::new_panic(*axe).as_atom();
let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1)?;
let hot_mem_ptr: *mut HotMem = stack.struct_alloc(1);
*hot_mem_ptr = HotMem {
a_path,
axis,
@ -1540,7 +1539,7 @@ impl Hot {
};
next = Hot(hot_mem_ptr);
}
Ok(next)
next
}
}
}
@ -1567,17 +1566,16 @@ struct HotMem {
}
impl Preserve for Hot {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
let mut it = self;
while !it.0.is_null() && stack.is_in_frame(it.0) {
let dest_mem = stack.struct_alloc_in_previous_frame(1)?;
let dest_mem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(it.0, dest_mem, 1);
it.0 = dest_mem;
(*it.0).a_path.preserve(stack)?;
(*it.0).axis.preserve(stack)?;
(*it.0).a_path.preserve(stack);
(*it.0).axis.preserve(stack);
it = &mut (*it.0).next;
}
Ok(())
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {

View File

@ -8,27 +8,27 @@ use crate::site::{site_slam, Site};
crate::gdb!();
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_flop(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
util::flop(&mut context.stack, sam)
}
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?;
util::lent(list).map(|x| D(x as u64))
}
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_roll(context: &mut Context, subject: Noun) -> Result {
let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?;
let mut prod = slot(gate, 13)?;
let site = Site::new(context, &mut gate)?;
let site = Site::new(context, &mut gate);
loop {
if let Ok(list_cell) = list.as_cell() {
list = list_cell.tail();
let sam = T(&mut context.stack, &[list_cell.head(), prod])?;
let sam = T(&mut context.stack, &[list_cell.head(), prod]);
prod = site_slam(context, &site, sam)?;
} else {
if unsafe { !list.raw_equals(D(0)) } {
@ -39,7 +39,7 @@ pub fn jet_roll(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let index = slot(sam, 2)?;
let list = slot(sam, 3)?;
@ -47,12 +47,12 @@ pub fn jet_snag(_context: &mut Context, subject: Noun) -> Result<Noun> {
util::snag(list, index)
}
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_snip(context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?;
util::snip(&mut context.stack, list)
}
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_turn(context: &mut Context, subject: Noun) -> Result {
let sample = slot(subject, 6)?;
let mut list = slot(sample, 2)?;
let mut gate = slot(sample, 3)?;
@ -61,12 +61,12 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
// Since the gate doesn't change, we can do a single jet check and use that through the whole
// loop
let site = Site::new(context, &mut gate)?;
let site = Site::new(context, &mut gate);
loop {
if let Ok(list_cell) = list.as_cell() {
list = list_cell.tail();
unsafe {
let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack)?;
let (new_cell, new_mem) = Cell::new_raw_mut(&mut context.stack);
(*new_mem).head = site_slam(context, &site, list_cell.head())?;
*dest = new_cell.as_noun();
dest = &mut (*new_mem).tail;
@ -83,7 +83,7 @@ pub fn jet_turn(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_zing(context: &mut Context, subject: Noun) -> Result {
let list = slot(subject, 6)?;
let stack = &mut context.stack;
@ -98,7 +98,7 @@ pub mod util {
use std::result;
/// Reverse order of list
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result<Noun> {
pub fn flop(stack: &mut NockStack, noun: Noun) -> Result {
let mut list = noun;
let mut tsil = D(0);
loop {
@ -107,7 +107,7 @@ pub mod util {
}
let cell = list.as_cell()?;
tsil = T(stack, &[cell.head(), tsil])?;
tsil = T(stack, &[cell.head(), tsil]);
list = cell.tail();
}
@ -133,7 +133,7 @@ pub mod util {
Ok(len)
}
pub fn snag(tape: Noun, index: Noun) -> Result<Noun> {
pub fn snag(tape: Noun, index: Noun) -> Result {
let mut list = tape;
let mut idx = index.as_atom()?.as_u64()? as usize;
loop {
@ -149,7 +149,7 @@ pub mod util {
}
}
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result<Noun> {
pub fn snip(stack: &mut NockStack, tape: Noun) -> Result {
let mut ret = D(0);
let mut dest = &mut ret as *mut Noun;
let mut list = tape;
@ -170,7 +170,7 @@ pub mod util {
}
}
unsafe {
let (new_cell, new_mem) = Cell::new_raw_mut(stack)?;
let (new_cell, new_mem) = Cell::new_raw_mut(stack);
(*new_mem).head = cell.head();
*dest = new_cell.as_noun();
dest = &mut (*new_mem).tail;
@ -181,7 +181,7 @@ pub mod util {
Ok(ret)
}
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result<Noun> {
pub fn zing(stack: &mut NockStack, mut list: Noun) -> Result {
unsafe {
let mut res: Noun = D(0);
let mut dest = &mut res as *mut Noun;
@ -196,7 +196,7 @@ pub mod util {
let i = it.head();
sublist = it.tail();
let (new_cell, new_memory) = Cell::new_raw_mut(stack)?;
let (new_cell, new_memory) = Cell::new_raw_mut(stack);
(*new_memory).head = i;
*dest = new_cell.as_noun();
dest = &mut (*new_memory).tail;
@ -212,19 +212,13 @@ pub mod util {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context};
use crate::jets::util::BAIL_EXIT;
use crate::noun::D;
// Override T with the panicky variants
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
use crate::noun::{D, T};
#[test]
fn test_flop() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
let res = T(&mut c.stack, &[D(3), D(2), D(1), D(0)]);
@ -261,7 +255,7 @@ mod tests {
#[test]
fn test_lent() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet(c, jet_lent, D(0), D(0));
let sam = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
@ -275,7 +269,7 @@ mod tests {
#[test]
fn test_snag() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let list1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);
let sam = T(&mut c.stack, &[D(1), list1]);
assert_jet(c, jet_snag, sam, D(2));
@ -293,7 +287,7 @@ mod tests {
#[test]
fn test_snip() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet(c, jet_snip, sam, D(0));
@ -319,7 +313,7 @@ mod tests {
#[test]
fn test_zing() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let list_0 = T(&mut c.stack, &[D(0), D(0), D(0), D(0)]);
let list_1 = T(&mut c.stack, &[D(1), D(2), D(3), D(0)]);

View File

@ -11,7 +11,7 @@ crate::gdb!();
// have fixed maximum key sizes, therefore we must punt if the key is
// too large.
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -27,7 +27,7 @@ pub fn jet_siva_en(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -45,7 +45,7 @@ pub fn jet_siva_de(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -61,7 +61,7 @@ pub fn jet_sivb_en(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -79,7 +79,7 @@ pub fn jet_sivb_de(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let txt = slot(subject, 6)?.as_atom()?;
let key = slot(subject, 60)?.as_atom()?;
@ -95,7 +95,7 @@ pub fn jet_sivc_en(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sivc_de(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let iv = slot(subject, 12)?.as_atom()?;
let len = slot(subject, 26)?.as_atom()?;
@ -142,7 +142,7 @@ mod util {
let length = list::util::lent(ads)?;
let siv_data: &mut [AcAesSivData] = unsafe {
let ptr = stack.struct_alloc::<AcAesSivData>(length)?;
let ptr = stack.struct_alloc::<AcAesSivData>(length);
std::slice::from_raw_parts_mut(ptr, length)
};
@ -153,7 +153,7 @@ mod util {
let bytes = head.as_bytes();
let len = met(3, head);
let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len())?;
let (mut atom, buffer) = IndirectAtom::new_raw_mut_bytes(stack, bytes.len());
buffer[0..len].copy_from_slice(&(bytes[0..len]));
item.length = bytes.len();
@ -171,7 +171,7 @@ mod util {
key: &mut [u8; N],
ads: Noun,
txt: Atom,
) -> Result<Noun> {
) -> Result {
unsafe {
let ac_siv_data = _allocate_ads(stack, ads)?;
let siv_data: &mut [&mut [u8]] = std::slice::from_raw_parts_mut(
@ -181,19 +181,19 @@ mod util {
let txt_len = met(3, txt);
let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack)?;
let (mut iv, iv_bytes) = IndirectAtom::new_raw_mut_bytearray::<16, NockStack>(stack);
// We match on length here and elsewhere where a similar pattern is followed
// to avoid panicking when a zero length is passed to IndirectAtom::new_raw_mut_bytes.
match txt_len {
0 => {
ac_aes_siv_en::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)])?)
Ok(T(stack, &[iv.normalize_as_atom().as_noun(), D(0), D(0)]))
}
_ => {
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
ac_aes_siv_en::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
Ok(T(
stack,
@ -202,7 +202,7 @@ mod util {
D(txt_len as u64),
out_atom.normalize_as_atom().as_noun(),
],
)?)
))
}
}
}
@ -215,7 +215,7 @@ mod util {
iv: Atom,
len: Atom,
txt: Atom,
) -> Result<Noun> {
) -> Result {
unsafe {
let txt_len = match len.as_direct() {
Ok(direct) => direct.data() as usize,
@ -231,20 +231,20 @@ mod util {
ac_siv_data.len(),
);
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
let (mut out_atom, out_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
match txt_len {
0 => {
ac_aes_siv_de::<N>(key, &mut [], siv_data, iv_bytes, &mut [0u8; 0]).unwrap();
}
_ => {
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len)?;
let (_txt_ida, txt_bytes) = IndirectAtom::new_raw_mut_bytes(stack, txt_len);
txt_bytes.copy_from_slice(&txt.as_bytes()[0..txt_len]);
ac_aes_siv_de::<N>(key, txt_bytes, siv_data, iv_bytes, out_bytes).unwrap();
}
}
Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()])?)
Ok(T(stack, &[D(0), out_atom.normalize_as_atom().as_noun()]))
}
}
}
@ -252,34 +252,33 @@ mod util {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_noun_eq, init_context, A};
use crate::jets::Jet;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Cell, D, T};
use ibig::ubig;
pub fn assert_jet_in_door(
c: &mut Context,
jet: Jet,
sam: &[fn(&mut NockStack) -> Noun], // regular sample
ctx: &[fn(&mut NockStack) -> AllocResult<Noun>], // door sample as context
ctx: &[fn(&mut NockStack) -> Noun], // door sample as context
res: Noun,
) {
let sam: Vec<Noun> = sam.iter().map(|f| f(&mut c.stack)).collect();
let ctx: Vec<Noun> = ctx.iter().flat_map(|f| f(&mut c.stack)).collect();
let ctx: Vec<Noun> = ctx.iter().map(|f| f(&mut c.stack)).collect();
let sam = if sam.len() > 1 {
T(&mut c.stack, &sam).expect("T alloc failed in assert_jet_in_door")
T(&mut c.stack, &sam)
} else {
sam[0]
};
let ctx = if ctx.len() > 1 {
T(&mut c.stack, &ctx).expect("2nd T alloc failed in assert_jet_in_door")
T(&mut c.stack, &ctx)
} else {
ctx[0]
};
let pay = Cell::new(&mut c.stack, sam, ctx).expect("Cell alloc failed in assert_jet_in_door").as_noun();
let sbj = Cell::new(&mut c.stack, D(0), pay).expect("2nd Cell alloc failed").as_noun();
let pay = Cell::new(&mut c.stack, sam, ctx).as_noun();
let sbj = Cell::new(&mut c.stack, D(0), pay).as_noun();
// std::io::stderr().flush().unwrap();
let jet_res = jet(c, sbj).unwrap();
// std::io::stderr().flush().unwrap();
@ -288,7 +287,7 @@ mod tests {
#[test]
pub fn test_siva_en() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/*
> (~(en siva:aes:crypto [key=0x0 vec=~]) txt=0x0)
[p=0xb0f7.a0df.be76.c85b.5e29.bb31.aaec.fc77 q=0 r=0x0]
@ -296,44 +295,44 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
let siv = A(&mut c.stack, &ubig!(0xb0f7a0dfbe76c85b5e29bb31aaecfc77));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_siva_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
A(s, &ubig!(0x112233445566778899aabbccddee))
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(
s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
)?;
);
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
let iv = A(&mut c.stack, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
let cyp = A(&mut c.stack, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_siva_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivb_en() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/*
> (~(en sivb:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -342,41 +341,41 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
let siv = A(&mut c.stack, &ubig!(0x8fb4085a9b93662ab44f911e47e9ccd));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_sivb_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
A(s, &ubig!(0x112233445566778899aabbccddee))
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
let iv = A(&mut c.stack, &ubig!(0x89e869b93256785154f0963962fe0740));
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
let cyp = A(&mut c.stack, &ubig!(0xf313e667b56478a032b9913e923c));
let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_sivb_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivc_en() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/*
> (~(en sivc:aes:crypto [key=0x0 vec=~]) txt=0x0)
@ -385,122 +384,122 @@ mod tests {
fn sample(_s: &mut NockStack) -> Noun {
D(0)
}
fn context(s: &mut NockStack) -> AllocResult<Noun> {
let sample = T(s, &[D(0), D(0)])?;
fn context(s: &mut NockStack) -> Noun {
let sample = T(s, &[D(0), D(0)]);
T(s, &[D(0), sample, D(0)])
}
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519)).unwrap();
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]).unwrap();
let siv = A(&mut c.stack, &ubig!(0x2c6aabc5bb251140e221d70bfb31c519));
let res = T(&mut c.stack, &[siv, D(0), D(0x0)]);
assert_jet_in_door(c, jet_sivc_en, &[sample], &[context], res);
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
A(s, &ubig!(0x112233445566778899aabbccddee)).unwrap()
A(s, &ubig!(0x112233445566778899aabbccddee))
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
let iv = A(&mut c.stack, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let len = D(14);
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
let res = T(&mut c.stack, &[iv, len, cyp]).unwrap();
let cyp = A(&mut c.stack, &ubig!(0x1206291a35ad3db0212773440fd0));
let res = T(&mut c.stack, &[iv, len, cyp]);
assert_jet_in_door(c, jet_sivc_en, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_siva_de() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93)).unwrap();
let iv = A(s, &ubig!(0x85632d07c6e8f37f950acd320a2ecc93));
let len = D(14);
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
let cyp = A(s, &ubig!(0x40c02b9690c4dc04daef7f6afe5c));
T(s, &[iv, len, cyp])
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(
s,
&ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff),
)?;
);
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_siva_de, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivb_de() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740)).unwrap();
let iv = A(s, &ubig!(0x89e869b93256785154f0963962fe0740));
let len = D(14);
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
let cyp = A(s, &ubig!(0xf313e667b56478a032b9913e923c));
T(s, &[iv, len, cyp])
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff))?;
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff));
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_sivb_de, &[gate_sample], &[gate_context], res);
}
#[test]
pub fn test_sivc_de() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
/* RFC 5297
* https://datatracker.ietf.org/doc/html/rfc5297#appendix-A
*/
fn gate_sample(s: &mut NockStack) -> Noun {
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e)).unwrap();
let iv = A(s, &ubig!(0x724dfb2eaf94dbb19b0ba3a299a0801e));
let len = D(14);
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0)).unwrap();
T(s, &[iv, len, cyp]).unwrap()
let cyp = A(s, &ubig!(0x1206291a35ad3db0212773440fd0));
T(s, &[iv, len, cyp])
}
fn gate_context(s: &mut NockStack) -> AllocResult<Noun> {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))?;
fn gate_context(s: &mut NockStack) -> Noun {
let key = A(s, &ubig!(_0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff));
let a = A(
s,
&ubig!(_0x101112131415161718191a1b1c1d1e1f2021222324252627),
)?;
let vec = T(s, &[a, D(0)])?;
let sample = T(s, &[key, vec])?;
);
let vec = T(s, &[a, D(0)]);
let sample = T(s, &[key, vec]);
T(s, &[D(0), sample, D(0)])
}
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee)).unwrap();
let res = T(&mut c.stack, &[D(0), txt]).unwrap();
let txt = A(&mut c.stack, &ubig!(0x112233445566778899aabbccddee));
let res = T(&mut c.stack, &[D(0), txt]);
assert_jet_in_door(c, jet_sivc_de, &[gate_sample], &[gate_context], res);
}
}

View File

@ -8,7 +8,7 @@ use sword_crypto::ed25519::{ac_ed_puck, ac_ed_shar, ac_ed_sign, ac_ed_veri};
crate::gdb!();
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_puck(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sed = slot(subject, 6)?.as_atom()?;
@ -21,14 +21,14 @@ pub fn jet_puck(context: &mut Context, subject: Noun) -> Result<Noun> {
let sed_bytes = &mut [0u8; 32];
sed_bytes[0..sed_len].copy_from_slice(&(sed.as_bytes())[0..sed_len]);
let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?;
let (mut pub_ida, pub_key) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
ac_ed_puck(sed_bytes, pub_key);
Ok(pub_ida.normalize_as_atom().as_noun())
}
}
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shar(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let pub_key = slot(subject, 12)?.as_atom()?;
let sec_key = slot(subject, 13)?.as_atom()?;
@ -53,14 +53,14 @@ pub fn jet_shar(context: &mut Context, subject: Noun) -> Result<Noun> {
public[0..pub_bytes.len()].copy_from_slice(pub_bytes);
secret[0..sec_bytes.len()].copy_from_slice(sec_bytes);
let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack)?;
let (mut shar_ida, shar) = IndirectAtom::new_raw_mut_bytearray::<32, NockStack>(stack);
ac_ed_shar(public, secret, shar);
Ok(shar_ida.normalize_as_atom().as_noun())
}
}
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sign(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let msg = slot(subject, 12)?.as_atom()?;
let sed = slot(subject, 13)?.as_atom()?;
@ -74,11 +74,11 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
let seed = &mut [0u8; 32];
seed[0..sed_len].copy_from_slice(sed_bytes);
let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack)?;
let (mut sig_ida, sig) = IndirectAtom::new_raw_mut_bytearray::<64, NockStack>(stack);
let msg_len = met(3, msg);
if msg_len > 0 {
let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len)?;
let (_msg_ida, message) = IndirectAtom::new_raw_mut_bytes(stack, msg_len);
message.copy_from_slice(&msg.as_bytes()[0..msg_len]);
ac_ed_sign(message, seed, sig);
} else {
@ -90,7 +90,7 @@ pub fn jet_sign(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result {
let sig = slot(subject, 12)?.as_atom()?;
let msg = slot(subject, 26)?.as_atom()?;
let puk = slot(subject, 27)?.as_atom()?;
@ -120,68 +120,64 @@ pub fn jet_veri(_context: &mut Context, subject: Noun) -> Result<Noun> {
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_jet, assert_jet_err, init_context, A};
use crate::noun::{D, T};
use ibig::ubig;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
// XX: Should use the test vectors from Section 7.1 of RFC 8032:
// https://tools.ietf.org/html/rfc8032#section-7.1
#[test]
fn test_puck() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = A(&mut c.stack, &ubig!(_0x0)).unwrap();
let sam = A(&mut c.stack, &ubig!(_0x0));
let ret = A(
&mut c.stack,
&ubig!(_0x29da598ba148c03aa643e21d77153265730d6f2ad0a8a3622da4b6cebc276a3b),
).unwrap();
);
assert_jet(c, jet_puck, sam, ret);
let sam = A(
&mut c.stack,
&ubig!(_0x607fae1c03ac3b701969327b69c54944c42cec92f44a84ba605afdef9db1619d),
).unwrap();
);
let ret = A(
&mut c.stack,
&ubig!(_0x1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7),
).unwrap();
);
assert_jet(c, jet_puck, sam, ret);
}
#[test]
fn test_shar() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x0)).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x0));
assert_jet(c, jet_shar, sam, ret);
let sam = T(&mut c.stack, &[D(234), D(234)]).unwrap();
let sam = T(&mut c.stack, &[D(234), D(234)]);
let ret = A(
&mut c.stack,
&ubig!(_0x6ecd5779a47841207a2cd0c9d085796aa646842885a332adac540027d768c1c5),
).unwrap();
);
assert_jet(c, jet_shar, sam, ret);
let sam = A(
&mut c.stack,
&ubig!(_0xfb099b0acc4d1ce37f9982a2ed331245e0cdfdf6979364b7676a142b8233e53b),
).unwrap();
);
assert_jet_err(c, jet_shar, sam, BAIL_EXIT);
}
#[test]
fn test_sign() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
unsafe {
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803)).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(&mut c.stack, &ubig!(_0x8f895b3cafe2c9506039d0e2a66382568004674fe8d237785092e40d6aaf483e4fc60168705f31f101596138ce21aa357c0d32a064f423dc3ee4aa3abf53f803));
assert_jet(c, jet_sign, sam, ret);
let message = D(0x72);
@ -191,18 +187,16 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes();
let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[message, seed]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00)).unwrap();
let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00));
assert_jet(c, jet_sign, sam, ret);
let msg_ubig = ubig!(_0xaf82);
let msg_bytes = msg_ubig.to_be_bytes();
let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun();
let sed_ubig =
@ -210,28 +204,26 @@ mod tests {
let sed_bytes = sed_ubig.to_be_bytes();
let seed =
IndirectAtom::new_raw_bytes(&mut c.stack, sed_bytes.len(), sed_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[message, seed]).unwrap();
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a)).unwrap();
let sam = T(&mut c.stack, &[message, seed]);
let ret = A(&mut c.stack, &ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a));
assert_jet(c, jet_sign, sam, ret);
}
}
#[test]
fn test_veri() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
unsafe {
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0), D(0)]);
assert_jet(c, jet_veri, sam, NO);
let sig_ubig = ubig!(_0x92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00);
let sig_bytes = sig_ubig.to_be_bytes();
let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun();
let message = D(0x72);
@ -241,24 +233,21 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes();
let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
let sam = T(&mut c.stack, &[signature, message, public_key]);
assert_jet(c, jet_veri, sam, YES);
let sig_ubig = ubig!(_0x6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a);
let sig_bytes = sig_ubig.to_be_bytes();
let signature =
IndirectAtom::new_raw_bytes(&mut c.stack, sig_bytes.len(), sig_bytes.as_ptr())
.unwrap()
.as_noun();
let msg_ubig = ubig!(0xaf82);
let msg_bytes = msg_ubig.to_be_bytes();
let message =
IndirectAtom::new_raw_bytes(&mut c.stack, msg_bytes.len(), msg_bytes.as_ptr())
.unwrap()
.as_noun();
let pub_ubig =
@ -266,10 +255,9 @@ mod tests {
let pub_bytes = pub_ubig.to_be_bytes();
let public_key =
IndirectAtom::new_raw_bytes(&mut c.stack, pub_bytes.len(), pub_bytes.as_ptr())
.unwrap()
.as_noun();
let sam = T(&mut c.stack, &[signature, message, public_key]).unwrap();
let sam = T(&mut c.stack, &[signature, message, public_key]);
assert_jet(c, jet_veri, sam, YES);
}
}

View File

@ -7,23 +7,23 @@ use sword_crypto::sha::{ac_sha1, ac_shal, ac_shas, ac_shay};
crate::gdb!();
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shas(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let sal = slot(sam, 2)?.as_atom()?;
let ruz = slot(sam, 3)?.as_atom()?;
unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
let sal_bytes = &(sal.as_bytes())[0..met(3, sal)]; // drop trailing zeros
let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len())?;
let (mut _salt_ida, salt) = IndirectAtom::new_raw_mut_bytes(stack, sal_bytes.len());
salt.copy_from_slice(sal_bytes);
let msg_len = met(3, ruz);
if msg_len > 0 {
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?;
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
msg.copy_from_slice(msg_bytes);
ac_shas(msg, salt, out);
} else {
@ -34,18 +34,18 @@ pub fn jet_shas(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shax(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let ruz = sam.as_atom()?;
let msg_len = met(3, ruz);
unsafe {
let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
let (mut ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
if msg_len > 0 {
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len())?;
let (_msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, msg_bytes.len());
msg.copy_from_slice(msg_bytes);
ac_shay(msg, out);
} else {
@ -56,7 +56,7 @@ pub fn jet_shax(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shay(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -69,16 +69,16 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz);
unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32)?;
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 32);
if length == 0 {
ac_shay(&mut [], out);
} else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_shay(msg, out);
} else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes);
ac_shay(msg, out);
}
@ -87,7 +87,7 @@ pub fn jet_shay(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shal(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -100,16 +100,16 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz);
unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64)?;
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 64);
if length == 0 {
ac_shal(&mut [], out);
} else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_shal(msg, out);
} else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes);
ac_shal(msg, out);
}
@ -118,7 +118,7 @@ pub fn jet_shal(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let len = slot(sam, 2)?.as_atom()?;
@ -131,16 +131,16 @@ pub fn jet_sha1(context: &mut Context, subject: Noun) -> Result<Noun> {
let msg_len = met(3, ruz);
unsafe {
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20)?;
let (mut out_ida, out) = IndirectAtom::new_raw_mut_bytes(stack, 20);
if length == 0 {
ac_sha1(&mut [], out);
} else if msg_len >= length {
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg.copy_from_slice(&(ruz.as_bytes())[0..length]);
ac_sha1(msg, out);
} else {
let msg_bytes = &(ruz.as_bytes())[0..msg_len];
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length)?;
let (mut _msg_ida, msg) = IndirectAtom::new_raw_mut_bytes(stack, length);
msg[0..msg_len].copy_from_slice(msg_bytes);
ac_sha1(msg, out);
}
@ -158,242 +158,242 @@ mod tests {
#[test]
fn test_shas() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig(
c,
jet_shas,
sam,
ubig!(_0x4abac214e1e95fe0c60df79d09cbd05454a4cb958683e02318aa147f2a5e6d60),
).unwrap();
);
let sam = T(&mut c.stack, &[D(1), D(1)]).unwrap();
let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet_ubig(
c,
jet_shas,
sam,
ubig!(_0x547da92584bc986e5784edb746c29504bfd6b34572c83b7b96440ca77d35cdfc),
).unwrap();
);
let sam = T(&mut c.stack, &[D(2), D(2)]).unwrap();
let sam = T(&mut c.stack, &[D(2), D(2)]);
assert_jet_ubig(
c,
jet_shas,
sam,
ubig!(_0x4cf01fe7cc56ef70d17735322488de0d31857afcfe451e199abe6295f78f5328),
).unwrap();
);
let a = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
);
let b = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap();
let sam = T(&mut c.stack, &[a, b]).unwrap();
);
let sam = T(&mut c.stack, &[a, b]);
assert_jet_ubig(
c,
jet_shas,
sam,
ubig!(_0xf7569a89650553ef13f9a8f0bb751fd42b70a4821be6bc1cbe197af33ce4843c),
).unwrap();
);
}
#[test]
fn test_shax() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet_ubig(
c,
jet_shax,
D(0), // ''
ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap();
);
assert_jet_ubig(
c,
jet_shax,
D(7303014), // 'foo'
ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
).unwrap();
);
let a = A(
&mut c.stack,
&ubig!(_0xaee76662885e8af9a0bf8364702d42133441301d3c459bf98fc6ff686bb4262c),
).unwrap();
);
assert_jet_ubig(
c,
jet_shax,
a,
ubig!(_0x9ee26e46c2028aa4a9c463aa722b82ed8bf6e185c3e5a5a69814a2c78fe8adc7),
).unwrap();
);
assert_jet_ubig(
c,
jet_shax,
D(123456789),
ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
);
let a = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
);
assert_jet_ubig(
c,
jet_shax,
a,
ubig!(_0xf90f3184d7347a20cfdd2d5f7ac5c82eb9ab7af54c9419fbc18832c5a33360c9),
).unwrap();
)
}
#[test]
fn test_shay() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
let ret = A(
&mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap();
assert_jet(c, jet_shay, sam, ret).unwrap();
);
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
let ret = A(
&mut c.stack,
&ubig!(_0x1da0af1706a31185763837b33f1d90782c0a78bbe644a59c987ab3ff9c0b346e),
).unwrap();
assert_jet(c, jet_shay, sam, ret).unwrap();
);
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(1)]);
let ret = A(
&mut c.stack,
&ubig!(_0x55b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3),
).unwrap();
assert_jet(c, jet_shay, sam, ret).unwrap();
);
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(1), D(478560413032)]).unwrap(); // [1 'hello']
let sam = T(&mut c.stack, &[D(1), D(478560413032)]); // [1 'hello']
let ret = A(
&mut c.stack,
&ubig!(_0x23b14de6713b28aadf8f95026636eb6ab63e99c952bceb401fa4f1642640a9aa),
).unwrap();
assert_jet(c, jet_shay, sam, ret).unwrap();
);
assert_jet(c, jet_shay, sam, ret);
let sam = T(&mut c.stack, &[D(2), D(478560413032)]).unwrap(); // [2 'hello']
let sam = T(&mut c.stack, &[D(2), D(478560413032)]); // [2 'hello']
let ret = A(
&mut c.stack,
&ubig!(_0xde1e7ee30cecf453f1d77c08a125fdc6a4bbac72c01dd7a1e21cd0d22f7e2f37),
).unwrap();
assert_jet(c, jet_shay, sam, ret).unwrap();
);
assert_jet(c, jet_shay, sam, ret);
let big = DIRECT_MAX + 1;
let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8).unwrap()
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u64 as *const u8)
};
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap();
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
let big: u128 = (DIRECT_MAX as u128) << 64;
let ida = unsafe {
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8).unwrap()
IndirectAtom::new_raw_bytes(&mut c.stack, 8, &big as *const u128 as *const u8)
};
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]).unwrap();
assert_jet_err(c, jet_shay, sam, BAIL_FAIL).unwrap();
let sam = T(&mut c.stack, &[ida.as_noun(), D(478560413032)]);
assert_jet_err(c, jet_shay, sam, BAIL_FAIL);
}
#[test]
fn test_shal() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
assert_jet_ubig(
c,
jet_shal,
sam,
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
).unwrap();
);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig(
c,
jet_shal,
sam,
ubig!(_0xee1069e3f03884c3e5d457253423844a323c29eb4cde70630b58c3712a804a70221d35d9506e242c9414ff192e283dd6caa4eff86a457baf93d68189024d24b8)
).unwrap();
);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(1)]);
assert_jet_ubig(
c,
jet_shal,
sam,
ubig!(_0x3eda27f97a3238a5817a4147bd31b9632fec7e87d21883ffb0f2855d3cd1d047cee96cd321a9f483dc15570b05e420d607806dd6502854f1bdb8ef7e35e183cf)
).unwrap();
);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
);
let dat = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap();
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap();
);
let sam = T(&mut c.stack, &[wid, dat]);
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
assert_jet_err(c, jet_shal, sam, BAIL_FAIL).unwrap();
);
let sam = T(&mut c.stack, &[wid, D(1)]);
assert_jet_err(c, jet_shal, sam, BAIL_FAIL);
}
#[test]
fn test_sha1() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(0), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(0)]);
assert_jet_ubig(
c,
jet_sha1,
sam,
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
).unwrap();
);
let sam = T(&mut c.stack, &[D(1), D(0)]).unwrap();
let sam = T(&mut c.stack, &[D(1), D(0)]);
assert_jet_ubig(
c,
jet_sha1,
sam,
ubig!(_0x5ba93c9db0cff93f52b521d7420e43f6eda2784f),
).unwrap();
);
let sam = T(&mut c.stack, &[D(0), D(1)]).unwrap();
let sam = T(&mut c.stack, &[D(0), D(1)]);
assert_jet_ubig(
c,
jet_sha1,
sam,
ubig!(_0xda39a3ee5e6b4b0d3255bfef95601890afd80709),
).unwrap();
);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
);
let dat = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de73),
).unwrap();
let sam = T(&mut c.stack, &[wid, dat]).unwrap();
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap();
);
let sam = T(&mut c.stack, &[wid, dat]);
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
let wid = A(
&mut c.stack,
&ubig!(_0xa1d6eb6ef33f233ae6980ca7c4fc65f90fe1bdee11c730d41607b4747c83de72),
).unwrap();
let sam = T(&mut c.stack, &[wid, D(1)]).unwrap();
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL).unwrap();
);
let sam = T(&mut c.stack, &[wid, D(1)]);
assert_jet_err(c, jet_sha1, sam, BAIL_FAIL);
}
}

View File

@ -8,7 +8,7 @@ use sword_macros::tas;
crate::gdb!();
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -25,19 +25,19 @@ pub fn jet_ut_crop(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = 141 + tas!(b"crop") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result {
// axe must be Atom, though we use it as Noun
let axe = slot(subject, 6)?.as_atom()?;
let van = slot(subject, 7)?;
@ -55,19 +55,19 @@ pub fn jet_ut_fish(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = 141 + tas!(b"fish") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, axe.as_noun(), bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result {
let rff = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -84,19 +84,19 @@ pub fn jet_ut_fuse(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = 141 + tas!(b"fuse") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?;
let gen = slot(subject, 13)?;
let van = slot(subject, 7)?;
@ -106,19 +106,19 @@ pub fn jet_ut_mint(context: &mut Context, subject: Noun) -> Result<Noun> {
let fun = 141 + tas!(b"mint");
let vet = slot(van, 59).map_or(NONE, |x| x);
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat])?;
let mut key = T(&mut context.stack, &[D(fun), vet, sut, gol, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result {
let gol = slot(subject, 12)?;
let dox = slot(subject, 26)?;
let gen = slot(subject, 27)?;
@ -137,19 +137,19 @@ pub fn jet_ut_mull(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = 141 + tas!(b"mull") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, gol, dox, gen, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}
}
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result {
let nest_in_core = slot(subject, 3)?;
let seg = slot(nest_in_core, 12)?;
@ -172,23 +172,23 @@ pub fn jet_ut_nest_dext(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = (141 + tas!(b"dext")) + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, rff, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
if unsafe { pro.raw_equals(YES) && reg.raw_equals(D(0)) }
|| unsafe { pro.raw_equals(NO) && seg.raw_equals(D(0)) }
{
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
}
Ok(pro)
}
}
}
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result {
let leg = slot(subject, 6)?;
let van = slot(subject, 7)?;
@ -205,13 +205,13 @@ pub fn jet_ut_rest(context: &mut Context, subject: Noun) -> Result<Noun> {
1
};
let fun = 141 + tas!(b"rest") + (flag << 8);
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat])?;
let mut key = T(&mut context.stack, &[D(fun), sut, leg, bat]);
match context.cache.lookup(&mut context.stack, &mut key)? {
match context.cache.lookup(&mut context.stack, &mut key) {
Some(pro) => Ok(pro),
None => {
let pro = interpret(context, subject, slot(subject, 2)?)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro)?;
context.cache = context.cache.insert(&mut context.stack, &mut key, pro);
Ok(pro)
}
}

View File

@ -22,14 +22,14 @@ use ibig::UBig;
crate::gdb!();
pub fn jet_add(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_add(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::add(&mut context.stack, a, b)?.as_noun())
Ok(util::add(&mut context.stack, a, b).as_noun())
}
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_dec(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
if let Ok(atom) = arg.as_atom() {
match atom.as_either() {
@ -48,7 +48,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
}
Some(first_one) => {
let (mut new_indirect, new_slice) = unsafe {
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())?
IndirectAtom::new_raw_mut_bitslice(&mut context.stack, indirect.size())
};
if first_one > 0 {
new_slice[..first_one].fill(true);
@ -67,7 +67,7 @@ pub fn jet_dec(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_div(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -78,14 +78,14 @@ pub fn jet_div(context: &mut Context, subject: Noun) -> Result<Noun> {
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Ok(unsafe { DirectAtom::new_unchecked(a.data() / b.data()) }.as_noun())
} else {
let a_big = a.as_ubig(stack)?;
let b_big = b.as_ubig(stack)?;
let res = UBig::div_stack(stack, a_big, b_big)?;
Ok(Atom::from_ubig(stack, &res)?.as_noun())
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::div_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res).as_noun())
}
}
pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -103,54 +103,54 @@ pub fn jet_dvr(context: &mut Context, subject: Noun) -> Result<Noun> {
)
}
} else {
let (div, rem) = a.as_ubig(stack)?.div_rem(b.as_ubig(stack)?);
let (div, rem) = a.as_ubig(stack).div_rem(b.as_ubig(stack));
(
Atom::from_ubig(stack, &div)?.as_noun(),
Atom::from_ubig(stack, &rem)?.as_noun(),
Atom::from_ubig(stack, &div).as_noun(),
Atom::from_ubig(stack, &rem).as_noun(),
)
};
Ok(T(stack, &[div, rem])?)
Ok(T(stack, &[div, rem]))
}
}
pub fn jet_gte(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_gte(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::gte(stack, a, b)?)
Ok(util::gte(stack, a, b))
}
pub fn jet_gth(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_gth(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::gth(stack, a, b)?)
Ok(util::gth(stack, a, b))
}
pub fn jet_lte(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_lte(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::lte(stack, a, b)?)
Ok(util::lte(stack, a, b))
}
pub fn jet_lth(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_lth(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
Ok(util::lth(stack, a, b)?)
Ok(util::lth(stack, a, b))
}
pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_max(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -166,14 +166,14 @@ pub fn jet_max(context: &mut Context, subject: Noun) -> Result<Noun> {
a.as_noun()
} else if a.bit_size() < b.bit_size() {
b.as_noun()
} else if a.as_ubig(stack)? >= b.as_ubig(stack)? {
} else if a.as_ubig(stack) >= b.as_ubig(stack) {
a.as_noun()
} else {
b.as_noun()
})
}
pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_min(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -189,14 +189,14 @@ pub fn jet_min(context: &mut Context, subject: Noun) -> Result<Noun> {
a.as_noun()
} else if a.bit_size() > b.bit_size() {
b.as_noun()
} else if a.as_ubig(stack)? <= b.as_ubig(stack)? {
} else if a.as_ubig(stack) <= b.as_ubig(stack) {
a.as_noun()
} else {
b.as_noun()
})
}
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mod(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -207,12 +207,12 @@ pub fn jet_mod(context: &mut Context, subject: Noun) -> Result<Noun> {
} else if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Ok(unsafe { DirectAtom::new_unchecked(a.data() % b.data()) }.as_noun())
} else {
let res = a.as_ubig(stack)? % b.as_ubig(stack)?;
Ok(Atom::from_ubig(stack, &res)?.as_noun())
let res = a.as_ubig(stack) % b.as_ubig(stack);
Ok(Atom::from_ubig(stack, &res).as_noun())
}
}
pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mul(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -221,26 +221,26 @@ pub fn jet_mul(context: &mut Context, subject: Noun) -> Result<Noun> {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
let res = a.data() as u128 * b.data() as u128;
if res < DIRECT_MAX as u128 {
Ok(Atom::new(stack, res as u64)?.as_noun())
Ok(Atom::new(stack, res as u64).as_noun())
} else {
Ok(unsafe {
IndirectAtom::new_raw_bytes(
stack,
if res < u64::MAX as u128 { 8 } else { 16 },
&res as *const u128 as *const u8,
)?
)
}
.as_noun())
}
} else {
let a_big = a.as_ubig(stack)?;
let b_big = b.as_ubig(stack)?;
let res = UBig::mul_stack(stack, a_big, b_big)?;
Ok(Atom::from_ubig(stack, &res)?.as_noun())
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::mul_stack(stack, a_big, b_big);
Ok(Atom::from_ubig(stack, &res).as_noun())
}
}
pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sub(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
let b = slot(arg, 3)?.as_atom()?;
@ -249,115 +249,108 @@ pub fn jet_sub(context: &mut Context, subject: Noun) -> Result<Noun> {
}
pub mod util {
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Atom, Error, Noun, Result, NO, YES};
use ibig::UBig;
/// Addition
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Atom> {
pub fn add(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
Atom::new(stack, a.data() + b.data())
} else {
let a_big = a.as_ubig(stack)?;
let b_big = b.as_ubig(stack)?;
let res = UBig::add_stack(stack, a_big, b_big)?;
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
let res = UBig::add_stack(stack, a_big, b_big);
Atom::from_ubig(stack, &res)
}
}
/// Greater than or equal to (boolean)
pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
pub fn gte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() >= b.data()
} else if a.bit_size() > b.bit_size() {
true
} else if a.bit_size() < b.bit_size() {
false
} else {
a.as_ubig(stack)? >= b.as_ubig(stack)?
};
Ok(res)
a.as_ubig(stack) >= b.as_ubig(stack)
}
}
/// Greater than or equal to
pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
if gte_b(stack, a, b)? {
Ok(YES)
pub fn gte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if gte_b(stack, a, b) {
YES
} else {
Ok(NO)
NO
}
}
/// Greater than (boolean)
pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
pub fn gth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() > b.data()
} else if a.bit_size() > b.bit_size() {
true
} else if a.bit_size() < b.bit_size() {
false
} else {
a.as_ubig(stack)? > b.as_ubig(stack)?
};
Ok(res)
a.as_ubig(stack) > b.as_ubig(stack)
}
}
/// Greater than
pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
let res = if gth_b(stack, a, b)? {
pub fn gth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if gth_b(stack, a, b) {
YES
} else {
NO
};
Ok(res)
}
}
/// Less than or equal to (boolean)
pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
pub fn lte_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() <= b.data()
} else if a.bit_size() < b.bit_size() {
true
} else if a.bit_size() > b.bit_size() {
false
} else {
a.as_ubig(stack)? <= b.as_ubig(stack)?
};
Ok(res)
a.as_ubig(stack) <= b.as_ubig(stack)
}
}
/// Less than or equal to
pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
let res = if lte_b(stack, a, b)? {
pub fn lte(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if lte_b(stack, a, b) {
YES
} else {
NO
};
Ok(res)
}
}
/// Less than (boolean)
pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<bool> {
let res = if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
pub fn lth_b(stack: &mut NockStack, a: Atom, b: Atom) -> bool {
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
a.data() < b.data()
} else if a.bit_size() > b.bit_size() {
false
} else if a.bit_size() < b.bit_size() {
true
} else {
a.as_ubig(stack)? < b.as_ubig(stack)?
};
Ok(res)
a.as_ubig(stack) < b.as_ubig(stack)
}
}
/// Less than
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> AllocResult<Noun> {
let res = if lth_b(stack, a, b)? {
pub fn lth(stack: &mut NockStack, a: Atom, b: Atom) -> Noun {
if lth_b(stack, a, b) {
YES
} else {
NO
};
Ok(res)
}
}
/// Subtraction
@ -369,19 +362,19 @@ pub mod util {
if a_small < b_small {
Err(Error::NotRepresentable)
} else {
Ok(Atom::new(stack, a_small - b_small)?)
Ok(Atom::new(stack, a_small - b_small))
}
} else {
let a_big = a.as_ubig(stack)?;
let b_big = b.as_ubig(stack)?;
let a_big = a.as_ubig(stack);
let b_big = b.as_ubig(stack);
if a_big < b_big {
Err(Error::NotRepresentable)
} else {
let a_big = a.as_ubig(stack)?;
let b_big = b.as_ubig(stack)?;
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)?)
Ok(Atom::from_ubig(stack, &res))
}
}
}
@ -392,17 +385,8 @@ mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::mem::NockStack;
use crate::noun::{Noun, D, NO, YES};
use crate::noun::{Noun, D, NO, T, YES};
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_ubig: AssertJetUBigFn = assert_jet_ubig_panicky;
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
@ -445,7 +429,7 @@ mod tests {
#[test]
fn test_add() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,
@ -464,7 +448,7 @@ mod tests {
#[test]
fn test_dec() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let s = &mut c.stack;
let (a0, _a24, a63, _a96, a128) = atoms(s);
@ -475,7 +459,7 @@ mod tests {
#[test]
fn test_div() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(c, jet_div, &[atom_128, atom_96], ubig!(0xe349f8f0));
assert_common_jet(c, jet_div, &[atom_96, atom_63], ubig!(0x1f59d6018));
@ -498,7 +482,7 @@ mod tests {
#[test]
fn test_dvr() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let (a0, a24, a63, a96, a128) = atoms(&mut c.stack);
let a264 = atom_264(&mut c.stack);
@ -544,7 +528,7 @@ mod tests {
#[test]
fn test_gte() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet_noun(c, jet_gte, &[atom_128, atom_96], YES);
assert_common_jet_noun(c, jet_gte, &[atom_96, atom_63], YES);
@ -558,7 +542,7 @@ mod tests {
#[test]
fn test_gth() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet_noun(c, jet_gth, &[atom_128, atom_96], YES);
assert_common_jet_noun(c, jet_gth, &[atom_96, atom_63], YES);
@ -572,7 +556,7 @@ mod tests {
#[test]
fn test_lte() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet_noun(c, jet_lte, &[atom_128, atom_96], NO);
assert_common_jet_noun(c, jet_lte, &[atom_96, atom_63], NO);
@ -586,7 +570,7 @@ mod tests {
#[test]
fn test_lth() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet_noun(c, jet_lth, &[atom_128, atom_96], NO);
assert_common_jet_noun(c, jet_lth, &[atom_96, atom_63], NO);
@ -600,7 +584,7 @@ mod tests {
#[test]
fn test_max() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,
@ -646,7 +630,7 @@ mod tests {
#[test]
fn test_min() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,
@ -687,7 +671,7 @@ mod tests {
#[test]
fn test_mod() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,
@ -707,7 +691,7 @@ mod tests {
#[test]
fn test_mul() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,
@ -732,7 +716,7 @@ mod tests {
#[test]
fn test_sub() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet(
c,

View File

@ -7,7 +7,7 @@ use crate::noun::{Noun, D, NO, T};
crate::gdb!();
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
// mink sample = [nock scry_namespace]
// = [[subject formula] scry_namespace]
@ -19,18 +19,18 @@ pub fn jet_mink(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(util::mink(context, v_subject, v_formula, scry_handler)?)
}
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mole(context: &mut Context, subject: Noun) -> Result {
jet_mure(context, subject)
}
pub fn jet_mule(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mule(context: &mut Context, subject: Noun) -> Result {
jet_mute(context, subject)
}
pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mure(context: &mut Context, subject: Noun) -> Result {
let tap = slot(subject, 6)?;
let fol = util::slam_gate_fol(&mut context.stack)?;
let scry = util::pass_thru_scry(&mut context.stack)?;
let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack);
match util::mink(context, tap, fol, scry) {
Ok(tone) => {
@ -44,10 +44,10 @@ pub fn jet_mure(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mute(context: &mut Context, subject: Noun) -> Result {
let tap = slot(subject, 6)?;
let fol = util::slam_gate_fol(&mut context.stack)?;
let scry = util::pass_thru_scry(&mut context.stack)?;
let fol = util::slam_gate_fol(&mut context.stack);
let scry = util::pass_thru_scry(&mut context.stack);
let tone = util::mink(context, tap, fol, scry);
@ -59,11 +59,9 @@ pub fn jet_mute(context: &mut Context, subject: Noun) -> Result<Noun> {
// XX: Need to check that result is actually of type path
// return [[%leaf "mute.hunk"] ~] if not
let bon = util::smyt(&mut context.stack, toon.tail())?;
Ok(T(&mut context.stack, &[NO, bon, D(0)])?)
}
x if unsafe { x.raw_equals(D(2)) } => {
Ok(T(&mut context.stack, &[NO, toon.tail()])?)
Ok(T(&mut context.stack, &[NO, bon, D(0)]))
}
x if unsafe { x.raw_equals(D(2)) } => Ok(T(&mut context.stack, &[NO, toon.tail()])),
_ => panic!("serf: mook: invalid toon"),
}
}
@ -77,7 +75,7 @@ pub mod util {
use crate::jets;
use crate::jets::bits::util::rip;
use crate::jets::form::util::scow;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{tape, Cell, Noun, D, T};
use either::{Left, Right};
use std::result;
@ -87,37 +85,37 @@ pub mod util {
pub const ROSE: Noun = D(tas!(b"rose"));
/// The classic "slam gate" formula.
pub fn slam_gate_fol(stack: &mut NockStack) -> AllocResult<Noun> {
pub fn slam_gate_fol(stack: &mut NockStack) -> Noun {
T(stack, &[D(9), D(2), D(0), D(1)])
}
/// The classic "pass-through" scry handler.
pub fn pass_thru_scry(stack: &mut NockStack) -> AllocResult<Noun> {
pub fn pass_thru_scry(stack: &mut NockStack) -> Noun {
// .* 0 != => ~ |=(a=^ ``.*(a [%12 [%0 2] %0 3]))
// [[[1 0] [1 0] 2 [0 6] 1 12 [0 2] 0 3] [0 0] 0]
let sig = T(stack, &[D(1), D(0)])?;
let sam = T(stack, &[D(0), D(6)])?;
let hed = T(stack, &[D(0), D(2)])?;
let tel = T(stack, &[D(0), D(3)])?;
let zap = T(stack, &[D(0), D(0)])?;
let sig = T(stack, &[D(1), D(0)]);
let sam = T(stack, &[D(0), D(6)]);
let hed = T(stack, &[D(0), D(2)]);
let tel = T(stack, &[D(0), D(3)]);
let zap = T(stack, &[D(0), D(0)]);
let cry = T(stack, &[D(12), hed, tel])?;
let fol = T(stack, &[D(1), cry])?;
let res = T(stack, &[D(2), sam, fol])?;
let uno = T(stack, &[sig, res])?;
let dos = T(stack, &[sig, uno])?;
let cry = T(stack, &[D(12), hed, tel]);
let fol = T(stack, &[D(1), cry]);
let res = T(stack, &[D(2), sam, fol]);
let uno = T(stack, &[sig, res]);
let dos = T(stack, &[sig, uno]);
let gat = T(stack, &[zap, D(0)])?;
let gat = T(stack, &[zap, D(0)]);
T(stack, &[dos, gat])
}
/// The "always-fail" scry
pub fn null_scry(stack: &mut NockStack) -> AllocResult<Noun> {
pub fn null_scry(stack: &mut NockStack) -> Noun {
// .* 0 != => ~ |=(^ ~)
// [[1 0] [0 0] 0]
let sig = T(stack, &[D(1), D(0)])?;
let zap = T(stack, &[D(0), D(0)])?;
let sig = T(stack, &[D(1), D(0)]);
let zap = T(stack, &[D(0), D(0)]);
T(stack, &[sig, zap, D(0)])
}
@ -151,25 +149,25 @@ pub mod util {
let cache_snapshot = context.cache;
let scry_snapshot = context.scry_stack;
context.cache = Hamt::<Noun>::new(&mut context.stack)?;
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack])?;
context.cache = Hamt::<Noun>::new(&mut context.stack);
context.scry_stack = T(&mut context.stack, &[scry, context.scry_stack]);
match interpret(context, subject, formula) {
Ok(res) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(0), res])?)
Ok(T(&mut context.stack, &[D(0), res]))
}
Err(err) => match err {
Error::ScryBlocked(path) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(1), path])?)
Ok(T(&mut context.stack, &[D(1), path]))
}
Error::Deterministic(_, trace) => {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Ok(T(&mut context.stack, &[D(2), trace])?)
Ok(T(&mut context.stack, &[D(2), trace]))
}
Error::ScryCrashed(trace) => {
context.cache = cache_snapshot;
@ -199,7 +197,7 @@ pub mod util {
context.cache = cache_snapshot;
context.scry_stack = scry_snapshot;
Err(err)
} // TODO: Implement the rest of the error handling
}
},
}
}
@ -234,8 +232,8 @@ pub mod util {
tas!(b"hunk") => match dat.as_either_atom_cell() {
Left(_) => {
let stack = &mut context.stack;
let tape = tape(stack, "mook.hunk")?;
T(stack, &[LEAF, tape])?
let tape = tape(stack, "mook.hunk");
T(stack, &[LEAF, tape])
}
Right(cell) => {
// XX: need to check that this is actually a path
@ -248,11 +246,11 @@ pub mod util {
Left(atom) => {
let stack = &mut context.stack;
let tape = rip(stack, 3, 1, atom)?;
T(stack, &[LEAF, tape])?
T(stack, &[LEAF, tape])
}
Right(cell) => {
'tank: {
let scry = null_scry(&mut context.stack)?;
let scry = null_scry(&mut context.stack);
// if +mink didn't crash...
if let Ok(tone) = mink(context, dat, cell.head(), scry) {
if let Some(tonc) = tone.cell() {
@ -272,8 +270,8 @@ pub mod util {
// This code only called when the break statement
// above doesn't trigger
let stack = &mut context.stack;
let tape = tape(stack, "####")?;
T(stack, &[LEAF, tape])?
let tape = tape(stack, "####");
T(stack, &[LEAF, tape])
}
}
},
@ -285,8 +283,8 @@ pub mod util {
let pstr = pint.head().as_cell()?;
let pend = pint.tail().as_cell()?;
let colo = T(stack, &[D(b':' as u64), D(0)])?;
let trel = T(stack, &[colo, D(0), D(0)])?;
let colo = T(stack, &[D(b':' as u64), D(0)]);
let trel = T(stack, &[colo, D(0), D(0)]);
let smyt = smyt(stack, spot.head())?;
@ -304,7 +302,7 @@ pub mod util {
list = list.tail().as_cell()?;
}
// "{end_col}]>"
let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)])?;
let p4 = T(stack, &[D(b']' as u64), D(b'>' as u64), D(0)]);
(*list.tail_as_mut()) = p4;
list = end_lin.as_cell()?;
@ -315,7 +313,7 @@ pub mod util {
list = list.tail().as_cell()?;
}
// "{end_lin} {end_col}]>"
let p3 = T(stack, &[D(b' ' as u64), end_col])?;
let p3 = T(stack, &[D(b' ' as u64), end_col]);
(*list.tail_as_mut()) = p3;
list = str_col.as_cell()?;
@ -329,7 +327,7 @@ pub mod util {
let p2 = T(
stack,
&[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin],
)?;
);
(*list.tail_as_mut()) = p2;
list = str_lin.as_cell()?;
@ -340,14 +338,14 @@ pub mod util {
list = list.tail().as_cell()?;
}
// "{str_lin} {str_col}].[{end_lin} {end_col}]>"
let p1 = T(stack, &[D(b' ' as u64), str_col])?;
let p1 = T(stack, &[D(b' ' as u64), str_col]);
(*list.tail_as_mut()) = p1;
// "<[{str_lin} {str_col}].[{end_lin} {end_col}]>"
let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin])?;
let finn = T(stack, &[LEAF, tape])?;
let tape = T(stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]);
let finn = T(stack, &[LEAF, tape]);
T(stack, &[ROSE, trel, smyt, finn, D(0)])?
T(stack, &[ROSE, trel, smyt, finn, D(0)])
}
_ => {
let stack = &mut context.stack;
@ -362,16 +360,16 @@ pub mod util {
D(tas!(b".")),
tape,
],
)?
)
} // XX: TODO
// %hand
// %lose
};
if flop {
res = T(&mut context.stack, &[tank, res])?;
res = T(&mut context.stack, &[tank, res]);
} else {
let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack)?;
let (new_cell, new_memory) = Cell::new_raw_mut(&mut context.stack);
(*new_memory).head = tank;
*dest = new_cell.as_noun();
dest = &mut (*new_memory).tail;
@ -381,23 +379,23 @@ pub mod util {
}
*dest = D(0);
let toon = Cell::new(&mut context.stack, D(2), res)?;
let toon = Cell::new(&mut context.stack, D(2), res);
Ok(toon)
}
}
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> {
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result {
let lash = D(tas!(b"/"));
let zero = D(0);
let sep = T(stack, &[lash, zero])?;
let sep = T(stack, &[lash, zero]);
let trel = T(stack, &[sep, sep, zero])?;
let trel = T(stack, &[sep, sep, zero]);
let tank = smyt_help(stack, path)?;
Ok(T(stack, &[ROSE, trel, tank])?)
Ok(T(stack, &[ROSE, trel, tank]))
}
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result<Noun> {
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result {
// XX: switch to using Cell:new_raw_mut
if unsafe { path.raw_equals(D(0)) } {
return Ok(D(0));
@ -406,23 +404,18 @@ pub mod util {
let cell = path.as_cell()?;
let tail = smyt_help(stack, cell.tail())?;
let trip = rip(stack, 3, 1, cell.head().as_atom()?)?;
let head = T(stack, &[LEAF, trip])?;
let head = T(stack, &[LEAF, trip]);
Ok(T(stack, &[head, tail])?)
Ok(T(stack, &[head, tail]))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::jets::util::test::{assert_jet, init_context};
use crate::mem::NockStack;
use crate::noun::D;
// Override T and A with the panicky variants
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
use crate::noun::{D, T};
#[test]
fn init() {
@ -438,7 +431,7 @@ mod tests {
#[test]
fn test_mink_success() {
let context = &mut init_context().unwrap();
let context = &mut init_context();
let stack = &mut context.stack;
let subj = D(0);
@ -452,7 +445,7 @@ mod tests {
#[test]
fn test_mink_zapzap() {
let context = &mut init_context().unwrap();
let context = &mut init_context();
let stack = &mut context.stack;
let subj = D(0);
@ -466,7 +459,7 @@ mod tests {
#[test]
fn test_mink_trace() {
let context = &mut init_context().unwrap();
let context = &mut init_context();
let stack = &mut context.stack;
let subj = D(0);
let scry = D(0);

View File

@ -13,7 +13,7 @@ crate::gdb!();
//
// Text conversion
//
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_trip(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?.as_atom()?;
let chars = met(3, sam);
if chars == 0 {
@ -27,7 +27,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
for byte in bytes {
unsafe {
let (it, it_mem) = Cell::new_raw_mut(&mut context.stack)?;
let (it, it_mem) = Cell::new_raw_mut(&mut context.stack);
// safe because a byte can't overflow a direct atom
(*it_mem).head = D((*byte) as u64);
@ -44,7 +44,7 @@ pub fn jet_trip(context: &mut Context, subject: Noun) -> Result<Noun> {
// Tracing
//
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_last(_context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let zyc = slot(sam, 2)?;
let naz = slot(sam, 3)?;
@ -56,7 +56,7 @@ pub fn jet_last(_context: &mut Context, subject: Noun) -> Result<Noun> {
// Combinators
//
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_bend(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -81,25 +81,25 @@ pub fn jet_bend(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex])?)
Ok(T(&mut context.stack, &[yur, q_vex]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?;
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?;
if unsafe { vux.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, q_vex])?)
Ok(T(&mut context.stack, &[yur, q_vex]))
} else {
let q_vux = vux.as_cell()?.tail();
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit])?)
Ok(T(&mut context.stack, &[yur, D(0), q_vux, quq_yit]))
}
}
}
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_comp(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -124,19 +124,19 @@ pub fn jet_comp(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?)
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let arg = T(&mut context.stack, &[puq_vex, puq_yit])?;
let arg = T(&mut context.stack, &[puq_vex, puq_yit]);
let vux = slam(context, raq, arg)?;
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit])?)
Ok(T(&mut context.stack, &[yur, D(0), vux, quq_yit]))
}
}
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_glue(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -161,7 +161,7 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?)
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail();
@ -173,19 +173,19 @@ pub fn jet_glue(context: &mut Context, subject: Noun) -> Result<Noun> {
let goy = util::last(yur, p_wam)?;
if unsafe { q_wam.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[goy, D(0)])?)
Ok(T(&mut context.stack, &[goy, D(0)]))
} else {
let uq_wam = q_wam.as_cell()?.tail().as_cell()?;
let puq_wam = uq_wam.head();
let quq_wam = uq_wam.tail();
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam])?;
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam])?)
let puq_arg = T(&mut context.stack, &[puq_vex, puq_wam]);
Ok(T(&mut context.stack, &[goy, D(0x0), puq_arg, quq_wam]))
}
}
}
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -207,10 +207,10 @@ pub fn jet_pfix(context: &mut Context, subject: Noun) -> Result<Noun> {
// XX: Why don't we just return yit? When would p_vex ever be the later of the two?
let arg = util::last(p_vex, p_yit)?;
Ok(T(&mut context.stack, &[arg, q_yit])?)
Ok(T(&mut context.stack, &[arg, q_yit]))
}
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_plug(context: &mut Context, subject: Noun) -> Result {
let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?;
let p_vex = vex.head();
@ -230,19 +230,19 @@ pub fn jet_plug(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?)
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let puq_yit = uq_yit.head();
let quq_yit = uq_yit.tail();
let inner = T(&mut context.stack, &[puq_vex, puq_yit])?;
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit])?)
let inner = T(&mut context.stack, &[puq_vex, puq_yit]);
Ok(T(&mut context.stack, &[yur, D(0), inner, quq_yit]))
}
}
}
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_pose(context: &mut Context, subject: Noun) -> Result {
let vex = slot(subject, 12)?.as_cell()?;
let sab = slot(subject, 13)?;
@ -255,10 +255,10 @@ pub fn jet_pose(context: &mut Context, subject: Noun) -> Result<Noun> {
let roq = kick(context, sab, D(2))?.as_cell()?;
let yur = util::last(p_vex, roq.head())?;
Ok(T(&mut context.stack, &[yur, roq.tail()])?)
Ok(T(&mut context.stack, &[yur, roq.tail()]))
}
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result {
let sam = slot(subject, 6)?;
let vex = slot(sam, 2)?.as_cell()?;
let sab = slot(sam, 3)?;
@ -281,12 +281,12 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
let yur = util::last(p_vex, p_yit)?;
if unsafe { q_yit.raw_equals(D(0)) } {
Ok(T(&mut context.stack, &[yur, D(0)])?)
Ok(T(&mut context.stack, &[yur, D(0)]))
} else {
let uq_yit = q_yit.as_cell()?.tail().as_cell()?;
let quq_yit = uq_yit.tail();
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit])?)
Ok(T(&mut context.stack, &[yur, D(0), puq_vex, quq_yit]))
}
}
@ -294,7 +294,7 @@ pub fn jet_sfix(context: &mut Context, subject: Noun) -> Result<Noun> {
// Rule Builders
//
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cold(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let cus = slot(van, 12)?;
@ -309,11 +309,11 @@ pub fn jet_cold(context: &mut Context, subject: Noun) -> Result<Noun> {
} else {
let quq_vex = q_vex.as_cell()?.tail().as_cell()?.tail();
Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex])?)
Ok(T(&mut context.stack, &[p_vex, D(0), cus, quq_vex]))
}
}
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cook(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let poq = slot(van, 12)?;
@ -331,11 +331,11 @@ pub fn jet_cook(context: &mut Context, subject: Noun) -> Result<Noun> {
let quq_vex = uq_vex.tail();
let wag = slam(context, poq, puq_vex)?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
}
}
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_easy(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let huf = slot(van, 6)?;
@ -343,10 +343,10 @@ pub fn jet_easy(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(T(
&mut context.stack,
&[tub.as_cell()?.head(), D(0), huf, tub],
)?)
))
}
pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_here(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let hez = slot(van, 12)?;
@ -368,14 +368,14 @@ pub fn jet_here(context: &mut Context, subject: Noun) -> Result<Noun> {
let quq_vex = uq_vex.tail();
let pquq_vex = quq_vex.as_cell()?.head();
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex])?;
let gud = T(&mut context.stack, &[inner_gud, puq_vex])?;
let inner_gud = T(&mut context.stack, &[p_tub, pquq_vex]);
let gud = T(&mut context.stack, &[inner_gud, puq_vex]);
let wag = slam(context, hez, gud)?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
}
pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_just(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let daf = slot(van, 6)?;
@ -390,7 +390,7 @@ pub fn jet_just(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mask(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let mut bud = slot(van, 6)?;
@ -413,7 +413,7 @@ pub fn jet_mask(context: &mut Context, subject: Noun) -> Result<Noun> {
util::fail(context, p_tub)
}
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_shim(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?.as_cell()?;
let van = slot(subject, 7)?;
let zep = slot(van, 6)?.as_cell()?;
@ -442,7 +442,7 @@ pub fn jet_shim(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_stag(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let gob = slot(van, 12)?;
@ -459,12 +459,12 @@ pub fn jet_stag(context: &mut Context, subject: Noun) -> Result<Noun> {
let puq_vex = uq_vex.head();
let quq_vex = uq_vex.tail();
let wag = T(&mut context.stack, &[gob, puq_vex])?;
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex])?)
let wag = T(&mut context.stack, &[gob, puq_vex]);
Ok(T(&mut context.stack, &[p_vex, D(0), wag, quq_vex]))
}
}
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_stew(context: &mut Context, subject: Noun) -> Result {
let tub = slot(subject, 6)?.as_cell()?;
let con = slot(subject, 7)?;
let mut hel = slot(con, 2)?;
@ -505,8 +505,8 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
match (hpn_hel.as_either(), tpn_hel.as_either()) {
(Left(_), Left(_)) => {
gte_b(&mut context.stack, iq_tub, hpn_hel)?
&& lte_b(&mut context.stack, iq_tub, tpn_hel)?
gte_b(&mut context.stack, iq_tub, hpn_hel)
&& lte_b(&mut context.stack, iq_tub, tpn_hel)
}
_ => {
// XX: Fixes jet mismatch in Vere
@ -525,7 +525,7 @@ pub fn jet_stew(context: &mut Context, subject: Noun) -> Result<Noun> {
Right(cell) => cell.head().as_atom()?,
};
if lth_b(&mut context.stack, iq_tub, wor)? {
if lth_b(&mut context.stack, iq_tub, wor) {
hel = l_hel;
} else {
hel = r_hel;
@ -542,9 +542,9 @@ struct StirPair {
pub res: Noun, // p.u.q.edge
}
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_stir(context: &mut Context, subject: Noun) -> Result {
unsafe {
let res = context.with_stack_frame(0, |context| {
context.with_stack_frame(0, |context| {
let mut tub = slot(subject, 6)?;
let van = slot(subject, 7)?;
let rud = slot(van, 12)?;
@ -565,7 +565,7 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
let puq_vex = slot(q_vex, 6)?;
let quq_vex = slot(q_vex, 7)?;
*(context.stack.push::<StirPair>()?) = StirPair {
*(context.stack.push::<StirPair>()) = StirPair {
har: p_vex,
res: puq_vex,
};
@ -586,15 +586,14 @@ pub fn jet_stir(context: &mut Context, subject: Noun) -> Result<Noun> {
while !context.stack.stack_is_empty() {
let par_u = *(context.stack.top::<StirPair>());
p_wag = util::last(par_u.har, p_wag)?;
let sam = T(&mut context.stack, &[par_u.res, puq_wag])?;
let sam = T(&mut context.stack, &[par_u.res, puq_wag]);
puq_wag = slam(context, raq, sam)?;
context.stack.pop::<StirPair>();
}
let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag])?;
let res = T(&mut context.stack, &[p_wag, D(0), puq_wag, quq_wag]);
Ok(res)
})?;
res
})
}
}
@ -604,7 +603,7 @@ pub mod util {
use crate::noun::{Noun, D, T};
use std::cmp::Ordering;
pub fn last(zyc: Noun, naz: Noun) -> Result<Noun> {
pub fn last(zyc: Noun, naz: Noun) -> Result {
let zyl = zyc.as_cell()?;
let nal = naz.as_cell()?;
@ -627,7 +626,7 @@ pub mod util {
}
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn next(context: &mut Context, tub: Noun) -> Result<Noun> {
pub fn next(context: &mut Context, tub: Noun) -> Result {
let p_tub = tub.as_cell()?.head();
let q_tub = tub.as_cell()?.tail();
@ -639,25 +638,25 @@ pub mod util {
let tq_tub = q_tub.as_cell()?.tail();
let zac = lust(context, iq_tub, p_tub)?;
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub])?)
Ok(T(&mut context.stack, &[zac, D(0), iq_tub, zac, tq_tub]))
}
// Passing Noun and doing Cell check inside next is best to keep jet semantics in sync w/ Hoon.
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result<Noun> {
pub fn lust(context: &mut Context, weq: Noun, naz: Noun) -> Result {
let p_naz = naz.as_cell()?.head().as_atom()?;
let q_naz = naz.as_cell()?.tail().as_atom()?;
if unsafe { weq.raw_equals(D(10)) } {
let arg = inc(&mut context.stack, p_naz)?.as_noun();
Ok(T(&mut context.stack, &[arg, D(1)])?)
let arg = inc(&mut context.stack, p_naz).as_noun();
Ok(T(&mut context.stack, &[arg, D(1)]))
} else {
let arg = inc(&mut context.stack, q_naz)?.as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg])?)
let arg = inc(&mut context.stack, q_naz).as_noun();
Ok(T(&mut context.stack, &[p_naz.as_noun(), arg]))
}
}
pub fn fail(context: &mut Context, hair: Noun) -> Result<Noun> {
Ok(T(&mut context.stack, &[hair, D(0)])?)
pub fn fail(context: &mut Context, hair: Noun) -> Result {
Ok(T(&mut context.stack, &[hair, D(0)]))
}
}
@ -665,13 +664,9 @@ pub mod util {
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::noun::D;
use crate::noun::{D, T};
use crate::serialization::cue;
use ibig::ubig;
// Override T and A with the panicky variants
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet_door: AssertJetDoorFn = assert_jet_door_panicky;
// XX: need unit tests for:
// +last
@ -688,7 +683,7 @@ mod tests {
#[test]
fn test_easy() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
// ((easy 'a') [[1 1] "abc"])
// [[1 1] "abc"]

View File

@ -6,27 +6,23 @@ use crate::serialization::{cue, jam};
crate::gdb!();
pub fn jet_cue(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cue(context: &mut Context, subject: Noun) -> Result {
Ok(cue(&mut context.stack, slot(subject, 6)?.as_atom()?)?)
}
pub fn jet_jam(context: &mut Context, subject: Noun) -> Result<Noun> {
Ok(jam(&mut context.stack, slot(subject, 6)?)?.as_noun())
pub fn jet_jam(context: &mut Context, subject: Noun) -> Result {
Ok(jam(&mut context.stack, slot(subject, 6)?).as_noun())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::noun::D;
// Override T with the panicky variant
use crate::test_fns::T;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
use crate::noun::{D, T};
#[test]
fn test_jam() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet(c, jet_jam, D(0x0), D(0x2));
assert_jet(c, jet_jam, D(0x1), D(0xc));
@ -38,7 +34,7 @@ mod tests {
#[test]
fn test_cue() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet(c, jet_cue, D(0x2), D(0x0));
assert_jet(c, jet_cue, D(0xc), D(0x1));

View File

@ -9,100 +9,95 @@ use std::cmp::Ordering;
crate::gdb!();
pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
pub fn jet_dor(context: &mut Context, subject: Noun) -> jets::Result {
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?;
let b = slot(sam, 3)?;
Ok(util::dor(&mut context.stack, a, b)?)
Ok(util::dor(&mut context.stack, a, b))
}
pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
pub fn jet_gor(context: &mut Context, subject: Noun) -> jets::Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?;
let b = slot(sam, 3)?;
let c = mug(stack, a)?;
let d = mug(stack, b)?;
let c = mug(stack, a);
let d = mug(stack, b);
match c.data().cmp(&d.data()) {
Ordering::Greater => Ok(NO),
Ordering::Less => Ok(YES),
Ordering::Equal => Ok(util::dor(stack, a, b)?),
Ordering::Equal => Ok(util::dor(stack, a, b)),
}
}
pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result<Noun> {
pub fn jet_mor(context: &mut Context, subject: Noun) -> jets::Result {
let stack = &mut context.stack;
let sam = slot(subject, 6)?;
let a = slot(sam, 2)?;
let b = slot(sam, 3)?;
let c = mug(stack, a)?;
let d = mug(stack, b)?;
let c = mug(stack, a);
let d = mug(stack, b);
let e = mug(stack, c.as_noun())?;
let f = mug(stack, d.as_noun())?;
let e = mug(stack, c.as_noun());
let f = mug(stack, d.as_noun());
match e.data().cmp(&f.data()) {
Ordering::Greater => Ok(NO),
Ordering::Less => Ok(YES),
Ordering::Equal => Ok(util::dor(stack, a, b)?),
Ordering::Equal => Ok(util::dor(stack, a, b)),
}
}
pub mod util {
use crate::jets::math::util::lth;
use crate::jets::util::slot;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Noun, NO, YES};
use either::{Left, Right};
pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> AllocResult<Noun> {
let res = if unsafe { a.raw_equals(b) } {
pub fn dor(stack: &mut NockStack, a: Noun, b: Noun) -> Noun {
if unsafe { a.raw_equals(b) } {
YES
} else {
match (a.as_either_atom_cell(), b.as_either_atom_cell()) {
(Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b)?,
(Left(atom_a), Left(atom_b)) => lth(stack, atom_a, atom_b),
(Left(_), Right(_)) => YES,
(Right(_), Left(_)) => NO,
(Right(cell_a), Right(cell_b)) => {
let a_head = match slot(cell_a.as_noun(), 2) {
Ok(n) => n,
Err(_) => return Ok(NO),
Err(_) => return NO,
};
let b_head = slot(cell_b.as_noun(), 2).unwrap();
let a_tail = slot(cell_a.as_noun(), 3).unwrap();
let b_tail = slot(cell_b.as_noun(), 3).unwrap();
if unsafe { a_head.raw_equals(b_head) } {
dor(stack, a_tail, b_tail)?
dor(stack, a_tail, b_tail)
} else {
dor(stack, a_head, b_head)?
dor(stack, a_head, b_head)
}
}
}
};
Ok(res)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jets::util::test::*;
use crate::noun::D;
use crate::jets::util::test::{assert_jet, init_context, A};
use crate::noun::{D, T};
use ibig::ubig;
// Override with the panicky variant
use crate::test_fns::{A, T};
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[test]
fn test_dor() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_dor, sam, YES);
@ -118,7 +113,7 @@ mod tests {
#[test]
fn test_gor() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_gor, sam, YES);
@ -130,7 +125,7 @@ mod tests {
#[test]
fn test_mor() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let sam = T(&mut c.stack, &[D(1), D(1)]);
assert_jet(c, jet_mor, sam, YES);

View File

@ -8,7 +8,7 @@ use crate::noun::{IndirectAtom, Noun, D};
crate::gdb!();
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
let arg = slot(subject, 6)?;
let tom = arg.as_atom()?;
let met = met(0, tom);
@ -24,7 +24,7 @@ pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let tom = slot(subject, 6)?.as_atom()?;
let met = met(0, tom);
@ -35,7 +35,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
let out_bits = met - 1;
let out_words = (out_bits + 63) >> 6;
let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? };
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
out_bs.set(met - 2, true); // Set MSB
if met > 2 {
out_bs[0..(met - 2)].copy_from_bitslice(&tom.as_bitslice()[0..(met - 2)]);
@ -44,7 +44,7 @@ pub fn jet_mas(context: &mut Context, subject: Noun) -> Result<Noun> {
}
}
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
pub fn jet_peg(context: &mut Context, subject: Noun) -> Result {
let stack = &mut context.stack;
let arg = slot(subject, 6)?;
let a = slot(arg, 2)?.as_atom()?;
@ -67,7 +67,7 @@ pub fn jet_peg(context: &mut Context, subject: Noun) -> Result<Noun> {
let out_words = (out_bits + 63) >> 6; // bits to 8-byte words
let (mut indirect_out, out_bs) =
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words)? };
unsafe { IndirectAtom::new_raw_mut_bitslice(stack, out_words) };
out_bs[0..b_bits - 1].copy_from_bitslice(&b.as_bitslice()[0..b_bits - 1]);
out_bs[b_bits - 1..out_bits].copy_from_bitslice(&a.as_bitslice()[0..a_bits]);
@ -82,13 +82,6 @@ mod tests {
use crate::mem::NockStack;
use crate::noun::{Noun, D, DIRECT_MAX};
use ibig::ubig;
// Override with the panicky variant
use crate::test_fns::A;
#[allow(non_upper_case_globals)]
const assert_jet: AssertJetFn = assert_jet_panicky;
#[allow(non_upper_case_globals)]
const assert_jet_err: AssertJetErrFn = assert_jet_err_panicky;
fn atom_0(_stack: &mut NockStack) -> Noun {
D(0x0)
@ -132,7 +125,7 @@ mod tests {
#[test]
fn test_cap() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_jet_err(c, jet_cap, D(0), BAIL_EXIT);
assert_jet_err(c, jet_cap, D(1), BAIL_EXIT);
@ -148,7 +141,7 @@ mod tests {
#[test]
fn test_mas() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
let a63 = atom_63(&mut c.stack);
let a64 = atom_64(&mut c.stack);
let a65 = atom_65(&mut c.stack);
@ -180,7 +173,7 @@ mod tests {
#[test]
fn test_peg() {
let c = &mut init_context().unwrap();
let c = &mut init_context();
assert_common_jet_err(c, jet_peg, &[atom_0, atom_1], BAIL_EXIT);
assert_common_jet_err(c, jet_peg, &[atom_1, atom_0], BAIL_EXIT);

View File

@ -2,7 +2,7 @@ use crate::hamt::Hamt;
use crate::jets::cold::{Batteries, Cold};
use crate::jets::hot::Hot;
use crate::jets::Jet;
use crate::mem::{AllocResult, NockStack, Preserve};
use crate::mem::{NockStack, Preserve};
use crate::noun::{Noun, Slots};
use std::ptr::{copy_nonoverlapping, null_mut};
@ -14,8 +14,8 @@ impl Preserve for Warm {
unsafe fn assert_in_stack(&self, stack: &NockStack) {
self.0.assert_in_stack(stack);
}
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
self.0.preserve(stack)
unsafe fn preserve(&mut self, stack: &mut NockStack) {
self.0.preserve(stack);
}
}
@ -47,17 +47,16 @@ impl Preserve for WarmEntry {
cursor = (*cursor.0).next;
}
}
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
// TODO: Should this panic? What is this?
unsafe fn preserve(&mut self, stack: &mut NockStack) {
if self.0.is_null() {
return Ok(());
return;
}
let mut ptr: *mut *mut WarmEntryMem = &mut self.0;
loop {
if stack.is_in_frame(*ptr) {
(**ptr).batteries.preserve(stack)?;
(**ptr).path.preserve(stack)?;
let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1)?;
(**ptr).batteries.preserve(stack);
(**ptr).path.preserve(stack);
let dest_mem: *mut WarmEntryMem = stack.struct_alloc_in_previous_frame(1);
copy_nonoverlapping(*ptr, dest_mem, 1);
*ptr = dest_mem;
ptr = &mut ((*dest_mem).next.0);
@ -68,7 +67,6 @@ impl Preserve for WarmEntry {
break;
}
}
Ok(())
}
}
@ -88,8 +86,8 @@ impl Iterator for WarmEntry {
impl Warm {
#[allow(clippy::new_without_default)]
pub fn new(stack: &mut NockStack) -> AllocResult<Self> {
Ok(Warm(Hamt::new(stack)?))
pub fn new(stack: &mut NockStack) -> Self {
Warm(Hamt::new(stack))
}
fn insert(
@ -99,32 +97,31 @@ impl Warm {
path: Noun,
batteries: Batteries,
jet: Jet,
) -> AllocResult<()> {
let current_warm_entry = self.0.lookup(stack, formula)?.unwrap_or(WARM_ENTRY_NIL);
) {
let current_warm_entry = self.0.lookup(stack, formula).unwrap_or(WARM_ENTRY_NIL);
unsafe {
let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1)?;
let warm_entry_mem_ptr: *mut WarmEntryMem = stack.struct_alloc(1);
*warm_entry_mem_ptr = WarmEntryMem {
batteries,
jet,
path,
next: current_warm_entry,
};
self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr))?;
self.0 = self.0.insert(stack, formula, WarmEntry(warm_entry_mem_ptr));
}
Ok(())
}
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> AllocResult<Self> {
let mut warm = Self::new(stack)?;
pub fn init(stack: &mut NockStack, cold: &mut Cold, hot: &Hot) -> Self {
let mut warm = Self::new(stack);
for (mut path, axis, jet) in *hot {
let batteries_list = cold.find(stack, &mut path)?;
let batteries_list = cold.find(stack, &mut path);
for batteries in batteries_list {
let mut batteries_tmp = batteries;
let (battery, _parent_axis) = batteries_tmp
.next()
.expect("IMPOSSIBLE: empty battery entry in cold state");
if let Ok(mut formula) = unsafe { (*battery).slot_atom(axis) } {
warm.insert(stack, &mut formula, path, batteries, jet)?;
warm.insert(stack, &mut formula, path, batteries, jet);
} else {
// XX: need NockStack allocated string interpolation
// eprintln!("Bad axis {} into formula {:?}", axis, battery);
@ -132,7 +129,7 @@ impl Warm {
}
}
}
Ok(warm)
warm
}
/// Walk through the linked list of WarmEntry objects and do a partial check
@ -143,17 +140,13 @@ impl Warm {
stack: &mut NockStack,
s: &mut Noun,
f: &mut Noun,
) -> AllocResult<Option<(Jet, Noun)>> {
) -> Option<(Jet, Noun)> {
let warm_it = self.0.lookup(stack, f)?;
if let Some(warm_entry) = warm_it {
unsafe {
let jet = (*warm_entry.0).jet;
let path = (*warm_entry.0).path;
if (*warm_entry.0).batteries.matches(stack, *s)? {
return Ok(Some((jet, path)));
}
for (path, batteries, jet) in warm_it {
if batteries.matches(stack, *s) {
return Some((jet, path));
}
}
Ok(None)
None
}
}

View File

@ -2,22 +2,15 @@ extern crate lazy_static;
extern crate num_derive;
#[macro_use]
extern crate static_assertions;
//pub mod bytecode;
pub mod flog;
pub mod hamt;
pub mod interpreter;
pub mod jets;
pub mod mem;
pub mod mug;
pub mod newt;
pub mod noun;
pub mod serialization;
pub mod site;
#[cfg(test)]
pub mod test_fns;
pub mod trace;
pub mod unifying_equality;
@ -78,10 +71,10 @@ mod tests {
use crate::noun::*;
use crate::serialization::jam;
let mut stack = NockStack::new(8 << 10 << 10, 0);
let head = Atom::new(&mut stack, 0).unwrap().as_noun();
let tail = Atom::new(&mut stack, 1).unwrap().as_noun();
let cell = Cell::new(&mut stack, head, tail).unwrap().as_noun();
let res = jam(&mut stack, cell).unwrap().as_direct().unwrap().data();
let head = Atom::new(&mut stack, 0).as_noun();
let tail = Atom::new(&mut stack, 1).as_noun();
let cell = Cell::new(&mut stack, head, tail).as_noun();
let res = jam(&mut stack, cell).as_direct().unwrap().data();
assert_eq!(res, 201);
}
}

View File

@ -6,6 +6,7 @@ use either::Either::{self, Left, Right};
use ibig::Stack;
use memmap::MmapMut;
use std::alloc::Layout;
use std::panic::panic_any;
use std::ptr::copy_nonoverlapping;
use std::{mem, ptr};
use thiserror::Error;
@ -65,8 +66,6 @@ impl From<AllocationError> for std::io::Error {
}
}
pub type AllocResult<T> = core::result::Result<T, AllocationError>;
#[derive(Debug, Error)]
pub enum NewStackError {
#[error("stack too small")]
@ -185,9 +184,11 @@ impl NockStack {
* top_slots is how many slots to allocate to the top stack frame.
*/
pub fn new(size: usize, top_slots: usize) -> NockStack {
Self::new_(size, top_slots)
.expect("Error making new NockStack")
.0
let result = Self::new_(size, top_slots);
match result {
Ok((stack, _)) => stack,
Err(e) => std::panic::panic_any(e),
}
}
pub fn new_(size: usize, top_slots: usize) -> Result<(NockStack, usize), NewStackError> {
@ -294,10 +295,10 @@ impl NockStack {
// Directionality parameters: (East/West), (Stack/Alloc), (pc: true/false)
// Types of size: word (words: usize)
/// Check if an allocation or pointer retrieval indicates an invalid request or an invalid state
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) -> AllocResult<()> {
pub fn alloc_would_oom_(&self, alloc: Allocation, words: usize) {
let _memory_state = self.memory_state(Some(words));
if self.pc && !alloc.alloc_type.allowed_when_pc() {
return Err(self.cannot_alloc_in_pc(Some(words)));
panic_any(self.cannot_alloc_in_pc(Some(words)));
}
// When self.pc is true
// west:
@ -409,30 +410,24 @@ impl NockStack {
};
match direction {
Direction::Increasing => {
if target_point <= limit_point {
Ok(())
} else {
Err(self.out_of_memory(alloc, Some(words)))
if !(target_point <= limit_point) {
panic_any(self.out_of_memory(alloc, Some(words)))
}
}
Direction::Decreasing => {
if target_point >= limit_point {
Ok(())
} else {
Err(self.out_of_memory(alloc, Some(words)))
if !(target_point >= limit_point) {
panic_any(self.out_of_memory(alloc, Some(words)))
}
}
// TODO this check is imprecise and should take into account the size of the pointer!
Direction::IncreasingDeref => {
if target_point < limit_point {
Ok(())
} else {
Err(self.out_of_memory(alloc, Some(words)))
if !(target_point < limit_point) {
panic_any(self.out_of_memory(alloc, Some(words)))
}
}
}
}
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) -> AllocResult<()> {
pub fn alloc_would_oom(&self, alloc_type: AllocationType, words: usize) {
let alloc = self.get_alloc_config(alloc_type);
self.alloc_would_oom_(alloc, words)
}
@ -443,7 +438,7 @@ impl NockStack {
* "popping" the top frame.
*/
// Pop analogue, doesn't need OOM check.
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) -> AllocResult<()> {
pub unsafe fn flip_top_frame(&mut self, top_slots: usize) {
// Assert that we are at the top
assert!((*self.prev_frame_pointer_pointer()).is_null());
assert!((*self.prev_stack_pointer_pointer()).is_null());
@ -459,7 +454,7 @@ impl NockStack {
pc: self.pc,
},
byte_size,
)?;
);
// new top frame will be east
let new_frame_pointer = self.start.add(self.size).sub(size) as *mut u64;
*new_frame_pointer.add(FRAME) = ptr::null::<u64>() as u64;
@ -481,7 +476,7 @@ impl NockStack {
pc: self.pc,
},
byte_size,
)?;
);
let new_frame_pointer = self.start.add(size) as *mut u64;
*new_frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64;
*new_frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64;
@ -492,7 +487,6 @@ impl NockStack {
self.pc = false;
assert!(self.is_west());
};
Ok(())
}
/// Resets the NockStack. The top frame is west as in the initial creation of the NockStack.
@ -615,32 +609,32 @@ impl NockStack {
/** Mutable pointer to a slot in a stack frame: east stack */
// TODO: slot_pointer_east_: Needs a simple bounds check
#[cfg(test)]
unsafe fn slot_pointer_east_(&self, slot: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom_(
unsafe fn slot_pointer_east_(&self, slot: usize) -> *mut u64 {
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::East,
alloc_type: AllocationType::SlotPointer,
pc: self.pc,
},
slot,
)?;
Ok(self.frame_pointer.add(slot))
);
self.frame_pointer.add(slot)
}
/** Mutable pointer to a slot in a stack frame: west stack */
// TODO: slot_pointer_west_: Needs a simple bounds check
#[cfg(test)]
unsafe fn slot_pointer_west_(&self, slot: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom_(
unsafe fn slot_pointer_west_(&self, slot: usize) -> *mut u64 {
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::West,
alloc_type: AllocationType::SlotPointer,
pc: self.pc,
},
slot,
)?;
Ok(self.frame_pointer.sub(slot + 1))
);
self.frame_pointer.sub(slot + 1)
}
/** Mutable pointer to a slot in a stack frame: east stack */
@ -659,7 +653,7 @@ impl NockStack {
/// Mutable pointer to a slot in a stack frame
/// Panics on out-of-bounds conditions
#[cfg(test)]
unsafe fn slot_pointer_(&self, slot: usize) -> AllocResult<*mut u64> {
unsafe fn slot_pointer_(&self, slot: usize) -> *mut u64 {
if self.is_west() {
self.slot_pointer_west_(slot)
} else {
@ -742,38 +736,38 @@ impl NockStack {
* allocation pointer is returned as the pointer to the newly allocated memory. */
/** Bump the alloc pointer for a west frame to make space for an allocation */
unsafe fn raw_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
unsafe fn raw_alloc_west(&mut self, words: usize) -> *mut u64 {
self.alloc_would_oom(AllocationType::Alloc, words);
if self.pc {
panic!("Allocation during cleanup phase is prohibited.");
}
self.alloc_pointer = self.alloc_pointer.sub(words);
Ok(self.alloc_pointer)
self.alloc_pointer
}
/** Bump the alloc pointer for an east frame to make space for an allocation */
unsafe fn raw_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom(AllocationType::Alloc, words)?;
unsafe fn raw_alloc_east(&mut self, words: usize) -> *mut u64 {
self.alloc_would_oom(AllocationType::Alloc, words);
if self.pc {
panic!("Allocation during cleanup phase is prohibited.");
}
let alloc = self.alloc_pointer;
self.alloc_pointer = self.alloc_pointer.add(words);
Ok(alloc)
alloc
}
/** Allocate space for an indirect pointer in a west frame */
unsafe fn indirect_alloc_west(&mut self, words: usize) -> AllocResult<*mut u64> {
unsafe fn indirect_alloc_west(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_west(words + 2)
}
/** Allocate space for an indirect pointer in an east frame */
unsafe fn indirect_alloc_east(&mut self, words: usize) -> AllocResult<*mut u64> {
unsafe fn indirect_alloc_east(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_east(words + 2)
}
/** Allocate space for an indirect pointer in a stack frame */
unsafe fn indirect_alloc(&mut self, words: usize) -> AllocResult<*mut u64> {
unsafe fn indirect_alloc(&mut self, words: usize) -> *mut u64 {
if self.is_west() {
self.indirect_alloc_west(words)
} else {
@ -782,19 +776,19 @@ impl NockStack {
}
/** Allocate space for a struct in a west frame */
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> AllocResult<*mut T> {
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count)?;
Ok(eigen_pointer as *mut T)
unsafe fn struct_alloc_west<T>(&mut self, count: usize) -> *mut T {
let eigen_pointer = self.raw_alloc_west(word_size_of::<T>() * count);
eigen_pointer as *mut T
}
/** Allocate space for a struct in an east frame */
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> AllocResult<*mut T> {
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count)?;
Ok(eigen_pointer as *mut T)
unsafe fn struct_alloc_east<T>(&mut self, count: usize) -> *mut T {
let eigen_pointer = self.raw_alloc_east(word_size_of::<T>() * count);
eigen_pointer as *mut T
}
/** Allocate space for a struct in a stack frame */
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> AllocResult<*mut T> {
pub unsafe fn struct_alloc<T>(&mut self, count: usize) -> *mut T {
if self.is_west() {
self.struct_alloc_west::<T>(count)
} else {
@ -802,40 +796,40 @@ impl NockStack {
}
}
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom_(
unsafe fn raw_alloc_in_previous_frame_west(&mut self, words: usize) -> *mut u64 {
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::West,
alloc_type: AllocationType::AllocPreviousFrame,
pc: self.pc,
},
words,
)?;
);
// note that the allocation is on the east frame, and thus resembles raw_alloc_east
let alloc = *self.prev_alloc_pointer_pointer();
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).add(words);
Ok(alloc)
alloc
}
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> AllocResult<*mut u64> {
let () = self.alloc_would_oom_(
unsafe fn raw_alloc_in_previous_frame_east(&mut self, words: usize) -> *mut u64 {
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::East,
alloc_type: AllocationType::AllocPreviousFrame,
pc: self.pc,
},
words,
)?;
);
// note that the allocation is on the west frame, and thus resembles raw_alloc_west
*(self.prev_alloc_pointer_pointer()) = (*(self.prev_alloc_pointer_pointer())).sub(words);
Ok(*(self.prev_alloc_pointer_pointer()))
*(self.prev_alloc_pointer_pointer())
}
/** Allocate space in the previous stack frame. This calls pre_copy() first to ensure that the
* stack frame is in cleanup phase, which is the only time we should be allocating in a previous
* frame. */
unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> {
self.pre_copy()?;
unsafe fn raw_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
self.pre_copy();
if self.is_west() {
self.raw_alloc_in_previous_frame_west(words)
} else {
@ -844,21 +838,18 @@ impl NockStack {
}
/** Allocates space in the previous frame for some number of T's. */
pub unsafe fn struct_alloc_in_previous_frame<T>(
&mut self,
count: usize,
) -> AllocResult<*mut T> {
let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count)?;
Ok(res as *mut T)
pub unsafe fn struct_alloc_in_previous_frame<T>(&mut self, count: usize) -> *mut T {
let res = self.raw_alloc_in_previous_frame(word_size_of::<T>() * count);
res as *mut T
}
/** Allocate space for an indirect atom in the previous stack frame. */
unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> AllocResult<*mut u64> {
unsafe fn indirect_alloc_in_previous_frame(&mut self, words: usize) -> *mut u64 {
self.raw_alloc_in_previous_frame(words + 2)
}
/** Allocate space for an alloc::Layout in a stack frame */
unsafe fn layout_alloc(&mut self, layout: Layout) -> AllocResult<*mut u64> {
unsafe fn layout_alloc(&mut self, layout: Layout) -> *mut u64 {
assert!(layout.align() <= 64, "layout alignment must be <= 64");
if self.is_west() {
self.raw_alloc_west((layout.size() + 7) >> 3)
@ -896,15 +887,14 @@ impl NockStack {
* lightweight stack (push(), pop(), top()) are the same regardless of whether
* or not pre_copy() has been called.
* */
unsafe fn pre_copy(&mut self) -> AllocResult<()> {
unsafe fn pre_copy(&mut self) {
// pre_copy is intended to be idempotent, so we don't need to do anything if it's already been called
if !self.pc {
let is_west = self.is_west();
let words = if is_west { RESERVED + 1 } else { RESERVED };
// TODO: pre_copy: Treating pre_copy like a FramePush for OOM checking purposes
// Is this correct?
let () =
self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words)?;
let () = self.alloc_would_oom_(self.get_alloc_config(AllocationType::FramePush), words);
*(self.free_slot(FRAME)) = *(self.slot_pointer(FRAME));
*(self.free_slot(STACK)) = *(self.slot_pointer(STACK));
*(self.free_slot(ALLOC)) = *(self.slot_pointer(ALLOC));
@ -916,22 +906,21 @@ impl NockStack {
self.stack_pointer = self.alloc_pointer.add(words);
}
}
Ok(())
}
unsafe fn copy(&mut self, noun: &mut Noun) -> AllocResult<()> {
unsafe fn copy(&mut self, noun: &mut Noun) {
assert_acyclic!(*noun);
assert_no_forwarding_pointers!(*noun);
assert_no_junior_pointers!(self, *noun);
self.pre_copy()?;
self.pre_copy();
assert!(self.stack_is_empty());
let noun_ptr = noun as *mut Noun;
// Add two slots to the lightweight stack
// Set the first new slot to the noun to be copied
*(self.push::<Noun>()?) = *noun;
*(self.push::<Noun>()) = *noun;
// Set the second new slot to a pointer to the noun being copied. this is the destination pointer, which will change
*(self.push::<*mut Noun>()?) = noun_ptr;
*(self.push::<*mut Noun>()) = noun_ptr;
loop {
if self.stack_is_empty() {
break;
@ -965,7 +954,7 @@ impl NockStack {
Either::Left(mut indirect) => {
// Make space for the atom
let alloc =
self.indirect_alloc_in_previous_frame(indirect.size())?;
self.indirect_alloc_in_previous_frame(indirect.size());
// Indirect atoms can be copied directly
copy_nonoverlapping(
@ -984,16 +973,16 @@ impl NockStack {
Either::Right(mut cell) => {
// Make space for the cell
let alloc =
self.struct_alloc_in_previous_frame::<CellMemory>(1)?;
self.struct_alloc_in_previous_frame::<CellMemory>(1);
// Copy the cell metadata
(*alloc).metadata = (*cell.to_raw_pointer()).metadata;
// Push the tail and the head to the work stack
*(self.push::<Noun>()?) = cell.tail();
*(self.push::<*mut Noun>()?) = &mut (*alloc).tail;
*(self.push::<Noun>()?) = cell.head();
*(self.push::<*mut Noun>()?) = &mut (*alloc).head;
*(self.push::<Noun>()) = cell.tail();
*(self.push::<*mut Noun>()) = &mut (*alloc).tail;
*(self.push::<Noun>()) = cell.head();
*(self.push::<*mut Noun>()) = &mut (*alloc).head;
// Set the forwarding pointer
cell.set_forwarding_pointer(alloc);
@ -1015,7 +1004,6 @@ impl NockStack {
assert_acyclic!(*noun);
assert_no_forwarding_pointers!(*noun);
assert_no_junior_pointers!(self, *noun);
Ok(())
}
// Doesn't need an OOM check, just an assertion. We expect it to panic.
@ -1103,7 +1091,7 @@ impl NockStack {
self.pc = false;
}
pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) -> AllocResult<()> {
pub unsafe fn preserve<T: Preserve>(&mut self, x: &mut T) {
x.preserve(self)
}
@ -1116,12 +1104,12 @@ impl NockStack {
/** Push a frame onto the stack with 0 or more local variable slots. */
/// This computation for num_locals is done in the east/west variants, but roughly speaking it's the input n words + 3 for prev frame alloc/stack/frame pointers
pub fn frame_push(&mut self, num_locals: usize) -> AllocResult<()> {
pub fn frame_push(&mut self, num_locals: usize) {
if self.pc {
panic!("frame_push during cleanup phase is prohibited.");
}
let words = num_locals + RESERVED;
let () = self.alloc_would_oom(AllocationType::FramePush, words)?;
self.alloc_would_oom(AllocationType::FramePush, words);
let current_frame_pointer = self.frame_pointer;
let current_stack_pointer = self.stack_pointer;
@ -1138,7 +1126,6 @@ impl NockStack {
*(self.slot_pointer(STACK)) = current_stack_pointer as u64;
*(self.slot_pointer(ALLOC)) = current_alloc_pointer as u64;
}
Ok(())
}
/** Run a closure inside a frame, popping regardless of the value returned by the closure.
@ -1146,16 +1133,16 @@ impl NockStack {
*
* Note that results allocated on the stack *must* be `preserve()`d by the closure.
*/
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> AllocResult<O>
pub unsafe fn with_frame<F, O>(&mut self, num_locals: usize, f: F) -> O
where
F: FnOnce(&mut NockStack) -> O,
O: Preserve,
{
self.frame_push(num_locals)?;
self.frame_push(num_locals);
let mut ret = f(self);
ret.preserve(self)?;
ret.preserve(self);
self.frame_pop();
Ok(ret)
ret
}
/** Lightweight stack.
@ -1182,7 +1169,7 @@ impl NockStack {
* this violates the _east/_west naming convention somewhat, since e.g.
* a west frame when pc == false has a west-oriented lightweight stack,
* but when pc == true it becomes east-oriented.*/
pub unsafe fn push<T>(&mut self) -> AllocResult<*mut T> {
pub unsafe fn push<T>(&mut self) -> *mut T {
if self.is_west() && !self.pc || !self.is_west() && self.pc {
self.push_west::<T>()
} else {
@ -1191,16 +1178,16 @@ impl NockStack {
}
/// Push onto a west-oriented lightweight stack, moving the stack_pointer.
unsafe fn push_west<T>(&mut self) -> AllocResult<*mut T> {
unsafe fn push_west<T>(&mut self) -> *mut T {
let words = word_size_of::<T>();
let () = self.alloc_would_oom_(
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::West,
alloc_type: AllocationType::Push,
pc: self.pc,
},
words,
)?;
);
let ap = if self.pc {
*(self.prev_alloc_pointer_pointer())
} else {
@ -1219,21 +1206,21 @@ impl NockStack {
);
} else {
self.stack_pointer = new_sp;
Ok(alloc as *mut T)
alloc as *mut T
}
}
/// Push onto an east-oriented ligthweight stack, moving the stack_pointer
unsafe fn push_east<T>(&mut self) -> AllocResult<*mut T> {
unsafe fn push_east<T>(&mut self) -> *mut T {
let words = word_size_of::<T>();
let () = self.alloc_would_oom_(
self.alloc_would_oom_(
Allocation {
orientation: ArenaOrientation::East,
alloc_type: AllocationType::Push,
pc: self.pc,
},
words,
)?;
);
let ap = if self.pc {
*(self.prev_alloc_pointer_pointer())
} else {
@ -1251,7 +1238,7 @@ impl NockStack {
);
} else {
self.stack_pointer = alloc;
Ok(alloc as *mut T)
alloc as *mut T
}
}
@ -1485,15 +1472,15 @@ impl NockStack {
}
impl NounAllocator for NockStack {
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64> {
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
self.indirect_alloc(words)
}
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory> {
unsafe fn alloc_cell(&mut self) -> *mut CellMemory {
self.struct_alloc::<CellMemory>(1)
}
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T> {
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T {
self.struct_alloc::<T>(count)
}
}
@ -1501,17 +1488,16 @@ impl NounAllocator for NockStack {
/// Immutable, acyclic objects which may be copied up the stack
pub trait Preserve {
/// Ensure an object will not be invalidated by popping the NockStack
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()>;
unsafe fn preserve(&mut self, stack: &mut NockStack);
unsafe fn assert_in_stack(&self, stack: &NockStack);
}
impl Preserve for IndirectAtom {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
let size = indirect_raw_size(*self);
let buf = stack.struct_alloc_in_previous_frame::<u64>(size)?;
let buf = stack.struct_alloc_in_previous_frame::<u64>(size);
copy_nonoverlapping(self.to_raw_pointer(), buf, size);
*self = IndirectAtom::from_raw_pointer(buf);
Ok(())
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
stack.assert_noun_in(self.as_atom().as_noun());
@ -1519,15 +1505,14 @@ impl Preserve for IndirectAtom {
}
impl Preserve for Atom {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self.as_either() {
Left(_direct) => {}
Right(mut indirect) => {
indirect.preserve(stack)?;
indirect.preserve(stack);
*self = indirect.as_atom();
}
}
Ok(())
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
stack.assert_noun_in(self.as_noun());
@ -1535,7 +1520,7 @@ impl Preserve for Atom {
}
impl Preserve for Noun {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
stack.copy(self)
}
unsafe fn assert_in_stack(&self, stack: &NockStack) {
@ -1544,14 +1529,13 @@ impl Preserve for Noun {
}
impl Stack for NockStack {
type AllocError = AllocationError;
unsafe fn alloc_layout(&mut self, layout: Layout) -> AllocResult<*mut u64> {
unsafe fn alloc_layout(&mut self, layout: Layout) -> *mut u64 {
self.layout_alloc(layout)
}
}
impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
unsafe fn preserve(&mut self, stack: &mut NockStack) -> AllocResult<()> {
unsafe fn preserve(&mut self, stack: &mut NockStack) {
match self.as_mut() {
Ok(t_ref) => t_ref.preserve(stack),
Err(e_ref) => e_ref.preserve(stack),
@ -1567,25 +1551,25 @@ impl<T: Preserve, E: Preserve> Preserve for Result<T, E> {
}
impl Preserve for bool {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
Ok(())
}
unsafe fn preserve(&mut self, _: &mut NockStack) {}
unsafe fn assert_in_stack(&self, _: &NockStack) {}
}
impl Preserve for u32 {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
Ok(())
}
unsafe fn preserve(&mut self, _: &mut NockStack) {}
unsafe fn assert_in_stack(&self, _: &NockStack) {}
}
impl Preserve for usize {
unsafe fn preserve(&mut self, _: &mut NockStack) {}
unsafe fn assert_in_stack(&self, _: &NockStack) {}
}
impl Preserve for AllocationError {
unsafe fn preserve(&mut self, _: &mut NockStack) -> AllocResult<()> {
Ok(())
}
unsafe fn preserve(&mut self, _: &mut NockStack) {}
unsafe fn assert_in_stack(&self, _: &NockStack) {}
}
@ -1593,6 +1577,7 @@ impl Preserve for AllocationError {
#[cfg(test)]
mod test {
use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
use super::*;
use crate::jets::cold::test::{make_noun_list, make_test_stack};
@ -1613,9 +1598,9 @@ mod test {
let vec = Vec::from_iter(0..item_count);
let items = vec.iter().map(|&x| D(x)).collect::<Vec<Noun>>();
let slice = vec.as_slice();
let noun_list = make_noun_list(&mut stack, slice)?;
let noun_list = make_noun_list(&mut stack, slice);
assert!(!noun_list.0.is_null());
let noun = noun_list.into_noun(&mut stack)?;
let noun = noun_list.into_noun(&mut stack);
let new_noun_list: NounList =
<NounList as Nounable>::from_noun::<NockStack>(&mut stack, &noun)?;
let mut tracking_item_count = 0;
@ -1642,9 +1627,9 @@ mod test {
const FAILS: u64 = 73;
const STACK_SIZE: usize = 512;
let should_fail_to_alloc = test_noun_list_alloc_fn(STACK_SIZE, FAILS);
let should_fail_to_alloc = catch_unwind(|| test_noun_list_alloc_fn(STACK_SIZE, FAILS));
assert!(should_fail_to_alloc
.map_err(|err| err.is_alloc_error())
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
let should_succeed = test_noun_list_alloc_fn(STACK_SIZE, PASSES);
assert!(should_succeed.is_ok());
@ -1654,32 +1639,36 @@ mod test {
#[test]
fn test_frame_push() {
// fails at 100, passes at 99, top_slots default to 100?
const PASSES: usize = 502;
const FAILS: usize = 503;
const PASSES: usize = 503;
const FAILS: usize = 504;
const STACK_SIZE: usize = 512;
let mut stack = make_test_stack(STACK_SIZE);
let frame_push_res = stack.frame_push(FAILS);
assert!(frame_push_res.is_err());
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(FAILS)));
assert!(frame_push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
let mut stack = make_test_stack(STACK_SIZE);
let frame_push_res = stack.frame_push(PASSES);
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(PASSES)));
assert!(frame_push_res.is_ok());
}
// cargo test -p sword test_stack_push -- --nocapture
#[test]
fn test_stack_push() {
const PASSES: usize = 505;
const PASSES: usize = 506;
const STACK_SIZE: usize = 512;
let mut stack = make_test_stack(STACK_SIZE);
let mut counter = 0;
// Fails at 102, probably because top_slots is 100?
while counter < PASSES {
let push_res = unsafe { stack.push::<u64>() };
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
counter += 1;
}
let push_res = unsafe { stack.push::<u64>() };
assert!(push_res.is_err());
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
}
// cargo test -p sword test_frame_and_stack_push -- --nocapture
@ -1690,27 +1679,31 @@ mod test {
let mut stack = make_test_stack(STACK_SIZE);
let mut counter = 0;
while counter < SUCCESS_PUSHES {
let frame_push_res = stack.frame_push(1);
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
assert!(
frame_push_res.is_ok(),
"Failed to frame_push, counter: {}",
counter
);
let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok(), "Failed to push, counter: {}", counter);
counter += 1;
}
let frame_push_res = stack.frame_push(1);
assert!(frame_push_res.is_err());
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(1)));
assert!(frame_push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
// a single stack u64 push won't cause an error but a frame push will
let push_res = unsafe { stack.push::<u64>() };
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<u64>() }));
assert!(push_res.is_ok());
// pushing an array of 1 u64 will NOT cause an error
let push_res = unsafe { stack.push::<[u64; 1]>() };
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 1]>() }));
assert!(push_res.is_ok());
// pushing an array of 2 u64s WILL cause an error
let push_res = unsafe { stack.push::<[u64; 2]>() };
assert!(push_res.is_err());
let push_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.push::<[u64; 2]>() }));
assert!(push_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err());
}
// cargo test -p sword test_slot_pointer -- --nocapture
@ -1721,12 +1714,13 @@ mod test {
const SLOT_POINTERS: usize = 32;
let mut stack = make_test_stack(STACK_SIZE);
// let push_res: Result<*mut u64, AllocationError> = unsafe { stack.push::<u64>() };
let frame_push_res = stack.frame_push(SLOT_POINTERS);
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(SLOT_POINTERS)));
assert!(frame_push_res.is_ok());
let mut counter = 0;
while counter < SLOT_POINTERS + RESERVED {
println!("counter: {counter}");
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) };
let slot_pointer_res =
catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
assert!(
slot_pointer_res.is_ok(),
"Failed to slot_pointer, counter: {}",
@ -1734,8 +1728,11 @@ mod test {
);
counter += 1;
}
let slot_pointer_res = unsafe { stack.slot_pointer_(counter) };
assert!(slot_pointer_res.is_err())
let slot_pointer_res =
catch_unwind(AssertUnwindSafe(|| unsafe { stack.slot_pointer_(counter) }));
assert!(slot_pointer_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err())
}
// cargo test -p sword test_prev_alloc -- --nocapture
@ -1743,18 +1740,20 @@ mod test {
#[test]
fn test_prev_alloc() {
const STACK_SIZE: usize = 512;
const SUCCESS_ALLOCS: usize = 502;
const SUCCESS_ALLOCS: usize = 503;
let mut stack = make_test_stack(STACK_SIZE);
println!("\n############## frame push \n");
let frame_push_res = stack.frame_push(0);
let frame_push_res = catch_unwind(AssertUnwindSafe(|| stack.frame_push(0)));
assert!(frame_push_res.is_ok());
let pre_copy_res = unsafe { stack.pre_copy() };
let pre_copy_res = catch_unwind(AssertUnwindSafe(|| unsafe { stack.pre_copy() }));
assert!(pre_copy_res.is_ok());
let mut counter = 0;
while counter < SUCCESS_ALLOCS {
println!("counter: {counter}");
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) };
let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
stack.raw_alloc_in_previous_frame(1)
}));
assert!(
prev_alloc_res.is_ok(),
"Failed to prev_alloc, counter: {}",
@ -1763,11 +1762,14 @@ mod test {
counter += 1;
}
println!("### This next raw_alloc_in_previous_frame should fail ###\n");
let prev_alloc_res = unsafe { stack.raw_alloc_in_previous_frame(1) };
let prev_alloc_res = catch_unwind(AssertUnwindSafe(|| unsafe {
stack.raw_alloc_in_previous_frame(1)
}));
assert!(
prev_alloc_res.is_err(),
"Didn't get expected alloc error, res: {:#?}",
prev_alloc_res
.map_err(|err| err.is::<AllocationError>())
.unwrap_err(),
"Didn't get expected alloc error",
);
}
}

View File

@ -1,6 +1,8 @@
use crate::assert_acyclic;
use crate::assert_no_forwarding_pointers;
use crate::assert_no_junior_pointers;
use crate::mem::*;
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
use either::Either::*;
use murmur3::murmur3_32_of_slice;
@ -126,67 +128,74 @@ pub fn mug_u32_one(noun: Noun) -> Option<u32> {
}
}
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> AllocResult<u32> {
pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
if let Some(mug) = get_mug(noun) {
return Ok(mug);
return mug;
}
assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun);
stack.frame_push(0);
unsafe {
stack.with_frame(0, |stack| {
*(stack.push()?) = noun;
loop {
if stack.stack_is_empty() {
break;
} else {
let noun: Noun = *(stack.top());
match noun.as_either_direct_allocated() {
Left(_direct) => {
*(stack.push()) = noun;
}
loop {
if stack.stack_is_empty() {
break;
} else {
let noun: Noun = unsafe { *(stack.top()) };
match noun.as_either_direct_allocated() {
Left(_direct) => {
unsafe {
stack.pop::<Noun>();
}
continue;
} // no point in calculating a direct mug here as we wont cache it
Right(allocated) => match allocated.get_cached_mug() {
Some(_mug) => {
unsafe {
stack.pop::<Noun>();
}
continue;
}
None => match allocated.as_either() {
Left(indirect) => unsafe {
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
stack.pop::<Noun>();
continue;
} // no point in calculating a direct mug here as we wont cache it
Right(allocated) => match allocated.get_cached_mug() {
Some(_mug) => {
stack.pop::<Noun>();
continue;
}
None => match allocated.as_either() {
Left(indirect) => {
set_mug(allocated, calc_atom_mug_u32(indirect.as_atom()));
},
Right(cell) => unsafe {
match (get_mug(cell.head()), get_mug(cell.tail())) {
(Some(head_mug), Some(tail_mug)) => {
set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug));
stack.pop::<Noun>();
continue;
}
Right(cell) => match (get_mug(cell.head()), get_mug(cell.tail())) {
(Some(head_mug), Some(tail_mug)) => {
set_mug(allocated, calc_cell_mug_u32(head_mug, tail_mug));
stack.pop::<Noun>();
continue;
}
_ => {
*(stack.push()?) = cell.tail();
*(stack.push()?) = cell.head();
continue;
}
},
},
_ => {
*(stack.push()) = cell.tail();
*(stack.push()) = cell.head();
continue;
}
}
},
}
}
},
},
}
assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun);
// TODO: Purge this expect.
Ok(get_mug(noun).expect("Noun should have a mug once it is mugged."))
})?
}
}
unsafe {
stack.frame_pop();
}
assert_acyclic!(noun);
assert_no_forwarding_pointers!(noun);
assert_no_junior_pointers!(stack, noun);
get_mug(noun).expect("Noun should have a mug once it is mugged.")
}
pub fn mug(stack: &mut NockStack, noun: Noun) -> AllocResult<DirectAtom> {
Ok(unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun)? as u64) })
pub fn mug(stack: &mut NockStack, noun: Noun) -> DirectAtom {
unsafe { DirectAtom::new_unchecked(mug_u32(stack, noun) as u64) }
}

View File

@ -1,307 +0,0 @@
use crate::interpreter::Slogger;
/** Newt: IPC to the king
*
* This manages an IPC connection to the king over stdin and stdout. The protocol is jammed nouns,
* with the following schema:
*
* |%
* :: +writ: from king to serf
* ::
* +$ writ
* $% $: %live
* $% [%cram eve=@]
* [%exit cod=@]
* [%save eve=@]
* [%meld ~]
* [%pack ~]
* == ==
* [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [%beam @tas beam]))
* [%play eve=@ lit=(list ?((pair @da ovum) *))]
* [%work mil=@ job=(pair @da ovum)]
* ==
* :: +plea: from serf to king
* ::
* +$ plea
* $% [%live ~]
* [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@]
* [%slog pri=@ tank]
* [%flog cord]
* $: %peek
* $% [%done dat=(unit (cask))]
* [%bail dud=goof]
* == ==
* $: %play
* $% [%done mug=@]
* [%bail eve=@ mug=@ dud=goof]
* == ==
* $: %work
* $% [%done eve=@ mug=@ fec=(list ovum)]
* [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)]
* [%bail lud=(list goof)]
* == ==
* ==
* --
*
* NB: stdin and stdout are generally buffered, and there's no officially supported way to work
* around that: https://github.com/rust-lang/rust/issues/58326.
*
* We use stdin and stdout with File::from_raw_fd(0) and File::from_raw_fd(1), which seems to get
* around this. We tested that using io::Stdout requires flushing while this doesn't, but we
* haven't tested the same for stdin.
*
* It's important to not use io::Stdin and io::Stdout directly. All printfs should use stderr.
*/
use crate::mem::{AllocResult, NockStack};
use crate::noun::{IndirectAtom, Noun, D, T};
use crate::serialization::{cue, jam};
use either::Either;
use std::io::{Read, Write};
use std::os::unix::prelude::FromRawFd;
use std::pin::Pin;
use std::ptr::copy_nonoverlapping;
use std::slice::from_raw_parts_mut;
use sword_macros::tas;
crate::gdb!();
pub struct Newt {
input: std::fs::File,
output: std::fs::File,
}
impl Newt {
pub fn new_from_files(input: std::fs::File, output: std::fs::File) -> Newt {
Newt { input, output }
}
pub fn new() -> Newt {
Newt {
input: unsafe { std::fs::File::from_raw_fd(0) },
output: unsafe { std::fs::File::from_raw_fd(1) },
}
}
pub fn new_mock() -> Newt {
Newt {
input: std::fs::File::open("/dev/null").expect("newt: could not open /dev/null"),
output: std::fs::File::options()
.read(true)
.write(true)
.open("/dev/null")
.expect("newt: could not open /dev/null"),
}
}
/** Write a noun to the newt.
*
* NB: we write 64-bit words, while vere writes bytes. The extra zero bytes shouldn't be a
* problem.
*/
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) -> AllocResult<()> {
let atom = jam(stack, noun)?;
let size = atom.size() << 3;
// XX: checked add?
let buf = unsafe { from_raw_parts_mut(stack.struct_alloc::<u8>(size + 5)?, size + 5) };
buf[0] = 0u8;
buf[1] = size as u8;
buf[2] = (size >> 8) as u8;
buf[3] = (size >> 16) as u8;
buf[4] = (size >> 24) as u8;
match atom.as_either() {
Either::Left(direct) => unsafe {
copy_nonoverlapping(
&direct.data() as *const u64 as *const u8,
buf.as_mut_ptr().add(5),
size,
);
},
Either::Right(indirect) => unsafe {
// REVIEW: is this safe/the right way to do this?
copy_nonoverlapping(
indirect.data_pointer() as *const u8,
buf.as_mut_ptr().add(5),
size,
);
},
};
self.output.write_all(buf).unwrap();
Ok(())
}
/** Send %ripe, the first event.
*
* eve = event number
* mug = mug of Arvo after above event
*/
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) -> AllocResult<()> {
let version = T(
stack,
&[
D(1), // newt protocol
D(139), // hoon kelvin
D(4), // nock kelvin
],
)?;
let ripe = T(stack, &[D(tas!(b"ripe")), version, D(eve), D(mug)])?;
self.write_noun(stack, ripe)?;
Ok(())
}
/** Send %live, acknowledging. */
pub fn live(&mut self, stack: &mut NockStack) -> AllocResult<()> {
let live = T(stack, &[D(tas!(b"live")), D(0)])?;
self.write_noun(stack, live)?;
Ok(())
}
/** Send %peek %done, successfully scried. */
pub fn peek_done(&mut self, stack: &mut NockStack, dat: Noun) -> AllocResult<()> {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"done")), dat])?;
self.write_noun(stack, peek)?;
Ok(())
}
/** Send %peek %bail, unsuccessfully scried.
*
* dud = goof
*/
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) -> AllocResult<()> {
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud])?;
self.write_noun(stack, peek)?;
Ok(())
}
/** Send %play %done, successfully replayed events.
*
* mug = mug of Arvo after full replay
*/
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) -> AllocResult<()> {
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)])?;
self.write_noun(stack, play)?;
Ok(())
}
/** Send %play %bail, failed to replay events.
*
* eve = last good event number
* mug = mug of Arvo after above event
* dud = goof when trying next event
*/
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) -> AllocResult<()> {
let play = T(
stack,
&[D(tas!(b"play")), D(tas!(b"bail")), D(eve), D(mug), dud],
)?;
self.write_noun(stack, play)?;
Ok(())
}
/** Send %work %done, successfully ran event.
*
* eve = new event number
* mug = mug of Arvo after above event
* fec = list of effects
*/
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) -> AllocResult<()> {
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"done")), D(eve), D(mug), fec],
)?;
self.write_noun(stack, work)?;
Ok(())
}
/** Send %work %swap, successfully replaced failed event.
*
* eve = new event number
* mug = mug of Arvo after above event
* job = event performed instead of the one given to serf by king
* fec = list of effects
*/
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) -> AllocResult<()> {
let work = T(
stack,
&[D(tas!(b"work")), D(tas!(b"swap")), D(eve), D(mug), job, fec],
)?;
self.write_noun(stack, work)?;
Ok(())
}
pub fn slogger(&self) -> Result<Pin<Box<dyn Slogger + Unpin>>, std::io::Error> {
let input = self.input.try_clone()?;
let output = self.output.try_clone()?;
Ok(std::boxed::Box::pin(NewtSlogger(Newt { input, output })))
}
/** Send %work %bail, failed to run event.
*
* lud = list of goof
*/
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) -> AllocResult<()> {
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud])?;
self.write_noun(stack, work)?;
Ok(())
}
/** Fetch next message. */
pub fn next(&mut self, stack: &mut NockStack) -> AllocResult<Option<Noun>> {
let mut header: Vec<u8> = vec![0; 5];
if let Err(err) = self.input.read_exact(&mut header) {
if err.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(None);
} else {
panic!("Newt::next: Error reading header: {}", err);
}
}
let byte_len = u32::from_le_bytes([header[1], header[2], header[3], header[4]]) as usize;
let atom = unsafe {
let (mut atom, dest) = IndirectAtom::new_raw_mut_bytes(stack, byte_len)?;
if let Err(err) = self.input.read_exact(dest) {
if err.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(None);
} else {
panic!("Newt::next: Error reading body: {}", err);
}
}
atom.normalize_as_atom()
};
Ok(Some(cue(stack, atom).expect("Newt::next: bad jammed noun")))
}
}
impl Slogger for Newt {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank])?;
self.write_noun(stack, slog)?;
Ok(())
}
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
let flog = T(stack, &[D(tas!(b"flog")), cord])?;
self.write_noun(stack, flog)?;
Ok(())
}
}
impl Default for Newt {
fn default() -> Self {
Self::new()
}
}
struct NewtSlogger(Newt);
impl Slogger for NewtSlogger {
fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) -> AllocResult<()> {
self.0.slog(stack, pri, tank)?;
Ok(())
}
fn flog(&mut self, stack: &mut NockStack, cord: Noun) -> AllocResult<()> {
self.0.flog(stack, cord)?;
Ok(())
}
}

View File

@ -1,4 +1,4 @@
use crate::mem::{word_size_of, AllocResult, NockStack};
use crate::mem::{word_size_of, NockStack};
use bitvec::prelude::{BitSlice, Lsb0};
use either::{Either, Left, Right};
use ibig::{Stack, UBig};
@ -155,7 +155,7 @@ fn is_cell(noun: u64) -> bool {
}
/** A noun-related error. */
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Error {
/** Expected type [`Allocated`]. */
NotAllocated,
@ -169,7 +169,6 @@ pub enum Error {
NotIndirectAtom,
/** The value can't be represented by the given type. */
NotRepresentable,
AllocationError(crate::mem::AllocationError),
}
impl error::Error for Error {}
@ -183,17 +182,10 @@ impl std::fmt::Display for Error {
Error::NotDirectAtom => f.write_str("not a direct atom"),
Error::NotIndirectAtom => f.write_str("not an indirect atom"),
Error::NotRepresentable => f.write_str("unrepresentable value"),
Error::AllocationError(_) => f.write_str("allocation error"),
}
}
}
impl From<crate::mem::AllocationError> for Error {
fn from(allocation_error: crate::mem::AllocationError) -> Self {
Error::AllocationError(allocation_error)
}
}
impl From<Error> for () {
fn from(_: Error) -> Self {}
}
@ -308,18 +300,18 @@ pub const fn D(n: u64) -> Noun {
}
#[allow(non_snake_case)]
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Noun> {
Ok(Cell::new_tuple(allocator, tup)?.as_noun())
pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
Cell::new_tuple(allocator, tup).as_noun()
}
/// Create $tape Noun from ASCII string
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> AllocResult<Noun> {
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> Noun {
// XX: Needs unit tests
let mut res = D(0);
for c in text.bytes().rev() {
res = T(allocator, &[D(c as u64), res])?
res = T(allocator, &[D(c as u64), res])
}
Ok(res)
res
}
/** An indirect atom.
@ -380,10 +372,10 @@ impl IndirectAtom {
allocator: &mut A,
size: usize,
data: *const u64,
) -> AllocResult<Self> {
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size)?;
) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut(allocator, size);
ptr::copy_nonoverlapping(data, buffer, size);
Ok(*(indirect.normalize()))
*(indirect.normalize())
}
/** Make an indirect atom by copying from other memory.
@ -394,16 +386,13 @@ impl IndirectAtom {
allocator: &mut A,
size: usize,
data: *const u8,
) -> AllocResult<Self> {
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size)?;
) -> Self {
let (mut indirect, buffer) = Self::new_raw_mut_bytes(allocator, size);
ptr::copy_nonoverlapping(data, buffer.as_mut_ptr(), size);
Ok(*(indirect.normalize()))
*(indirect.normalize())
}
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(
allocator: &mut A,
data: &[u8],
) -> AllocResult<Self> {
pub unsafe fn new_raw_bytes_ref<A: NounAllocator>(allocator: &mut A, data: &[u8]) -> Self {
IndirectAtom::new_raw_bytes(allocator, data.len(), data.as_ptr())
}
@ -414,12 +403,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut<A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> AllocResult<(Self, *mut u64)> {
) -> (Self, *mut u64) {
debug_assert!(size > 0);
let buffer = allocator.alloc_indirect(size)?;
let buffer = allocator.alloc_indirect(size);
*buffer = 0;
*buffer.add(1) = size as u64;
Ok((Self::from_raw_pointer(buffer), buffer.add(2)))
(Self::from_raw_pointer(buffer), buffer.add(2))
}
/** Make an indirect atom that can be written into, and zero the whole data buffer.
@ -429,10 +418,10 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_zeroed<A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> AllocResult<(Self, *mut u64)> {
let allocation = Self::new_raw_mut(allocator, size)?;
) -> (Self, *mut u64) {
let allocation = Self::new_raw_mut(allocator, size);
ptr::write_bytes(allocation.1, 0, size);
Ok(allocation)
allocation
}
/** Make an indirect atom that can be written into as a bitslice. The constraints of
@ -441,12 +430,12 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bitslice<'a, A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> AllocResult<(Self, &'a mut BitSlice<u64, Lsb0>)> {
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size)?;
Ok((
) -> (Self, &'a mut BitSlice<u64, Lsb0>) {
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, size);
(
noun,
BitSlice::from_slice_mut(from_raw_parts_mut(ptr, size)),
))
)
}
/** Make an indirect atom that can be written into as a slice of bytes. The constraints of
@ -457,19 +446,19 @@ impl IndirectAtom {
pub unsafe fn new_raw_mut_bytes<'a, A: NounAllocator>(
allocator: &mut A,
size: usize,
) -> AllocResult<(Self, &'a mut [u8])> {
) -> (Self, &'a mut [u8]) {
let word_size = (size + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
Ok((noun, from_raw_parts_mut(ptr as *mut u8, size)))
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
(noun, from_raw_parts_mut(ptr as *mut u8, size))
}
/// Create an indirect atom backed by a fixed-size array
pub unsafe fn new_raw_mut_bytearray<'a, const N: usize, A: NounAllocator>(
allocator: &mut A,
) -> AllocResult<(Self, &'a mut [u8; N])> {
) -> (Self, &'a mut [u8; N]) {
let word_size = (std::mem::size_of::<[u8; N]>() + 7) >> 3;
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size)?;
Ok((noun, &mut *(ptr as *mut [u8; N])))
let (noun, ptr) = Self::new_raw_mut_zeroed(allocator, word_size);
(noun, &mut *(ptr as *mut [u8; N]))
}
/** Size of an indirect atom in 64-bit words */
@ -519,7 +508,7 @@ impl IndirectAtom {
BitSlice::from_slice_mut(self.as_mut_slice())
}
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
pub fn as_ubig<S: Stack>(&self, stack: &mut S) -> UBig {
UBig::from_le_bytes_stack(stack, self.as_bytes())
}
@ -649,34 +638,32 @@ impl Cell {
}
}
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> AllocResult<Cell> {
pub fn new<T: NounAllocator>(allocator: &mut T, head: Noun, tail: Noun) -> Cell {
unsafe {
let (cell, memory) = Self::new_raw_mut(allocator)?;
let (cell, memory) = Self::new_raw_mut(allocator);
(*memory).head = head;
(*memory).tail = tail;
Ok(cell)
cell
}
}
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> AllocResult<Cell> {
pub fn new_tuple<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Cell {
if tup.len() < 2 {
panic!("Cannot create tuple with fewer than 2 elements");
}
let len = tup.len();
let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1])?;
let mut cell = Cell::new(allocator, tup[len - 2], tup[len - 1]);
for i in (0..len - 2).rev() {
cell = Cell::new(allocator, tup[i], cell.as_noun())?;
cell = Cell::new(allocator, tup[i], cell.as_noun());
}
Ok(cell)
cell
}
pub unsafe fn new_raw_mut<A: NounAllocator>(
allocator: &mut A,
) -> AllocResult<(Cell, *mut CellMemory)> {
let memory = allocator.alloc_cell()?;
pub unsafe fn new_raw_mut<A: NounAllocator>(allocator: &mut A) -> (Cell, *mut CellMemory) {
let memory = allocator.alloc_cell();
(*memory).metadata = 0;
Ok((Self::from_raw_pointer(memory), memory))
(Self::from_raw_pointer(memory), memory)
}
pub fn head(&self) -> Noun {
@ -761,21 +748,20 @@ pub union Atom {
}
impl Atom {
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> AllocResult<Atom> {
let res = if value <= DIRECT_MAX {
pub fn new<A: NounAllocator>(allocator: &mut A, value: u64) -> Atom {
if value <= DIRECT_MAX {
unsafe { DirectAtom::new_unchecked(value).as_atom() }
} else {
unsafe { IndirectAtom::new_raw(allocator, 1, &value)?.as_atom() }
};
Ok(res)
unsafe { IndirectAtom::new_raw(allocator, 1, &value).as_atom() }
}
}
// to_le_bytes and new_raw are copies. We should be able to do this completely without copies
// if we integrate with ibig properly.
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> AllocResult<Atom> {
pub fn from_ubig<A: NounAllocator>(allocator: &mut A, big: &UBig) -> Atom {
let bit_size = big.bit_len();
let buffer = big.to_le_bytes_stack();
let atom = if bit_size < 64 {
if bit_size < 64 {
let mut value = 0u64;
for i in (0..bit_size).step_by(8) {
value |= (buffer[i / 8] as u64) << i;
@ -783,9 +769,8 @@ impl Atom {
unsafe { DirectAtom::new_unchecked(value).as_atom() }
} else {
let byte_size = (big.bit_len() + 7) >> 3;
unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr())?.as_atom() }
};
Ok(atom)
unsafe { IndirectAtom::new_raw_bytes(allocator, byte_size, buffer.as_ptr()).as_atom() }
}
}
pub fn is_direct(&self) -> bool {
@ -882,13 +867,12 @@ impl Atom {
}
}
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> core::result::Result<UBig, S::AllocError> {
let ubig = if self.is_indirect() {
unsafe { self.indirect.as_ubig(stack)? }
pub fn as_ubig<S: Stack>(self, stack: &mut S) -> UBig {
if self.is_indirect() {
unsafe { self.indirect.as_ubig(stack) }
} else {
unsafe { self.direct.as_ubig(stack) }
};
Ok(ubig)
}
}
pub fn direct(&self) -> Option<DirectAtom> {
@ -1314,13 +1298,13 @@ pub trait NounAllocator: Sized {
*
* This should allocate *two more* `u64`s than `words` to make space for the size and metadata
*/
unsafe fn alloc_indirect(&mut self, words: usize) -> AllocResult<*mut u64>;
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64;
/** Allocate memory for a cell */
unsafe fn alloc_cell(&mut self) -> AllocResult<*mut CellMemory>;
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
/** Allocate space for a struct in a stack frame */
unsafe fn alloc_struct<T>(&mut self, count: usize) -> AllocResult<*mut T>;
unsafe fn alloc_struct<T>(&mut self, count: usize) -> *mut T;
}
/**

View File

@ -1,7 +1,7 @@
use crate::hamt::MutHamt;
use crate::interpreter::Error::{self, *};
use crate::interpreter::Mote::*;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
use bitvec::prelude::{BitSlice, Lsb0};
use either::Either::{Left, Right};
@ -103,13 +103,13 @@ enum CueStackEntry {
/// # Returns
/// A Result containing either the deserialized Noun or an Error
pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Result<Noun, Error> {
let backref_map = MutHamt::<Noun>::new(stack)?;
let backref_map = MutHamt::<Noun>::new(stack);
let mut result = D(0);
let mut cursor = 0;
let res = unsafe {
unsafe {
stack.with_frame(0, |stack: &mut NockStack| {
*(stack.push::<CueStackEntry>()?) =
*(stack.push::<CueStackEntry>()) =
CueStackEntry::DestinationPointer(&mut result as *mut Noun);
loop {
if stack.stack_is_empty() {
@ -125,43 +125,42 @@ pub fn cue_bitslice(stack: &mut NockStack, buffer: &BitSlice<u64, Lsb0>) -> Resu
// 11 tag: backref
if next_bit(&mut cursor, buffer) {
let mut backref_noun =
Atom::new(stack, rub_backref(&mut cursor, buffer)?)?.as_noun();
Atom::new(stack, rub_backref(&mut cursor, buffer)?).as_noun();
*dest_ptr = backref_map
.lookup(stack, &mut backref_noun)?
.lookup(stack, &mut backref_noun)
.ok_or(Deterministic(Exit, D(0)))?;
} else {
// 10 tag: cell
let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack)?;
let (cell, cell_mem_ptr) = Cell::new_raw_mut(stack);
*dest_ptr = cell.as_noun();
let mut backref_atom =
Atom::new(stack, (cursor - 2) as u64)?.as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?;
*(stack.push()?) = CueStackEntry::BackRef(
Atom::new(stack, (cursor - 2) as u64).as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr);
*(stack.push()) = CueStackEntry::BackRef(
cursor as u64 - 2,
dest_ptr as *const Noun,
);
*(stack.push()?) =
*(stack.push()) =
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).tail);
*(stack.push()?) =
*(stack.push()) =
CueStackEntry::DestinationPointer(&mut (*cell_mem_ptr).head);
}
} else {
// 0 tag: atom
let backref: u64 = (cursor - 1) as u64;
*dest_ptr = rub_atom(stack, &mut cursor, buffer)?.as_noun();
let mut backref_atom = Atom::new(stack, backref)?.as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr)?;
let mut backref_atom = Atom::new(stack, backref).as_noun();
backref_map.insert(stack, &mut backref_atom, *dest_ptr);
}
}
CueStackEntry::BackRef(backref, noun_ptr) => {
let mut backref_atom = Atom::new(stack, backref)?.as_noun();
backref_map.insert(stack, &mut backref_atom, *noun_ptr)?
let mut backref_atom = Atom::new(stack, backref).as_noun();
backref_map.insert(stack, &mut backref_atom, *noun_ptr)
}
}
}
})?
};
res
})
}
}
/// Deserialize a noun from an Atom
@ -236,7 +235,7 @@ fn rub_atom(
} else {
// Need an indirect atom
let wordsize = (size + 63) >> 6;
let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize)? };
let (mut atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, wordsize) };
slice[0..bits.len()].copy_from_bitslice(bits);
debug_assert!(atom.size() > 0);
unsafe { Ok(atom.normalize_as_atom()) }
@ -273,71 +272,79 @@ struct JamState<'a> {
/// Corresponds to ++jam in the hoon stdlib.
///
/// Implements a compact encoding scheme for nouns, with backreferences for shared structures.
pub fn jam(stack: &mut NockStack, noun: Noun) -> AllocResult<Atom> {
let backref_map = MutHamt::new(stack)?;
pub fn jam(stack: &mut NockStack, noun: Noun) -> Atom {
let backref_map = MutHamt::new(stack);
let size = 8;
let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size)? };
let (atom, slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(stack, size) };
let mut state = JamState {
cursor: 0,
size,
atom,
slice,
};
stack.frame_push(0);
unsafe {
stack.with_frame(0, |stack| {
*(stack.push::<Noun>()?) = noun;
'jam: loop {
if stack.stack_is_empty() {
break;
} else {
let mut noun = *(stack.top::<Noun>());
if let Some(backref) = backref_map.lookup(stack, &mut noun)? {
match noun.as_either_atom_cell() {
Left(atom) => {
let atom_size = met0_usize(atom);
let backref_size = met0_u64_to_usize(backref);
if atom_size <= backref_size {
jam_atom(stack, &mut state, atom)?;
} else {
jam_backref(stack, &mut state, backref)?;
}
}
Right(_cell) => {
jam_backref(stack, &mut state, backref)?;
}
}
stack.pop::<Noun>();
continue 'jam;
};
backref_map.insert(stack, &mut noun, state.cursor as u64)?;
match noun.as_either_atom_cell() {
Left(atom) => {
jam_atom(stack, &mut state, atom)?;
stack.pop::<Noun>();
continue;
}
Right(cell) => {
jam_cell(stack, &mut state)?;
stack.pop::<Noun>();
*(stack.push::<Noun>()?) = cell.tail();
*(stack.push::<Noun>()?) = cell.head();
continue;
*(stack.push::<Noun>()) = noun;
};
'jam: loop {
if stack.stack_is_empty() {
break;
} else {
let mut noun = unsafe { *(stack.top::<Noun>()) };
if let Some(backref) = backref_map.lookup(stack, &mut noun) {
match noun.as_either_atom_cell() {
Left(atom) => {
let atom_size = met0_usize(atom);
let backref_size = met0_u64_to_usize(backref);
if atom_size <= backref_size {
jam_atom(stack, &mut state, atom);
} else {
jam_backref(stack, &mut state, backref);
}
}
Right(_cell) => {
jam_backref(stack, &mut state, backref);
}
}
unsafe {
stack.pop::<Noun>();
};
continue 'jam;
};
backref_map.insert(stack, &mut noun, state.cursor as u64);
match noun.as_either_atom_cell() {
Left(atom) => {
jam_atom(stack, &mut state, atom);
unsafe {
stack.pop::<Noun>();
};
continue;
}
Right(cell) => {
jam_cell(stack, &mut state);
unsafe {
stack.pop::<Noun>();
*(stack.push::<Noun>()) = cell.tail();
*(stack.push::<Noun>()) = cell.head();
};
continue;
}
}
let result = state.atom.normalize_as_atom();
Ok(result)
})?
}
}
unsafe {
let mut result = state.atom.normalize_as_atom();
stack.preserve(&mut result);
stack.frame_pop();
result
}
}
/// Serialize an atom into the jam state
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<()> {
fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) {
loop {
if state.cursor + 1 > state.slice.len() {
double_atom_size(traversal, state)?;
double_atom_size(traversal, state);
} else {
break;
}
@ -345,20 +352,19 @@ fn jam_atom(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Allo
state.slice.set(state.cursor, false); // 0 tag for atom
state.cursor += 1;
loop {
if let Ok(()) = mat(traversal, state, atom)? {
if let Ok(()) = mat(traversal, state, atom) {
break;
} else {
double_atom_size(traversal, state)?;
double_atom_size(traversal, state);
}
}
Ok(())
}
/// Serialize a cell into the jam state
fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> {
fn jam_cell(traversal: &mut NockStack, state: &mut JamState) {
loop {
if state.cursor + 2 > state.slice.len() {
double_atom_size(traversal, state)?;
double_atom_size(traversal, state);
} else {
break;
}
@ -366,14 +372,13 @@ fn jam_cell(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()>
state.slice.set(state.cursor, true); // 1 bit
state.slice.set(state.cursor + 1, false); // 0 bit, forming 10 tag for cell
state.cursor += 2;
Ok(())
}
/// Serialize a backreference into the jam state
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) -> AllocResult<()> {
fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) {
loop {
if state.cursor + 2 > state.slice.len() {
double_atom_size(traversal, state)?;
double_atom_size(traversal, state);
} else {
break;
}
@ -381,46 +386,44 @@ fn jam_backref(traversal: &mut NockStack, state: &mut JamState, backref: u64) ->
state.slice.set(state.cursor, true); // 1 bit
state.slice.set(state.cursor + 1, true); // 1 bit, forming 11 tag for backref
state.cursor += 2;
let backref_atom = Atom::new(traversal, backref)?;
let backref_atom = Atom::new(traversal, backref);
loop {
if let Ok(()) = mat(traversal, state, backref_atom)? {
if let Ok(()) = mat(traversal, state, backref_atom) {
break;
} else {
double_atom_size(traversal, state)?;
double_atom_size(traversal, state);
}
}
Ok(())
}
/// Double the size of the atom in the jam state
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) -> AllocResult<()> {
fn double_atom_size(traversal: &mut NockStack, state: &mut JamState) {
let new_size = state.size + state.size;
let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size)? };
let (new_atom, new_slice) = unsafe { IndirectAtom::new_raw_mut_bitslice(traversal, new_size) };
new_slice[0..state.cursor].copy_from_bitslice(&state.slice[0..state.cursor]);
state.size = new_size;
state.atom = new_atom;
state.slice = new_slice;
Ok(())
}
/// Encode an atom's size and value into the jam state
///
/// INVARIANT: mat must not modify state.cursor unless it will also return `Ok(())`
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResult<Result<(), ()>> {
fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> Result<(), ()> {
let b_atom_size = met0_usize(atom);
let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64)?;
let b_atom_size_atom = Atom::new(traversal, b_atom_size as u64);
if b_atom_size == 0 {
if state.cursor + 1 > state.slice.len() {
Ok(Err(()))
Err(())
} else {
state.slice.set(state.cursor, true);
state.cursor += 1;
Ok(Ok(()))
Ok(())
}
} else {
let c_b_size = met0_usize(b_atom_size_atom);
if state.cursor + c_b_size + c_b_size + b_atom_size > state.slice.len() {
Ok(Err(()))
Err(())
} else {
state.slice[state.cursor..state.cursor + c_b_size].fill(false); // a 0 bit for each bit in the atom size
state.slice.set(state.cursor + c_b_size, true); // a terminating 1 bit
@ -430,7 +433,7 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
..state.cursor + c_b_size + c_b_size + b_atom_size]
.copy_from_bitslice(&atom.as_bitslice()[0..b_atom_size]);
state.cursor += c_b_size + c_b_size + b_atom_size;
Ok(Ok(()))
Ok(())
}
}
}
@ -438,12 +441,14 @@ fn mat(traversal: &mut NockStack, state: &mut JamState, atom: Atom) -> AllocResu
#[cfg(test)]
mod tests {
use std::mem::size_of;
use rand::prelude::*;
use super::*;
use crate::jets::util::test::assert_noun_eq;
use crate::mem::NockStack;
use crate::noun::{Atom, Cell, Noun};
use crate::noun::{Atom, Cell, CellMemory, Noun};
fn setup_stack() -> NockStack {
NockStack::new(1 << 30, 0)
}
@ -451,8 +456,8 @@ mod tests {
#[test]
fn test_jam_cue_atom() {
let mut stack = setup_stack();
let atom = Atom::new(&mut stack, 42).unwrap();
let jammed = jam(&mut stack, atom.as_noun()).unwrap();
let atom = Atom::new(&mut stack, 42);
let jammed = jam(&mut stack, atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, atom.as_noun());
}
@ -460,10 +465,10 @@ mod tests {
#[test]
fn test_jam_cue_cell() {
let mut stack = setup_stack();
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
let n2 = Atom::new(&mut stack, 2).unwrap().as_noun();
let cell = Cell::new(&mut stack, n1, n2).unwrap().as_noun();
let jammed = jam(&mut stack, cell).unwrap();
let n1 = Atom::new(&mut stack, 1).as_noun();
let n2 = Atom::new(&mut stack, 2).as_noun();
let cell = Cell::new(&mut stack, n1, n2).as_noun();
let jammed = jam(&mut stack, cell);
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell);
}
@ -471,12 +476,12 @@ mod tests {
#[test]
fn test_jam_cue_nested_cell() {
let mut stack = setup_stack();
let n3 = Atom::new(&mut stack, 3).unwrap().as_noun();
let n4 = Atom::new(&mut stack, 4).unwrap().as_noun();
let inner_cell = Cell::new(&mut stack, n3, n4).unwrap();
let n1 = Atom::new(&mut stack, 1).unwrap().as_noun();
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun()).unwrap();
let jammed = jam(&mut stack, outer_cell.as_noun()).unwrap();
let n3 = Atom::new(&mut stack, 3).as_noun();
let n4 = Atom::new(&mut stack, 4).as_noun();
let inner_cell = Cell::new(&mut stack, n3, n4);
let n1 = Atom::new(&mut stack, 1).as_noun();
let outer_cell = Cell::new(&mut stack, n1, inner_cell.as_noun());
let jammed = jam(&mut stack, outer_cell.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, outer_cell.as_noun());
}
@ -484,9 +489,9 @@ mod tests {
#[test]
fn test_jam_cue_shared_structure() {
let mut stack = setup_stack();
let shared_atom = Atom::new(&mut stack, 42).unwrap();
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun()).unwrap();
let jammed = jam(&mut stack, cell.as_noun()).unwrap();
let shared_atom = Atom::new(&mut stack, 42);
let cell = Cell::new(&mut stack, shared_atom.as_noun(), shared_atom.as_noun());
let jammed = jam(&mut stack, cell.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell.as_noun());
}
@ -494,8 +499,8 @@ mod tests {
#[test]
fn test_jam_cue_large_atom() {
let mut stack = setup_stack();
let large_atom = Atom::new(&mut stack, u64::MAX).unwrap();
let jammed = jam(&mut stack, large_atom.as_noun()).unwrap();
let large_atom = Atom::new(&mut stack, u64::MAX);
let jammed = jam(&mut stack, large_atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, large_atom.as_noun());
}
@ -503,8 +508,8 @@ mod tests {
#[test]
fn test_jam_cue_empty_atom() {
let mut stack = setup_stack();
let empty_atom = Atom::new(&mut stack, 0).unwrap();
let jammed = jam(&mut stack, empty_atom.as_noun()).unwrap();
let empty_atom = Atom::new(&mut stack, 0);
let jammed = jam(&mut stack, empty_atom.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, empty_atom.as_noun());
}
@ -512,12 +517,12 @@ mod tests {
#[test]
fn test_jam_cue_complex_structure() {
let mut stack = setup_stack();
let atom1 = Atom::new(&mut stack, 1).unwrap();
let atom2 = Atom::new(&mut stack, 2).unwrap();
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun()).unwrap();
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun()).unwrap();
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun()).unwrap();
let jammed = jam(&mut stack, cell3.as_noun()).unwrap();
let atom1 = Atom::new(&mut stack, 1);
let atom2 = Atom::new(&mut stack, 2);
let cell1 = Cell::new(&mut stack, atom1.as_noun(), atom2.as_noun());
let cell2 = Cell::new(&mut stack, cell1.as_noun(), atom2.as_noun());
let cell3 = Cell::new(&mut stack, cell2.as_noun(), cell1.as_noun());
let jammed = jam(&mut stack, cell3.as_noun());
let cued = cue(&mut stack, jammed).unwrap();
assert_noun_eq(&mut stack, cued, cell3.as_noun());
}
@ -525,7 +530,7 @@ mod tests {
#[test]
fn test_cue_invalid_input() {
let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid tag
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid tag
let result = cue(&mut stack, invalid_atom);
assert!(result.is_err());
}
@ -538,15 +543,14 @@ mod tests {
let mut stack = setup_stack();
let mut rng_clone = rng.clone();
let (original, total_size) =
generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone).unwrap();
let (original, total_size) = generate_deeply_nested_noun(&mut stack, depth, &mut rng_clone);
println!(
"Total size of all generated nouns: {:.2} KB",
total_size as f64 / 1024.0
);
println!("Original size: {:.2} KB", original.mass() as f64 / 1024.0);
let jammed = jam(&mut stack, original.clone()).unwrap();
let jammed = jam(&mut stack, original.clone());
println!(
"Jammed size: {:.2} KB",
jammed.as_noun().mass() as f64 / 1024.0
@ -557,26 +561,7 @@ mod tests {
assert_noun_eq(&mut stack, cued, original);
}
fn noun_size(noun: Noun) -> usize {
let mut size = 0;
let mut stack = vec![noun];
while let Some(top) = stack.pop() {
if let Ok(i) = top.as_indirect() {
size += i.raw_size();
} else if let Ok(c) = top.as_cell() {
size += (std::mem::size_of::<crate::noun::CellMemory>() + 7) << 3;
stack.push(c.tail());
stack.push(c.head());
}
}
size
}
fn generate_random_noun(
stack: &mut NockStack,
bits: usize,
rng: &mut StdRng,
) -> AllocResult<(Noun, usize)> {
fn generate_random_noun(stack: &mut NockStack, bits: usize, rng: &mut StdRng) -> (Noun, usize) {
const MAX_DEPTH: usize = 100; // Adjust this value as needed
fn inner(
stack: &mut NockStack,
@ -584,7 +569,7 @@ mod tests {
rng: &mut StdRng,
depth: usize,
accumulated_size: usize,
) -> AllocResult<(Noun, usize)> {
) -> (Noun, usize) {
let mut done = false;
if depth >= MAX_DEPTH || stack.size() < 1024 || accumulated_size > stack.size() - 1024 {
// println!("Done at depth and size: {} {:.2} KB", depth, accumulated_size as f64 / 1024.0);
@ -593,51 +578,78 @@ mod tests {
let result = if rng.gen_bool(0.5) || done {
let value = rng.gen::<u64>();
let atom = Atom::new(stack, value).unwrap();
let atom = Atom::new(stack, value);
let noun = atom.as_noun();
(noun, accumulated_size + noun.mass())
} else {
let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size)?;
let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size)?;
let (left, left_size) = inner(stack, bits / 2, rng, depth + 1, accumulated_size);
let (right, _) = inner(stack, bits / 2, rng, depth + 1, left_size);
let cell = Cell::new(stack, left, right).unwrap();
let cell = Cell::new(stack, left, right);
let noun = cell.as_noun();
(noun, noun.mass())
};
if noun_size(result.0) > stack.size() {
if space_needed_noun(result.0, stack) > stack.size() {
eprintln!(
"Stack size exceeded with noun size {:.2} KB",
result.0.mass() as f64 / 1024.0
);
unsafe {
let top_noun = *stack.top::<Noun>();
Ok((top_noun, result.1))
(top_noun, result.1)
}
} else {
Ok(result)
result
}
}
inner(stack, bits, rng, 0, 0)
}
fn space_needed_noun(noun: Noun, stack: &mut NockStack) -> usize {
unsafe {
stack.with_frame(0, |stack| {
*(stack.push::<Noun>()) = noun;
let mut size = 0;
while !stack.stack_is_empty() {
let noun = *(stack.top::<Noun>());
stack.pop::<Noun>();
match noun.as_either_atom_cell() {
Left(atom) => match atom.as_either() {
Left(_) => {}
Right(indirect) => {
size += indirect.raw_size();
}
},
Right(cell) => {
size += size_of::<CellMemory>();
*(stack.push::<Noun>()) = cell.tail();
*(stack.push::<Noun>()) = cell.head();
}
}
}
size
})
}
}
fn generate_deeply_nested_noun(
stack: &mut NockStack,
depth: usize,
rng: &mut StdRng,
) -> AllocResult<(Noun, usize)> {
) -> (Noun, usize) {
if depth == 0 {
let (noun, size) = generate_random_noun(stack, 100, rng)?;
Ok((noun, size))
let (noun, size) = generate_random_noun(stack, 100, rng);
(noun, size)
} else {
let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?;
let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng)?;
let cell = Cell::new(stack, left, right).unwrap();
let (left, left_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
let (right, right_size) = generate_deeply_nested_noun(stack, depth - 1, rng);
let cell = Cell::new(stack, left, right);
let noun = cell.as_noun();
let total_size = left_size + right_size + noun.mass();
if noun_size(noun) > stack.size() {
if { space_needed_noun(noun, stack) } > stack.size() {
eprintln!(
"Stack size exceeded at depth {} with noun size {:.2} KB",
depth,
@ -645,11 +657,11 @@ mod tests {
);
unsafe {
let top_noun = *stack.top::<Noun>();
Ok((top_noun, total_size))
(top_noun, total_size)
}
} else {
// println!("Size: {:.2} KB, depth: {}", noun.mass() as f64 / 1024.0, depth);
Ok((noun, total_size))
(noun, total_size)
}
}
}
@ -659,7 +671,7 @@ mod tests {
std::env::set_var("RUST_BACKTRACE", "full");
let mut stack = setup_stack();
let invalid_atom = Atom::new(&mut stack, 0b11).unwrap(); // Invalid atom representation
let invalid_atom = Atom::new(&mut stack, 0b11); // Invalid atom representation
let result = cue(&mut stack, invalid_atom);
assert!(result.is_err());
@ -668,6 +680,8 @@ mod tests {
assert!(matches!(e, Error::Deterministic(_, _)));
}
}
#[ignore] // We will put this back when we have proper error catching
#[test]
fn test_cue_nondeterministic_error() {
let mut big_stack = NockStack::new(1 << 30, 0);
@ -675,10 +689,10 @@ mod tests {
let mut rng = StdRng::seed_from_u64(1);
// Create an atom with a very large value to potentially cause overflow
let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng).unwrap();
let (large_atom, _) = generate_deeply_nested_noun(&mut big_stack, 5, &mut rng);
// Attempt to jam and then cue the large atom in the big stack
let jammed = jam(&mut big_stack, large_atom).unwrap();
let jammed = jam(&mut big_stack, large_atom);
// make a smaller stack to try to cause a nondeterministic error
// NOTE: if the stack is big enough to fit the jammed atom, cue panics
@ -697,10 +711,7 @@ mod tests {
println!("Result: {:?}", result);
assert!(result.is_err());
if let Err(e) = result {
assert!(matches!(
e,
Error::NonDeterministic(crate::interpreter::Mote::Meme, _)
));
assert!(matches!(e, Error::NonDeterministic(_, _)));
println!("got expected error: {:?}", e);
}
}

View File

@ -5,7 +5,6 @@ use bitvec::slice::BitSlice;
use crate::interpreter::{interpret, Context};
use crate::jets::util::slot;
use crate::jets::{Jet, JetErr};
use crate::mem::AllocResult;
use crate::noun::{Noun, D, T};
/// Return Err if the computation crashed or should punt to Nock
@ -20,13 +19,13 @@ pub struct Site {
impl Site {
/// Prepare a locally cached gate to call repeatedly.
pub fn new(ctx: &mut Context, core: &mut Noun) -> AllocResult<Site> {
pub fn new(ctx: &mut Context, core: &mut Noun) -> Site {
let mut battery = slot(*core, 2).unwrap();
let context = slot(*core, 7).unwrap();
let warm_result = ctx
.warm
.find_jet(&mut ctx.stack, core, &mut battery)?
.find_jet(&mut ctx.stack, core, &mut battery)
.filter(|(_jet, mut path)| {
// check that 7 is a prefix of the parent battery axis,
// to ensure that the sample (axis 6) is not part of the jet match.
@ -35,12 +34,10 @@ impl Site {
// jet and we only actually match one of them, but we check all of them and run
// unjetted if any have an axis outside 7.
let axis_7_bits: &BitSlice<u64, Lsb0> = BitSlice::from_element(&7u64);
// TODO: This panic is ugly but the code is awkward.
let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path).ok().expect("OOM'd on ctx.cold.find in Site::new");
let batteries_list = ctx.cold.find(&mut ctx.stack, &mut path);
let mut ret = true;
for mut batteries in batteries_list {
if let Some((_, parent_axis)) = batteries.next() {
// let parent_axis = unsafe { (*battery.0).parent_axis };
if let Some((_battery, parent_axis)) = batteries.next() {
let parent_axis_prefix_bits = &parent_axis.as_bitslice()[0..3];
if parent_axis_prefix_bits == axis_7_bits {
continue;
@ -54,19 +51,19 @@ impl Site {
}
}
ret
});
Ok(Site {
});
Site {
battery,
context,
jet: warm_result.map(|(jet, _)| jet),
path: warm_result.map(|(_, path)| path).unwrap_or(D(0)),
})
}
}
}
/// Slam a cached call site.
pub fn site_slam(ctx: &mut Context, site: &Site, sample: Noun) -> Result {
let subject = T(&mut ctx.stack, &[site.battery, sample, site.context])?;
let subject = T(&mut ctx.stack, &[site.battery, sample, site.context]);
if site.jet.is_some() {
let jet = site.jet.unwrap();
jet(ctx, subject)

View File

@ -1,11 +0,0 @@
use crate::{mem::NockStack, noun::Noun};
#[allow(non_snake_case)]
pub fn T<A: crate::noun::NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
crate::noun::T(allocator, tup).unwrap()
}
#[allow(non_snake_case)]
pub fn A(stack: &mut NockStack, atom: &ibig::UBig) -> Noun {
crate::jets::util::test::A(stack, atom).unwrap()
}

View File

@ -2,7 +2,7 @@ use crate::flog;
use crate::interpreter::Context;
use crate::jets::bits::util::rap;
use crate::jets::form::util::scow;
use crate::mem::{AllocResult, NockStack};
use crate::mem::NockStack;
use crate::mug::met3_usize;
use crate::noun::{Atom, DirectAtom, IndirectAtom, Noun};
use either::Either::*;
@ -153,7 +153,7 @@ pub unsafe fn write_nock_trace(
continue;
}
let pc = path_to_cord(stack, (*trace_stack).path)?;
let pc = path_to_cord(stack, (*trace_stack).path);
let pc_len = met3_usize(pc);
let pc_bytes = &pc.as_bytes()[0..pc_len];
let pc_str = match std::str::from_utf8(pc_bytes) {
@ -185,7 +185,7 @@ pub unsafe fn write_nock_trace(
}
// XX: Need Rust string interpolation helper that doesn't allocate
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> Atom {
let mut cursor = path;
let mut length = 0usize;
@ -218,7 +218,7 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
// reset cursor, then actually write the path
cursor = path;
let mut idx = 0;
let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length)? };
let (mut deres, buffer) = unsafe { IndirectAtom::new_raw_mut_bytes(stack, length) };
let slash = (b"/")[0];
while let Ok(c) = cursor.as_cell() {
@ -254,5 +254,5 @@ pub fn path_to_cord(stack: &mut NockStack, path: Noun) -> AllocResult<Atom> {
cursor = c.tail();
}
Ok(unsafe { deres.normalize_as_atom() })
unsafe { deres.normalize_as_atom() }
}

View File

@ -1,4 +1,4 @@
use crate::mem::{AllocResult, NockStack, ALLOC, FRAME, STACK};
use crate::mem::{NockStack, ALLOC, FRAME, STACK};
use crate::noun::Noun;
use crate::{assert_acyclic, assert_no_forwarding_pointers, assert_no_junior_pointers};
use either::Either::*;
@ -20,22 +20,7 @@ macro_rules! assert_no_junior_pointers {
( $x:expr, $y:expr ) => {};
}
#[cfg(test)]
pub(crate) mod test {
use crate::mem::NockStack;
use crate::noun::Noun;
/// Tests only, not part of the actual implementation. Use this outside of #[cfg(test)] and I will sic the linter on you.
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
super::unifying_equality(stack, a, b).expect("OOM error in test::unifying_equality")
}
}
pub unsafe fn unifying_equality(
stack: &mut NockStack,
a: *mut Noun,
b: *mut Noun,
) -> AllocResult<bool> {
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
/* This version of unifying equality is not like that of vere.
* Vere does a tree comparison (accelerated by pointer equality and short-circuited by mug
* equality) and then unifies the nouns at the top level if they are equal.
@ -68,109 +53,108 @@ pub unsafe fn unifying_equality(
// If the nouns are already word-equal we have nothing to do
if (*a).raw_equals(*b) {
return Ok(true);
return true;
};
// If the nouns have cached mugs which are disequal we have nothing to do
if let (Ok(a_alloc), Ok(b_alloc)) = ((*a).as_allocated(), (*b).as_allocated()) {
if let (Some(a_mug), Some(b_mug)) = (a_alloc.get_cached_mug(), b_alloc.get_cached_mug()) {
if a_mug != b_mug {
return Ok(false);
return false;
};
};
};
stack.with_frame(0, |stack| {
*(stack.push::<(*mut Noun, *mut Noun)>()?) = (a, b);
loop {
if stack.stack_is_empty() {
break;
stack.frame_push(0);
*(stack.push::<(*mut Noun, *mut Noun)>()) = (a, b);
loop {
if stack.stack_is_empty() {
break;
};
let (x, y): (*mut Noun, *mut Noun) = *(stack.top());
if (*x).raw_equals(*y) {
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
};
if let (Ok(x_alloc), Ok(y_alloc)) = (
// equal direct atoms return true for raw_equals()
(*x).as_allocated(),
(*y).as_allocated(),
) {
if let (Some(x_mug), Some(y_mug)) = (x_alloc.get_cached_mug(), y_alloc.get_cached_mug())
{
if x_mug != y_mug {
break; // short-circuit, the mugs differ therefore the nouns must differ
}
};
let (x, y): (*mut Noun, *mut Noun) = *(stack.top());
if (*x).raw_equals(*y) {
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
};
if let (Ok(x_alloc), Ok(y_alloc)) = (
// equal direct atoms return true for raw_equals()
(*x).as_allocated(),
(*y).as_allocated(),
) {
if let (Some(x_mug), Some(y_mug)) =
(x_alloc.get_cached_mug(), y_alloc.get_cached_mug())
{
if x_mug != y_mug {
break; // short-circuit, the mugs differ therefore the nouns must differ
}
};
match (x_alloc.as_either(), y_alloc.as_either()) {
(Left(x_indirect), Left(y_indirect)) => {
let x_as_ptr = x_indirect.to_raw_pointer();
let y_as_ptr = y_indirect.to_raw_pointer();
if x_indirect.size() == y_indirect.size()
&& memcmp(
x_indirect.data_pointer() as *const c_void,
y_indirect.data_pointer() as *const c_void,
x_indirect.size() << 3,
) == 0
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
match (x_alloc.as_either(), y_alloc.as_either()) {
(Left(x_indirect), Left(y_indirect)) => {
let x_as_ptr = x_indirect.to_raw_pointer();
let y_as_ptr = y_indirect.to_raw_pointer();
if x_indirect.size() == y_indirect.size()
&& memcmp(
x_indirect.data_pointer() as *const c_void,
y_indirect.data_pointer() as *const c_void,
x_indirect.size() << 3,
) == 0
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
break;
*y = *x;
}
}
(Right(x_cell), Right(y_cell)) => {
let x_as_ptr = x_cell.to_raw_pointer() as *const u64;
let y_as_ptr = y_cell.to_raw_pointer() as *const u64;
if x_cell.head().raw_equals(y_cell.head())
&& x_cell.tail().raw_equals(y_cell.tail())
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else {
/* THIS ISN'T AN INFINITE LOOP
* If we discover a disequality in either side, we will
* short-circuit the entire loop and reset the work stack.
*
* If both sides are equal, then we will discover pointer
* equality when we return and unify the cell.
*/
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
*(stack.push::<(*mut Noun, *mut Noun)>()?) =
(x_cell.head_as_mut(), y_cell.head_as_mut());
continue;
}
}
(_, _) => {
break; // cells don't unify with atoms
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else {
break;
}
}
} else {
break; // direct atom not raw equal, so short circuit
(Right(x_cell), Right(y_cell)) => {
let x_as_ptr = x_cell.to_raw_pointer() as *const u64;
let y_as_ptr = y_cell.to_raw_pointer() as *const u64;
if x_cell.head().raw_equals(y_cell.head())
&& x_cell.tail().raw_equals(y_cell.tail())
{
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
if x_as_ptr == junior {
*x = *y;
} else {
*y = *x;
}
stack.pop::<(*mut Noun, *mut Noun)>();
continue;
} else {
/* THIS ISN'T AN INFINITE LOOP
* If we discover a disequality in either side, we will
* short-circuit the entire loop and reset the work stack.
*
* If both sides are equal, then we will discover pointer
* equality when we return and unify the cell.
*/
*(stack.push::<(*mut Noun, *mut Noun)>()) =
(x_cell.tail_as_mut(), y_cell.tail_as_mut());
*(stack.push::<(*mut Noun, *mut Noun)>()) =
(x_cell.head_as_mut(), y_cell.head_as_mut());
continue;
}
}
(_, _) => {
break; // cells don't unify with atoms
}
}
} else {
break; // direct atom not raw equal, so short circuit
}
}
stack.frame_pop();
assert_acyclic!(*a);
assert_acyclic!(*b);
assert_no_forwarding_pointers!(*a);
assert_no_forwarding_pointers!(*b);
assert_no_junior_pointers!(stack, *a);
assert_no_junior_pointers!(stack, *b);
assert_acyclic!(*a);
assert_acyclic!(*b);
assert_no_forwarding_pointers!(*a);
assert_no_forwarding_pointers!(*b);
assert_no_junior_pointers!(stack, *a);
assert_no_junior_pointers!(stack, *b);
Ok((*a).raw_equals(*b))
})?
(*a).raw_equals(*b)
}
unsafe fn senior_pointer_first(