<commit_before>use common::bitpacker::compute_num_bits;
use common::bitpacker::{BitPacker, BitUnpacker};
use common::CountingWriter;
use std::cmp;
use std::io::Write;
use super::super::{compressed_block_size, COMPRESSION_BLOCK_SIZE};

const COMPRESSED_BLOCK_MAX_SIZE: usize = COMPRESSION_BLOCK_SIZE * 4 + 1;

pub fn compress_sorted(vals: &mut [u32], output: &mut [u8], offset: u32) -> usize {
    let mut max_delta = 0;
    {
        let mut local_offset = offset;
        for i in 0..COMPRESSION_BLOCK_SIZE {
            let val = vals[i];
            let delta = val - local_offset;
            max_delta = cmp::max(max_delta, delta);
            vals[i] = delta;
            local_offset = val;
        }
    }
    let mut counting_writer = CountingWriter::wrap(output);
    let num_bits = compute_num_bits(max_delta as u64);
    counting_writer.write_all(&[num_bits]).unwrap();

    let mut bit_packer = BitPacker::new();
    for val in vals {
        bit_packer
            .write(*val as u64, num_bits, &mut counting_writer)
            .unwrap();
    }
    let compressed_size = counting_writer.written_bytes();
    assert_eq!(compressed_size, compute_block_size(num_bits));
    compressed_size
}

pub struct BlockEncoder {
    pub output: [u8; COMPRESSED_BLOCK_MAX_SIZE],
    pub output_len: usize,
    input_buffer: [u32; COMPRESSION_BLOCK_SIZE],
}

impl BlockEncoder {
    pub fn new() -> BlockEncoder {
        BlockEncoder {
            output: [0u8; COMPRESSED_BLOCK_MAX_SIZE],
            output_len: 0,
            input_buffer: [0u32; COMPRESSION_BLOCK_SIZE],
        }
    }

    pub fn compress_block_sorted(&mut self, vals: &[u32], offset: u32) -> &[u8] {
        self.input_buffer.clone_from_slice(vals);
        let compressed_size = compress_sorted(&mut self.input_buffer, &mut self.output, offset);
        &self.output[..compressed_size]
    }

    pub fn compress_block_unsorted(&mut self, vals: &[u32]) -> &[u8] {
        let compressed_size = {
            let output: &mut [u8] = &mut self.output;
            let max = vals.iter()
                .cloned()
                .max()
                .expect("compress unsorted called with an empty array");
            let num_bits = compute_num_bits(max as u64);
            let mut counting_writer = CountingWriter::wrap(output);
            counting_writer.write_all(&[num_bits]).unwrap();
            let mut bit_packer = BitPacker::new();
            for val in vals {
                bit_packer
                    .write(*val as u64, num_bits, &mut counting_writer)
                    .unwrap();
            }
            for _ in vals.len()..COMPRESSION_BLOCK_SIZE {
                bit_packer
                    .write(vals[0] as u64, num_bits, &mut counting_writer)
                    .unwrap();
            }
            bit_packer.flush(&mut counting_writer).expect(
                "Flushing the bitpacking \
                 in an in RAM buffer should never fail",
            );
            // we avoid writing "closing", because we
            // do not want 7 bytes of padding here.
            counting_writer.written_bytes()
        };
        &self.output[..compressed_size]
    }
}

pub struct BlockDecoder {
    pub output: [u32; COMPRESSED_BLOCK_MAX_SIZE],
    pub output_len: usize,
}

impl BlockDecoder {
    pub fn new() -> BlockDecoder {
        BlockDecoder::with_val(0u32)
    }

    pub fn with_val(val: u32) -> BlockDecoder {
        BlockDecoder {
            output: [val; COMPRESSED_BLOCK_MAX_SIZE],
            output_len: 0,
        }
    }

    pub fn uncompress_block_sorted<'a>(
        &mut self,
        compressed_data: &'a [u8],
        mut offset: u32,
    ) -> usize {
        let consumed_size = {
            let num_bits = compressed_data[0];
            let bit_unpacker = BitUnpacker::new(&compressed_data[1..], num_bits as usize);
            for i in 0..COMPRESSION_BLOCK_SIZE {
                let delta = bit_unpacker.get(i);
                let val = offset + delta as u32;
                self.output[i] = val;
                offset = val;
            }
            compute_block_size(num_bits)
        };
        self.output_len = COMPRESSION_BLOCK_SIZE;
        consumed_size
    }

    pub fn uncompress_block_unsorted<'a>(&mut self, compressed_data: &'a [u8]) -> usize {
        let num_bits = compressed_data[0];
        let bit_unpacker = BitUnpacker::new(&compressed_data[1..], num_bits as usize);
        for i in 0..COMPRESSION_BLOCK_SIZE {
            self.output[i] = bit_unpacker.get(i) as u32;
        }
        let consumed_size = 1 + (num_bits as usize * COMPRESSION_BLOCK_SIZE + 7) / 8;
        self.output_len = COMPRESSION_BLOCK_SIZE;
        consumed_size
    }

    #[inline]
    pub fn output_array(&self) -> &[u32] {
        &self.output[..self.output_len]
    }

    #[inline]
    pub fn output(&self, idx: usize) -> u32 {
        self.output[idx]
    }
}
<commit_msg>NOBUG no-simd compression fix<commit_after>use common::compute_num_bits;
use common::bitpacker::{BitPacker, BitUnpacker};
use common::CountingWriter;
use std::cmp;
use std::io::Write;
use super::super::{compressed_block_size, COMPRESSION_BLOCK_SIZE};

const COMPRESSED_BLOCK_MAX_SIZE: usize = COMPRESSION_BLOCK_SIZE * 4 + 1;

pub fn compress_sorted(vals: &mut [u32], output: &mut [u8], offset: u32) -> usize {
    let mut max_delta = 0;
    {
        let mut local_offset = offset;
        for i in 0..COMPRESSION_BLOCK_SIZE {
            let val = vals[i];
            let delta = val - local_offset;
            max_delta = cmp::max(max_delta, delta);
            vals[i] = delta;
            local_offset = val;
        }
    }
    let mut counting_writer = CountingWriter::wrap(output);
    let num_bits = compute_num_bits(max_delta as u64);
    counting_writer.write_all(&[num_bits]).unwrap();

    let mut bit_packer = BitPacker::new();
    for val in vals {
        bit_packer
            .write(*val as u64, num_bits, &mut counting_writer)
            .unwrap();
    }
    let compressed_size = counting_writer.written_bytes();
    assert_eq!(compressed_size, compressed_block_size(num_bits));
    compressed_size
}

pub struct BlockEncoder {
    pub output: [u8; COMPRESSED_BLOCK_MAX_SIZE],
    pub output_len: usize,
    input_buffer: [u32; COMPRESSION_BLOCK_SIZE],
}

impl BlockEncoder {
    pub fn new() -> BlockEncoder {
        BlockEncoder {
            output: [0u8; COMPRESSED_BLOCK_MAX_SIZE],
            output_len: 0,
            input_buffer: [0u32; COMPRESSION_BLOCK_SIZE],
        }
    }

    pub fn compress_block_sorted(&mut self, vals: &[u32], offset: u32) -> &[u8] {
        self.input_buffer.clone_from_slice(vals);
        let compressed_size = compress_sorted(&mut self.input_buffer, &mut self.output, offset);
        &self.output[..compressed_size]
    }

    pub fn compress_block_unsorted(&mut self, vals: &[u32]) -> &[u8] {
        let compressed_size = {
            let output: &mut [u8] = &mut self.output;
            let max = vals.iter()
                .cloned()
                .max()
                .expect("compress unsorted called with an empty array");
            let num_bits = compute_num_bits(max as u64);
            let mut counting_writer = CountingWriter::wrap(output);
            counting_writer.write_all(&[num_bits]).unwrap();
            let mut bit_packer = BitPacker::new();
            for val in vals {
                bit_packer
                    .write(*val as u64, num_bits, &mut counting_writer)
                    .unwrap();
            }
            for _ in vals.len()..COMPRESSION_BLOCK_SIZE {
                bit_packer
                    .write(vals[0] as u64, num_bits, &mut counting_writer)
                    .unwrap();
            }
            bit_packer.flush(&mut counting_writer).expect(
                "Flushing the bitpacking \
                 in an in RAM buffer should never fail",
            );
            // we avoid writing "closing", because we
            // do not want 7 bytes of padding here.
            counting_writer.written_bytes()
        };
        &self.output[..compressed_size]
    }
}

pub struct BlockDecoder {
    pub output: [u32; COMPRESSED_BLOCK_MAX_SIZE],
    pub output_len: usize,
}

impl BlockDecoder {
    pub fn new() -> BlockDecoder {
        BlockDecoder::with_val(0u32)
    }

    pub fn with_val(val: u32) -> BlockDecoder {
        BlockDecoder {
            output: [val; COMPRESSED_BLOCK_MAX_SIZE],
            output_len: 0,
        }
    }

    pub fn uncompress_block_sorted<'a>(
        &mut self,
        compressed_data: &'a [u8],
        mut offset: u32,
    ) -> usize {
        let consumed_size = {
            let num_bits = compressed_data[0];
            let bit_unpacker = BitUnpacker::new(&compressed_data[1..], num_bits);
            for i in 0..COMPRESSION_BLOCK_SIZE {
                let delta = bit_unpacker.get(i);
                let val = offset + delta as u32;
                self.output[i] = val;
                offset = val;
            }
            compressed_block_size(num_bits)
        };
        self.output_len = COMPRESSION_BLOCK_SIZE;
        consumed_size
    }

    pub fn uncompress_block_unsorted<'a>(&mut self, compressed_data: &'a [u8]) -> usize {
        let num_bits = compressed_data[0];
        let bit_unpacker = BitUnpacker::new(&compressed_data[1..], num_bits);
        for i in 0..COMPRESSION_BLOCK_SIZE {
            self.output[i] = bit_unpacker.get(i) as u32;
        }
        let consumed_size = 1 + (num_bits as usize * COMPRESSION_BLOCK_SIZE + 7) / 8;
        self.output_len = COMPRESSION_BLOCK_SIZE;
        consumed_size
    }

    #[inline]
    pub fn output_array(&self) -> &[u32] {
        &self.output[..self.output_len]
    }

    #[inline]
    pub fn output(&self, idx: usize) -> u32 {
        self.output[idx]
    }
}
<|endoftext|>


<commit_before>extern crate inkwell;

use self::inkwell::context::Context;
use self::inkwell::values::InstructionOpcode;

use std::ffi::CString;

