<commit_before>extern crate rand;

use rand::distributions::{IndependentSample, Sample, Weighted, WeightedChoice};
use rand::{weak_rng, Rng};

const DATA: [(&str, f64); 8] = [
    ("aleph", 1.0 / 5.0),
    ("beth", 1.0 / 6.0),
    ("gimel", 1.0 / 7.0),
    ("daleth", 1.0 / 8.0),
    ("he", 1.0 / 9.0),
    ("waw", 1.0 / 10.0),
    ("zayin", 1.0 / 11.0),
    ("heth", 1759.0 / 27720.0),
];

const SAMPLES: usize = 1_000_000;

// Generate a mapping to be used by `WeightedChoice`
fn gen_mapping() -> Vec<Weighted<usize>> {
    DATA.iter()
        .enumerate()
        .map(|(i, &(_, p))| Weighted {
            // `WeightedChoice` requires `u32` weights rather than raw probabilities.  For each
            // probability, we convert it to a `u32` weight, and associate it with an index. We
            // multiply by a constant because small numbers such as 0.2 when casted to `u32`
            // become `0`.  This conversion decreases the accuracy of the mapping, which is why we
            // provide an implementation which uses `f64`s for the best accuracy.
            weight: (p * 1_000_000_000.0) as u32,
            item: i,
        })
        .collect()
}

// Generate a mapping of the raw probabilities
fn gen_mapping_float() -> Vec<f64> {
    // This does the work of `WeightedChoice::new`, splitting a number into various ranges.  The
    // `item` of `Weighted` is represented here merely by the probability's position in the `Vec`.
    let mut running_total = 0.0;
    DATA.iter()
        .map(|&(_, p)| {
            running_total += p;
            running_total
        })
        .collect()
}

// An implementation of `WeightedChoice` which uses probabilities rather than weights.  Refer to
// the `WeightedChoice` source for serious usage.
struct WcFloat {
    mapping: Vec<f64>,
}

impl WcFloat {
    fn new(mapping: &[f64]) -> Self {
        Self {
            mapping: mapping.to_vec(),
        }
    }

    // This is roughly the same logic as `WeightedChoice::ind_sample` (though is likely slower)
    fn search(&self, sample_prob: f64) -> usize {
        let idx = self.mapping
            .binary_search_by(|p| p.partial_cmp(&sample_prob).unwrap());
        match idx {
            Ok(i) | Err(i) => i,
        }
    }
}

impl IndependentSample<usize> for WcFloat {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        // Because we know the total is exactly 1.0, we can merely use a raw float value.
        // Otherwise caching `Range::new(0.0, running_total)` and sampling with
        // `range.ind_sample(&mut rng)` is recommended.
        let sample_prob = rng.next_f64();
        self.search(sample_prob)
    }
}

impl Sample<usize> for WcFloat {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

fn take_samples<R: Rng, T>(rng: &mut R, wc: &T) -> [usize; 8]
where
    T: IndependentSample<usize>,
{
    let mut counts = [0; 8];
    for _ in 0..SAMPLES {
        let sample = wc.ind_sample(rng);
        counts[sample] += 1;
    }
    counts
}

fn print_mapping(counts: &[usize]) {
    println!("Item   | Expected | Actual   ");
    println!("-------+----------+----------");
    for (&(name, expected), &count) in DATA.iter().zip(counts.iter()) {
        let real = count as f64 / SAMPLES as f64;
        println!("{:06} | {:.6} | {:.6}", name, expected, real);
    }
}

fn main() {
    let mut rng = weak_rng();

    println!("    ~~~ U32 METHOD ~~~");
    let mut mapping = gen_mapping();
    let wc = WeightedChoice::new(&mut mapping);

    let counts = take_samples(&mut rng, &wc);
    print_mapping(&counts);

    println!();

    println!("   ~~~ FLOAT METHOD ~~~");
    // initialize the float version of `WeightedChoice`
    let mapping = gen_mapping_float();
    let wc = WcFloat::new(&mapping);

    let counts = take_samples(&mut rng, &wc);
    print_mapping(&counts);
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_sample_logic(samples: usize) {
        let mut rng = weak_rng();

        let mapping = gen_mapping_float();
        let wc = WcFloat::new(&mapping);

        for _ in 0..samples {
            let prob = rng.next_f64();
            let i = wc.search(prob);

            assert!(prob <= mapping[i], "p:{} m:{}", prob, mapping[i]);
            if i != 0 {
                assert!(mapping[i - 1] <= prob, "p:{} m:{}", prob, mapping[i - 1]);
            }
        }
    }

    #[test]
    fn small_logic() {
        test_sample_logic(1000);
    }

    #[test]
    #[ignore]
    fn large_logic() {
        test_sample_logic(100_000_000);
    }

    fn test_deviation<T: IndependentSample<usize>>(wc: T) {
        let mut rng = weak_rng();

        let counts = take_samples(&mut rng, &wc);
        for (&(_, expected), &count) in DATA.iter().zip(counts.iter()) {
            let real = count as f64 / SAMPLES as f64;
            let dev = (1.0 - real / expected).abs();
            assert!(dev < 0.01, "{}", dev);
        }
    }

    #[test]
    fn wcf_deviation() {
        let mapping = gen_mapping_float();
        let wc = WcFloat::new(&mapping);

        test_deviation(wc);
    }

    #[test]
    fn wc_deviation() {
        let mut mapping = gen_mapping();
        let wc = WeightedChoice::new(&mut mapping);

        test_deviation(wc);
    }
}
<commit_msg>switch to doc comments<commit_after>extern crate rand;

use rand::distributions::{IndependentSample, Sample, Weighted, WeightedChoice};
use rand::{weak_rng, Rng};

const DATA: [(&str, f64); 8] = [
    ("aleph", 1.0 / 5.0),
    ("beth", 1.0 / 6.0),
    ("gimel", 1.0 / 7.0),
    ("daleth", 1.0 / 8.0),
    ("he", 1.0 / 9.0),
    ("waw", 1.0 / 10.0),
    ("zayin", 1.0 / 11.0),
    ("heth", 1759.0 / 27720.0),
];

const SAMPLES: usize = 1_000_000;

/// Generate a mapping to be used by `WeightedChoice`
fn gen_mapping() -> Vec<Weighted<usize>> {
    DATA.iter()
        .enumerate()
        .map(|(i, &(_, p))| Weighted {
            // `WeightedChoice` requires `u32` weights rather than raw probabilities.  For each
            // probability, we convert it to a `u32` weight, and associate it with an index. We
            // multiply by a constant because small numbers such as 0.2 when casted to `u32`
            // become `0`.  This conversion decreases the accuracy of the mapping, which is why we
            // provide an implementation which uses `f64`s for the best accuracy.
            weight: (p * 1_000_000_000.0) as u32,
            item: i,
        })
        .collect()
}

/// Generate a mapping of the raw probabilities
fn gen_mapping_float() -> Vec<f64> {
    // This does the work of `WeightedChoice::new`, splitting a number into various ranges.  The
    // `item` of `Weighted` is represented here merely by the probability's position in the `Vec`.
    let mut running_total = 0.0;
    DATA.iter()
        .map(|&(_, p)| {
            running_total += p;
            running_total
        })
        .collect()
}

/// An implementation of `WeightedChoice` which uses probabilities rather than weights.  Refer to
/// the `WeightedChoice` source for serious usage.
struct WcFloat {
    mapping: Vec<f64>,
}

impl WcFloat {
    fn new(mapping: &[f64]) -> Self {
        Self {
            mapping: mapping.to_vec(),
        }
    }

