<commit_before>extern crate html2text;
#[cfg(unix)] extern crate termion;
#[cfg(unix)] extern crate argparse;
#[cfg(unix)] extern crate unicode_width;
#[cfg(unix)]
mod top {
    use ::termion;
    use ::std;
    use ::html2text;
    use std::io::{self, Write};
    use html2text::render::text_renderer::{RichAnnotation,TaggedLine};
    use argparse::{ArgumentParser, Store};
    use termion::input::TermRead;
    use termion::event::Key;
    use termion::raw::IntoRawMode;
    use termion::cursor::Goto;
    use termion::screen::AlternateScreen;
    use unicode_width::UnicodeWidthStr;

    fn to_style(tag: &Vec<RichAnnotation>) -> String {
        let mut style = String::new();

        for ann in tag {
            match *ann {
                RichAnnotation::Default => (),
                RichAnnotation::Link(_) => {
                    style.push_str(&format!("{}", termion::style::Underline));
                },
                RichAnnotation::Image => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlue)));
                },
                RichAnnotation::Emphasis => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightGreen)));
                },
                RichAnnotation::Strong => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightGreen)));
                },
                RichAnnotation::Code => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightYellow)));
                },
                RichAnnotation::Preformat(_is_cont) => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlack)));
                },
            }
        }
        style
    }

    struct LinkMap {
        lines: Vec<Vec<Option<String>>>,  // lines[y][x] => Some(URL) or None
    }

    impl LinkMap {
        pub fn link_at(&self, x: usize, y: usize) -> Option<&str> {
            if let Some(ref linevec) = self.lines.get(y) {
                if let Some(&Some(ref text)) = linevec.get(x) {
                    return Some(&text)
                }
            }
            None
        }
    }

    fn link_from_tag(tag: &Vec<RichAnnotation>) -> Option<String> {
        let mut link = None;
        for annotation in tag {
            if let RichAnnotation::Link(ref text) = *annotation {
                link = Some(text.clone());
            }
        }
        link
    }

    fn find_links(lines: &Vec<TaggedLine<Vec<RichAnnotation>>>) -> LinkMap {
        let mut map = Vec::new();
        for line in lines {
            let mut linevec = Vec::new();

            for (s, tag) in line.iter() {
                let link = link_from_tag(tag);
                for _ in 0..UnicodeWidthStr::width(s) {
                    linevec.push(link.clone());
                }
            }

            map.push(linevec);
        }
        LinkMap {
            lines: map,
        }
    }

    pub fn main() {
        let mut filename = String::new();
        {
            let mut ap = ArgumentParser::new();
            ap.refer(&mut filename)
              .add_argument("filename", Store, "Set HTML filename");
            ap.parse_args_or_exit();
        }

        let (width, height) = termion::terminal_size().unwrap();
        let (width, height) = (width as usize, height as usize);

        let mut file = std::fs::File::open(filename).expect("Tried to open file");
        let annotated = html2text::from_read_rich(&mut file, width as usize);

        let link_map = find_links(&annotated);

        let mut keys = io::stdin().keys();
        let mut pos = 0;
        // 1-based screen co-ordinates
        let mut cursor_x = 1;
        let mut cursor_y = 1;
        let mut screen = AlternateScreen::from(
            io::stdout().into_raw_mode().unwrap());
        loop {
            let opt_url = link_map.link_at(cursor_x as usize - 1, cursor_y as usize +pos-1);
            let maxpos = std::cmp::min(pos+height, annotated.len());
            write!(screen, "{}", termion::clear::All).unwrap();
            for (i, line) in annotated[pos..maxpos].iter().enumerate() {
                write!(screen, "{}", Goto(1, i as u16 +1)).unwrap();
                for (s, tag) in line.iter() {
                    let style = to_style(tag);
                    let link = link_from_tag(tag);
                    match (opt_url, link) {
                        (Some(ref t1), Some(ref t2)) if t1 == t2 => {
                            write!(screen, "{}", termion::style::Invert).unwrap();
                        },
                        _ => (),
                    }
                    write!(screen, "{}{}{}", style, s, termion::style::Reset).unwrap();
                }
            }
            write!(screen, "{}", Goto(cursor_x, cursor_y)).unwrap();
            screen.flush().unwrap();
            if let Some(Ok(k)) = keys.next() {
                match k {
                    Key::Char('q') => break,
                    Key::Char('j') | Key::Down => {
                        if cursor_y < height as u16 {
                            cursor_y += 1;
                        }
                    },
                    Key::Char('k') | Key::Up => {
                        if cursor_y > 1 {
                            cursor_y -= 1;
                        }
                    },
                    Key::Char('h') | Key::Left => {
                        if cursor_x > 1 {
                            cursor_x -= 1;
                        }
                    },
                    Key::Char('l') | Key::Right => {
                        if cursor_x < width as u16 {
                            cursor_x += 1;
                        }
                    },
                    Key::Char(' ') | Key::PageDown => {
                        if pos + height-1 < annotated.len() {
                            pos += height-1;
                        }
                    },
                    Key::PageUp => {
                        if pos >= height-1 {
                            pos -= height-1;
                        }
                    },
                    Key::Char('\t') => {
                    },
                    _ => {},
                }
            }
        }
    }
}

#[cfg(not(unix))]
mod top {
    pub fn main() {}
}

fn main() {
    top::main()
}
<commit_msg>html2term: rework position, scrolling and navigation.<commit_after>extern crate html2text;
#[cfg(unix)] extern crate termion;
#[cfg(unix)] extern crate argparse;
#[cfg(unix)] extern crate unicode_width;
#[cfg(unix)]
mod top {
    use ::termion;
    use ::std;
    use ::html2text;
    use std::io::{self, Write};
    use html2text::render::text_renderer::{RichAnnotation,TaggedLine};
    use argparse::{ArgumentParser, Store};
    use termion::input::TermRead;
    use termion::event::Key;
    use termion::raw::IntoRawMode;
    use termion::cursor::Goto;
    use termion::screen::AlternateScreen;
    use unicode_width::UnicodeWidthStr;

    fn to_style(tag: &Vec<RichAnnotation>) -> String {
        let mut style = String::new();

        for ann in tag {
            match *ann {
                RichAnnotation::Default => (),
                RichAnnotation::Link(_) => {
                    style.push_str(&format!("{}", termion::style::Underline));
                },
                RichAnnotation::Image => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlue)));
                },
                RichAnnotation::Emphasis => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightGreen)));
                },
                RichAnnotation::Strong => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightGreen)));
                },
                RichAnnotation::Code => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightYellow)));
                },
                RichAnnotation::Preformat(_is_cont) => {
                    style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlack)));
                },
            }
        }
        style
    }

    struct LinkMap {
        lines: Vec<Vec<Option<String>>>,  // lines[y][x] => Some(URL) or None
    }

    impl LinkMap {
        pub fn link_at(&self, x: usize, y: usize) -> Option<&str> {
            if let Some(ref linevec) = self.lines.get(y) {
                if let Some(&Some(ref text)) = linevec.get(x) {
                    return Some(&text)
                }
            }
            None
        }
    }

    fn link_from_tag(tag: &Vec<RichAnnotation>) -> Option<String> {
        let mut link = None;
        for annotation in tag {
            if let RichAnnotation::Link(ref text) = *annotation {
                link = Some(text.clone());
            }
        }
        link
    }

    fn find_links(lines: &Vec<TaggedLine<Vec<RichAnnotation>>>) -> LinkMap {
        let mut map = Vec::new();
        for line in lines {
            let mut linevec = Vec::new();

            for (s, tag) in line.iter() {
                let link = link_from_tag(tag);
                for _ in 0..UnicodeWidthStr::width(s) {
                    linevec.push(link.clone());
                }
            }

            map.push(linevec);
        }
        LinkMap {
            lines: map,
        }
    }

    pub fn main() {
        let mut filename = String::new();
        {
            let mut ap = ArgumentParser::new();
            ap.refer(&mut filename)
              .add_argument("filename", Store, "Set HTML filename");
            ap.parse_args_or_exit();
        }

        let (width, height) = termion::terminal_size().unwrap();
        let (width, height) = (width as usize, height as usize);

        let mut file = std::fs::File::open(filename).expect("Tried to open file");
        let annotated = html2text::from_read_rich(&mut file, width as usize);

        let link_map = find_links(&annotated);

        let mut keys = io::stdin().keys();

        // max_y is the largest (0-based) index of a real document line.
        let max_y = annotated.len() - 1;
        // top_y is the (0-based) index of the document line shown at
        // the top of the visible screen.
        let mut top_y = 0;
        // doc_x and doc_y are the logical (0-based) x and y of the
        // cursor position within the document.
        let mut doc_x = 0;
        let mut doc_y = 0;

        let mut screen = AlternateScreen::from(
            io::stdout().into_raw_mode().unwrap());

        loop {
            // Sanity-check the current screen position. max_y should
            // be small enough that no blank lines beyond the end of
            // the document are visible on screen (except when the
            // document is shorter than a screenful); large enough
            // that the cursor isn't off the bottom of the visible
            // screen; and small enough that the cursor isn't off the
            // top.
            if max_y >= height-1 {
                top_y = std::cmp::min(top_y, max_y - (height-1));
            }
            if doc_y >= height-1 {
                top_y = std::cmp::max(top_y, doc_y - (height-1));
            }
            top_y = std::cmp::min(top_y, doc_y);

            let opt_url = link_map.link_at(doc_x, doc_y);
            let vis_y_limit = std::cmp::min(top_y + height, max_y + 1);
            write!(screen, "{}", termion::clear::All).unwrap();
            for (i, line) in annotated[top_y..vis_y_limit].iter().enumerate() {
                write!(screen, "{}", Goto(1, i as u16 +1)).unwrap();
                for (s, tag) in line.iter() {
                    let style = to_style(tag);
                    let link = link_from_tag(tag);
                    match (opt_url, link) {
                        (Some(ref t1), Some(ref t2)) if t1 == t2 => {
                            write!(screen, "{}", termion::style::Invert).unwrap();
                        },
                        _ => (),
                    }
                    write!(screen, "{}{}{}", style, s, termion::style::Reset).unwrap();
                }
            }

            // 1-based screen coordinates
            let cursor_x = (doc_x + 1) as u16;
            let cursor_y = (doc_y - top_y + 1) as u16;
            write!(screen, "{}", Goto(cursor_x, cursor_y)).unwrap();

            screen.flush().unwrap();
            if let Some(Ok(k)) = keys.next() {
                match k {
                    Key::Char('q') => break,
                    Key::Char('j') | Key::Down => {
                        if doc_y < max_y {
                            doc_y += 1;
                        }
                    },
                    Key::Char('k') | Key::Up => {
                        if doc_y > 0 {
                            doc_y -= 1;
                        }
                    },
                    Key::Char('h') | Key::Left => {
                        if doc_x > 0 {
                            doc_x -= 1;
                        }
                    },
                    Key::Char('l') | Key::Right => {
                        if doc_x + 1 < width {
                            doc_x += 1;
                        }
                    },
                    Key::Char(' ') | Key::PageDown => {
                        // Ideally, move both the cursor and the top
                        // visible line down by a whole page
                        doc_y += height;
                        top_y += height;

                        // But bound the cursor within the document
                        doc_y = std::cmp::min(doc_y, max_y);

                        // And the standard bounds checking for top_y
                        // will take care of the rest of the special
                        // cases.
                    },
                    Key::PageUp => {
                        // Ideally, move both the cursor and the top
                        // visible line up by a whole page. But bound
                        // both at zero.
                        doc_y = std::cmp::max(doc_y, height) - height;
                        top_y = std::cmp::max(top_y, height) - height;
                    },
                    Key::Home => {
                        doc_y = 0;
                    },
                    Key::End => {
                        doc_y = max_y;
                    },
                    Key::Char('\t') => {
                    },
                    _ => {},
                }
            }
        }
    }
}