#[test]
fn test_basic_block_ordering() {
    let context = Context::create();
    let module = context.create_module("test");
    let builder = context.create_builder();

    assert!(builder.get_insert_block().is_none());

    let i128_type = context.i128_type();
    let fn_type = i128_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);

    assert!(function.get_first_basic_block().is_none());

    let basic_block = context.append_basic_block(function, "entry");
    let basic_block4 = context.insert_basic_block_after(basic_block, "block4");
    let basic_block2 = context.insert_basic_block_after(basic_block, "block2");
    let basic_block3 = context.prepend_basic_block(basic_block4, "block3");

    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 4);
    assert_eq!(basic_blocks[0], basic_block);
    assert_eq!(basic_blocks[1], basic_block2);
    assert_eq!(basic_blocks[2], basic_block3);
    assert_eq!(basic_blocks[3], basic_block4);

    assert!(basic_block3.move_before(basic_block2).is_ok());
    assert!(basic_block.move_after(basic_block4).is_ok());

    let basic_block5 = context.prepend_basic_block(basic_block, "block5");
    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 5);
    assert_eq!(basic_blocks[0], basic_block3);
    assert_eq!(basic_blocks[1], basic_block2);
    assert_eq!(basic_blocks[2], basic_block4);
    assert_eq!(basic_blocks[3], basic_block5);
    assert_eq!(basic_blocks[4], basic_block);

    assert_ne!(basic_blocks[0], basic_block);
    assert_ne!(basic_blocks[1], basic_block3);
    assert_ne!(basic_blocks[2], basic_block2);
    assert_ne!(basic_blocks[3], basic_block4);
    assert_ne!(basic_blocks[4], basic_block5);

    context.append_basic_block(function, "block6");

    let bb1 = function.get_first_basic_block().unwrap();
    let bb4 = basic_block5.get_previous_basic_block().unwrap();

    assert_eq!(bb1, basic_block3);
    assert_eq!(bb4, basic_block4);
    assert!(basic_block3.get_previous_basic_block().is_none());

    unsafe {
        assert!(bb4.delete().is_ok());
    }

    let bb2 = basic_block5.get_previous_basic_block().unwrap();

    assert_eq!(bb2, basic_block2);

    let bb3 = function.get_first_basic_block().unwrap();

    assert_eq!(bb3, basic_block3);

    #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7", feature = "llvm3-8")))]
    {
        assert_eq!(*basic_block.get_name(), *CString::new("entry").unwrap());
        assert_eq!(*basic_block2.get_name(), *CString::new("block2").unwrap());
        assert_eq!(*basic_block3.get_name(), *CString::new("block3").unwrap());
        assert_eq!(*basic_block5.get_name(), *CString::new("block5").unwrap());
    }
}

#[test]
fn test_get_basic_blocks() {
    let context = Context::create();
    let module = context.create_module("test");

    let bool_type = context.bool_type();
    let fn_type = bool_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);

    assert_eq!(function.get_name(), &*CString::new("testing").unwrap());
    assert_eq!(fn_type.get_return_type().unwrap().into_int_type().get_bit_width(), 1);

    assert!(function.get_last_basic_block().is_none());
    assert_eq!(function.get_basic_blocks().len(), 0);

    let basic_block = context.append_basic_block(function, "entry");

    let last_basic_block = function.get_last_basic_block()
                                   .expect("Did not find expected basic block");

    assert_eq!(last_basic_block, basic_block);

    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 1);
    assert_eq!(basic_blocks[0], basic_block);
}

#[test]
fn test_get_terminator() {
    let context = Context::create();
    let module = context.create_module("test");
    let builder = context.create_builder();

    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);
    let basic_block = context.append_basic_block(function, "entry");

    builder.position_at_end(basic_block);

    // REVIEW: What's the difference between a terminator and last instruction?
    assert!(basic_block.get_terminator().is_none());
    assert!(basic_block.get_first_instruction().is_none());
    assert!(basic_block.get_last_instruction().is_none());

    builder.build_return(None);

    assert_eq!(basic_block.get_terminator().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_first_instruction().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_last_instruction().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_last_instruction(), basic_block.get_terminator());
}

#[test]
fn test_no_parent() {
    let context = Context::create();
    let module = context.create_module("test");

    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);
    let basic_block = context.append_basic_block(function, "entry");
    let basic_block2 = context.append_basic_block(function, "next");

    assert_eq!(basic_block.get_parent().unwrap(), function);
    assert_eq!(basic_block.get_next_basic_block().unwrap(), basic_block2);

    assert!(basic_block.remove_from_function().is_ok());

    assert!(basic_block.get_next_basic_block().is_none());
    assert!(basic_block2.get_previous_basic_block().is_none());

    assert!(basic_block.remove_from_function().is_err());
    assert!(basic_block.remove_from_function().is_err());

    assert!(basic_block.get_parent().is_none());
}

#[test]
fn test_rauw() {
    let context = Context::create();
    let builder = context.create_builder();
    let module = context.create_module("my_mod");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let fn_val = module.add_function("my_fn", fn_type, None);
    let entry = context.append_basic_block(fn_val, "entry");
    let bb1 = context.append_basic_block(fn_val, "bb1");
    let bb2 = context.append_basic_block(fn_val, "bb2");
    builder.position_at_end(entry);
    let branch_inst = builder.build_unconditional_branch(bb1);

    bb1.replace_all_uses_with(&bb2);

    assert_eq!(branch_inst.get_operand(0).unwrap().right().unwrap(), bb2);
}
<commit_msg>Add simple test for BB.rauw(BB).<commit_after>extern crate inkwell;

use self::inkwell::context::Context;
use self::inkwell::values::InstructionOpcode;

use std::ffi::CString;

#[test]
fn test_basic_block_ordering() {
    let context = Context::create();
    let module = context.create_module("test");
    let builder = context.create_builder();

    assert!(builder.get_insert_block().is_none());

    let i128_type = context.i128_type();
    let fn_type = i128_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);

    assert!(function.get_first_basic_block().is_none());

    let basic_block = context.append_basic_block(function, "entry");
    let basic_block4 = context.insert_basic_block_after(basic_block, "block4");
    let basic_block2 = context.insert_basic_block_after(basic_block, "block2");
    let basic_block3 = context.prepend_basic_block(basic_block4, "block3");

    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 4);
    assert_eq!(basic_blocks[0], basic_block);
    assert_eq!(basic_blocks[1], basic_block2);
    assert_eq!(basic_blocks[2], basic_block3);
    assert_eq!(basic_blocks[3], basic_block4);

    assert!(basic_block3.move_before(basic_block2).is_ok());
    assert!(basic_block.move_after(basic_block4).is_ok());

    let basic_block5 = context.prepend_basic_block(basic_block, "block5");
    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 5);
    assert_eq!(basic_blocks[0], basic_block3);
    assert_eq!(basic_blocks[1], basic_block2);
    assert_eq!(basic_blocks[2], basic_block4);
    assert_eq!(basic_blocks[3], basic_block5);
    assert_eq!(basic_blocks[4], basic_block);

    assert_ne!(basic_blocks[0], basic_block);
    assert_ne!(basic_blocks[1], basic_block3);
    assert_ne!(basic_blocks[2], basic_block2);
    assert_ne!(basic_blocks[3], basic_block4);
    assert_ne!(basic_blocks[4], basic_block5);

    context.append_basic_block(function, "block6");

    let bb1 = function.get_first_basic_block().unwrap();
    let bb4 = basic_block5.get_previous_basic_block().unwrap();

    assert_eq!(bb1, basic_block3);
    assert_eq!(bb4, basic_block4);
    assert!(basic_block3.get_previous_basic_block().is_none());

    unsafe {
        assert!(bb4.delete().is_ok());
    }

    let bb2 = basic_block5.get_previous_basic_block().unwrap();

    assert_eq!(bb2, basic_block2);

    let bb3 = function.get_first_basic_block().unwrap();

    assert_eq!(bb3, basic_block3);

    #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7", feature = "llvm3-8")))]
    {
        assert_eq!(*basic_block.get_name(), *CString::new("entry").unwrap());
        assert_eq!(*basic_block2.get_name(), *CString::new("block2").unwrap());
        assert_eq!(*basic_block3.get_name(), *CString::new("block3").unwrap());
        assert_eq!(*basic_block5.get_name(), *CString::new("block5").unwrap());
    }
}

#[test]
fn test_get_basic_blocks() {
    let context = Context::create();
    let module = context.create_module("test");

    let bool_type = context.bool_type();
    let fn_type = bool_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);

    assert_eq!(function.get_name(), &*CString::new("testing").unwrap());
    assert_eq!(fn_type.get_return_type().unwrap().into_int_type().get_bit_width(), 1);

    assert!(function.get_last_basic_block().is_none());
    assert_eq!(function.get_basic_blocks().len(), 0);

    let basic_block = context.append_basic_block(function, "entry");

    let last_basic_block = function.get_last_basic_block()
                                   .expect("Did not find expected basic block");

    assert_eq!(last_basic_block, basic_block);

    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 1);
    assert_eq!(basic_blocks[0], basic_block);
}

#[test]
fn test_get_terminator() {
    let context = Context::create();
    let module = context.create_module("test");
    let builder = context.create_builder();

    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);
    let basic_block = context.append_basic_block(function, "entry");

    builder.position_at_end(basic_block);

    // REVIEW: What's the difference between a terminator and last instruction?
    assert!(basic_block.get_terminator().is_none());
    assert!(basic_block.get_first_instruction().is_none());
    assert!(basic_block.get_last_instruction().is_none());

    builder.build_return(None);

    assert_eq!(basic_block.get_terminator().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_first_instruction().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_last_instruction().unwrap().get_opcode(), InstructionOpcode::Return);
    assert_eq!(basic_block.get_last_instruction(), basic_block.get_terminator());
}

#[test]
fn test_no_parent() {
    let context = Context::create();
    let module = context.create_module("test");

    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);

    let function = module.add_function("testing", fn_type, None);
    let basic_block = context.append_basic_block(function, "entry");
    let basic_block2 = context.append_basic_block(function, "next");

    assert_eq!(basic_block.get_parent().unwrap(), function);
    assert_eq!(basic_block.get_next_basic_block().unwrap(), basic_block2);

    assert!(basic_block.remove_from_function().is_ok());

    assert!(basic_block.get_next_basic_block().is_none());
    assert!(basic_block2.get_previous_basic_block().is_none());

    assert!(basic_block.remove_from_function().is_err());
    assert!(basic_block.remove_from_function().is_err());

    assert!(basic_block.get_parent().is_none());
}