    // This is roughly the same logic as `WeightedChoice::ind_sample` (though is likely slower)
    fn search(&self, sample_prob: f64) -> usize {
        let idx = self.mapping
            .binary_search_by(|p| p.partial_cmp(&sample_prob).unwrap());
        match idx {
            Ok(i) | Err(i) => i,
        }
    }
}

impl IndependentSample<usize> for WcFloat {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        // Because we know the total is exactly 1.0, we can merely use a raw float value.
        // Otherwise caching `Range::new(0.0, running_total)` and sampling with
        // `range.ind_sample(&mut rng)` is recommended.
        let sample_prob = rng.next_f64();
        self.search(sample_prob)
    }
}

impl Sample<usize> for WcFloat {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

fn take_samples<R: Rng, T>(rng: &mut R, wc: &T) -> [usize; 8]
where
    T: IndependentSample<usize>,
{
    let mut counts = [0; 8];
    for _ in 0..SAMPLES {
        let sample = wc.ind_sample(rng);
        counts[sample] += 1;
    }
    counts
}

fn print_mapping(counts: &[usize]) {
    println!("Item   | Expected | Actual   ");
    println!("-------+----------+----------");
    for (&(name, expected), &count) in DATA.iter().zip(counts.iter()) {
        let real = count as f64 / SAMPLES as f64;
        println!("{:06} | {:.6} | {:.6}", name, expected, real);
    }
}

fn main() {
    let mut rng = weak_rng();

    println!("    ~~~ U32 METHOD ~~~");
    let mut mapping = gen_mapping();
    let wc = WeightedChoice::new(&mut mapping);

    let counts = take_samples(&mut rng, &wc);
    print_mapping(&counts);

    println!();

    println!("   ~~~ FLOAT METHOD ~~~");
    // initialize the float version of `WeightedChoice`
    let mapping = gen_mapping_float();
    let wc = WcFloat::new(&mapping);

    let counts = take_samples(&mut rng, &wc);
    print_mapping(&counts);
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_sample_logic(samples: usize) {
        let mut rng = weak_rng();

        let mapping = gen_mapping_float();
        let wc = WcFloat::new(&mapping);

        for _ in 0..samples {
            let prob = rng.next_f64();
            let i = wc.search(prob);

            assert!(prob <= mapping[i], "p:{} m:{}", prob, mapping[i]);
            if i != 0 {
                assert!(mapping[i - 1] <= prob, "p:{} m:{}", prob, mapping[i - 1]);
            }
        }
    }

    #[test]
    fn small_logic() {
        test_sample_logic(1000);
    }

    #[test]
    #[ignore]
    fn large_logic() {
        test_sample_logic(100_000_000);
    }

    fn test_deviation<T: IndependentSample<usize>>(wc: T) {
        let mut rng = weak_rng();

        let counts = take_samples(&mut rng, &wc);
        for (&(_, expected), &count) in DATA.iter().zip(counts.iter()) {
            let real = count as f64 / SAMPLES as f64;
            let dev = (1.0 - real / expected).abs();
            assert!(dev < 0.01, "{}", dev);
        }
    }

    #[test]
    fn wcf_deviation() {
        let mapping = gen_mapping_float();
        let wc = WcFloat::new(&mapping);

        test_deviation(wc);
    }

    #[test]
    fn wc_deviation() {
        let mut mapping = gen_mapping();
        let wc = WeightedChoice::new(&mut mapping);

        test_deviation(wc);
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};

use state::State;
use result::BfResult;
use interpreter::Interpretable;
use super::*;

impl Interpretable for Program {
    fn interpret_state<R: Read, W: Write>(
        &self, mut state: State, mut input: R, mut output: W) -> BfResult<()>
    {
        interpret(self, &mut state, &mut input, &mut output)
    }
}

fn interpret<R, W>(instructions: &Program, state: &mut State,
                       input: &mut R, output: &mut W)
                       -> BfResult<()>
    where R: Read, W: Write
{
    for instruction in instructions {
        interpret_instruction(instruction, state, input, output)?;
    }

    Ok(())
}

#[inline]
fn interpret_instruction<R, W>(instruction: &Instruction, state: &mut State,
                               input: &mut R, output: &mut W)
                               -> BfResult<()>
    where R: Read, W: Write
{
    match *instruction {
        Instruction::Op(OpCode::Left) => state.left(1)?,
        Instruction::Op(OpCode::Right) => state.right(1)?,
        Instruction::Op(OpCode::Up) => state.up(1),
        Instruction::Op(OpCode::Down) => state.down(1),
        Instruction::Op(OpCode::In) => state.read(input),
        Instruction::Op(OpCode::Out) => state.write(output),
        Instruction::Op(OpCode::Begin) | Instruction::Op(OpCode::End) =>
            panic!("Invalid opcode"),
        Instruction::Loop(ref program) => {
            while state.load() != 0  {
                interpret(&program, state, input, output)?;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::interpret;
    use super::super::*;

    #[test]
    fn assert_no_output() {
        assert_interpret(&[mk_right()], &[], &[]);
    }

    #[test]
    fn assert_output_0() {
        assert_interpret(&[mk_right(), mk_out()], &[], &[0]);
    }

    #[test]
    fn assert_output_1() {
        assert_interpret(&[mk_up(), mk_out()], &[], &[1]);
    }

    #[test]
    fn assert_increment_input() {
        let prog = &[mk_in(), mk_up(), mk_out()];
        assert_interpret(prog, &[0], &[1]);
        assert_interpret(prog, &[5], &[6]);
        assert_interpret(prog, &[255], &[0]);
    }

    #[test]
    fn assert_increment_loop() {
        let prog = &[mk_in(), mk_loop(vec![mk_up(), mk_out(), mk_in()])];
        assert_interpret(prog, &[0], &[]);
        assert_interpret(prog, &[1, 0], &[2]);
        assert_interpret(prog, &[1, 4, 0], &[2, 5]);
        assert_interpret(prog, &[8, 255, 18, 0], &[9, 0, 19]);
    }

    #[test]
    fn hello_world() {
        assert_parse_interpret("++++++[>++++++++++++<-]>.\
                                >++++++++++[>++++++++++<-]>+.\
                                +++++++..+++.>++++[>+++++++++++<-]>.\
                                <+++[>----<-]>.<<<<<+++[>+++++<-]>.\
                                >>.+++.------.--------.>>+.",
            "",
            "Hello, World!");
    }

    fn assert_interpret(program: &[Instruction], input: &[u8], output: &[u8]) {
        use ::state::State;
        use std::io::Cursor;
        use std::str;

        let mut reader = Cursor::new(input);
        let mut writer = Cursor::new(Vec::<u8>::new());
        let mut state  = State::new();

        assert_eq!(interpret(program, &mut state, &mut reader, &mut writer),
                   Ok(()));
        assert_eq!(str::from_utf8(writer.into_inner().as_slice()),
                   str::from_utf8(output));
    }

    fn assert_parse_interpret(program: &str, input: &str, output: &str) {
        use super::super::parser::parse_program;

        let program = parse_program(program.as_bytes()).unwrap();
        assert_interpret(&program, input.as_bytes(), output.as_bytes());
    }
}
<commit_msg>Indentation<commit_after>use std::io::{Read, Write};

use state::State;
use result::BfResult;
use interpreter::Interpretable;
use super::*;

impl Interpretable for Program {
    fn interpret_state<R: Read, W: Write>(
        &self, mut state: State, mut input: R, mut output: W) -> BfResult<()>
    {
        interpret(self, &mut state, &mut input, &mut output)
    }
}

fn interpret<R, W>(instructions: &Program, state: &mut State,
                   input: &mut R, output: &mut W)
                   -> BfResult<()>
    where R: Read, W: Write
{
    for instruction in instructions {
        interpret_instruction(instruction, state, input, output)?;
    }

    Ok(())
}

#[inline]
fn interpret_instruction<R, W>(instruction: &Instruction, state: &mut State,
                               input: &mut R, output: &mut W)
                               -> BfResult<()>
    where R: Read, W: Write
{
    match *instruction {
        Instruction::Op(OpCode::Left) => state.left(1)?,
        Instruction::Op(OpCode::Right) => state.right(1)?,
        Instruction::Op(OpCode::Up) => state.up(1),
        Instruction::Op(OpCode::Down) => state.down(1),
        Instruction::Op(OpCode::In) => state.read(input),
        Instruction::Op(OpCode::Out) => state.write(output),
        Instruction::Op(OpCode::Begin) | Instruction::Op(OpCode::End) =>
            panic!("Invalid opcode"),
        Instruction::Loop(ref program) => {
            while state.load() != 0  {
                interpret(&program, state, input, output)?;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::interpret;
    use super::super::*;

    #[test]
    fn assert_no_output() {
        assert_interpret(&[mk_right()], &[], &[]);
    }

    #[test]
    fn assert_output_0() {
        assert_interpret(&[mk_right(), mk_out()], &[], &[0]);
    }

    #[test]
    fn assert_output_1() {
        assert_interpret(&[mk_up(), mk_out()], &[], &[1]);
    }

    #[test]
    fn assert_increment_input() {
        let prog = &[mk_in(), mk_up(), mk_out()];
        assert_interpret(prog, &[0], &[1]);
        assert_interpret(prog, &[5], &[6]);
        assert_interpret(prog, &[255], &[0]);
    }

    #[test]
    fn assert_increment_loop() {
        let prog = &[mk_in(), mk_loop(vec![mk_up(), mk_out(), mk_in()])];
        assert_interpret(prog, &[0], &[]);
        assert_interpret(prog, &[1, 0], &[2]);
        assert_interpret(prog, &[1, 4, 0], &[2, 5]);
        assert_interpret(prog, &[8, 255, 18, 0], &[9, 0, 19]);
    }

    #[test]
    fn hello_world() {
        assert_parse_interpret("++++++[>++++++++++++<-]>.\
                                >++++++++++[>++++++++++<-]>+.\
                                +++++++..+++.>++++[>+++++++++++<-]>.\
                                <+++[>----<-]>.<<<<<+++[>+++++<-]>.\
                                >>.+++.------.--------.>>+.",
            "",
            "Hello, World!");
    }

    fn assert_interpret(program: &[Instruction], input: &[u8], output: &[u8]) {
        use ::state::State;
        use std::io::Cursor;
        use std::str;

        let mut reader = Cursor::new(input);
        let mut writer = Cursor::new(Vec::<u8>::new());
        let mut state  = State::new();

        assert_eq!(interpret(program, &mut state, &mut reader, &mut writer),
                   Ok(()));
        assert_eq!(str::from_utf8(writer.into_inner().as_slice()),
                   str::from_utf8(output));
    }

    fn assert_parse_interpret(program: &str, input: &str, output: &str) {
        use super::super::parser::parse_program;

        let program = parse_program(program.as_bytes()).unwrap();
        assert_interpret(&program, input.as_bytes(), output.as_bytes());
    }
}
<|endoftext|>


<commit_before>use objects::user::User;
use objects::chat::Chat;
use objects::message_entity::MessageEntity;

/// Represents a Telegram message.
#[derive(Clone, Deserialize, Debug)]
pub struct Message {
    pub message_id: i64,
    pub from_user: Option<User>,
    pub date: i64,
    pub chat: Chat,
    pub forward_from: Option<User>,
    pub forward_from_chat: Option<Chat>,
    pub forward_from_message_id: Option<i64>,
    pub forward_date: Option<i64>,
    pub reply_to_message: Option<Box<Message>>,
    pub edit_date: Option<i64>,
    pub text: Option<String>,
    pub entities: Option<Vec<MessageEntity>>,
    pub audio: Option<String>,
    pub document: Option<String>,
    pub game: Option<String>,
    pub photo: Option<String>,
    pub sticker: Option<String>,
    pub video: Option<String>,
    pub voice: Option<String>,
    pub caption: Option<String>,
    pub contact: Option<String>,
    pub location: Option<String>,
    pub venue: Option<String>,
    pub new_chat_member: Option<User>,
    pub left_chat_member: Option<User>,
    pub new_chat_title: Option<String>,
    pub new_chat_photo: Option<String>,
    pub delete_chat_photo: Option<bool>,
    pub group_chat_created: Option<bool>,
    pub supergroup_chat_created: Option<bool>,
    pub channel_chat_created: Option<bool>,
    pub migrate_to_chat_id: Option<i64>,
    pub migrate_from_chat_id: Option<i64>,
    pub pinned_message: Option<Box<Message>>,
}
<commit_msg>Closing issue #8<commit_after>use objects::user::User;
use objects::chat::Chat;
use objects::message_entity::MessageEntity;

/// Represents a Telegram message.
#[derive(Clone, Deserialize, Debug)]
pub struct Message {
    pub message_id: i64,
    pub from: Option<User>,
    pub date: i64,
    pub chat: Chat,
    pub forward_from: Option<User>,
    pub forward_from_chat: Option<Chat>,
    pub forward_from_message_id: Option<i64>,
    pub forward_date: Option<i64>,
    pub reply_to_message: Option<Box<Message>>,
    pub edit_date: Option<i64>,
    pub text: Option<String>,
    pub entities: Option<Vec<MessageEntity>>,
    pub audio: Option<String>,
    pub document: Option<String>,
    pub game: Option<String>,
    pub photo: Option<String>,
    pub sticker: Option<String>,
    pub video: Option<String>,
    pub voice: Option<String>,
    pub caption: Option<String>,
    pub contact: Option<String>,
    pub location: Option<String>,
    pub venue: Option<String>,
    pub new_chat_member: Option<User>,
    pub left_chat_member: Option<User>,
    pub new_chat_title: Option<String>,
    pub new_chat_photo: Option<String>,
    pub delete_chat_photo: Option<bool>,
    pub group_chat_created: Option<bool>,
    pub supergroup_chat_created: Option<bool>,
    pub channel_chat_created: Option<bool>,
    pub migrate_to_chat_id: Option<i64>,
    pub migrate_from_chat_id: Option<i64>,
    pub pinned_message: Option<Box<Message>>,
}
<|endoftext|>


<commit_before>#[link(name="tee", vers="1.0.0", author="Aleksander Bielawski")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::io::{stdin, stdout, Append, File, Truncate, Write};
use std::io::{io_error, result, EndOfFile};
use std::io::signal::{Interrupt, Listener};
use std::io::util::{copy, MultiWriter};
use std::os::{args, set_exit_status};
use extra::getopts::groups::{getopts, optflag, usage};

static NAME: &'static str = "tee";
static VERSION: &'static str = "1.0.0";

fn main() {
    match options(args()).and_then(exec) {
        Err(message) => {
            error!("{}: {}", args()[0], message);
            set_exit_status(1)
        },
        Ok(status) => set_exit_status(status)
    }
}

struct Options {
    program: ~str,
    append: bool,
    ignore_interrupts: bool,
    print_and_exit: Option<~str>,
    files: ~[Path]
}

fn options(args: &[~str]) -> Result<Options, ~str> {
    let opts = ~[
        optflag("a", "append", "append to the given FILEs, do not overwrite"),
        optflag("i", "ignore-interrupts", "ignore interrupt signals"),
        optflag("", "help", "display this help and exit"),
        optflag("", "version", "output version information and exit")];
    getopts(args.tail(), opts).map_err(|e| e.to_err_msg()).and_then(|m| {
        let version = format!("{} {}", NAME, VERSION);
        let program = args[0].clone();
        let arguments = "[OPTION]... [FILE]...";
        let brief = "Copy standard input to each FILE, and also to standard " +
                    "output.";
        let comment = "If a FILE is -, copy again to standard output.";
        let help = format!("{}\n\nUsage:\n  {} {}\n\n{}\n{}",
                           version, program, arguments, usage(brief, opts),
                           comment);
        let names = m.free + ~[~"-"];
        let to_print = if m.opt_present("help") { Some(help) }
                       else if m.opt_present("version") { Some(version) }
                       else { None };
        Ok(Options {
            program: program,
            append: m.opt_present("append"),
            ignore_interrupts: m.opt_present("ignore-interrupts"),
            print_and_exit: to_print,
            files: names.map(|name| Path::new(name.clone()))
        })
    })
}

fn open(path: &Path, append: bool) -> ~Writer {
    if *path == Path::new("-") {
        ~stdout() as ~Writer
    } else {
        let mode = if append { Append } else { Truncate };
        ~File::open_mode(path, mode, Write) as ~Writer
    }
}

fn exec(options: Options) -> Result<int, ~str> {
    match options.print_and_exit {
        Some(text) => {
            println(text);
            Ok(0)
        },
        None => tee(options)
    }
}

fn tee(options: Options) -> Result<int, ~str> {
    let mut handler = Listener::new();
    if options.ignore_interrupts {
        handler.register(Interrupt);
    }
    result(|| io_error::cond.trap(|e| {
        if e.kind != EndOfFile {
            io_error::cond.raise(e);
        }
    }).inside(|| {
        let writers = options.files.map(|path| open(path, options.append));
        let output = &mut MultiWriter::new(writers);
        let input = &mut stdin();
        copy(input, output);
        output.flush();
        0
    })).map_err(|err| err.desc.to_owned())
}
<commit_msg>Update crate attributes for tee<commit_after>#[crate_id(name="tee", vers="1.0.0", author="Aleksander Bielawski")];
#[license="MIT"];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::io::{stdin, stdout, Append, File, Truncate, Write};
use std::io::{io_error, result, EndOfFile};
use std::io::signal::{Interrupt, Listener};
use std::io::util::{copy, MultiWriter};
use std::os::{args, set_exit_status};
use extra::getopts::groups::{getopts, optflag, usage};

static NAME: &'static str = "tee";
static VERSION: &'static str = "1.0.0";

fn main() {
    match options(args()).and_then(exec) {
        Err(message) => {
            error!("{}: {}", args()[0], message);
            set_exit_status(1)
        },
        Ok(status) => set_exit_status(status)
    }
}

struct Options {
    program: ~str,
    append: bool,
    ignore_interrupts: bool,
    print_and_exit: Option<~str>,
    files: ~[Path]
}

fn options(args: &[~str]) -> Result<Options, ~str> {
    let opts = ~[
        optflag("a", "append", "append to the given FILEs, do not overwrite"),
        optflag("i", "ignore-interrupts", "ignore interrupt signals"),
        optflag("", "help", "display this help and exit"),
        optflag("", "version", "output version information and exit")];
    getopts(args.tail(), opts).map_err(|e| e.to_err_msg()).and_then(|m| {
        let version = format!("{} {}", NAME, VERSION);
        let program = args[0].clone();
        let arguments = "[OPTION]... [FILE]...";
        let brief = "Copy standard input to each FILE, and also to standard " +
                    "output.";
        let comment = "If a FILE is -, copy again to standard output.";
        let help = format!("{}\n\nUsage:\n  {} {}\n\n{}\n{}",
                           version, program, arguments, usage(brief, opts),
                           comment);
        let names = m.free + ~[~"-"];
        let to_print = if m.opt_present("help") { Some(help) }
                       else if m.opt_present("version") { Some(version) }
                       else { None };
        Ok(Options {
            program: program,
            append: m.opt_present("append"),
            ignore_interrupts: m.opt_present("ignore-interrupts"),
            print_and_exit: to_print,
            files: names.map(|name| Path::new(name.clone()))
        })
    })
}

fn open(path: &Path, append: bool) -> ~Writer {
    if *path == Path::new("-") {
        ~stdout() as ~Writer
    } else {
        let mode = if append { Append } else { Truncate };
        ~File::open_mode(path, mode, Write) as ~Writer
    }
}

fn exec(options: Options) -> Result<int, ~str> {
    match options.print_and_exit {
        Some(text) => {
            println(text);
            Ok(0)
        },
        None => tee(options)
    }
}

fn tee(options: Options) -> Result<int, ~str> {
    let mut handler = Listener::new();
    if options.ignore_interrupts {
        handler.register(Interrupt);
    }
    result(|| io_error::cond.trap(|e| {
        if e.kind != EndOfFile {
            io_error::cond.raise(e);
        }
    }).inside(|| {
        let writers = options.files.map(|path| open(path, options.append));
        let output = &mut MultiWriter::new(writers);
        let input = &mut stdin();
        copy(input, output);
        output.flush();
        0
    })).map_err(|err| err.desc.to_owned())
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any nages
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Constant(Const)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Const { IntConst(i64)
               , UintConst(u64)
               }

impl fmt::Display for Const {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Const::IntConst(ref n)    => write!(f, "{}", n)
                    , Const::UintConst(ref n)   => write!(f, "{}", n)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub body: Body<'a, S>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({}{})"
                      , fun.to_sexpr(level)
                      , body.iter()
                            .fold(String::new(), |mut s, expr| {
                                  write!(s, " {}", expr.to_sexpr(level))
                                      .expect("Could not write to string!");
                                  s
                             }))
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Constant(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", name)
                     , NameRef::Deref(ref name)      => format!("*{}", name)
                     , NameRef::Unique(ref name)     => format!("@{}", name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<commit_msg>Fixed incorrect to_sexpr for NameRefs<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any nages
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Constant(Const)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Const { IntConst(i64)
               , UintConst(u64)
               }

impl fmt::Display for Const {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Const::IntConst(ref n)    => write!(f, "{}", n)
                    , Const::UintConst(ref n)   => write!(f, "{}", n)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub body: Body<'a, S>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({}{})"
                      , fun.to_sexpr(level)
                      , body.iter()
                            .fold(String::new(), |mut s, expr| {
                                  write!(s, " {}", expr.to_sexpr(level))
                                      .expect("Could not write to string!");
                                  s
                             }))
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Constant(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", **name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", **name)
                     , NameRef::Deref(ref name)      => format!("*{}", **name)
                     , NameRef::Unique(ref name)     => format!("@{}", **name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<|endoftext|>


<commit_before>//! This crate defines the core datastructure representing IDE state -- `RootDatabase`.
//!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.

mod apply_change;
pub mod assists;
pub mod label;
pub mod line_index;
pub mod symbol_index;
pub mod defs;
pub mod items_locator;
pub mod source_change;
pub mod ty_filter;
pub mod traits;
pub mod call_info;
pub mod helpers;
pub mod path_transform;

pub mod search;
pub mod rename;

use std::{fmt, sync::Arc};

use base_db::{
    salsa::{self, Durability},
    AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
};
use hir::db::{AstDatabase, DefDatabase, HirDatabase};
use rustc_hash::FxHashSet;

use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};

/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
pub use base_db;

#[salsa::database(
    base_db::SourceDatabaseStorage,
    base_db::SourceDatabaseExtStorage,
    LineIndexDatabaseStorage,
    symbol_index::SymbolsDatabaseStorage,
    hir::db::InternDatabaseStorage,
    hir::db::AstDatabaseStorage,
    hir::db::DefDatabaseStorage,
    hir::db::HirDatabaseStorage
)]
pub struct RootDatabase {
    storage: salsa::Storage<RootDatabase>,
}

impl fmt::Debug for RootDatabase {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("RootDatabase").finish()
    }
}

impl Upcast<dyn AstDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn DefDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn HirDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn HirDatabase + 'static) {
        &*self
    }
}

impl FileLoader for RootDatabase {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        FileLoaderDelegate(self).file_text(file_id)
    }
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
        FileLoaderDelegate(self).resolve_path(path)
    }
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        FileLoaderDelegate(self).relevant_crates(file_id)
    }
}

impl salsa::Database for RootDatabase {}

impl Default for RootDatabase {
    fn default() -> RootDatabase {
        RootDatabase::new(None)
    }
}

impl RootDatabase {
    pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
        let mut db = RootDatabase { storage: salsa::Storage::default() };
        db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
        db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
        db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
        db.set_enable_proc_attr_macros(Default::default());
        db.update_lru_capacity(lru_capacity);
        db
    }

    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
        let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
        base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
        hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
    }
}

impl salsa::ParallelDatabase for RootDatabase {
    fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
        salsa::Snapshot::new(RootDatabase { storage: self.storage.snapshot() })
    }
}