#[cfg(not(unix))]
mod top {
    pub fn main() {}
}

fn main() {
    top::main()
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

use perlin_core::utils::seeking_iterator::{PeekableSeekable};
use perlin_core::index::posting::DocId;

use query::{Operand, ChainingOperator, ToOperands};

mod stemmers;
pub mod integers;
mod stopword_filter;

pub use language::stopword_filter::StopwordFilter;
pub use language::stemmers::Stemmer;

/// The single central trait of the push-based splittable pipeline!
/// Any element in it can be called passing a typed and generic input and a common value
pub trait CanApply<Input> {
    type Output;
    fn apply(&mut self, Input);
}

pub struct AlphaNumericTokenizer<TCB> {
    cb: TCB
}
impl<TCB> AlphaNumericTokenizer<TCB> {
    pub fn create(cb: TCB) -> Self {
        AlphaNumericTokenizer{
            cb: cb
        }
    }
}
impl<'a, TCB> CanApply<&'a str> for AlphaNumericTokenizer<TCB>
    where TCB: CanApply<&'a str>
{
    type Output = TCB::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split(|c: char| !c.is_alphanumeric()) {
            if !token.is_empty() {
                self.cb.apply(token);
            }
        }
    }
}

impl<'a, TCB> ToOperands<'a> for AlphaNumericTokenizer<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.cb.to_operands()
    }
}

pub struct Debugger<TCallback>
{
    callback: TCallback,
}
impl<TCallback> Debugger<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        Debugger{
            callback: callback
        }
    }
}

impl<TCallback, T: Debug> CanApply<T> for Debugger<TCallback>
    where TCallback: CanApply<T>
{
    type Output = TCallback::Output;

    fn apply(&mut self, input: T) {
        println!("{:?}", input);
        self.callback.apply(input);
    }
}

impl<'a, TCB> ToOperands<'a> for Debugger<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

pub struct WhitespaceTokenizer<TCallback>
{
    callback: TCallback,
}

impl<TCallback> WhitespaceTokenizer<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        WhitespaceTokenizer {
            callback: callback
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for WhitespaceTokenizer<TCallback>
    where TCallback: CanApply<&'a str> {
    type Output = TCallback::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split_whitespace() {
            self.callback.apply(token);
        }
    }
}

impl<'a, TCallback> ToOperands<'a> for WhitespaceTokenizer<TCallback>
    where TCallback: ToOperands<'a> {
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

pub struct LowercaseFilter<TCallback>
{
    callback: TCallback,
}

impl<TCallback> LowercaseFilter<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        LowercaseFilter{
            callback: callback,
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for LowercaseFilter<TCallback>
    where TCallback: CanApply<String>
{
    type Output = TCallback::Output;
    fn apply(&mut self, input: &str) {
        self.callback.apply(input.to_lowercase())
    }
}

impl<'a, TCallback> ToOperands<'a> for LowercaseFilter<TCallback>
    where TCallback: ToOperands<'a> {

    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

use perlin_core::index::Index;
use std::hash::Hash;

pub struct IndexerFunnel<'a, T: 'a + Hash + Eq>
{
    doc_id: DocId,
    index: &'a mut Index<T>
}

impl<'a, T: Hash + Eq> IndexerFunnel<'a, T> {
    pub fn create(doc_id: DocId, index: &'a mut Index<T>) -> Self {
        IndexerFunnel {
            doc_id: doc_id,
            index: index
        }
    }
}

impl<'a, TTerm: 'a + Debug + Hash + Ord + Eq> CanApply<TTerm> for IndexerFunnel<'a, TTerm>{

    type Output = TTerm;

    fn apply(&mut self, input: TTerm) {
        self.index.index_term(input, self.doc_id);
    }
}

#[macro_export]
macro_rules! inner_pipeline {
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     > $($x:tt)*) => {
        // >
        inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*)
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params) | [field]
    {
        $element::create($($param),+ ,
                         IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
                         inner_pipeline!(;$INDEX; ;$doc_id; ;$field_id; ($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params)
    {
        $element::create($($param),+ , inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element | [field]
    {
        $element::create(
            IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
            inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident $($x:tt)*) =>
    // ;doc_id; ;field_id; Element
    {
        $element::create(inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;) => {
        IndexerFunnel::create($doc_id, &mut $INDEX.$field)
    };
    () => {}
}

#[macro_export]
macro_rules! pipeline {
    ($field:ident $($x:tt)*) => {
        Box::new(move |doc_id, index, content| {
            use $crate::language::CanApply;
            use $crate::language::IndexerFunnel;
            use std::marker::PhantomData;
            let mut pipe = inner_pipeline!(;index; ;doc_id; ;$field; $($x)*);
            pipe.apply(content);
            PhantomData
        })
    }
}

<commit_msg>abstract funnel over trait<commit_after>use std::fmt::Debug;
use std::marker::PhantomData;

use perlin_core::utils::seeking_iterator::{PeekableSeekable};
use perlin_core::index::posting::DocId;

use query::{Operand, ChainingOperator, ToOperands};

mod stemmers;
pub mod integers;
mod stopword_filter;

pub use language::stopword_filter::StopwordFilter;
pub use language::stemmers::Stemmer;

/// The single central trait of the push-based splittable pipeline!
/// Any element in it can be called passing a typed and generic input and a common value
pub trait CanApply<Input> {
    type Output;
    fn apply(&mut self, Input);
}

pub trait PipelineBucket<Term> {
    fn put(&mut self, DocId, Term);
}

pub struct AlphaNumericTokenizer<TCB> {
    cb: TCB
}
impl<TCB> AlphaNumericTokenizer<TCB> {
    pub fn create(cb: TCB) -> Self {
        AlphaNumericTokenizer{
            cb: cb
        }
    }
}
impl<'a, TCB> CanApply<&'a str> for AlphaNumericTokenizer<TCB>
    where TCB: CanApply<&'a str>
{
    type Output = TCB::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split(|c: char| !c.is_alphanumeric()) {
            if !token.is_empty() {
                self.cb.apply(token);
            }
        }
    }
}

impl<'a, TCB> ToOperands<'a> for AlphaNumericTokenizer<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.cb.to_operands()
    }
}

pub struct Debugger<TCallback>
{
    callback: TCallback,
}
impl<TCallback> Debugger<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        Debugger{
            callback: callback
        }
    }
}

impl<TCallback, T: Debug> CanApply<T> for Debugger<TCallback>
    where TCallback: CanApply<T>
{
    type Output = TCallback::Output;

    fn apply(&mut self, input: T) {
        println!("{:?}", input);
        self.callback.apply(input);
    }
}

impl<'a, TCB> ToOperands<'a> for Debugger<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

pub struct WhitespaceTokenizer<TCallback>
{
    callback: TCallback,
}

impl<TCallback> WhitespaceTokenizer<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        WhitespaceTokenizer {
            callback: callback
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for WhitespaceTokenizer<TCallback>
    where TCallback: CanApply<&'a str> {
    type Output = TCallback::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split_whitespace() {
            self.callback.apply(token);
        }
    }
}