#[test]
fn test_rauw() {
    let context = Context::create();
    let builder = context.create_builder();
    let module = context.create_module("my_mod");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let fn_val = module.add_function("my_fn", fn_type, None);
    let entry = context.append_basic_block(fn_val, "entry");
    let bb1 = context.append_basic_block(fn_val, "bb1");
    let bb2 = context.append_basic_block(fn_val, "bb2");
    builder.position_at_end(entry);
    let branch_inst = builder.build_unconditional_branch(bb1);

    bb1.replace_all_uses_with(&bb1);  // no-op
    bb1.replace_all_uses_with(&bb2);

    assert_eq!(branch_inst.get_operand(0).unwrap().right().unwrap(), bb2);
}
<|endoftext|>


<commit_before>// This is a brute-force solution, use `cargo test --release` for faster testing

extern crate itertools;
extern crate permutohedron;

use itertools::Itertools;
use permutohedron::Heap as Permutations;

use std::char;
use std::collections::HashMap;
use std::collections::HashSet;

fn test_equation(puzzle: &str, substitutions: &HashMap<char, u8>) -> bool {
    // Create a new String with characters changed to numbers
    let puzzle: String = puzzle
        .chars()
        .map(|c| {
            if let Some(&n) = substitutions.get(&c) {
                // If the character is in the substitutions, get the number and
                // convert it to a char
                char::from_digit(u32::from(n), 10).unwrap()
            } else {
                // Otherwise just copy over the character
                c
            }
        })
        .collect();

    // Split the puzzle into left and right side
    let equation: Vec<&str> = puzzle.split("==").collect();

    // Parse the number on the right side
    let right = equation[1].trim().parse::<u32>().unwrap();

    // Sum the parts on the left side
    let left: u32 = equation[0]
        .split('+')
        .map(str::trim)
        .map(|n| n.parse::<u32>().unwrap())
        .sum();

    // Create a String with just the numbers and spaces
    let just_numbers = puzzle
        .chars()
        .filter(|c| c.is_digit(10) || c.is_whitespace())
        .collect::<String>();
    // Split this into the numbers and check every number's first character
    let no_leading_zeroes = just_numbers
        .split_whitespace()
        .all(|number| !number.starts_with('0'));

    // Return true if left and right side is equal and the equation doesnt
    // contain leading zeroes.
    left == right && no_leading_zeroes
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    // Get unique letters from the puzzle
    let letters: HashSet<char> = puzzle
        .chars()
        .filter(|&c| c.is_alphabetic() && c.is_uppercase())
        .collect();
    let letters: Vec<char> = letters.into_iter().collect();

    // All available numbers for substitution
    let numbers: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    // Iterate every combination with the length of unique letters in the puzzle
    for combinations in numbers.iter().combinations(letters.len()) {
        let mut c = combinations;
        let permutations = Permutations::new(&mut c);
        // Iterate every permutation of a letter combination
        for p in permutations {
            let substitution: HashMap<char, u8> =
                letters.iter().zip(p).map(|(&c, &n)| (c, n)).collect();
            if test_equation(puzzle, &substitution) {
                // We found a good substitution
                return Some(substitution);
            }
        }
    }
    // If we tested every combination and did not found a solution then return None
    None
}
<commit_msg>alphametics: Parse equation only once<commit_after>// This is a brute-force solution, use `cargo test --release` for faster testing

extern crate itertools;
extern crate permutohedron;

use itertools::Itertools;
use permutohedron::Heap as Permutations;

use std::char;
use std::collections::HashMap;
use std::collections::HashSet;

fn test_equation(coefficients: &HashMap<char, i32>, cant_be_zero: &HashSet<char>, substitutions: &HashMap<char, u8>) -> bool {
    if cant_be_zero.iter().any(|d| substitutions[d] == 0) {
        return false;
    }

    coefficients.iter().map(|(d, &coeff)| i32::from(substitutions[d]) * coeff).sum::<i32>() == 0
}

fn letter_coefficients(puzzle: &str) -> (HashMap<char, i32>, HashSet<char>) {
    let mut coefficients = HashMap::new();
    let mut cant_be_zero = HashSet::new();

    // Split the puzzle into left and right side
    let equation: Vec<&str> = puzzle.split("==").collect();

    {
        let mut insert_term = |term: &str, polarity: i32| {
            cant_be_zero.insert(term.chars().next().unwrap());
            let mut power_of_ten = polarity;
            for letter in term.chars().rev() {
                *coefficients.entry(letter).or_insert(0) += power_of_ten;
                power_of_ten *= 10;
            }
        };

        // Sum the parts on the left side
        for left_term in equation[0].split('+').map(str::trim) {
            insert_term(left_term, 1);
        }

        let right_term = equation[1].trim();
        insert_term(right_term, -1);
    }

    (coefficients, cant_be_zero)
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let (coefficients, cant_be_zero) = letter_coefficients(puzzle);
    let letters: Vec<char> = coefficients.keys().cloned().collect();

    // All available numbers for substitution
    let numbers: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    // Iterate every combination with the length of unique letters in the puzzle
    for combinations in numbers.iter().combinations(letters.len()) {
        let mut c = combinations;
        let permutations = Permutations::new(&mut c);
        // Iterate every permutation of a letter combination
        for p in permutations {
            let substitution: HashMap<char, u8> =
                letters.iter().zip(p).map(|(&c, &n)| (c, n)).collect();
            if test_equation(&coefficients, &cant_be_zero, &substitution) {
                // We found a good substitution
                return Some(substitution);
            }
        }
    }
    // If we tested every combination and did not found a solution then return None
    None
}
<|endoftext|>


<commit_before>use std::ptr::NonNull;

type NodePtr<T> = NonNull<Node<T>>;
type OptNodePtr<T> = Option<NodePtr<T>>;

pub struct LinkedList<T> {
    head: OptNodePtr<T>,
    tail: OptNodePtr<T>,
    len: usize,
    marker: std::marker::PhantomData<Box<T>>, // for dropck
}

pub struct Cursor<'a, T: 'a> {
    list: &'a mut LinkedList<T>,
    node: OptNodePtr<T>,
}

struct Node<T> {
    element: T,
    next: OptNodePtr<T>,
    prev: OptNodePtr<T>,
}

impl<T> Node<T> {
    fn new_linkless(element: T) -> NodePtr<T> {
        Self::allocate(element, None, None)
    }

    fn allocate(element: T, prev: OptNodePtr<T>, next: OptNodePtr<T>) -> NodePtr<T> {
        unsafe {
            NonNull::new_unchecked(Box::into_raw(Box::new(Self {
                element,
                next,
                prev,
            })))
        }
    }

    /* TODO: allocate and link, shorter and maybe optimized
    fn new(element: T, prev: NodePtr<T>, next: NodePtr<T>) -> NodePtr<T> {
        Self::allocate(element, Some(prev), Some(next))
    }

    fn with_prev(element: T, prev: NodePtr<T>) -> NodePtr<T> {
        Self::allocate(element, Some(prev), None)
    }

    fn with_next(element: T, next: NodePtr<T>) -> NodePtr<T> {
        Self::allocate(element, None, Some(next))
    }
    */
}

trait NodePtrHelper<T> {
    fn get_next(&mut self) -> &mut OptNodePtr<T>;
    fn get_prev(&mut self) -> &mut OptNodePtr<T>;
    fn link(left: NodePtr<T>, right: NodePtr<T>);
    fn insert_between(self, prev: NodePtr<T>, next: NodePtr<T>) -> NodePtr<T>;
    fn insert_new_after(self, element: T) -> NodePtr<T>;
    fn insert_new_before(self, element: T) -> NodePtr<T>;
    fn unlink_next(&mut self) -> OptNodePtr<T>;
    fn unlink_prev(&mut self) -> OptNodePtr<T>;
    fn into_inner(self) -> T;
}

impl<T> NodePtrHelper<T> for NodePtr<T> {
    fn get_next(&mut self)-> &mut OptNodePtr<T> {
        unsafe { &mut self.as_mut().next }
    }

    fn get_prev(&mut self)-> &mut OptNodePtr<T> {
        unsafe { &mut self.as_mut().prev }
    }

    fn link(mut left: NodePtr<T>, mut right: NodePtr<T>) {
        *left.get_next() = Some(right);
        *right.get_prev() = Some(left);
    }

    fn insert_between(self, prev: NodePtr<T>, next: NodePtr<T>) -> Self {
        Self::link(prev, self);
        Self::link(self, next);
        self
    }

    fn insert_new_after(mut self, element: T) -> Self {
        if let Some(next) = *self.get_next() {
            Node::new_linkless(element)
                .insert_between(self, next)
        } else {
            let new_node = Node::new_linkless(element);
            NodePtr::link(self, new_node);
            new_node
        }
    }

    fn insert_new_before(mut self, element: T) -> Self {
        if let Some(prev) = *self.get_prev() {
            Node::new_linkless(element)
                .insert_between(prev, self)
        } else {
            let new_node = Node::new_linkless(element);
            NodePtr::link(new_node, self);
            new_node
        }
    }

    // returns next of self, if it exists
    fn unlink_next(&mut self) -> OptNodePtr<T> {
        self.get_next().map(|mut next| {
            *next.get_prev() = None;
            //self.as_mut().next = None;
            next
        })    }

    // returns prev of self, if it exists
    fn unlink_prev(&mut self) -> OptNodePtr<T> {
        self.get_prev().map(|mut prev| {
            *prev.get_next() = None;
            //self.as_mut().prev = None;
            prev
        })
    }

    // must be unlinked from all others
    fn into_inner(self) -> T {
        unsafe {
            Box::from_raw(self.as_ptr()).element
        }
    }
}

impl<T> LinkedList<T> {
    pub fn new() -> Self {
        LinkedList {
            head: None,
            tail: None,
            len: 0,
            marker: std::marker::PhantomData,
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    fn _insert_first(&mut self, element: T) {
        let new_node = Node::new_linkless(element);
        self.head = Some(new_node);
        self.tail = self.head;
    }

    pub fn push_back(&mut self, element: T) {
        self.cursor_head().insert_after(element);
    }

    pub fn push_front(&mut self, element: T) {
        self.cursor_tail().insert_before(element);
    }

    pub fn pop_back(&mut self) -> Option<T> {
        self.cursor_head().take()
    }

    pub fn pop_front(&mut self) -> Option<T> {
        self.cursor_tail().take()
    }

    pub fn cursor_tail(&mut self) -> Cursor<T> {
        Cursor {
            node: self.tail,
            list: self,
        }
    }

    pub fn cursor_head(&mut self) -> Cursor<T> {
        Cursor {
            node: self.head,
            list: self,
        }
    }

    unsafe fn immutable_cursor_tail(&self) -> Cursor<T> {
        let list = &mut *(self as *const LinkedList<T> as *mut LinkedList<T>);
        list.cursor_tail()
    }

    pub fn iter(&self) -> Iter<T> {
        Iter {
            first: true,
            cursor: unsafe { self.immutable_cursor_tail() },
        }
    }
}

impl<T> Drop for LinkedList<T> {
    fn drop(&mut self) {
        while let Some(_) = self.pop_back() {}
    }
}

impl<T: Clone> Clone for LinkedList<T> {
    fn clone(&self) -> Self {
        let mut new_list = LinkedList::new();
        for element in self.iter().cloned() {
            new_list.push_back(element);
        }
        new_list
    }
}

pub struct Iter<'a, T: 'a> {
    first: bool,
    cursor: Cursor<'a, T>,
}

impl<'a, T: 'a> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        // transmuting lifetimes
        // FIXME: obviously remove this
        unsafe {
            if self.first {
                self.first = false;
                std::mem::transmute::<Option<&T>, Option<&T>>(self.cursor.peek())
            } else {
                std::mem::transmute::<Option<&mut T>, Option<&mut T>>(self.cursor.next()).map(|r| &*r)
            }
        }
    }
}