#[salsa::query_group(LineIndexDatabaseStorage)]
pub trait LineIndexDatabase: base_db::SourceDatabase {
    fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
}

fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
    let text = db.file_text(file_id);
    Arc::new(LineIndex::new(&*text))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum SymbolKind {
    Const,
    ConstParam,
    Enum,
    Field,
    Function,
    Impl,
    Label,
    LifetimeParam,
    Local,
    Macro,
    Module,
    SelfParam,
    Static,
    Struct,
    Trait,
    TypeAlias,
    TypeParam,
    Union,
    ValueParam,
    Variant,
}
<commit_msg>Use `ManuallyDrop` in `RootDatabase`<commit_after>//! This crate defines the core datastructure representing IDE state -- `RootDatabase`.
//!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.

mod apply_change;
pub mod assists;
pub mod label;
pub mod line_index;
pub mod symbol_index;
pub mod defs;
pub mod items_locator;
pub mod source_change;
pub mod ty_filter;
pub mod traits;
pub mod call_info;
pub mod helpers;
pub mod path_transform;

pub mod search;
pub mod rename;

use std::{fmt, mem::ManuallyDrop, sync::Arc};

use base_db::{
    salsa::{self, Durability},
    AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
};
use hir::db::{AstDatabase, DefDatabase, HirDatabase};
use rustc_hash::FxHashSet;