impl<'a, TCallback> ToOperands<'a> for WhitespaceTokenizer<TCallback>
    where TCallback: ToOperands<'a> {
    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

pub struct LowercaseFilter<TCallback>
{
    callback: TCallback,
}

impl<TCallback> LowercaseFilter<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        LowercaseFilter{
            callback: callback,
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for LowercaseFilter<TCallback>
    where TCallback: CanApply<String>
{
    type Output = TCallback::Output;
    fn apply(&mut self, input: &str) {
        self.callback.apply(input.to_lowercase())
    }
}

impl<'a, TCallback> ToOperands<'a> for LowercaseFilter<TCallback>
    where TCallback: ToOperands<'a> {

    fn to_operands(self) -> Vec<(ChainingOperator, PeekableSeekable<Operand<'a>>)> {
        self.callback.to_operands()
    }
}

pub struct Funnel<'a, TTerm, TBucket: 'a>
{
    doc_id: DocId,
    bucket: &'a mut TBucket,
    _term: PhantomData<TTerm>
}

impl<'a, TTerm, TBucket> Funnel<'a, TTerm, TBucket> {
    pub fn create(doc_id: DocId, bucket: &'a mut TBucket) -> Self {
        Funnel {
            doc_id: doc_id,
            bucket: bucket,
            _term: PhantomData
        }
    }
}

impl<'a, TTerm, TBucket> CanApply<TTerm> for Funnel<'a, TTerm, TBucket>
    where TBucket: PipelineBucket<TTerm>
{

    type Output = TTerm;

    fn apply(&mut self, input: TTerm) {
        self.bucket.put(self.doc_id, input);
    }
}

#[macro_export]
macro_rules! inner_pipeline {
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     > $($x:tt)*) => {
        // >
        inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*)
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params) | [field]
    {
        $element::create($($param),+ ,
                         Funnel::create($doc_id, &mut $INDEX.$this_field),
                         inner_pipeline!(;$INDEX; ;$doc_id; ;$field_id; ($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params)
    {
        $element::create($($param),+ , inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element | [field]
    {
        $element::create(
            Funnel::create($doc_id, &mut $INDEX.$this_field),
            inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident $($x:tt)*) =>
    // ;doc_id; ;field_id; Element
    {
        $element::create(inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;) => {
        Funnel::create($doc_id, &mut $INDEX.$field)
    };
    () => {}
}

#[macro_export]
macro_rules! pipeline {
    ($field:ident $($x:tt)*) => {
        Box::new(move |doc_id, index, content| {
            use $crate::language::CanApply;
            use $crate::language::Funnel;
            use std::marker::PhantomData;
            let mut pipe = inner_pipeline!(;index; ;doc_id; ;$field; $($x)*);
            pipe.apply(content);
            PhantomData
        })
    }
}

<|endoftext|>


<commit_before>/*
 * Region resolution. This pass runs before typechecking and resolves region
 * names to the appropriate block.
 */

import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import std::map;
import std::map::hashmap;

type region_map = {
    /* Mapping from a block to its parent block, if there is one. */
    parent_blocks: hashmap<ast::node_id,ast::node_id>,
    /* Mapping from a region type in the AST to its resolved region. */
    ast_type_to_region: hashmap<ast::node_id,ty::region>,
    /* Mapping from a local variable to its containing block. */
    local_blocks: hashmap<ast::node_id,ast::node_id>
};

/* Represents the type of the most immediate parent node. */
enum parent {
    pa_item(ast::node_id),
    pa_block(ast::node_id),
    pa_alt,
    pa_crate
}

type ctxt = {
    sess: session,
    def_map: resolve::def_map,
    region_map: @region_map,
    names_in_scope: hashmap<str,ast::def_id>,

    /*
     * A list of local IDs that will be parented to the next block we
     * traverse. This is used when resolving `alt` statements. Since we see
     * the pattern before the associated block, upon seeing a pattern we must
     * parent all the bindings in that pattern to the next block we see.
     */
    mut queued_locals: [ast::node_id],

    parent: parent
};

// Returns true if `subblock` is equal to or is lexically nested inside
// `superblock` and false otherwise.
fn block_contains(region_map: @region_map, superblock: ast::node_id,
                  subblock: ast::node_id) -> bool {
    let subblock = subblock;
    while superblock != subblock {
        alt region_map.parent_blocks.find(subblock) {
            none { ret false; }
            some(blk) { subblock = blk; }
        }
    }
    ret true;
}

fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt ty.node {
        ast::ty_rptr({id: region_id, node: node}, _) {
            let region;
            alt node {
                ast::re_inferred {
                    // We infer to the caller region if we're at item scope
                    // and to the block region if we're at block scope.
                    alt cx.parent {
                        pa_item(item_id) {
                            let def_id = {crate: ast::local_crate,
                                          node: item_id};
                            region = ty::re_caller(def_id);
                        }
                        pa_block(block_id) {
                            region = ty::re_block(block_id);
                        }
                        pa_alt {
                            // FIXME: Need a design decision here.
                            cx.sess.span_bug(ty.span,
                                             "what does & in an alt " +
                                             "resolve to?");
                        }
                        pa_crate {
                            cx.sess.span_bug(ty.span,
                                             "region type outside item");
                        }
                    }
                }

                ast::re_named(ident) {
                    // If at item scope, introduce or reuse a binding. If at
                    // block scope, require that the binding be introduced.
                    alt cx.names_in_scope.find(ident) {
                        some(def_id) { region = ty::re_named(def_id); }
                        none {
                            alt cx.parent {
                                pa_item(_) { /* ok; fall through */ }
                                pa_block(_) | pa_alt {
                                    cx.sess.span_err(ty.span,
                                                     "unknown region `" +
                                                     ident + "`");
                                }
                                pa_crate {
                                    cx.sess.span_bug(ty.span,
                                                     "named region at " +
                                                     "crate scope?!");
                                }
                            }

                            let def_id = {crate: ast::local_crate,
                                          node: region_id};
                            cx.names_in_scope.insert(ident, def_id);
                            region = ty::re_named(def_id);
                        }
                    }
                }

                ast::re_self {
                    // For blocks, "self" means "the current block".
                    alt cx.parent {
                        pa_item(_) {
                            cx.sess.span_unimpl(ty.span,
                                                "'self' region for items");
                        }
                        pa_block(block_id) {
                            region = ty::re_block(block_id);
                        }
                        pa_alt {
                            // FIXME: Need a design decision here.
                            cx.sess.span_bug(ty.span,
                                             "what does &self. in an alt " +
                                             "resolve to?");
                        }
                        pa_crate {
                            cx.sess.span_bug(ty.span,
                                             "region type outside item");
                        }
                    }
                }

            }

            cx.region_map.ast_type_to_region.insert(region_id, region);
        }
        _ { /* nothing to do */ }
    }

    visit::visit_ty(ty, cx, visitor);
}

fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt cx.parent {
        pa_item(_) | pa_alt { /* no-op */ }
        pa_block(parent_block_id) {
            cx.region_map.parent_blocks.insert(blk.node.id, parent_block_id);
        }
        pa_crate { cx.sess.span_bug(blk.span, "block outside item?!"); }
    }

    // Resolve queued locals to this block.
    for local_id in cx.queued_locals {
        cx.region_map.local_blocks.insert(local_id, blk.node.id);
    }

    let new_cx: ctxt = {parent: pa_block(blk.node.id),
                        mut queued_locals: [] with cx};
    visit::visit_block(blk, new_cx, visitor);
}

fn resolve_arm(arm: ast::arm, cx: ctxt, visitor: visit::vt<ctxt>) {
    let new_cx: ctxt = {parent: pa_alt,
                        mut queued_locals: [] with cx};
    visit::visit_arm(arm, new_cx, visitor);
}

fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt pat.node {
        ast::pat_ident(path, _) {
            let defn_opt = cx.def_map.find(pat.id);
            alt defn_opt {
                some(ast::def_variant(_,_)) {
                    /* Nothing to do; this names a variant. */
                }
                _ {
                    /*
                     * This names a local. Enqueue it or bind it to the
                     * containing block, depending on whether we're in an alt
                     * or not.
                     */
                    alt cx.parent {
                        pa_block(block_id) {
                            let local_blocks = cx.region_map.local_blocks;
                            local_blocks.insert(pat.id, block_id);
                        }
                        pa_alt {
                            vec::push(cx.queued_locals, pat.id);
                        }
                        _ { cx.sess.span_bug(pat.span, "unexpected parent"); }
                    }
                }
            }
        }
        _ { /* no-op */ }
    }

    visit::visit_pat(pat, cx, visitor);
}

fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
    // Items create a new outer block scope as far as we're concerned.
    let new_cx: ctxt = {names_in_scope: map::new_str_hash(),
                        parent: pa_item(item.id)
                        with cx};
    visit::visit_item(item, new_cx, visitor);
}

fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
        -> @region_map {
    let cx: ctxt = {sess: sess,
                    def_map: def_map,
                    region_map: @{parent_blocks: map::new_int_hash(),
                                  ast_type_to_region: map::new_int_hash(),
                                  local_blocks: map::new_int_hash()},
                    names_in_scope: map::new_str_hash(),
                    mut queued_locals: [],
                    parent: pa_crate};
    let visitor = visit::mk_vt(@{
        visit_block: resolve_block,
        visit_item: resolve_item,
        visit_ty: resolve_ty,
        visit_arm: resolve_arm,
        visit_pat: resolve_pat
        with *visit::default_visitor()
    });
    visit::visit_crate(*crate, cx, visitor);
    ret cx.region_map;
}

<commit_msg>rustc: Record the parent function of each function<commit_after>/*
 * Region resolution. This pass runs before typechecking and resolves region
 * names to the appropriate block.
 */

import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import std::map;
import std::map::hashmap;

type region_map = {
    /* Mapping from a block to its parent block, if there is one. */
    parent_blocks: hashmap<ast::node_id,ast::node_id>,
    /* Mapping from a lambda to its parent function, if there is one. */
    parent_fns: hashmap<ast::node_id,ast::node_id>,
    /* Mapping from a region type in the AST to its resolved region. */
    ast_type_to_region: hashmap<ast::node_id,ty::region>,
    /* Mapping from a local variable to its containing block. */
    local_blocks: hashmap<ast::node_id,ast::node_id>
};

/* Represents the type of the most immediate parent node. */
enum parent {
    pa_item(ast::node_id),
    pa_block(ast::node_id),
    pa_alt,
    pa_crate
}

type ctxt = {
    sess: session,
    def_map: resolve::def_map,
    region_map: @region_map,
    names_in_scope: hashmap<str,ast::def_id>,

    /*
     * A list of local IDs that will be parented to the next block we
     * traverse. This is used when resolving `alt` statements. Since we see
     * the pattern before the associated block, upon seeing a pattern we must
     * parent all the bindings in that pattern to the next block we see.
     */
    mut queued_locals: [ast::node_id],

    parent: parent,
    mut parent_fn: option<ast::node_id>
};

// Returns true if `subblock` is equal to or is lexically nested inside
// `superblock` and false otherwise.
fn block_contains(region_map: @region_map, superblock: ast::node_id,
                  subblock: ast::node_id) -> bool {
    let subblock = subblock;
    while superblock != subblock {
        alt region_map.parent_blocks.find(subblock) {
            none { ret false; }
            some(blk) { subblock = blk; }
        }
    }
    ret true;
}

fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt ty.node {
        ast::ty_rptr({id: region_id, node: node}, _) {
            let region;
            alt node {
                ast::re_inferred {
                    // We infer to the caller region if we're at item scope
                    // and to the block region if we're at block scope.
                    alt cx.parent {
                        pa_item(item_id) {
                            let def_id = {crate: ast::local_crate,
                                          node: item_id};
                            region = ty::re_caller(def_id);
                        }
                        pa_block(block_id) {
                            region = ty::re_block(block_id);
                        }
                        pa_alt {
                            // FIXME: Need a design decision here.
                            cx.sess.span_bug(ty.span,
                                             "what does & in an alt " +
                                             "resolve to?");
                        }
                        pa_crate {
                            cx.sess.span_bug(ty.span,
                                             "region type outside item");
                        }
                    }
                }

                ast::re_named(ident) {
                    // If at item scope, introduce or reuse a binding. If at
                    // block scope, require that the binding be introduced.
                    alt cx.names_in_scope.find(ident) {
                        some(def_id) { region = ty::re_named(def_id); }
                        none {
                            alt cx.parent {
                                pa_item(_) { /* ok; fall through */ }
                                pa_block(_) | pa_alt {
                                    cx.sess.span_err(ty.span,
                                                     "unknown region `" +
                                                     ident + "`");
                                }
                                pa_crate {
                                    cx.sess.span_bug(ty.span,
                                                     "named region at " +
                                                     "crate scope?!");
                                }
                            }

                            let def_id = {crate: ast::local_crate,
                                          node: region_id};
                            cx.names_in_scope.insert(ident, def_id);
                            region = ty::re_named(def_id);
                        }
                    }
                }

                ast::re_self {
                    // For blocks, "self" means "the current block".
                    alt cx.parent {
                        pa_item(_) {
                            cx.sess.span_unimpl(ty.span,
                                                "'self' region for items");
                        }
                        pa_block(block_id) {
                            region = ty::re_block(block_id);
                        }
                        pa_alt {
                            // FIXME: Need a design decision here.
                            cx.sess.span_bug(ty.span,
                                             "what does &self. in an alt " +
                                             "resolve to?");
                        }
                        pa_crate {
                            cx.sess.span_bug(ty.span,
                                             "region type outside item");
                        }
                    }
                }

            }

            cx.region_map.ast_type_to_region.insert(region_id, region);
        }
        _ { /* nothing to do */ }
    }

    visit::visit_ty(ty, cx, visitor);
}

fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt cx.parent {
        pa_item(_) | pa_alt { /* no-op */ }
        pa_block(parent_block_id) {
            cx.region_map.parent_blocks.insert(blk.node.id, parent_block_id);
        }
        pa_crate { cx.sess.span_bug(blk.span, "block outside item?!"); }
    }

    // Resolve queued locals to this block.
    for local_id in cx.queued_locals {
        cx.region_map.local_blocks.insert(local_id, blk.node.id);
    }

    let new_cx: ctxt = {parent: pa_block(blk.node.id),
                        mut queued_locals: [] with cx};
    visit::visit_block(blk, new_cx, visitor);
}