impl<'a, T: 'a> Cursor<'a, T> {
    pub fn peek(&self) -> Option<&T> {
        unsafe {
            self.node.map(|node| &(*node.as_ptr()).element)
        }
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        unsafe {
            self.node.map(|node| &mut (*node.as_ptr()).element)
        }
    }

    // FIXME: I'm pretty certain this lifetime is UNSOUND
    //        hacked only to get Iter working, temporarily
    pub fn next(&mut self) -> Option<&mut T> {
        self._step(|node| node.next)
    }

    pub fn prev(&mut self) -> Option<&mut T> {
        self._step(|node| node.prev)
    }

    fn _step(
        &mut self,
        get_next: impl Fn(&mut Node<T>) -> OptNodePtr<T>
    ) -> Option<&mut T> {
        unsafe {
            if let Some(new_pos) = get_next(self.node.as_mut()?.as_mut()) {
                self.node = Some(new_pos);
                Some(&mut (*new_pos.as_ptr()).element)
            } else {
                None
            }
        }
    }

    pub fn take(&mut self) -> Option<T> {
        let mut node = self.node?;
        let next = node.unlink_next();
        let prev = node.unlink_prev();

        match (prev, next) {
            (Some(prev), Some(next)) => NodePtr::link(prev, next),
            (Some(_), None) => self.list.head = prev,
            (None, Some(_)) => self.list.tail = next,
            _ => {
                self.list.head = None;
                self.list.tail = None;
            },
        };
        self.list.len -= 1;
        Some(node.into_inner())
    }

    pub fn insert_after(&mut self, element: T) {
        self._insert(element, |list, cursor_node, element| {
            let new_node = cursor_node.insert_new_after(element);
            if list.head == Some(cursor_node) {
                list.head = Some(new_node);
            }
        });
    }

    pub fn insert_before(&mut self, element: T) {
        self._insert(element, |list, cursor_node, element| {
            let new_node = cursor_node.insert_new_before(element);
            if list.tail == Some(cursor_node) {
                list.tail = Some(new_node);
            }
        });
    }

    // put into list, if empty, else do whatever callback says
    fn _insert(&mut self, element: T, callback: impl Fn(&mut LinkedList<T>, NodePtr<T>, T)) {
        let cursor_node = match self.node {
            Some(node) => node,
            None => { // list empty
                self.node = Some(Node::new_linkless(element));
                self.list.head = self.node;
                self.list.tail = self.node;
                self.list.len += 1;
                return
            }
        };
        callback(&mut self.list, cursor_node, element);
        self.list.len += 1;
    }

    fn _insert_list_on_empty_list(&mut self, other: &mut LinkedList<T>) {
        debug_assert!(self.list.len == 0);
        std::mem::swap(self.list, other);
        self.node = self.list.tail;
    }

    fn _insert_list(
        &mut self,
        other: &mut LinkedList<T>,
        callback: impl Fn(NodePtr<T>, NodePtr<T>, NodePtr<T>)
    ) {
        unsafe {
            let cursor_node = match self.node {
                Some(node) => node,
                None => {
                    self._insert_list_on_empty_list(other);
                    return;
                }
            };

            if let LinkedList { head: Some(head), tail: Some(tail), len, .. } = *other {
                debug_assert!(head.as_ref().next.is_none());
                debug_assert!(tail.as_ref().prev.is_none());
                std::ptr::write(other, LinkedList::new()); // empty without dropping

                // link up on the right or left side
                callback(cursor_node, head, tail);
                self.list.len += len; // may overflow
            }
        }
    }

    pub fn insert_list_after(&mut self, other: &mut LinkedList<T>) {
        unsafe {
            self._insert_list(other, |mut cursor_node, head, tail| {
                if let Some(next) = cursor_node.as_mut().next {
                    NodePtr::link(head, next);
                }
                NodePtr::link(cursor_node, tail);
            });
        }
    }

    pub fn insert_list_before(&mut self, other: &mut LinkedList<T>) {
        unsafe {
            self._insert_list(other, |mut cursor_node, head, tail| {
                if let Some(prev) = cursor_node.as_mut().prev {
                    NodePtr::link(prev, tail);
                }
                NodePtr::link(head, cursor_node);
            });
        }
    }
}
<commit_msg>linked-list: remove unnecessary code<commit_after>use std::ptr::NonNull;

type NodePtr<T> = NonNull<Node<T>>;
type OptNodePtr<T> = Option<NodePtr<T>>;

pub struct LinkedList<T> {
    head: OptNodePtr<T>,
    tail: OptNodePtr<T>,
    len: usize,
    marker: std::marker::PhantomData<Box<T>>, // for dropck
}

pub struct Cursor<'a, T: 'a> {
    list: &'a mut LinkedList<T>,
    node: OptNodePtr<T>,
}

struct Node<T> {
    element: T,
    next: OptNodePtr<T>,
    prev: OptNodePtr<T>,
}

impl<T> Node<T> {
    fn new_linkless(element: T) -> NodePtr<T> {
        Self::allocate(element, None, None)
    }

    fn allocate(element: T, prev: OptNodePtr<T>, next: OptNodePtr<T>) -> NodePtr<T> {
        unsafe {
            NonNull::new_unchecked(Box::into_raw(Box::new(Self {
                element,
                next,
                prev,
            })))
        }
    }
}

trait NodePtrHelper<T> {
    fn get_next(&mut self) -> &mut OptNodePtr<T>;
    fn get_prev(&mut self) -> &mut OptNodePtr<T>;
    fn link(left: NodePtr<T>, right: NodePtr<T>);
    fn insert_between(self, prev: NodePtr<T>, next: NodePtr<T>) -> NodePtr<T>;
    fn insert_new_after(self, element: T) -> NodePtr<T>;
    fn insert_new_before(self, element: T) -> NodePtr<T>;
    fn unlink_next(&mut self) -> OptNodePtr<T>;
    fn unlink_prev(&mut self) -> OptNodePtr<T>;
    fn into_inner(self) -> T;
}

impl<T> NodePtrHelper<T> for NodePtr<T> {
    fn get_next(&mut self)-> &mut OptNodePtr<T> {
        unsafe { &mut self.as_mut().next }
    }

    fn get_prev(&mut self)-> &mut OptNodePtr<T> {
        unsafe { &mut self.as_mut().prev }
    }

    fn link(mut left: NodePtr<T>, mut right: NodePtr<T>) {
        *left.get_next() = Some(right);
        *right.get_prev() = Some(left);
    }

    fn insert_between(self, prev: NodePtr<T>, next: NodePtr<T>) -> Self {
        Self::link(prev, self);
        Self::link(self, next);
        self
    }

    fn insert_new_after(mut self, element: T) -> Self {
        if let Some(next) = *self.get_next() {
            Node::new_linkless(element)
                .insert_between(self, next)
        } else {
            let new_node = Node::new_linkless(element);
            NodePtr::link(self, new_node);
            new_node
        }
    }

    fn insert_new_before(mut self, element: T) -> Self {
        if let Some(prev) = *self.get_prev() {
            Node::new_linkless(element)
                .insert_between(prev, self)
        } else {
            let new_node = Node::new_linkless(element);
            NodePtr::link(new_node, self);
            new_node
        }
    }

    // returns next of self, if it exists
    fn unlink_next(&mut self) -> OptNodePtr<T> {
        self.get_next().map(|mut next| {
            *next.get_prev() = None;
            //self.as_mut().next = None;
            next
        })    }

    // returns prev of self, if it exists
    fn unlink_prev(&mut self) -> OptNodePtr<T> {
        self.get_prev().map(|mut prev| {
            *prev.get_next() = None;
            //self.as_mut().prev = None;
            prev
        })
    }

    // must be unlinked from all others
    fn into_inner(self) -> T {
        unsafe {
            Box::from_raw(self.as_ptr()).element
        }
    }
}

impl<T> LinkedList<T> {
    pub fn new() -> Self {
        LinkedList {
            head: None,
            tail: None,
            len: 0,
            marker: std::marker::PhantomData,
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn push_back(&mut self, element: T) {
        self.cursor_head().insert_after(element);
    }

    pub fn push_front(&mut self, element: T) {
        self.cursor_tail().insert_before(element);
    }

    pub fn pop_back(&mut self) -> Option<T> {
        self.cursor_head().take()
    }

    pub fn pop_front(&mut self) -> Option<T> {
        self.cursor_tail().take()
    }

    pub fn cursor_tail(&mut self) -> Cursor<T> {
        Cursor {
            node: self.tail,
            list: self,
        }
    }

    pub fn cursor_head(&mut self) -> Cursor<T> {
        Cursor {
            node: self.head,
            list: self,
        }
    }

    unsafe fn immutable_cursor_tail(&self) -> Cursor<T> {
        let list = &mut *(self as *const LinkedList<T> as *mut LinkedList<T>);
        list.cursor_tail()
    }

    pub fn iter(&self) -> Iter<T> {
        Iter {
            first: true,
            cursor: unsafe { self.immutable_cursor_tail() },
        }
    }
}

impl<T> Drop for LinkedList<T> {
    fn drop(&mut self) {
        while let Some(_) = self.pop_back() {}
    }
}

impl<T: Clone> Clone for LinkedList<T> {
    fn clone(&self) -> Self {
        let mut new_list = LinkedList::new();
        for element in self.iter().cloned() {
            new_list.push_back(element);
        }
        new_list
    }
}

pub struct Iter<'a, T: 'a> {
    first: bool,
    cursor: Cursor<'a, T>,
}

impl<'a, T: 'a> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        // transmuting lifetimes
        // FIXME: obviously remove this
        unsafe {
            if self.first {
                self.first = false;
                std::mem::transmute::<Option<&T>, Option<&T>>(self.cursor.peek())
            } else {
                std::mem::transmute::<Option<&mut T>, Option<&mut T>>(self.cursor.next()).map(|r| &*r)
            }
        }
    }
}