use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};

/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
pub use base_db;

#[salsa::database(
    base_db::SourceDatabaseStorage,
    base_db::SourceDatabaseExtStorage,
    LineIndexDatabaseStorage,
    symbol_index::SymbolsDatabaseStorage,
    hir::db::InternDatabaseStorage,
    hir::db::AstDatabaseStorage,
    hir::db::DefDatabaseStorage,
    hir::db::HirDatabaseStorage
)]
pub struct RootDatabase {
    // We use `ManuallyDrop` here because every codegen unit that contains a
    // `&RootDatabase -> &dyn OtherDatabase` cast will instantiate its drop glue in the vtable,
    // which duplicates `Weak::drop` and `Arc::drop` tens of thousands of times, which makes
    // compile times of all `ide_*` and downstream crates suffer greatly.
    storage: ManuallyDrop<salsa::Storage<RootDatabase>>,
}

impl Drop for RootDatabase {
    fn drop(&mut self) {
        unsafe {
            ManuallyDrop::drop(&mut self.storage);
        }
    }
}

impl fmt::Debug for RootDatabase {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("RootDatabase").finish()
    }
}

impl Upcast<dyn AstDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn DefDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn HirDatabase> for RootDatabase {
    fn upcast(&self) -> &(dyn HirDatabase + 'static) {
        &*self
    }
}