fn resolve_arm(arm: ast::arm, cx: ctxt, visitor: visit::vt<ctxt>) {
    let new_cx: ctxt = {parent: pa_alt,
                        mut queued_locals: [] with cx};
    visit::visit_arm(arm, new_cx, visitor);
}

fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt pat.node {
        ast::pat_ident(path, _) {
            let defn_opt = cx.def_map.find(pat.id);
            alt defn_opt {
                some(ast::def_variant(_,_)) {
                    /* Nothing to do; this names a variant. */
                }
                _ {
                    /*
                     * This names a local. Enqueue it or bind it to the
                     * containing block, depending on whether we're in an alt
                     * or not.
                     */
                    alt cx.parent {
                        pa_block(block_id) {
                            let local_blocks = cx.region_map.local_blocks;
                            local_blocks.insert(pat.id, block_id);
                        }
                        pa_alt {
                            vec::push(cx.queued_locals, pat.id);
                        }
                        _ { cx.sess.span_bug(pat.span, "unexpected parent"); }
                    }
                }
            }
        }
        _ { /* no-op */ }
    }

    visit::visit_pat(pat, cx, visitor);
}

fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
    alt expr.node {
        ast::expr_fn(_, _, _, _) | ast::expr_fn_block(_, _) {
            let parent_fns = cx.region_map.parent_fns;
            parent_fns.insert(expr.id, option::get(cx.parent_fn));
            let new_cx = {parent_fn: some(expr.id) with cx};
            visit::visit_expr(expr, new_cx, visitor);
        }
        _ { visit::visit_expr(expr, cx, visitor); }
    }
}

fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
    // Items create a new outer block scope as far as we're concerned.
    let new_cx: ctxt = {names_in_scope: map::new_str_hash(),
                        parent: pa_item(item.id),
                        parent_fn: some(item.id)
                        with cx};
    visit::visit_item(item, new_cx, visitor);
}

fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
        -> @region_map {
    let cx: ctxt = {sess: sess,
                    def_map: def_map,
                    region_map: @{parent_blocks: map::new_int_hash(),
                                  parent_fns: map::new_int_hash(),
                                  ast_type_to_region: map::new_int_hash(),
                                  local_blocks: map::new_int_hash()},
                    names_in_scope: map::new_str_hash(),
                    mut queued_locals: [],
                    parent: pa_crate,
                    mut parent_fn: none};
    let visitor = visit::mk_vt(@{
        visit_block: resolve_block,
        visit_item: resolve_item,
        visit_ty: resolve_ty,
        visit_arm: resolve_arm,
        visit_pat: resolve_pat,
        visit_expr: resolve_expr
        with *visit::default_visitor()
    });
    visit::visit_crate(*crate, cx, visitor);
    ret cx.region_map;
}

<|endoftext|>


<commit_before>// This is an implementation of the Sutherland-Hodgman (1974) reentrant polygon
// clipping algorithm. It takes a polygon represented as a number of vertices
// and cuts it according to the given planes.

// The implementation borrows heavily from Pucella-Tov (2008). See that paper
// for more explanation.

#![feature(plugin, custom_derive)]
#![plugin(rand_macros)]

extern crate rust_sessions;
extern crate rand;

use rust_sessions::*;

use std::sync::mpsc::{Sender, Receiver, channel};
use std::thread::spawn;

#[derive(Debug, Copy, Clone, Rand)]
struct Point(f64, f64, f64);

#[derive(Debug, Copy, Clone, Rand)]
struct Plane(f64, f64, f64, f64);

fn above(Point(x, y, z): Point, Plane(a, b, c, d): Plane) -> bool {
    (a * x + b * y + c * z + d) / (a * a + b * b + c * c).sqrt() > 0.0
}

fn intersect(p1: Point, p2: Point, plane: Plane) -> Option<Point> {
    let Point(x1, y1, z1) = p1;
    let Point(x2, y2, z2) = p2;
    let Plane(a, b, c, d) = plane;

    if above(p1, plane) == above(p2, plane) {
        None
    } else {
        let t = (a * x1 + b * y1 + c * z1 + d) /
            (a * (x1 - x2) + b * (y1 - y2) + c * (z1 - z2));
        let x = x1 + (x2 - x1) * t;
        let y = y1 + (y2 - y1) * t;
        let z = z1 + (z2 - z1) * t;
        Some(Point(x, y, z))
    }
}

type SendList = Rec<Choose<Eps, Send<A, Var<Z>>>>;

fn sendlist
    (tx: Sender<Chan<(), SendList>>, xs: Vec)
{
    let c = accept(tx).unwrap();
    let mut c = c.enter();
    for x in xs.iter() {
        let c1 = c.sel2().send(*x);
        c = c1.zero();
    }
    c.sel1().close();
}