impl<'a, T: 'a> Cursor<'a, T> {
    pub fn peek_mut(&mut self) -> Option<&mut T> {
        unsafe {
            self.node.map(|node| &mut (*node.as_ptr()).element)
        }
    }

    // FIXME: I'm pretty certain this lifetime is UNSOUND
    //        hacked only to get Iter working, temporarily
    pub fn next(&mut self) -> Option<&mut T> {
        self._step(|node| node.next)
    }

    pub fn prev(&mut self) -> Option<&mut T> {
        self._step(|node| node.prev)
    }

    fn _step(
        &mut self,
        get_next: impl Fn(&mut Node<T>) -> OptNodePtr<T>
    ) -> Option<&mut T> {
        unsafe {
            if let Some(new_pos) = get_next(self.node.as_mut()?.as_mut()) {
                self.node = Some(new_pos);
                Some(&mut (*new_pos.as_ptr()).element)
            } else {
                None
            }
        }
    }

    pub fn take(&mut self) -> Option<T> {
        let mut node = self.node?;
        let next = node.unlink_next();
        let prev = node.unlink_prev();

        match (prev, next) {
            (Some(prev), Some(next)) => NodePtr::link(prev, next),
            (Some(_), None) => self.list.head = prev,
            (None, Some(_)) => self.list.tail = next,
            _ => {
                self.list.head = None;
                self.list.tail = None;
            },
        };
        self.list.len -= 1;
        Some(node.into_inner())
    }

    pub fn insert_after(&mut self, element: T) {
        self._insert(element, |list, cursor_node, element| {
            let new_node = cursor_node.insert_new_after(element);
            if list.head == Some(cursor_node) {
                list.head = Some(new_node);
            }
        });
    }

    pub fn insert_before(&mut self, element: T) {
        self._insert(element, |list, cursor_node, element| {
            let new_node = cursor_node.insert_new_before(element);
            if list.tail == Some(cursor_node) {
                list.tail = Some(new_node);
            }
        });
    }

    // put into list, if empty, else do whatever callback says
    fn _insert(&mut self, element: T, callback: impl Fn(&mut LinkedList<T>, NodePtr<T>, T)) {
        let cursor_node = match self.node {
            Some(node) => node,
            None => { // list empty
                self.node = Some(Node::new_linkless(element));
                self.list.head = self.node;
                self.list.tail = self.node;
                self.list.len += 1;
                return
            }
        };
        callback(&mut self.list, cursor_node, element);
        self.list.len += 1;
    }

    fn _insert_list_on_empty_list(&mut self, other: &mut LinkedList<T>) {
        debug_assert!(self.list.len == 0);
        std::mem::swap(self.list, other);
        self.node = self.list.tail;
    }

    fn _insert_list(
        &mut self,
        other: &mut LinkedList<T>,
        callback: impl Fn(NodePtr<T>, NodePtr<T>, NodePtr<T>)
    ) {
        unsafe {
            let cursor_node = match self.node {
                Some(node) => node,
                None => {
                    self._insert_list_on_empty_list(other);
                    return;
                }
            };

            if let LinkedList { head: Some(head), tail: Some(tail), len, .. } = *other {
                debug_assert!(head.as_ref().next.is_none());
                debug_assert!(tail.as_ref().prev.is_none());
                std::ptr::write(other, LinkedList::new()); // empty without dropping

                // link up on the right or left side
                callback(cursor_node, head, tail);
                self.list.len += len; // may overflow
            }
        }
    }

    pub fn insert_list_after(&mut self, other: &mut LinkedList<T>) {
        unsafe {
            self._insert_list(other, |mut cursor_node, head, tail| {
                if let Some(next) = cursor_node.as_mut().next {
                    NodePtr::link(head, next);
                }
                NodePtr::link(cursor_node, tail);
            });
        }
    }

    pub fn insert_list_before(&mut self, other: &mut LinkedList<T>) {
        unsafe {
            self._insert_list(other, |mut cursor_node, head, tail| {
                if let Some(prev) = cursor_node.as_mut().prev {
                    NodePtr::link(prev, tail);
                }
                NodePtr::link(head, cursor_node);
            });
        }
    }
}
<|endoftext|>


<commit_before>use crate::ast;
use crate::evaluation::object;
use crate::lexer;
use crate::parser;
use crate::token;

// TODO: Consider this to be a hack.
//
// We have 3 types of untis now.
// 1. Program
// 2. Statement
// 3. Expression
//
// To generalize eval API we would wrap program in a special
// wrapper enum, which knows how to handle every unit.

#[derive(Debug)]
pub enum WrappedNode {
    P(ast::Program),
    S(token::Statements),
    E(token::Expression),
}
pub type WN = WrappedNode; // Just alias to avoid typing :)

// Option number 2.
// Write 3 different functions to work with 3
// different types of values.
//
// It's super bad design decision, cause I'll have to
// use different evalers in my REPL implementation,
// but I don't see the design clearly for now.

// For now we'll stick with design approach with WrappedNode.
// Perhaps use From/Into modification?

// To save some typing in creating basic object
// we will use constants.

const NIL: object::Object = object::Object::Nil(object::Nil {});
const TRUE: object::Object = object::Object::Boolean(object::Boolean { value: true });
const FALSE: object::Object = object::Object::Boolean(object::Boolean { value: false });

pub fn eval(node: WN) -> object::Object {
    match node {
        WN::P(program) => eval_statements(program.statements),
        WN::S(statement) => match statement {
            token::Statements::ExpressionStatement(expr) => eval(WN::E(expr.expression)),
            token::Statements::LetStatement(_) => panic!("don't know how to handle let statement"),
            token::Statements::ReturnStatement(_) => {
                panic!("don't know how to handle return statement")
            }
        },
        WN::E(expression) => match expression {
            token::Expression::IntegerLiteral(il) => {
                object::Object::Integer(object::Integer { value: il.value })
            }
            token::Expression::Identifier(_i) => panic!("don't how to handle identifier"),
            token::Expression::PrefixExpression(pe) => {
                let right = eval(WN::E(pe.right));
                match pe.operator.as_ref() {
                    "!" => match right {
                        TRUE => FALSE,
                        FALSE => TRUE,
                        NIL => TRUE,
                        _ => FALSE,
                    },
                    "-" => match right {
                        object::Object::Integer(int_obj) => {
                            object::Object::Integer(object::Integer {
                                value: -int_obj.value,
                            })
                        }
                        _ => NIL, // terrible semantics
                    },
                    _ => object::Object::Nil(object::Nil {}), // just nil, ok
                }
            }
            token::Expression::InfixExpression(ie) => {
                let left = eval(WN::E(ie.left));
                let right = eval(WN::E(ie.right));
                if let (object::Object::Integer(left_obj), object::Object::Integer(right_obj)) =
                    (left, right)
                {
                    match ie.operator.as_ref() {
                        "+" => object::Object::Integer(object::Integer {
                            value: left_obj.value + right_obj.value,
                        }),
                        "-" => object::Object::Integer(object::Integer {
                            value: left_obj.value - right_obj.value,
                        }),
                        "*" => object::Object::Integer(object::Integer {
                            value: left_obj.value * right_obj.value,
                        }),
                        "/" => object::Object::Integer(object::Integer {
                            value: left_obj.value / right_obj.value,
                        }),
                        "<" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value < right_obj.value
                        }),
                        ">" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value > right_obj.value
                        }),
                        "==" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value == right_obj.value
                        }),
                        "!=" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value != right_obj.value
                        }),
                        _ => panic!(
                            "Unexpected operator `{}`, while evaling expression",
                            ie.operator
                        ),
                    }
                } else {
                    NIL
                }
            }
            token::Expression::Boolean(b) => {
                // TODO: Check possible perf optimization? Needed?
                // Reuse TRUE and FALSE I mean
                object::Object::Boolean(object::Boolean { value: b.value })
            }
            token::Expression::IfExpression(_ie) => panic!("don't how to handle if expression"),
            token::Expression::FunctionLiteral(_fl) => {
                panic!("don't how to handle function literal")
            }
            token::Expression::CallExpression(_ce) => panic!("don't how to handle call expression"),
        },
    }
}

pub fn eval_statements(statements: Vec<token::Statements>) -> object::Object {
    // TODO: not sure we need unwrap here.
    statements
        .into_iter()
        .map(|statement| eval(WN::S(statement)))
        .last()
        .unwrap()
}

#[cfg(test)]
mod tests {
    use crate::evaluation;
    use crate::lexer;
    use crate::parser;
    use std::collections::HashMap;

    #[test]
    fn test_eval_integer_expression() {
        let pairs = vec![("1".to_string(), 1), ("2".to_string(), 2)];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_integer_object(evaluated, expected);
        })
    }

    #[test]
    fn test_eval_boolean_expression() {
        let pairs = vec![
            ("true".to_string(), true),
            ("false".to_string(), false),
            ("1 < 2".to_string(), true),
            ("1 > 2".to_string(), false),
            ("1 < 1".to_string(), false),
            ("1 < 1".to_string(), false),
            ("1 == 1".to_string(), true),
            ("1 != 1".to_string(), false),
            ("1 == 2".to_string(), false),
            ("1 != 2".to_string(), true),
        ];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_boolean_object(evaluated, expected);
        })
    }

    #[test]
    fn test_bang_operator() {
        let pairs = vec![
            ("!true".to_string(), false),
            ("!false".to_string(), true),
            ("!1".to_string(), false),
            ("!!true".to_string(), true),
            ("!!false".to_string(), false),
            ("!!1".to_string(), true),
        ];

        for (value, expected) in pairs {
            assert_boolean_object(run_eval(value), expected)
        }
    }

    #[test]
    fn test_prefix_negate_operator() {
        let pairs = vec![("-1".to_string(), -1), ("--1".to_string(), 1)];

        for (value, expected) in pairs {
            assert_integer_object(run_eval(value), expected)
        }
    }

    #[test]
    fn test_integer_arithmetic() {
        let pairs = vec![
            ("1 + 1 + 1".to_string(), 3),
            ("2 * 2 * 2".to_string(), 8),
            ("4 / 2 * 2".to_string(), 4),
            ("1 + 3 * 2".to_string(), 7),
        ];

        for (value, expected) in pairs {
            assert_integer_object(run_eval(value), expected)
        }
    }

    fn run_eval(source_code: String) -> evaluation::object::Object {
        let lexer = lexer::Lexer::new(source_code);
        let mut parser = parser::Parser::new(lexer);

        let mut lambda_parsers = parser::LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };
        lambda_parsers.register_parsers();

        let program = parser.parse_program(&lambda_parsers);

        evaluation::evaluator::eval(evaluation::evaluator::WN::P(program))
    }

    fn assert_integer_object(object: evaluation::object::Object, expected: i32) {
        let integer = match object {
            evaluation::object::Object::Integer(int) => int,
            otherwise => panic!("expected integer, got {:?}", otherwise),
        };

        assert_eq!(integer.value, expected)
    }

    fn assert_boolean_object(object: evaluation::object::Object, expected: bool) {
        let bool = match object {
            evaluation::object::Object::Boolean(b) => b,
            otherwise => panic!("expected boolean, got {:?}", otherwise),
        };

        assert_eq!(bool.value, expected)
    }
}
<commit_msg>adds boolean's == and != evaler<commit_after>use crate::ast;
use crate::evaluation::object;
use crate::lexer;
use crate::parser;
use crate::token;