impl FileLoader for RootDatabase {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        FileLoaderDelegate(self).file_text(file_id)
    }
    fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
        FileLoaderDelegate(self).resolve_path(path)
    }
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        FileLoaderDelegate(self).relevant_crates(file_id)
    }
}

impl salsa::Database for RootDatabase {}

impl Default for RootDatabase {
    fn default() -> RootDatabase {
        RootDatabase::new(None)
    }
}

impl RootDatabase {
    pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
        let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) };
        db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
        db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
        db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
        db.set_enable_proc_attr_macros(Default::default());
        db.update_lru_capacity(lru_capacity);
        db
    }

    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
        let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
        base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
        hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
    }
}

impl salsa::ParallelDatabase for RootDatabase {
    fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
        salsa::Snapshot::new(RootDatabase { storage: ManuallyDrop::new(self.storage.snapshot()) })
    }
}

#[salsa::query_group(LineIndexDatabaseStorage)]
pub trait LineIndexDatabase: base_db::SourceDatabase {
    fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
}

fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
    let text = db.file_text(file_id);
    Arc::new(LineIndex::new(&*text))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum SymbolKind {
    Const,
    ConstParam,
    Enum,
    Field,
    Function,
    Impl,
    Label,
    LifetimeParam,
    Local,
    Macro,
    Module,
    SelfParam,
    Static,
    Struct,
    Trait,
    TypeAlias,
    TypeParam,
    Union,
    ValueParam,
    Variant,
}
<|endoftext|>