fn recvlist
    (rx: Receiver<Chan<(), SendList>>) -> Vec
{
    let c = request(rx).unwrap();
    let mut v = Vec::new();
    let mut c = c.enter();
    loop {
        c = match c.offer() {
            Ok(c) => {
                c.close();
                break;
            }
            Err(c) => {
                let (c, x) = c.recv();
                v.push(x);
                c.zero()
            }
        }
    }

    v
}

fn clipper(plane: Plane,
           inrv: Receiver<Chan<(), SendList<Point>>>,
           outrv: Sender<Chan<(), SendList<Point>>>)
{
    let oc = accept(outrv).unwrap();
    let ic = request(inrv).unwrap();

    let mut oc = oc.enter();
    let mut ic = ic.enter();
    let (pt0, mut pt);

    match ic.offer() {
        Ok(c) => {
            c.close();
            oc.sel1().close();
            return
        }
        Err(c) => {
            let (c, ptz) = c.recv();
            ic = c.zero();
            pt0 = ptz;
            pt = ptz;
        }
    }

    loop {
        if above(pt, plane) {
            oc = oc.sel2().send(pt).zero();
        }
        ic = match ic.offer() {
            Ok(c) => {
                if let Some(pt) = intersect(pt, pt0, plane) {
                    oc = oc.sel2().send(pt).zero();
                }
                c.close();
                oc.sel1().close();
                break;
            }
            Err(ic) => {
                let (ic, pt2) = ic.recv();
                if let Some(pt) = intersect(pt, pt2, plane) {
                    oc = oc.sel2().send(pt).zero();
                }
                pt = pt2;
                ic.zero()
            }
        }
    }
}

fn clipmany(planes: Vec<Plane>, points: Vec<Point>) -> Vec<Point> {
    let (tx, rx) = channel();
    spawn(move || sendlist(tx, points));
    let mut rx = rx;

    for plane in planes.into_iter() {
        let (tx2, rx2) = channel();
        spawn(move || clipper(plane, rx, tx2));
        rx = rx2;
    }
    recvlist(rx)
}

fn normalize_point(Point(a,b,c): Point) -> Point {
    Point(10.0 * (a - 0.5),
          10.0 * (b - 0.5),
          10.0 * (c - 0.5))
}

fn normalize_plane(Plane(a,b,c,d): Plane) -> Plane {
    Plane(10.0 * (a - 0.5),
          10.0 * (b - 0.5),
          10.0 * (c - 0.5),
          10.0 * (d - 0.5))
}

fn bench(n: usize, m: usize) {
    let mut g = rand::thread_rng();
    let points = (0..n)
        .map(|_| rand::Rand::rand(&mut g))
        .map(normalize_point)
        .collect();
    let planes = (0..m)
        .map(|_| rand::Rand::rand(&mut g))
        .map(normalize_plane)
        .collect();

    let points = clipmany(planes, points);
    println!("{}", points.len());
}

fn main() {
    bench(100, 5);
}
<commit_msg>Update planeclip<commit_after>// This is an implementation of the Sutherland-Hodgman (1974) reentrant polygon
// clipping algorithm. It takes a polygon represented as a number of vertices
// and cuts it according to the given planes.

// The implementation borrows heavily from Pucella-Tov (2008). See that paper
// for more explanation.

#![feature(plugin, custom_derive)]
#![plugin(rand_macros)]

extern crate rust_sessions;
extern crate rand;

use rust_sessions::*;

use std::thread::spawn;

#[derive(Debug, Copy, Clone, Rand)]
struct Point(f64, f64, f64);

#[derive(Debug, Copy, Clone, Rand)]
struct Plane(f64, f64, f64, f64);

fn above(Point(x, y, z): Point, Plane(a, b, c, d): Plane) -> bool {
    (a * x + b * y + c * z + d) / (a * a + b * b + c * c).sqrt() > 0.0
}

fn intersect(p1: Point, p2: Point, plane: Plane) -> Option<Point> {
    let Point(x1, y1, z1) = p1;
    let Point(x2, y2, z2) = p2;
    let Plane(a, b, c, d) = plane;

    if above(p1, plane) == above(p2, plane) {
        None
    } else {
        let t = (a * x1 + b * y1 + c * z1 + d) /
            (a * (x1 - x2) + b * (y1 - y2) + c * (z1 - z2));
        let x = x1 + (x2 - x1) * t;
        let y = y1 + (y2 - y1) * t;
        let z = z1 + (z2 - z1) * t;
        Some(Point(x, y, z))
    }
}

type SendList = Rec<Choose<Eps, Send<A, Var<Z>>>>;
type RecvList = Rec<Offer<Eps, Recv<A, Var<Z>>>>;

fn sendlist
    (c: Chan<(), SendList>, xs: Vec)
{
    let mut c = c.enter();
    for x in xs.iter() {
        let c1 = c.sel2().send(*x);
        c = c1.zero();
    }
    c.sel1().close();
}

fn recvlist
    (c: Chan<(), RecvList>) -> Vec
{
    let mut v = Vec::new();
    let mut c = c.enter();
    loop {
        c = match c.offer() {
            Ok(c) => {
                c.close();
                break;
            }
            Err(c) => {
                let (c, x) = c.recv();
                v.push(x);
                c.zero()
            }
        }
    }

    v
}

fn clipper(plane: Plane,
           ic: Chan<(), RecvList<Point>>,
           oc: Chan<(), SendList<Point>>)
{
    let mut oc = oc.enter();
    let mut ic = ic.enter();
    let (pt0, mut pt);

    match ic.offer() {
        Ok(c) => {
            c.close();
            oc.sel1().close();
            return
        }
        Err(c) => {
            let (c, ptz) = c.recv();
            ic = c.zero();
            pt0 = ptz;
            pt = ptz;
        }
    }

    loop {
        if above(pt, plane) {
            oc = oc.sel2().send(pt).zero();
        }
        ic = match ic.offer() {
            Ok(c) => {
                if let Some(pt) = intersect(pt, pt0, plane) {
                    oc = oc.sel2().send(pt).zero();
                }
                c.close();
                oc.sel1().close();
                break;
            }
            Err(ic) => {
                let (ic, pt2) = ic.recv();
                if let Some(pt) = intersect(pt, pt2, plane) {
                    oc = oc.sel2().send(pt).zero();
                }
                pt = pt2;
                ic.zero()
            }
        }
    }
}

fn clipmany(planes: Vec<Plane>, points: Vec<Point>) -> Vec<Point> {
    let (tx, rx) = session_channel();
    spawn(move || sendlist(tx, points));
    let mut rx = rx;

    for plane in planes.into_iter() {
        let (tx2, rx2) = session_channel();
        spawn(move || clipper(plane, rx, tx2));
        rx = rx2;
    }
    recvlist(rx)
}

fn normalize_point(Point(a,b,c): Point) -> Point {
    Point(10.0 * (a - 0.5),
          10.0 * (b - 0.5),
          10.0 * (c - 0.5))
}

fn normalize_plane(Plane(a,b,c,d): Plane) -> Plane {
    Plane(10.0 * (a - 0.5),
          10.0 * (b - 0.5),
          10.0 * (c - 0.5),
          10.0 * (d - 0.5))
}

fn bench(n: usize, m: usize) {
    let mut g = rand::thread_rng();
    let points = (0..n)
        .map(|_| rand::Rand::rand(&mut g))
        .map(normalize_point)
        .collect();
    let planes = (0..m)
        .map(|_| rand::Rand::rand(&mut g))
        .map(normalize_plane)
        .collect();

    let points = clipmany(planes, points);
    println!("{}", points.len());
}

fn main() {
    bench(100, 5);
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Boolean logic

use option::{None, Option, Some};
use from_str::FromStr;

#[cfg(notest)] use cmp;

/// Negation / inverse
pub fn not(v: bool) -> bool { !v }

/// Conjunction
pub fn and(a: bool, b: bool) -> bool { a && b }

/// Disjunction
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
 * Exclusive or
 *
 * Identical to `or(and(a, not(b)), and(not(a), b))`
 */
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/// Implication in the logic, i.e. from `a` follows `b`
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/// true if truth values `a` and `b` are indistinguishable in the logic
pub fn eq(a: bool, b: bool) -> bool { a == b }

/// true if truth values `a` and `b` are distinguishable in the logic
pub fn ne(a: bool, b: bool) -> bool { a != b }

/// true if `v` represents truth in the logic
pub fn is_true(v: bool) -> bool { v }

/// true if `v` represents falsehood in the logic
pub fn is_false(v: bool) -> bool { !v }

/// Parse logic value from `s`
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        if s == "true" {
            Some(true)
        } else if s == "false" {
            Some(false)
        } else {
            None
        }
    }
}

/// Convert `v` into a string
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }

/**
 * Iterates over all truth values by passing them to `blk` in an unspecified
 * order
 */
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/// converts truth value to an 8 bit byte
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[cfg(notest)]
impl cmp::Eq for bool {
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

#[test]
pub fn test_bool_from_str() {
    use from_str::FromStr;

    do all_values |v| {
        assert!(Some(v) == FromStr::from_str(to_str(v)))
    }
}

#[test]
pub fn test_bool_to_str() {
    assert!(to_str(false) == ~"false");
    assert!(to_str(true) == ~"true");
}

#[test]
pub fn test_bool_to_bit() {
    do all_values |v| {
        assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>auto merge of #5845 : thestinger/rust/bool, r=catamorphism<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Boolean logic

#[cfg(notest)]
use cmp::{Eq, Ord, TotalOrd, Ordering};
use option::{None, Option, Some};
use from_str::FromStr;

/// Negation / inverse
pub fn not(v: bool) -> bool { !v }

/// Conjunction
pub fn and(a: bool, b: bool) -> bool { a && b }

/// Disjunction
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
 * Exclusive or
 *
 * Identical to `or(and(a, not(b)), and(not(a), b))`
 */
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/// Implication in the logic, i.e. from `a` follows `b`
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/// true if truth values `a` and `b` are indistinguishable in the logic
pub fn eq(a: bool, b: bool) -> bool { a == b }

/// true if truth values `a` and `b` are distinguishable in the logic
pub fn ne(a: bool, b: bool) -> bool { a != b }

/// true if `v` represents truth in the logic
pub fn is_true(v: bool) -> bool { v }

/// true if `v` represents falsehood in the logic
pub fn is_false(v: bool) -> bool { !v }

/// Parse logic value from `s`
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        if s == "true" {
            Some(true)
        } else if s == "false" {
            Some(false)
        } else {
            None
        }
    }
}

/// Convert `v` into a string
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }

/**
 * Iterates over all truth values by passing them to `blk` in an unspecified
 * order
 */
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/// converts truth value to an 8 bit byte
#[inline(always)]
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[cfg(notest)]
impl Ord for bool {
    #[inline(always)]
    fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) }
    #[inline(always)]
    fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) }
    #[inline(always)]
    fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) }
    #[inline(always)]
    fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) }
}

#[cfg(notest)]
impl TotalOrd for bool {
    #[inline(always)]
    fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) }
}

#[cfg(notest)]
impl Eq for bool {
    #[inline(always)]
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    #[inline(always)]
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

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

    #[test]
    fn test_bool_from_str() {
        use from_str::FromStr;

        do all_values |v| {
            assert!(Some(v) == FromStr::from_str(to_str(v)))
        }
    }

    #[test]
    fn test_bool_to_str() {
        assert!(to_str(false) == ~"false");
        assert!(to_str(true) == ~"true");
    }

    #[test]
    fn test_bool_to_bit() {
        do all_values |v| {
            assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
        }
    }

    #[test]
    fn test_bool_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_bool_totalord() {
        assert_eq!(true.cmp(&true), Equal);
        assert_eq!(false.cmp(&false), Equal);
        assert_eq!(true.cmp(&false), Greater);
        assert_eq!(false.cmp(&true), Less);
    }
}
<|endoftext|>


<commit_before>/// Common PCI constants from the PCI spec
pub mod config {
    /// Legacy PCI Configuration Space Access registers
    pub const PCI_CONFIG_ADDRESS: u16 = 0xCF8;
    pub const PCI_CONFIG_DATA: u16 = 0xCFC;
    pub const PCI_CONFIG_ADDRESS_ENABLE: u32 = 0x80000000;
    pub const PCI_BUS_OFFSET: u32 = 16;
    pub const PCI_SLOT_OFFSET: u32 = 11;
    pub const PCI_FUNC_OFFSET: u32 = 8;

    /// PCI Configuration Space registers (256 bytes window)
    /// In theory 32 bit aligned access only.
    /// In practice, however, things seem to be working even with unaligned access.
    pub const PCI_CFG_VENDOR_ID: u8 = 0x00;
    pub const PCI_CFG_DEVICE_ID: u8 = 0x02;
    pub const PCI_CFG_COMMAND: u8 = 0x04;
    pub const PCI_CFG_STATUS: u8 = 0x06;
    pub const PCI_CFG_REVISION_ID: u8 = 0x08;
    pub const PCI_CFG_PROG_INTERFACE: u8 = 0x09;
    pub const PCI_CFG_SUBCLASS: u8 = 0x0A;
    pub const PCI_CFG_BASECLASS: u8 = 0x0B;
    pub const PCI_CFG_CACHELINE_SIZE: u8 = 0x0C;
    pub const PCI_CFG_LATENCY_TIMER: u8 = 0x0D;
    pub const PCI_CFG_HEADER_TYPE: u8 = 0x0E;
    pub const PCI_CFG_BIST: u8 = 0x0F;
    pub const PCI_CFG_BAR_1: u8 = 0x10;
    pub const PCI_CFG_BAR_2: u8 = 0x14;
    pub const PCI_CFG_BAR_3: u8 = 0x18;
    pub const PCI_CFG_BAR_4: u8 = 0x1C;
    pub const PCI_CFG_BAR_5: u8 = 0x20;
    pub const PCI_CFG_BAR_6: u8 = 0x24;
    pub const PCI_CFG_CARDBUS_CIS_PTR: u8 = 0x28;
    pub const PCI_CFG_SUBSYSTEM_VENDOR_ID: u8 = 0x2C;
    pub const PCI_CFG_SUBSYSTEM_ID: u8 = 0x2E;
    pub const PCI_CFG_CAPABILITIES_PTR: u8 = 0x34;
    pub const PCI_CFG_INTERRUPT_LINE: u8 = 0x3C;
    pub const CI_CFG_INTERRUPT_PIN: u8 = 0x3D;
}

pub mod class {
    /// PCI Class Codes
    pub const NONE: u8 = 0x00;
    pub const MASS_STORAGE: u8 = 0x01;
    pub const NETWORK: u8 = 0x02;
    pub const DISPLAY: u8 = 0x03;
    pub const MULTIMEDIA: u8 = 0x04;
    pub const MEMORY: u8 = 0x05;
    pub const BRIDGE_DEVICE: u8 = 0x06;
    pub const COMMUNICATION: u8 = 0x07;
    pub const SYSTEM_PERIPHERALS: u8 = 0x08;
    pub const INPUT: u8 = 0x09;
    pub const DOCKING_STATION: u8 = 0x0A;
    pub const PROCESSOR: u8 = 0x0B;
    pub const SERIAL_BUS: u8 = 0x0C;
    pub const WIRELESS: u8 = 0x0D;
    pub const INTELLIGENT_IO: u8 = 0x0E;
    pub const SATTELITE_COMMUNICATION: u8 = 0x0F;
    pub const ENCRYPTION: u8 = 0x10;
    pub const DATA_ACQUISITION: u8 = 0x11;
    // Class codes 0x12 - 0xFE are reserved
    pub const OTHER: u8 = 0xFF;
}

pub mod subclass {
    /// PCI Mass Storage Subclass Codes
    pub const SCSI: u8 = 0x00;
    pub const IDE: u8 = 0x01;
    pub const FLOPPY: u8 = 0x02;
    pub const IPI: u8 = 0x03;
    pub const RAID: u8 = 0x04;
    pub const ATA: u8 = 0x05;
    pub const SATA: u8 = 0x06;
    pub const SAS: u8 = 0x07;
    pub const NVM: u8 = 0x08;

    /// PCI Network Subclass Codes
    pub const ETHERNET: u8 = 0x00;
    pub const INFINIBAND: u8 = 0x07;
    pub const FABRIC: u8 = 0x08;

    /// PCI Display Subclass Codes
    pub const VGA: u8 = 0x00;
    pub const XGA: u8 = 0x01;

    /// PCI Serial Bus Subclass Codes
    pub const FIREWIRE: u8 = 0x00;
    pub const USB: u8 = 0x03;
}

pub mod programming_interface {
    /// PCI SATA Programming Interface
    pub const AHCI: u8 = 0x01;

    /// PCI USB Programming Interface
    pub const UHCI: u8 = 0x00;
    pub const OHCI: u8 = 0x10;
    pub const EHCI: u8 = 0x20;
    pub const XHCI: u8 = 0x30;
}
<commit_msg>Add PCI Vendor Id and Device Id<commit_after>/// Common PCI constants from the PCI spec
pub mod config {
    /// Legacy PCI Configuration Space Access registers
    pub const PCI_CONFIG_ADDRESS: u16 = 0xCF8;
    pub const PCI_CONFIG_DATA: u16 = 0xCFC;
    pub const PCI_CONFIG_ADDRESS_ENABLE: u32 = 0x80000000;
    pub const PCI_BUS_OFFSET: u32 = 16;
    pub const PCI_SLOT_OFFSET: u32 = 11;
    pub const PCI_FUNC_OFFSET: u32 = 8;

    /// PCI Configuration Space registers (256 bytes window)
    /// In theory 32 bit aligned access only.
    /// In practice, however, things seem to be working even with unaligned access.
    pub const PCI_CFG_VENDOR_ID: u8 = 0x00;
    pub const PCI_CFG_DEVICE_ID: u8 = 0x02;
    pub const PCI_CFG_COMMAND: u8 = 0x04;
    pub const PCI_CFG_STATUS: u8 = 0x06;
    pub const PCI_CFG_REVISION_ID: u8 = 0x08;
    pub const PCI_CFG_PROG_INTERFACE: u8 = 0x09;
    pub const PCI_CFG_SUBCLASS: u8 = 0x0A;
    pub const PCI_CFG_BASECLASS: u8 = 0x0B;
    pub const PCI_CFG_CACHELINE_SIZE: u8 = 0x0C;
    pub const PCI_CFG_LATENCY_TIMER: u8 = 0x0D;
    pub const PCI_CFG_HEADER_TYPE: u8 = 0x0E;
    pub const PCI_CFG_BIST: u8 = 0x0F;
    pub const PCI_CFG_BAR_1: u8 = 0x10;
    pub const PCI_CFG_BAR_2: u8 = 0x14;
    pub const PCI_CFG_BAR_3: u8 = 0x18;
    pub const PCI_CFG_BAR_4: u8 = 0x1C;
    pub const PCI_CFG_BAR_5: u8 = 0x20;
    pub const PCI_CFG_BAR_6: u8 = 0x24;
    pub const PCI_CFG_CARDBUS_CIS_PTR: u8 = 0x28;
    pub const PCI_CFG_SUBSYSTEM_VENDOR_ID: u8 = 0x2C;
    pub const PCI_CFG_SUBSYSTEM_ID: u8 = 0x2E;
    pub const PCI_CFG_CAPABILITIES_PTR: u8 = 0x34;
    pub const PCI_CFG_INTERRUPT_LINE: u8 = 0x3C;
    pub const CI_CFG_INTERRUPT_PIN: u8 = 0x3D;
}