// TODO: Consider this to be a hack.
//
// We have 3 types of untis now.
// 1. Program
// 2. Statement
// 3. Expression
//
// To generalize eval API we would wrap program in a special
// wrapper enum, which knows how to handle every unit.

#[derive(Debug)]
pub enum WrappedNode {
    P(ast::Program),
    S(token::Statements),
    E(token::Expression),
}
pub type WN = WrappedNode; // Just alias to avoid typing :)

// Option number 2.
// Write 3 different functions to work with 3
// different types of values.
//
// It's super bad design decision, cause I'll have to
// use different evalers in my REPL implementation,
// but I don't see the design clearly for now.

// For now we'll stick with design approach with WrappedNode.
// Perhaps use From/Into modification?

// To save some typing in creating basic object
// we will use constants.

const NIL: object::Object = object::Object::Nil(object::Nil {});
const TRUE: object::Object = object::Object::Boolean(object::Boolean { value: true });
const FALSE: object::Object = object::Object::Boolean(object::Boolean { value: false });

pub fn eval(node: WN) -> object::Object {
    match node {
        WN::P(program) => eval_statements(program.statements),
        WN::S(statement) => match statement {
            token::Statements::ExpressionStatement(expr) => eval(WN::E(expr.expression)),
            token::Statements::LetStatement(_) => panic!("don't know how to handle let statement"),
            token::Statements::ReturnStatement(_) => {
                panic!("don't know how to handle return statement")
            }
        },
        WN::E(expression) => match expression {
            token::Expression::IntegerLiteral(il) => {
                object::Object::Integer(object::Integer { value: il.value })
            }
            token::Expression::Identifier(_i) => panic!("don't how to handle identifier"),
            token::Expression::PrefixExpression(pe) => {
                let right = eval(WN::E(pe.right));
                match pe.operator.as_ref() {
                    "!" => match right {
                        TRUE => FALSE,
                        FALSE => TRUE,
                        NIL => TRUE,
                        _ => FALSE,
                    },
                    "-" => match right {
                        object::Object::Integer(int_obj) => {
                            object::Object::Integer(object::Integer {
                                value: -int_obj.value,
                            })
                        }
                        _ => NIL, // terrible semantics
                    },
                    _ => object::Object::Nil(object::Nil {}), // just nil, ok
                }
            }
            token::Expression::InfixExpression(ie) => {
                let left = eval(WN::E(ie.left));
                let right = eval(WN::E(ie.right));
                if let (object::Object::Integer(left_obj), object::Object::Integer(right_obj)) =
                    (left.clone(), right.clone())
                {
                    match ie.operator.as_ref() {
                        "+" => object::Object::Integer(object::Integer {
                            value: left_obj.value + right_obj.value,
                        }),
                        "-" => object::Object::Integer(object::Integer {
                            value: left_obj.value - right_obj.value,
                        }),
                        "*" => object::Object::Integer(object::Integer {
                            value: left_obj.value * right_obj.value,
                        }),
                        "/" => object::Object::Integer(object::Integer {
                            value: left_obj.value / right_obj.value,
                        }),
                        "<" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value < right_obj.value
                        }),
                        ">" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value > right_obj.value
                        }),
                        "==" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value == right_obj.value
                        }),
                        "!=" => object::Object::Boolean(object::Boolean {
                            value: left_obj.value != right_obj.value
                        }),
                        _ => panic!(
                            "Unexpected operator `{}`, while evaling expression",
                            ie.operator
                        ),
                    }
                    // what if not boolean?
                } else if let (object::Object::Boolean(left_obj), object::Object::Boolean(right_obj)) =
                    (left, right) {
                        match ie.operator.as_ref() {
                            "==" => object::Object::Boolean(object::Boolean {
                                value: left_obj.value == right_obj.value,
                            }),
                            "!=" => object::Object::Boolean(object::Boolean {
                                value: left_obj.value != right_obj.value,
                            }),
                            _ => panic!("Unxepected operator applied to bool `{}`", ie.operator)
                        }
                } else {
                    NIL
                }
            }
            token::Expression::Boolean(b) => {
                // TODO: Check possible perf optimization? Needed?
                // Reuse TRUE and FALSE I mean
                object::Object::Boolean(object::Boolean { value: b.value })
            }
            token::Expression::IfExpression(_ie) => panic!("don't how to handle if expression"),
            token::Expression::FunctionLiteral(_fl) => {
                panic!("don't how to handle function literal")
            }
            token::Expression::CallExpression(_ce) => panic!("don't how to handle call expression"),
        },
    }
}

pub fn eval_statements(statements: Vec<token::Statements>) -> object::Object {
    // TODO: not sure we need unwrap here.
    statements
        .into_iter()
        .map(|statement| eval(WN::S(statement)))
        .last()
        .unwrap()
}

#[cfg(test)]
mod tests {
    use crate::evaluation;
    use crate::lexer;
    use crate::parser;
    use std::collections::HashMap;

    #[test]
    fn test_eval_integer_expression() {
        let pairs = vec![("1".to_string(), 1), ("2".to_string(), 2)];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_integer_object(evaluated, expected);
        })
    }

    #[test]
    fn test_eval_boolean_expression() {
        let pairs = vec![
            ("true".to_string(), true),
            ("false".to_string(), false),
            ("1 < 2".to_string(), true),
            ("1 > 2".to_string(), false),
            ("1 < 1".to_string(), false),
            ("1 < 1".to_string(), false),
            ("1 == 1".to_string(), true),
            ("1 != 1".to_string(), false),
            ("1 == 2".to_string(), false),
            ("1 != 2".to_string(), true),
            ("true == true".to_string(), true),
            ("false == false".to_string(), true),
            ("true == false".to_string(), false),
        ];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_boolean_object(evaluated, expected);
        })
    }

    #[test]
    fn test_bang_operator() {
        let pairs = vec![
            ("!true".to_string(), false),
            ("!false".to_string(), true),
            ("!1".to_string(), false),
            ("!!true".to_string(), true),
            ("!!false".to_string(), false),
            ("!!1".to_string(), true),
        ];

        for (value, expected) in pairs {
            assert_boolean_object(run_eval(value), expected)
        }
    }

    #[test]
    fn test_prefix_negate_operator() {
        let pairs = vec![("-1".to_string(), -1), ("--1".to_string(), 1)];

        for (value, expected) in pairs {
            assert_integer_object(run_eval(value), expected)
        }
    }

    #[test]
    fn test_integer_arithmetic() {
        let pairs = vec![
            ("1 + 1 + 1".to_string(), 3),
            ("2 * 2 * 2".to_string(), 8),
            ("4 / 2 * 2".to_string(), 4),
            ("1 + 3 * 2".to_string(), 7),
        ];

        for (value, expected) in pairs {
            assert_integer_object(run_eval(value), expected)
        }
    }

    fn run_eval(source_code: String) -> evaluation::object::Object {
        let lexer = lexer::Lexer::new(source_code);
        let mut parser = parser::Parser::new(lexer);

        let mut lambda_parsers = parser::LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };
        lambda_parsers.register_parsers();

        let program = parser.parse_program(&lambda_parsers);

        evaluation::evaluator::eval(evaluation::evaluator::WN::P(program))
    }

    fn assert_integer_object(object: evaluation::object::Object, expected: i32) {
        let integer = match object {
            evaluation::object::Object::Integer(int) => int,
            otherwise => panic!("expected integer, got {:?}", otherwise),
        };

        assert_eq!(integer.value, expected)
    }

    fn assert_boolean_object(object: evaluation::object::Object, expected: bool) {
        let bool = match object {
            evaluation::object::Object::Boolean(b) => b,
            otherwise => panic!("expected boolean, got {:?}", otherwise),
        };

        assert_eq!(bool.value, expected)
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsString;

use crate::core::compiler::{Compilation, CompileKind, Doctest};
use crate::core::shell::Verbosity;
use crate::core::Workspace;
use crate::ops;
use crate::util::errors::CargoResult;
use crate::util::{CargoTestError, Config, ProcessError, Test};

pub struct TestOptions {
    pub compile_opts: ops::CompileOptions,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

pub fn run_tests(
    ws: &Workspace<'_>,
    options: &TestOptions,
    test_args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }
    let (test, mut errors) = run_unit_tests(ws.config(), options, test_args, &compilation)?;

    // If we have an error and want to fail fast, then return.
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(test, errors)));
    }

    let (doctest, docerrors) = run_doc_tests(ws.config(), options, test_args, &compilation)?;
    let test = if docerrors.is_empty() { test } else { doctest };
    errors.extend(docerrors);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(test, errors)))
    }
}

pub fn run_benches(
    ws: &Workspace<'_>,
    options: &TestOptions,
    args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }

    let mut args = args.to_vec();
    args.push("--bench");

    let (test, errors) = run_unit_tests(ws.config(), options, &args, &compilation)?;

    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(test, errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation
        .tests
        .sort_by(|a, b| (a.0.package_id(), &a.1, &a.2).cmp(&(b.0.package_id(), &b.1, &b.2)));
    Ok(compilation)
}

/// Runs the unit and integration tests of a package.
fn run_unit_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let cwd = config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, ref target, ref exe) in &compilation.tests {
        let kind = target.kind();
        let test = target.name().to_string();
        let exe_display = exe.strip_prefix(cwd).unwrap_or(exe).display();
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        if target.harness() && config.shell().verbosity() == Verbosity::Quiet {
            cmd.arg("--quiet");
        }
        config
            .shell()
            .concise(|shell| shell.status("Running", &exe_display))?;
        config
            .shell()
            .verbose(|shell| shell.status("Running", &cmd))?;

        let result = cmd.exec();

        match result {
            Err(e) => {
                let e = e.downcast::<ProcessError>()?;
                errors.push((kind.clone(), test.clone(), pkg.name().to_string(), e));
                if !options.no_fail_fast {
                    break;
                }
            }
            Ok(()) => {}
        }
    }

    if errors.len() == 1 {
        let (kind, name, pkg_name, e) = errors.pop().unwrap();
        Ok((
            Test::UnitTest {
                kind,
                name,
                pkg_name,
            },
            vec![e],
        ))
    } else {
        Ok((
            Test::Multiple,
            errors.into_iter().map(|(_, _, _, e)| e).collect(),
        ))
    }
}