<commit_before>use ram::cell::CellHeader;
use ram::chunk::Chunks;
use ram::tombstone::Tombstone;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

pub mod combine;
pub mod compact;

pub struct Cleaner {
    chunks: Arc<Chunks>,
    stopped: Arc<AtomicBool>
}

// The two-level cleaner
impl Cleaner {
    pub fn new_and_start(chunks: Arc<Chunks>) -> Cleaner {
        debug!("Starting cleaner for {} chunks", chunks.list.len());
        let stop_tag = Arc::new(AtomicBool::new(false));
        let cleaner = Cleaner {
            chunks: chunks.clone(),
            stopped: stop_tag.clone()
        };
        let stop_tag_ref_clone = stop_tag.clone();
        let checks_ref_clone = chunks.clone();
        thread::Builder::new()
            .name("Cleaner sweeper".into())
            .spawn(move || {
                while !stop_tag.load(Ordering::Relaxed) {
                    for chunk in &chunks.list {
                        chunk.apply_dead_entry();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
            });
        thread::Builder::new()
            .name("Cleaner main".into())
            .spawn(move || {
                while !stop_tag_ref_clone.load(Ordering::Relaxed) {
                    for chunk in &checks_ref_clone.list {
                        let segments_compact_per_turn = chunk.segs.len() / 10 + 1;
                        let segments_combine_per_turn = chunk.segs.len() / 20 + 2;
                        // have to put it right here for cleaners will clear the tombstone death counter
                        chunk.scan_tombstone_survival();
                        trace!("Cleaning chunk {}", chunk.id);
                        let mut cleaned_space: usize = 0;
                        {
                            // compact
                            let segments_for_compact = chunk.segs_for_compact_cleaner();
                            if !segments_for_compact.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to compact, overflow {}",
                                    chunk.id,
                                    segments_for_compact.len(),
                                    segments_compact_per_turn
                                );
                                cleaned_space += segments_for_compact
                                    .into_iter()
                                    .take(segments_compact_per_turn) // limit max segment to clean per turn
                                    .map(|segment| {
                                        compact::CompactCleaner::clean_segment(chunk, &segment)
                                    })
                                    .sum::<usize>();
                            }
                        }

                        {
                            // combine
                            let segments_candidates_for_combine: Vec<_> =
                                chunk.segs_for_combine_cleaner();
                            let segments_for_combine: Vec<_> = segments_candidates_for_combine
                                .into_iter()
                                .take(segments_combine_per_turn)
                                .collect();
                            if !segments_for_combine.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to combine, overflow {}",
                                    chunk.id,
                                    segments_for_combine.len(),
                                    segments_combine_per_turn
                                );
                                cleaned_space += combine::CombinedCleaner::combine_segments(
                                    chunk,
                                    &segments_for_combine,
                                );
                            }
                        }

                        chunk
                            .total_space
                            .fetch_sub(cleaned_space, Ordering::Relaxed);
                        chunk.check_and_archive_segments();
                    }
                    thread::sleep(Duration::from_millis(100));
                }
                warn!("Cleaner main thread stopped");
            });
        return cleaner;
    }
}
<commit_msg>adjustable cleaner sleep interval<commit_after>use ram::cell::CellHeader;
use ram::chunk::Chunks;
use ram::tombstone::Tombstone;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::env;

pub mod combine;
pub mod compact;

pub struct Cleaner {
    chunks: Arc<Chunks>,
    stopped: Arc<AtomicBool>
}

// The two-level cleaner
impl Cleaner {
    pub fn new_and_start(chunks: Arc<Chunks>) -> Cleaner {
        debug!("Starting cleaner for {} chunks", chunks.list.len());
        let stop_tag = Arc::new(AtomicBool::new(false));
        let cleaner = Cleaner {
            chunks: chunks.clone(),
            stopped: stop_tag.clone()
        };
        let stop_tag_ref_clone = stop_tag.clone();
        let checks_ref_clone = chunks.clone();
        let sleep_interval_ms = env::var("NEB_CLEANER_SLEEP_INTERVAL_MS")
            .unwrap_or("100".to_string())
            .parse::<u64>()
            .unwrap();
        thread::Builder::new()
            .name("Cleaner sweeper".into())
            .spawn(move || {
                while !stop_tag.load(Ordering::Relaxed) {
                    for chunk in &chunks.list {
                        chunk.apply_dead_entry();
                    }
                    thread::sleep(Duration::from_millis(sleep_interval_ms));
                }
            });
        thread::Builder::new()
            .name("Cleaner main".into())
            .spawn(move || {
                while !stop_tag_ref_clone.load(Ordering::Relaxed) {
                    for chunk in &checks_ref_clone.list {
                        let segments_compact_per_turn = chunk.segs.len() / 10 + 1;
                        let segments_combine_per_turn = chunk.segs.len() / 20 + 2;
                        // have to put it right here for cleaners will clear the tombstone death counter
                        chunk.scan_tombstone_survival();
                        trace!("Cleaning chunk {}", chunk.id);
                        let mut cleaned_space: usize = 0;
                        {
                            // compact
                            let segments_for_compact = chunk.segs_for_compact_cleaner();
                            if !segments_for_compact.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to compact, overflow {}",
                                    chunk.id,
                                    segments_for_compact.len(),
                                    segments_compact_per_turn
                                );
                                cleaned_space += segments_for_compact
                                    .into_iter()
                                    .take(segments_compact_per_turn) // limit max segment to clean per turn
                                    .map(|segment| {
                                        compact::CompactCleaner::clean_segment(chunk, &segment)
                                    })
                                    .sum::<usize>();
                            }
                        }

                        {
                            // combine
                            let segments_candidates_for_combine: Vec<_> =
                                chunk.segs_for_combine_cleaner();
                            let segments_for_combine: Vec<_> = segments_candidates_for_combine
                                .into_iter()
                                .take(segments_combine_per_turn)
                                .collect();
                            if !segments_for_combine.is_empty() {
                                debug!(
                                    "Chunk {} have {} segments to combine, overflow {}",
                                    chunk.id,
                                    segments_for_combine.len(),
                                    segments_combine_per_turn
                                );
                                cleaned_space += combine::CombinedCleaner::combine_segments(
                                    chunk,
                                    &segments_for_combine,
                                );
                            }
                        }

                        chunk
                            .total_space
                            .fetch_sub(cleaned_space, Ordering::Relaxed);
                        chunk.check_and_archive_segments();
                    }
                    thread::sleep(Duration::from_millis(sleep_interval_ms));
                }
                warn!("Cleaner main thread stopped");
            });
        return cleaner;
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;
extern crate bifrost_hasher;