pub mod class {
    /// PCI Class Codes
    pub const NONE: u8 = 0x00;
    pub const MASS_STORAGE: u8 = 0x01;
    pub const NETWORK: u8 = 0x02;
    pub const DISPLAY: u8 = 0x03;
    pub const MULTIMEDIA: u8 = 0x04;
    pub const MEMORY: u8 = 0x05;
    pub const BRIDGE_DEVICE: u8 = 0x06;
    pub const COMMUNICATION: u8 = 0x07;
    pub const SYSTEM_PERIPHERALS: u8 = 0x08;
    pub const INPUT: u8 = 0x09;
    pub const DOCKING_STATION: u8 = 0x0A;
    pub const PROCESSOR: u8 = 0x0B;
    pub const SERIAL_BUS: u8 = 0x0C;
    pub const WIRELESS: u8 = 0x0D;
    pub const INTELLIGENT_IO: u8 = 0x0E;
    pub const SATTELITE_COMMUNICATION: u8 = 0x0F;
    pub const ENCRYPTION: u8 = 0x10;
    pub const DATA_ACQUISITION: u8 = 0x11;
    // Class codes 0x12 - 0xFE are reserved
    pub const OTHER: u8 = 0xFF;
}

pub mod subclass {
    /// PCI Mass Storage Subclass Codes
    pub const SCSI: u8 = 0x00;
    pub const IDE: u8 = 0x01;
    pub const FLOPPY: u8 = 0x02;
    pub const IPI: u8 = 0x03;
    pub const RAID: u8 = 0x04;
    pub const ATA: u8 = 0x05;
    pub const SATA: u8 = 0x06;
    pub const SAS: u8 = 0x07;
    pub const NVM: u8 = 0x08;

    /// PCI Network Subclass Codes
    pub const ETHERNET: u8 = 0x00;
    pub const INFINIBAND: u8 = 0x07;
    pub const FABRIC: u8 = 0x08;

    /// PCI Display Subclass Codes
    pub const VGA: u8 = 0x00;
    pub const XGA: u8 = 0x01;

    /// PCI Serial Bus Subclass Codes
    pub const FIREWIRE: u8 = 0x00;
    pub const USB: u8 = 0x03;
}

pub mod programming_interface {
    /// PCI SATA Programming Interface
    pub const AHCI: u8 = 0x01;

    /// PCI USB Programming Interface
    pub const UHCI: u8 = 0x00;
    pub const OHCI: u8 = 0x10;
    pub const EHCI: u8 = 0x20;
    pub const XHCI: u8 = 0x30;
}

pub mod vendorid {
    pub const INTEL: u16 = 0x8086;
    pub const REALTEK: u16 = 0x10EC;
    pub const REDHAT: u16 = 0x1AF4;
    pub const ILLEGAL: u16 = 0xFFFF;
}

pub mod deviceid {
    // Realtek
    pub const RTL8139: u16 = 0x8139;        // RTL-8100/8101L/8139 PCI Fast Ethernet Adapter

    // Intel
    pub const GBE_82540EM: u16 = 0x100E;    // 82540EM Gigabit Ethernet Controller
    pub const AC97_82801AA: u16 = 0x2415;   // 82801AA AC'97 Audio Controller
    pub const AC97_ICH4: u16 = 0x24C5;      // 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio
    pub const INTELHDA_ICH6: u16 = 0x2668;  // 82801FB/FBM/FR/FW/FRW High Definition Audio
}
<|endoftext|>


<commit_before>use super::break_xor_cipher;
use super::english;
use std::convert::From;
use crypto::xor_cipher::SingleCharXorCipher;
use crypto::xor_cipher::BlockCipher;

#[test]
fn test_most_likely_byte() {
    let plaintext  = Vec::from("Cooking MC\'s like a pound of bacon");
    let key        = 0x58 as u8;
    let cipher     = SingleCharXorCipher::new(key);
    let ciphertext = cipher.process_block(plaintext.as_ref());

    let guessed_key = english::most_likely_byte(ciphertext.as_slice());
    let guessed_cipher = SingleCharXorCipher::new(guessed_key);
    let guessed_plaintext = guessed_cipher.process_block(ciphertext.as_slice());

    assert_eq!(key, guessed_key);
    assert_eq!(plaintext.as_slice(), guessed_plaintext.as_slice());
}
<commit_msg>Add unit test.<commit_after>use super::break_xor_cipher;
use super::english;
use std::convert::From;
use crypto::xor_cipher::SingleCharXorCipher;
use crypto::xor_cipher::BlockCipher;

#[test]
fn test_most_likely_byte() {
    let plaintext  = Vec::from("Cooking MC\'s like a pound of bacon");
    let key        = 0x58 as u8;
    let cipher     = SingleCharXorCipher::new(key);
    let ciphertext = cipher.process_block(plaintext.as_ref());

    let guessed_key = english::most_likely_byte(ciphertext.as_slice());
    let guessed_cipher = SingleCharXorCipher::new(guessed_key);
    let guessed_plaintext = guessed_cipher.process_block(ciphertext.as_slice());

    assert_eq!(key, guessed_key);
    assert_eq!(plaintext.as_slice(), guessed_plaintext.as_slice());
}

#[test]
fn test_score_with() {
    use num_rational::Ratio;
    use std::collections::HashMap;
    use super::frequency_analysis::Histogram;
    use std::convert::From;

    fn make_table(array: &[(u8, usize)]) -> (usize, HashMap<u8,usize>) {
        let mut table = HashMap::new();
        let mut total = 0;

        for ref kv in array {
            table.insert(kv.0, kv.1);
            total += kv.1;
        }

        (total, table)
    }

    let plaintext = Vec::from("Cooking MC\'s like a pound of bacon");
    let (total, table): (usize, HashMap<u8,usize>)
         = make_table(english::FREQUENCY_LIST.as_ref());

    let model     = Histogram::from(english::FREQUENCY_LIST.as_ref());
    let score     = break_xor_cipher::score_with(&model, plaintext.as_ref());

    let mut expected_score = Ratio::from_integer(0);
    for ch in plaintext.into_iter() {
        if table.contains_key(&ch) {
            expected_score = expected_score + Ratio::new_raw(*table.get(&ch).unwrap(), total);
        }
    }

    assert_eq!(expected_score, score);
}
<|endoftext|>


<commit_before>// -*- rust -*-

use std;
import comm;
import comm::send;
import comm::chan;
import comm::recv;
import task;

fn a(c: chan<int>) {
    if true {
        #debug("task a");
        #debug("task a");
        #debug("task a");
        #debug("task a");
        #debug("task a");
    }
    send(c, 10);
}

fn k(x: int) -> int { ret 15; }

fn g(x: int, y: str) -> int {
    log(debug, x);
    log(debug, y);
    let z: int = k(1);
    ret z;
}

fn main() {
    let mut n: int = 2 + 3 * 7;
    let s: str = "hello there";
    let p = comm::port();
    let ch = comm::chan(p);
    task::spawn {|| a(ch); };
    task::spawn {|| b(ch); };
    let mut x: int = 10;
    x = g(n, s);
    log(debug, x);
    n = recv(p);
    n = recv(p);
    // FIXME: use signal-channel for this. (#2600)
    #debug("children finished, root finishing");
}

fn b(c: chan<int>) {
    if true {
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
    }
    send(c, 10);
}
<commit_msg>Remove FIXME from run-pass/basic.rs. Closes #2600<commit_after>// -*- rust -*-

use std;
import comm;
import comm::send;
import comm::chan;
import comm::recv;
import task;

fn a(c: chan<int>) {
    if true {
        #debug("task a");
        #debug("task a");
        #debug("task a");
        #debug("task a");
        #debug("task a");
    }
    send(c, 10);
}

fn k(x: int) -> int { ret 15; }

fn g(x: int, y: str) -> int {
    log(debug, x);
    log(debug, y);
    let z: int = k(1);
    ret z;
}

fn main() {
    let mut n: int = 2 + 3 * 7;
    let s: str = "hello there";
    let p = comm::port();
    let ch = comm::chan(p);
    task::spawn {|| a(ch); };
    task::spawn {|| b(ch); };
    let mut x: int = 10;
    x = g(n, s);
    log(debug, x);
    n = recv(p);
    n = recv(p);
    #debug("children finished, root finishing");
}