fn run_doc_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let mut errors = Vec::new();

    // The unstable doctest-xcompile feature enables both per-target-ignores and
    // cross-compiling doctests. As a side effect, this feature also gates running
    // doctests with runtools when target == host.
    let doctest_xcompile = config.cli_unstable().doctest_xcompile;
    let mut runtool: &Option<(std::path::PathBuf, Vec<String>)> = &None;
    if doctest_xcompile {
        runtool = compilation.target_runner();
    } else if options.compile_opts.build_config.requested_kind.is_host() {
        return Ok((Test::Doc, errors));
    }

    for doctest_info in &compilation.to_doc_test {
        let Doctest {
            package,
            target,
            args,
            unstable_opts,
        } = doctest_info;
        config.shell().status("Doc-tests", target.name())?;
        let mut p = compilation.rustdoc_process(package, target)?;
        p.arg("--test")
            .arg(target.src_path().path().unwrap())
            .arg("--crate-name")
            .arg(&target.crate_name());

        if doctest_xcompile {
            if let CompileKind::Target(target) = options.compile_opts.build_config.requested_kind {
                p.arg("--target").arg(target.rustc_target());
            }
            p.arg("-Zunstable-options");
            p.arg("--enable-per-target-ignores");
        }

        if let Some((runtool, runtool_args)) = runtool {
            p.arg("--runtool").arg(runtool);
            for arg in runtool_args {
                p.arg("--runtool-arg").arg(arg);
            }
        }

        for &rust_dep in &[&compilation.deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(rust_dep);
            p.arg("-L").arg(arg);
        }

        for native_dep in compilation.native_dirs.iter() {
            p.arg("-L").arg(native_dep);
        }

        for &host_rust_dep in &[&compilation.host_deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(host_rust_dep);
            p.arg("-L").arg(arg);
        }

        for arg in test_args {
            p.arg("--test-args").arg(arg);
        }

        if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
            for cfg in cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }
        }

        for arg in args {
            p.arg(arg);
        }

        if *unstable_opts {
            p.arg("-Zunstable-options");
        }

        if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) {
            p.args(flags);
        }
        config
            .shell()
            .verbose(|shell| shell.status("Running", p.to_string()))?;
        if let Err(e) = p.exec() {
            let e = e.downcast::<ProcessError>()?;
            errors.push(e);
            if !options.no_fail_fast {
                return Ok((Test::Doc, errors));
            }
        }
    }
    Ok((Test::Doc, errors))
}
<commit_msg>fix running doctest for host target<commit_after>use std::ffi::OsString;

use crate::core::compiler::{Compilation, CompileKind, Doctest};
use crate::core::shell::Verbosity;
use crate::core::Workspace;
use crate::ops;
use crate::util::errors::CargoResult;
use crate::util::{CargoTestError, Config, ProcessError, Test};

pub struct TestOptions {
    pub compile_opts: ops::CompileOptions,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

pub fn run_tests(
    ws: &Workspace<'_>,
    options: &TestOptions,
    test_args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }
    let (test, mut errors) = run_unit_tests(ws.config(), options, test_args, &compilation)?;

    // If we have an error and want to fail fast, then return.
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(test, errors)));
    }

    let (doctest, docerrors) = run_doc_tests(ws.config(), options, test_args, &compilation)?;
    let test = if docerrors.is_empty() { test } else { doctest };
    errors.extend(docerrors);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(test, errors)))
    }
}

pub fn run_benches(
    ws: &Workspace<'_>,
    options: &TestOptions,
    args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }

    let mut args = args.to_vec();
    args.push("--bench");

    let (test, errors) = run_unit_tests(ws.config(), options, &args, &compilation)?;

    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(test, errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation
        .tests
        .sort_by(|a, b| (a.0.package_id(), &a.1, &a.2).cmp(&(b.0.package_id(), &b.1, &b.2)));
    Ok(compilation)
}

/// Runs the unit and integration tests of a package.
fn run_unit_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let cwd = config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, ref target, ref exe) in &compilation.tests {
        let kind = target.kind();
        let test = target.name().to_string();
        let exe_display = exe.strip_prefix(cwd).unwrap_or(exe).display();
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        if target.harness() && config.shell().verbosity() == Verbosity::Quiet {
            cmd.arg("--quiet");
        }
        config
            .shell()
            .concise(|shell| shell.status("Running", &exe_display))?;
        config
            .shell()
            .verbose(|shell| shell.status("Running", &cmd))?;

        let result = cmd.exec();

        match result {
            Err(e) => {
                let e = e.downcast::<ProcessError>()?;
                errors.push((kind.clone(), test.clone(), pkg.name().to_string(), e));
                if !options.no_fail_fast {
                    break;
                }
            }
            Ok(()) => {}
        }
    }

    if errors.len() == 1 {
        let (kind, name, pkg_name, e) = errors.pop().unwrap();
        Ok((
            Test::UnitTest {
                kind,
                name,
                pkg_name,
            },
            vec![e],
        ))
    } else {
        Ok((
            Test::Multiple,
            errors.into_iter().map(|(_, _, _, e)| e).collect(),
        ))
    }
}

fn run_doc_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let mut errors = Vec::new();

    // The unstable doctest-xcompile feature enables both per-target-ignores and
    // cross-compiling doctests. As a side effect, this feature also gates running
    // doctests with runtools when target == host.
    let doctest_xcompile = config.cli_unstable().doctest_xcompile;
    let mut runtool: &Option<(std::path::PathBuf, Vec<String>)> = &None;
    if doctest_xcompile {
        runtool = compilation.target_runner();
    } else if !options.compile_opts.build_config.requested_kind.is_host() {
        return Ok((Test::Doc, errors));
    }

    for doctest_info in &compilation.to_doc_test {
        let Doctest {
            package,
            target,
            args,
            unstable_opts,
        } = doctest_info;
        config.shell().status("Doc-tests", target.name())?;
        let mut p = compilation.rustdoc_process(package, target)?;
        p.arg("--test")
            .arg(target.src_path().path().unwrap())
            .arg("--crate-name")
            .arg(&target.crate_name());

        if doctest_xcompile {
            if let CompileKind::Target(target) = options.compile_opts.build_config.requested_kind {
                p.arg("--target").arg(target.rustc_target());
            }
            p.arg("-Zunstable-options");
            p.arg("--enable-per-target-ignores");
        }

        if let Some((runtool, runtool_args)) = runtool {
            p.arg("--runtool").arg(runtool);
            for arg in runtool_args {
                p.arg("--runtool-arg").arg(arg);
            }
        }

        for &rust_dep in &[&compilation.deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(rust_dep);
            p.arg("-L").arg(arg);
        }

        for native_dep in compilation.native_dirs.iter() {
            p.arg("-L").arg(native_dep);
        }

        for &host_rust_dep in &[&compilation.host_deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(host_rust_dep);
            p.arg("-L").arg(arg);
        }

        for arg in test_args {
            p.arg("--test-args").arg(arg);
        }

        if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
            for cfg in cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }
        }

        for arg in args {
            p.arg(arg);
        }

        if *unstable_opts {
            p.arg("-Zunstable-options");
        }

        if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) {
            p.args(flags);
        }
        config
            .shell()
            .verbose(|shell| shell.status("Running", p.to_string()))?;
        if let Err(e) = p.exec() {
            let e = e.downcast::<ProcessError>()?;
            errors.push(e);
            if !options.no_fail_fast {
                return Ok((Test::Doc, errors));
            }
        }
    }
    Ok((Test::Doc, errors))
}
<|endoftext|>


<commit_before>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Helper library for accessing Oak storage services.

extern crate protobuf;

use crate::grpc;
use crate::{ReadHandle, WriteHandle};
use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use proto::storage_channel::{
    StorageChannelDeleteRequest, StorageChannelDeleteResponse, StorageChannelReadRequest,
    StorageChannelReadResponse, StorageChannelWriteRequest, StorageChannelWriteResponse,
};
use protobuf::Message;

/// Local representation of the connection to an external storage service.
pub struct Storage {
    write_channel: crate::io::Channel,
    wait_space: Vec<u8>,
    read_channel: crate::ReadHandle,
}

impl Default for Storage {
    /// Create a default `Storage` instance assuming the standard port names
    /// (`"storage_in"`, `"storage_out"`) for pre-defined channels for storage
    /// communication.
    fn default() -> Storage {
        Storage::new("storage_in", "storage_out")
    }
}

impl Storage {
    /// Create a `Storage` instance using the given port names for pre-defined
    /// channels for storage communication.
    pub fn new(in_port_name: &str, out_port_name: &str) -> Storage {
        let read_handle = ReadHandle {
            handle: crate::channel_find(in_port_name),
        };
        let write_handle = WriteHandle {
            handle: crate::channel_find(out_port_name),
        };
        let handles = vec![read_handle];
        Storage {
            write_channel: crate::io::Channel::new(write_handle),
            wait_space: crate::new_handle_space(&handles),
            read_channel: read_handle,
        }
    }

    fn execute_operation<Req, Res>(
        &mut self,
        grpc_method_name: &str,
        operation_request: &Req,
    ) -> grpc::Result<Res>
    where
        Req: protobuf::Message,
        Res: protobuf::Message,
    {
        info!(
            "StorageChannelRequest: {}",
            protobuf::text_format::print_to_string(operation_request)
        );

        let mut request_any = protobuf::well_known_types::Any::new();
        operation_request
            .write_to_writer(&mut request_any.value)
            .unwrap();
        let mut grpc_request = GrpcRequest::new();
        grpc_request.method_name = grpc_method_name.to_owned();
        grpc_request.set_req_msg(request_any);

        grpc_request
            .write_to_writer(&mut self.write_channel)
            .unwrap();

        // Block until there is a response available.
        unsafe {
            crate::wasm::wait_on_channels(self.wait_space.as_mut_ptr(), 1);
        }

        let mut buffer = Vec::<u8>::with_capacity(256);
        let mut handles = Vec::<crate::Handle>::with_capacity(1);
        crate::channel_read(self.read_channel, &mut buffer, &mut handles);
        if !handles.is_empty() {
            panic!("unexpected handles received alongside storage request")
        }
        let mut grpc_response: GrpcResponse =
            protobuf::parse_from_reader(&mut &buffer[..]).unwrap();
        info!(
            "StorageChannelResponse: {}",
            protobuf::text_format::print_to_string(&grpc_response)
        );

        let status = grpc_response.take_status();
        if status.code != 0 {
            Err(status)
        } else {
            let response =
                protobuf::parse_from_bytes(grpc_response.get_rsp_msg().value.as_slice()).unwrap();
            Ok(response)
        }
    }