use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use syntax::ext::quote::rt::Span;
use syntax::parse::token;
use rustc_plugin::Registry;
use bifrost_hasher::hash_str;

fn hash_ident (cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'static> {
    if args.len() != 1 {
        cx.span_err(
            sp,
            &format!("argument should be a single identifier, but got {} arguments {:?}",
                     args.len(), args));
        return DummyResult::any(sp);
    }

    let text = match args[0] {
        TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
        _ => {
            cx.span_err(sp, "argument should be a single identifier");
            return DummyResult::any(sp);
        }
    };
    let text = &*text;
    let str = String::from(text);
    MacEager::expr(cx.expr_usize(sp, hash_str(&str) as usize))
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("hash_ident", hash_ident);
}<commit_msg>regression test on ICE<commit_after>#![feature(plugin_registrar, rustc_private)]

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;
extern crate bifrost_hasher;

use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use syntax::ext::quote::rt::Span;
use syntax::parse::token;
use rustc_plugin::Registry;
use bifrost_hasher::hash_str;

fn hash_ident (cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'static> {
    if args.len() != 1 {
        cx.span_err(
            sp,
            &format!("argument should be a single identifier, but got {} arguments {:?}",
                     args.len(), args));
        return DummyResult::any(sp);
    }

    let text = match args[0] {
        TokenTree::Token(_, token::Ident(s)) => s.to_string(),
        _ => {
            cx.span_err(sp, "argument should be a single identifier");
            return DummyResult::any(sp);
        }
    };
    let text = &*text;
    let str = String::from(text);
    MacEager::expr(cx.expr_usize(sp, hash_str(&str) as usize))
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("hash_ident", hash_ident);
}<|endoftext|>


<commit_before>//! Defines the `SearchExecutor` trait.

use std::time::Duration;
use std::sync::Arc;
use std::sync::mpsc::TryRecvError;
use uci::SetOption;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;
use time_manager::RemainingTime;

/// Parameters describing a search.
///
/// **Important note:** `lower_bound` and `upper_bound` fields
/// together give the interval within which an as precise as possible
/// evaluation is required. If during the search is determined that
/// the exact evaluation is outside of this interval, the search may
/// return a value that is closer to the the interval bounds than the
/// exact evaluation, but always staying on the correct side of the
/// interval (i.e. "fail-soft").
#[derive(Clone)]
pub struct SearchParams<T: SearchNode> {
    /// A number identifying the search.
    pub search_id: usize,

    /// The root position for the search.
    pub position: T,

    /// The requested search depth.
    ///
    /// Should be between `0` and `DEPTH_MAX`.
    pub depth: Depth,

    /// The lower bound for the search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Restricts the analysis to the supplied list of moves only.
    ///
    /// * All moves in the list should be legal.
    ///
    /// * The same move should not occur more than once.
    ///
    /// * If the root position is final, the supplied list of moves
    ///   should be empty.
    ///
    /// The behavior of the search is *undefined* if the root position
    /// is not final, but `searchmoves` is empty.
    pub searchmoves: Vec<Move>,
}

/// A progress report from a search.
#[derive(Clone)]
pub struct SearchReport<T> {
    /// The ID assigned to the search.
    ///
    /// Should be the same for all reports from a given search.
    pub search_id: usize,

    /// The number of positions searched so far.
    ///
    /// Should be no lesser than the value sent in the previous
    /// report.
    pub searched_nodes: u64,

    /// The search depth completed so far.
    ///
    /// Should be no lesser than `0`. Also, no lesser than the value
    /// sent in the previous report, and no greater than the requested
    /// search depth. If the search has not been forcefully stopped,
    /// the last reported `depth` should be the requested search
    /// depth.
    ///
    /// **Note:** Depth-first searches should send `0` in all reports
    /// except the last one.
    pub depth: Depth,

    /// The evaluation of the root position so far, or `VALUE_UNKNOWN`
    /// if not available.
    ///
    /// If the search has not been forcefully stopped, the last report
    /// should contain the calculated final evaluation.
    ///
    /// **Note:** Depth-first searches should send `VALUE_UNKNOWN` in
    /// all reports except the last one.
    pub value: Value,

    /// Whether the search is done.
    ///
    /// Should be `false` for all reports except the last one.
    pub done: bool,

    /// Auxiliary data.
    ///
    /// For example, this may contain calculated principal
    /// variation(s).
    pub data: T,
}