fn b(c: chan<int>) {
    if true {
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
        #debug("task b");
    }
    send(c, 10);
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Standard` distribution for other built-in types.

use core::char;
use core::num::Wrapping;

use crate::Rng;
use crate::distributions::{Distribution, Standard, Uniform};

// ----- Sampling distributions -----

/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
///
/// # Example
///
/// ```
/// use std::iter;
/// use rand::{Rng, thread_rng};
/// use rand::distributions::Alphanumeric;
///
/// let mut rng = thread_rng();
/// let chars: String = iter::repeat(())
///         .map(|()| rng.sample(Alphanumeric))
///         .take(7)
///         .collect();
/// println!("Random chars: {}", chars);
/// ```
#[derive(Debug)]
pub struct Alphanumeric;

// ----- Implementations of distributions -----

impl Distribution<char> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // A valid `char` is either in the interval `[0, 0xD800)` or
        // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
        // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
        // reserved for surrogates. This is the size of that gap.
        const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;

        // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
        // seemed slower.
        let range = Uniform::new(GAP_SIZE, 0x11_0000);

        let mut n = range.sample(rng);
        if n <= 0xDFFF {
            n -= GAP_SIZE;
        }
        unsafe { char::from_u32_unchecked(n) }
    }
}

impl Distribution<char> for Alphanumeric {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        const RANGE: u32 = 26 + 26 + 10;
        const GEN_ASCII_STR_CHARSET: &[u8] =
            b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                abcdefghijklmnopqrstuvwxyz\
                0123456789";
        // We can pick from 62 characters. This is so close to a power of 2, 64,
        // that we can do better than `Uniform`. Use a simple bitshift and
        // rejection sampling. We do not use a bitmask, because for small RNGs
        // the most significant bits are usually of higher quality.
        loop {
            let var = rng.next_u32() >> (32 - 6);
            if var < RANGE {
                return GEN_ASCII_STR_CHARSET[var as usize] as char
            }
        }
    }
}

impl Distribution<bool> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        // We can compare against an arbitrary bit of an u32 to get a bool.
        // Because the least significant bits of a lower quality RNG can have
        // simple patterns, we compare against the most significant bit. This is
        // easiest done using a sign test.
        (rng.next_u32() as i32) < 0
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Standard
            where $( Standard: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Standard {
    #[allow(clippy::unused_unit)]
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}

macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Standard {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
        Wrapping(rng.gen())
    }
}

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

    #[test]
    fn test_misc() {
        let rng: &mut dyn RngCore = &mut crate::test::rng(820);

        rng.sample::<char, _>(Standard);
        rng.sample::<bool, _>(Standard);
    }

    #[cfg(feature="alloc")]
    #[test]
    fn test_chars() {
        use core::iter;
        let mut rng = crate::test::rng(805);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let word: String = iter::repeat(())
                .map(|()| rng.gen::<char>()).take(1000).collect();
        assert!(word.len() != 0);
    }

    #[test]
    fn test_alphanumeric() {
        let mut rng = crate::test::rng(806);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let mut incorrect = false;
        for _ in 0..100 {
            let c = rng.sample(Alphanumeric);
            incorrect |= !((c >= '0' && c <= '9') ||
                           (c >= 'A' && c <= 'Z') ||
                           (c >= 'a' && c <= 'z') );
        }
        assert!(incorrect == false);
    }

    #[test]
    fn value_stability() {
        fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
            distr: &D, zero: T, expected: &[T]) {
            let mut rng = crate::test::rng(807);
            let mut buf = [zero; 5];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(&buf, expected);
        }

        test_samples(&Standard, 'a', &['\u{8cdac}', '\u{a346a}', '\u{80120}', '\u{ed692}', '\u{35888}']);
        test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
        test_samples(&Standard, false, &[true, true, false, true, false]);
        test_samples(&Standard, Option::<bool>::None,
                &[Some(true), None, Some(false), None, Some(false)]);
        test_samples(&Standard, Wrapping(0i32), &[Wrapping(-2074640887),
                Wrapping(-1719949321), Wrapping(2018088303),
                Wrapping(-547181756), Wrapping(838957336)]);

        // We test only sub-sets of tuple and array impls
        test_samples(&Standard, (), &[(), (), (), (), ()]);
        test_samples(&Standard, (false,), &[(true,), (true,), (false,), (true,), (false,)]);
        test_samples(&Standard, (false,false), &[(true,true), (false,true),
                (false,false), (true,false), (false,false)]);

        test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
        test_samples(&Standard, [0u8; 3], &[[9, 247, 111],
                [68, 24, 13], [174, 19, 194],
                [172, 69, 213], [149, 207, 29]]);
    }
}
<commit_msg>Fix tests<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of the `Standard` distribution for other built-in types.

use core::char;
use core::num::Wrapping;

use crate::Rng;
use crate::distributions::{Distribution, Standard, Uniform};

// ----- Sampling distributions -----

/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
///
/// # Example
///
/// ```
/// use std::iter;
/// use rand::{Rng, thread_rng};
/// use rand::distributions::Alphanumeric;
///
/// let mut rng = thread_rng();
/// let chars: String = iter::repeat(())
///         .map(|()| rng.sample(Alphanumeric))
///         .take(7)
///         .collect();
/// println!("Random chars: {}", chars);
/// ```
#[derive(Debug)]
pub struct Alphanumeric;

// ----- Implementations of distributions -----

impl Distribution<char> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        // A valid `char` is either in the interval `[0, 0xD800)` or
        // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
        // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
        // reserved for surrogates. This is the size of that gap.
        const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;

        // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
        // seemed slower.
        let range = Uniform::new(GAP_SIZE, 0x11_0000);

        let mut n = range.sample(rng);
        if n <= 0xDFFF {
            n -= GAP_SIZE;
        }
        unsafe { char::from_u32_unchecked(n) }
    }
}

impl Distribution<char> for Alphanumeric {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
        const RANGE: u32 = 26 + 26 + 10;
        const GEN_ASCII_STR_CHARSET: &[u8] =
            b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                abcdefghijklmnopqrstuvwxyz\
                0123456789";
        // We can pick from 62 characters. This is so close to a power of 2, 64,
        // that we can do better than `Uniform`. Use a simple bitshift and
        // rejection sampling. We do not use a bitmask, because for small RNGs
        // the most significant bits are usually of higher quality.
        loop {
            let var = rng.next_u32() >> (32 - 6);
            if var < RANGE {
                return GEN_ASCII_STR_CHARSET[var as usize] as char
            }
        }
    }
}

impl Distribution<bool> for Standard {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
        // We can compare against an arbitrary bit of an u32 to get a bool.
        // Because the least significant bits of a lower quality RNG can have
        // simple patterns, we compare against the most significant bit. This is
        // easiest done using a sign test.
        (rng.next_u32() as i32) < 0
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl< $( $tyvar ),* >
            Distribution<( $( $tyvar ),* , )>
            for Standard
            where $( Standard: Distribution<$tyvar> ),*
        {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Distribution<()> for Standard {
    #[allow(clippy::unused_unit)]
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}

macro_rules! array_impl {
    // recursive, given at least one type parameter:
    {$n:expr, $t:ident, $($ts:ident,)*} => {
        array_impl!{($n - 1), $($ts,)*}

        impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
            #[inline]
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
                [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
            }
        }
    };
    // empty case:
    {$n:expr,} => {
        impl<T> Distribution<[T; $n]> for Standard {
            fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
        }
    };
}

array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
        // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
        if rng.gen::<bool>() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
        Wrapping(rng.gen())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::RngCore;
    #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String;

    #[test]
    fn test_misc() {
        let rng: &mut dyn RngCore = &mut crate::test::rng(820);

        rng.sample::<char, _>(Standard);
        rng.sample::<bool, _>(Standard);
    }

    #[cfg(feature="alloc")]
    #[test]
    fn test_chars() {
        use core::iter;
        let mut rng = crate::test::rng(805);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let word: String = iter::repeat(())
                .map(|()| rng.gen::<char>()).take(1000).collect();
        assert!(word.len() != 0);
    }

    #[test]
    fn test_alphanumeric() {
        let mut rng = crate::test::rng(806);

        // Test by generating a relatively large number of chars, so we also
        // take the rejection sampling path.
        let mut incorrect = false;
        for _ in 0..100 {
            let c = rng.sample(Alphanumeric);
            incorrect |= !((c >= '0' && c <= '9') ||
                           (c >= 'A' && c <= 'Z') ||
                           (c >= 'a' && c <= 'z') );
        }
        assert!(incorrect == false);
    }

    #[test]
    fn value_stability() {
        fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
            distr: &D, zero: T, expected: &[T]) {
            let mut rng = crate::test::rng(807);
            let mut buf = [zero; 5];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(&buf, expected);
        }

        test_samples(&Standard, 'a', &['\u{8cdac}', '\u{a346a}', '\u{80120}', '\u{ed692}', '\u{35888}']);
        test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
        test_samples(&Standard, false, &[true, true, false, true, false]);
        test_samples(&Standard, None as Option<bool>,
                &[Some(true), None, Some(false), None, Some(false)]);
        test_samples(&Standard, Wrapping(0i32), &[Wrapping(-2074640887),
                Wrapping(-1719949321), Wrapping(2018088303),
                Wrapping(-547181756), Wrapping(838957336)]);

        // We test only sub-sets of tuple and array impls
        test_samples(&Standard, (), &[(), (), (), (), ()]);
        test_samples(&Standard, (false,), &[(true,), (true,), (false,), (true,), (false,)]);
        test_samples(&Standard, (false,false), &[(true,true), (false,true),
                (false,false), (true,false), (false,false)]);

        test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
        test_samples(&Standard, [0u8; 3], &[[9, 247, 111],
                [68, 24, 13], [174, 19, 194],
                [172, 69, 213], [149, 207, 29]]);
    }
}
<|endoftext|>