    /// Read the value associated with the given `name` from the storage
    /// instance identified by `name`.
    pub fn read(&mut self, storage_name: &[u8], name: &[u8]) -> grpc::Result<Vec<u8>> {
        let mut read_request = StorageChannelReadRequest::new();
        read_request.storage_name = storage_name.to_owned();
        read_request.datum_name = name.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelReadRequest, StorageChannelReadResponse>(
            "/oak.StorageNode/Read",
            &read_request,
        )
        .map(|r| r.get_datum_value().to_vec())
    }

    /// Set the value associated with the given `name` from the storage instance
    /// identified by `name`.
    pub fn write(&mut self, storage_name: &[u8], name: &[u8], value: &[u8]) -> grpc::Result<()> {
        let mut write_request = StorageChannelWriteRequest::new();
        write_request.storage_name = storage_name.to_owned();
        write_request.datum_name = name.to_owned();
        write_request.datum_value = value.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelWriteRequest, StorageChannelWriteResponse>(
            "/oak.StorageNode/Write",
            &write_request,
        )
        .map(|_| ())
    }

    /// Delete the value associated with the given `name` from the storage
    /// instance identified by `name`.
    pub fn delete(&mut self, storage_name: &[u8], name: &[u8]) -> grpc::Result<()> {
        let mut delete_request = StorageChannelDeleteRequest::new();
        delete_request.storage_name = storage_name.to_owned();
        delete_request.datum_name = name.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelDeleteRequest, StorageChannelDeleteResponse>(
            "/oak.StorageNode/Delete",
            &delete_request,
        )
        .map(|_| ())
    }
}
<commit_msg>Fix gRPC encapsulated storage operations (#291)<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Helper library for accessing Oak storage services.

extern crate protobuf;

use crate::grpc;
use crate::{ReadHandle, WriteHandle};
use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use proto::storage_channel::{
    StorageChannelDeleteRequest, StorageChannelDeleteResponse, StorageChannelReadRequest,
    StorageChannelReadResponse, StorageChannelWriteRequest, StorageChannelWriteResponse,
};
use protobuf::Message;

/// Local representation of the connection to an external storage service.
pub struct Storage {
    write_channel: crate::io::Channel,
    wait_space: Vec<u8>,
    read_channel: crate::ReadHandle,
}

impl Default for Storage {
    /// Create a default `Storage` instance assuming the standard port names
    /// (`"storage_in"`, `"storage_out"`) for pre-defined channels for storage
    /// communication.
    fn default() -> Storage {
        Storage::new("storage_in", "storage_out")
    }
}

impl Storage {
    /// Create a `Storage` instance using the given port names for pre-defined
    /// channels for storage communication.
    pub fn new(in_port_name: &str, out_port_name: &str) -> Storage {
        let read_handle = ReadHandle {
            handle: crate::channel_find(in_port_name),
        };
        let write_handle = WriteHandle {
            handle: crate::channel_find(out_port_name),
        };
        let handles = vec![read_handle];
        Storage {
            write_channel: crate::io::Channel::new(write_handle),
            wait_space: crate::new_handle_space(&handles),
            read_channel: read_handle,
        }
    }

    fn execute_operation<Req, Res>(
        &mut self,
        grpc_method_name: &str,
        operation_request: &Req,
    ) -> grpc::Result<Res>
    where
        Req: protobuf::Message,
        Res: protobuf::Message,
    {
        info!(
            "StorageChannelRequest: {}",
            protobuf::text_format::print_to_string(operation_request)
        );

        let mut request_any = protobuf::well_known_types::Any::new();
        // TODO: rust-protobuf does not provide pack_from/unpack_to functions.
        // https://github.com/stepancheg/rust-protobuf/issues/455
        request_any.set_type_url(
            String::from("type.googleapis.com/") + operation_request.descriptor().full_name(),
        );
        operation_request
            .write_to_writer(&mut request_any.value)
            .unwrap();
        let mut grpc_request = GrpcRequest::new();
        grpc_request.method_name = grpc_method_name.to_owned();
        grpc_request.set_req_msg(request_any);

        grpc_request
            .write_to_writer(&mut self.write_channel)
            .unwrap();

        // Block until there is a response available.
        unsafe {
            crate::wasm::wait_on_channels(self.wait_space.as_mut_ptr(), 1);
        }

        let mut buffer = Vec::<u8>::with_capacity(256);
        let mut handles = Vec::<crate::Handle>::with_capacity(1);
        crate::channel_read(self.read_channel, &mut buffer, &mut handles);
        if !handles.is_empty() {
            panic!("unexpected handles received alongside storage request")
        }
        let mut grpc_response: GrpcResponse =
            protobuf::parse_from_reader(&mut &buffer[..]).unwrap();
        info!(
            "StorageChannelResponse: {}",
            protobuf::text_format::print_to_string(&grpc_response)
        );

        let status = grpc_response.take_status();
        if status.code != 0 {
            Err(status)
        } else {
            let response =
                protobuf::parse_from_bytes(grpc_response.get_rsp_msg().value.as_slice()).unwrap();
            Ok(response)
        }
    }

    /// Read the value associated with the given `name` from the storage
    /// instance identified by `name`.
    pub fn read(&mut self, storage_name: &[u8], name: &[u8]) -> grpc::Result<Vec<u8>> {
        let mut read_request = StorageChannelReadRequest::new();
        read_request.storage_name = storage_name.to_owned();
        read_request.datum_name = name.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelReadRequest, StorageChannelReadResponse>(
            "/oak.StorageNode/Read",
            &read_request,
        )
        .map(|r| r.get_datum_value().to_vec())
    }

    /// Set the value associated with the given `name` from the storage instance
    /// identified by `name`.
    pub fn write(&mut self, storage_name: &[u8], name: &[u8], value: &[u8]) -> grpc::Result<()> {
        let mut write_request = StorageChannelWriteRequest::new();
        write_request.storage_name = storage_name.to_owned();
        write_request.datum_name = name.to_owned();
        write_request.datum_value = value.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelWriteRequest, StorageChannelWriteResponse>(
            "/oak.StorageNode/Write",
            &write_request,
        )
        .map(|_| ())
    }

    /// Delete the value associated with the given `name` from the storage
    /// instance identified by `name`.
    pub fn delete(&mut self, storage_name: &[u8], name: &[u8]) -> grpc::Result<()> {
        let mut delete_request = StorageChannelDeleteRequest::new();
        delete_request.storage_name = storage_name.to_owned();
        delete_request.datum_name = name.to_owned();

        // TODO: Automatically generate boilerplate from the proto definition.
        self.execute_operation::<StorageChannelDeleteRequest, StorageChannelDeleteResponse>(
            "/oak.StorageNode/Delete",
            &delete_request,
        )
        .map(|_| ())
    }
}
<|endoftext|>


<commit_before>extern crate orbital;

use orbital::Color;

use std::fs::File;
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::syscall::*;
use std::thread;

use window::ConsoleWindow;

mod window;

macro_rules! readln {
    () => ({
        let mut buffer = String::new();
        match std::io::stdin().read_line(&mut buffer) {
            Ok(_) => Some(buffer),
            Err(_) => None
        }
    });
}

pub fn pipe() -> [usize; 2] {
    let mut fds = [0; 2];
    SysError::demux(unsafe { sys_pipe2(fds.as_mut_ptr(), 0) }).unwrap();
    fds
}

#[no_mangle] pub fn main() {
    let to_shell_fds = pipe();
    let from_shell_fds = pipe();

    unsafe {
        if SysError::demux(sys_clone(0)).unwrap() == 0{
            //Close STDIO
            sys_close(2);
            sys_close(1);
            sys_close(0);

            //Create piped STDIO
            sys_dup(to_shell_fds[0]);
            sys_dup(from_shell_fds[1]);
            sys_dup(from_shell_fds[1]);

            //Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(to_shell_fds[1]);
            sys_close(from_shell_fds[0]);
            sys_close(from_shell_fds[1]);

            //Execute the shell
            let shell = "file:/apps/shell/main.bin\0";
            sys_execve(shell.as_ptr(), 0 as *const *const u8);
            panic!("Shell not found");
        } else{
            //Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(from_shell_fds[1]);
        }
    };

    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let mut from_shell = unsafe { File::from_fd(from_shell_fds[0]).unwrap() };
    loop {
        let mut output = String::new();
        if let Ok(_) = from_shell.read_to_string(&mut output) {
            window.print(&output, Color::rgb(255, 255, 255));
            window.sync();
        } else {
            break;
        }
    }
}
<commit_msg>Cleanup missing spaces in terminal<commit_after>extern crate orbital;

use orbital::Color;

use std::fs::File;
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::syscall::*;
use std::thread;

use window::ConsoleWindow;

mod window;

macro_rules! readln {
    () => ({
        let mut buffer = String::new();
        match std::io::stdin().read_line(&mut buffer) {
            Ok(_) => Some(buffer),
            Err(_) => None
        }
    });
}

pub fn pipe() -> [usize; 2] {
    let mut fds = [0; 2];
    SysError::demux(unsafe { sys_pipe2(fds.as_mut_ptr(), 0) }).unwrap();
    fds
}

#[no_mangle]
pub fn main() {
    let to_shell_fds = pipe();
    let from_shell_fds = pipe();

    unsafe {
        if SysError::demux(sys_clone(0)).unwrap() == 0 {
            // Close STDIO
            sys_close(2);
            sys_close(1);
            sys_close(0);

            // Create piped STDIO
            sys_dup(to_shell_fds[0]);
            sys_dup(from_shell_fds[1]);
            sys_dup(from_shell_fds[1]);

            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(to_shell_fds[1]);
            sys_close(from_shell_fds[0]);
            sys_close(from_shell_fds[1]);

            // Execute the shell
            let shell = "file:/apps/shell/main.bin\0";
            sys_execve(shell.as_ptr(), 0 as *const *const u8);
            panic!("Shell not found");
        } else {
            // Close extra pipes
            sys_close(to_shell_fds[0]);
            sys_close(from_shell_fds[1]);
        }
    };

    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let mut from_shell = unsafe { File::from_fd(from_shell_fds[0]).unwrap() };
    loop {
        let mut output = String::new();
        if let Ok(_) = from_shell.read_to_string(&mut output) {
            window.print(&output, Color::rgb(255, 255, 255));
            window.sync();
        } else {
            break;
        }
    }
}
<|endoftext|>