/// A trait for executing consecutive searches in different starting
/// positions.
///
/// Chess programs must rely on some type of search in order to play
/// reasonably. Searching involves looking ahead at different move
/// sequences and evaluating the positions after making the
/// moves. Normally, this is done by traversing and min-maxing a
/// tree-like data-structure by some algorithm. To implement your own
/// search algorithm, you must define a type that implements the
/// `SearchExecutor` trait.
///
/// There are two types of searches that should be distinguished:
///
/// * **Depth-first search.**
///
///   Starts at the root and explores as far as possible along each
///   branch before backtracking.
///
/// * **Iterative deepening search.**
///
///   A depth-first search is executed with a depth of one ply, then
///   the depth is incremented and another search is executed. This
///   process is repeated until the search is terminated or the
///   requested search depth is reached. In case of a terminated
///   search, the engine can always fall back to the move selected in
///   the last iteration of the search.
///
///   You can use `stock::Deepening` to turn a depth-first searcher
///   into a deepening searcher.
///
/// Here is what the engine does on each move:
///
/// 1. Calls `start_search`.
///
/// 2. Continues calling `wait_report` and `try_recv_report`
///    periodically, until the returned report indicates that the
///    search is done.
///
/// 3. Obtains the principal variation(s) from search reports, or
///    directly from the transposition table.
pub trait SearchExecutor: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    fn new(tt: Arc<Self::HashTable>) -> Self;

    /// Starts a new search.
    ///
    /// * `params` describes the new search.
    ///
    /// * `time` gives the remaining time on the clocks, which is
    ///   useful when the search executor wants to implement its own
    ///   time management logic. `None` indicates that there are no
    ///   time restrictions.
    ///
    /// After calling `start_search`, `wait_report` and
    /// `try_recv_report` will be called periodically until the
    /// returned report indicates that the search is done. A new
    /// search will not be started until the previous search is done.
    ///
    /// **Important note:** The executing search must send periodic
    /// reports, informing about its current progress. Also, the
    /// executing search must continuously update the transposition
    /// table so that, at each moment, it contains the results of the
    /// work done so far.
    fn start_search(&mut self,
                    params: SearchParams<Self::SearchNode>,
                    time: Option<&RemainingTime>);

    /// Attempts to return a search progress report without blocking.
    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError>;

    /// Waits until a search progress report is available, timing out
    /// after a specified duration or earlier.
    fn wait_report(&self, duration: Duration);

    /// Requests the termination of the current search.
    ///
    /// Can be called more than once for the same search. After
    /// calling `terminate_search`, `wait_report` and
    /// `try_recv_report` will continue to be called periodically
    /// until the returned report indicates that the search is done.
    fn terminate_search(&mut self);
}
<commit_msg>clarify time meaning in start_search<commit_after>//! Defines the `SearchExecutor` trait.

use std::time::Duration;
use std::sync::Arc;
use std::sync::mpsc::TryRecvError;
use uci::SetOption;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;
use time_manager::RemainingTime;

/// Parameters describing a search.
///
/// **Important note:** `lower_bound` and `upper_bound` fields
/// together give the interval within which an as precise as possible
/// evaluation is required. If during the search is determined that
/// the exact evaluation is outside of this interval, the search may
/// return a value that is closer to the the interval bounds than the
/// exact evaluation, but always staying on the correct side of the
/// interval (i.e. "fail-soft").
#[derive(Clone)]
pub struct SearchParams<T: SearchNode> {
    /// A number identifying the search.
    pub search_id: usize,

    /// The root position for the search.
    pub position: T,

    /// The requested search depth.
    ///
    /// Should be between `0` and `DEPTH_MAX`.
    pub depth: Depth,

    /// The lower bound for the search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Restricts the analysis to the supplied list of moves only.
    ///
    /// * All moves in the list should be legal.
    ///
    /// * The same move should not occur more than once.
    ///
    /// * If the root position is final, the supplied list of moves
    ///   should be empty.
    ///
    /// The behavior of the search is *undefined* if the root position
    /// is not final, but `searchmoves` is empty.
    pub searchmoves: Vec<Move>,
}

/// A progress report from a search.
#[derive(Clone)]
pub struct SearchReport<T> {
    /// The ID assigned to the search.
    ///
    /// Should be the same for all reports from a given search.
    pub search_id: usize,

    /// The number of positions searched so far.
    ///
    /// Should be no lesser than the value sent in the previous
    /// report.
    pub searched_nodes: u64,

    /// The search depth completed so far.
    ///
    /// Should be no lesser than `0`. Also, no lesser than the value
    /// sent in the previous report, and no greater than the requested
    /// search depth. If the search has not been forcefully stopped,
    /// the last reported `depth` should be the requested search
    /// depth.
    ///
    /// **Note:** Depth-first searches should send `0` in all reports
    /// except the last one.
    pub depth: Depth,

    /// The evaluation of the root position so far, or `VALUE_UNKNOWN`
    /// if not available.
    ///
    /// If the search has not been forcefully stopped, the last report
    /// should contain the calculated final evaluation.
    ///
    /// **Note:** Depth-first searches should send `VALUE_UNKNOWN` in
    /// all reports except the last one.
    pub value: Value,

    /// Whether the search is done.
    ///
    /// Should be `false` for all reports except the last one.
    pub done: bool,

    /// Auxiliary data.
    ///
    /// For example, this may contain calculated principal
    /// variation(s).
    pub data: T,
}

/// A trait for executing consecutive searches in different starting
/// positions.
///
/// Chess programs must rely on some type of search in order to play
/// reasonably. Searching involves looking ahead at different move
/// sequences and evaluating the positions after making the
/// moves. Normally, this is done by traversing and min-maxing a
/// tree-like data-structure by some algorithm. To implement your own
/// search algorithm, you must define a type that implements the
/// `SearchExecutor` trait.
///
/// There are two types of searches that should be distinguished:
///
/// * **Depth-first search.**
///
///   Starts at the root and explores as far as possible along each
///   branch before backtracking.
///
/// * **Iterative deepening search.**
///
///   A depth-first search is executed with a depth of one ply, then
///   the depth is incremented and another search is executed. This
///   process is repeated until the search is terminated or the
///   requested search depth is reached. In case of a terminated
///   search, the engine can always fall back to the move selected in
///   the last iteration of the search.
///
///   You can use `stock::Deepening` to turn a depth-first searcher
///   into a deepening searcher.
///
/// Here is what the engine does on each move:
///
/// 1. Calls `start_search`.
///
/// 2. Continues calling `wait_report` and `try_recv_report`
///    periodically, until the returned report indicates that the
///    search is done.
///
/// 3. Obtains the principal variation(s) from search reports, or
///    directly from the transposition table.
pub trait SearchExecutor: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    fn new(tt: Arc<Self::HashTable>) -> Self;

    /// Starts a new search.
    ///
    /// * `params` describes the new search.
    ///
    /// * `time` gives the remaining time on the clocks, which is
    ///   useful when the search executor wants to implement its own
    ///   time management logic. Otherwise, it can be ignored. `None`
    ///   indicates that there are no time restrictions.
    ///
    /// After calling `start_search`, `wait_report` and
    /// `try_recv_report` will be called periodically until the
    /// returned report indicates that the search is done. A new
    /// search will not be started until the previous search is done.
    ///
    /// **Important note:** The executing search must send periodic
    /// reports, informing about its current progress. Also, the
    /// executing search must continuously update the transposition
    /// table so that, at each moment, it contains the results of the
    /// work done so far.
    fn start_search(&mut self,
                    params: SearchParams<Self::SearchNode>,
                    time: Option<&RemainingTime>);

    /// Attempts to return a search progress report without blocking.
    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError>;

    /// Waits until a search progress report is available, timing out
    /// after a specified duration or earlier.
    fn wait_report(&self, duration: Duration);

    /// Requests the termination of the current search.
    ///
    /// Can be called more than once for the same search. After
    /// calling `terminate_search`, `wait_report` and
    /// `try_recv_report` will continue to be called periodically
    /// until the returned report indicates that the search is done.
    fn terminate_search(&mut self);
}
<|endoftext|>