<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 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 stdout = io::stdout().into_raw_mode().unwrap();
        let mut pos = 0;
        // 1-based screen co-ordinates
        let mut cursor_x = 1;
        let mut cursor_y = 1;
        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!(stdout, "{}", termion::clear::All).unwrap();
            for (i, line) in annotated[pos..maxpos].iter().enumerate() {
                write!(stdout, "{}", 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!(stdout, "{}", termion::style::Invert).unwrap();
                        },
                        _ => (),
                    }
                    write!(stdout, "{}{}{}", style, s, termion::style::Reset).unwrap();
                }
            }
            write!(stdout, "{}", Goto(cursor_x, cursor_y)).unwrap();
            stdout.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: use the alternate screen.<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();
        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()
}
<|endoftext|>


<commit_before>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;

use unicode_width::UnicodeWidthStr;

use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{SizeCache, View, ScrollBase, ScrollStrategy};

/// A simple view showing a fixed text
pub struct TextView {
    content: String,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Option<XY<SizeCache>>,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &mut String) {
    if content.ends_with('\n') {
        content.pop().unwrap();
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        let mut content = content.into();
        strip_last_newline(&mut content);
        TextView {
            content: content,
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: None,
            width: None,
        }
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let mut content = content.into();
        strip_last_newline(&mut content);
        self.content = content;
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    // Apply the scrolling strategy to the current scroll position.
    //
    // Called when computing rows and when applying a new strategy.
    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        self.last_size = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        // First attempt: naively hope that we won't need a scrollbar_width
        // (This means we try to use the entire available width for text).
        self.rows = LinesIterator::new(&self.content, size.x).collect();

        // Width taken by the scrollbar. Without a scrollbar, it's 0.
        let mut scrollbar_width = 0;

        if self.scrollable && self.rows.len() > size.y {
            // We take 1 column for the bar itself + 1 spacing column
            scrollbar_width = 2;

            if size.x < scrollbar_width {
                // Again, this is a lost cause.
                return;
            }

            // If we're too high, include a scrollbar_width
            let available = size.x - scrollbar_width;
            self.rows = LinesIterator::new(&self.content, available).collect();

            if self.rows.is_empty() && !self.content.is_empty() {
                // We have some content, we we didn't find any row for it?
                // This probably means we couldn't even make a single row
                // (for instance we only have 1 column and we have a wide character).
                return;
            }
        }

        // Desired width, including the scrollbar_width.
        self.width = self.rows
            .iter()
            .map(|row| row.width)
            .max()
            .map(|w| w + scrollbar_width);

        // The entire "virtual" size (includes all rows)
        let mut my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // If we're scrolling, cap the the available size.
        if self.scrollable && my_size.y > size.y {
            my_size.y = size.y;
        }

        // Build a fresh cache.
        self.last_size = Some(SizeCache::build(my_size, size));

        // Adjust scrolling, in case we're sticking to the bottom for instance.
        self.scrollbase.set_heights(size.y, self.rows.len());
        self.adjust_scroll();
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        self.last_size = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {

        let h = self.rows.len();
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer =
            &printer.sub_printer(Vec2::new(0, offset), printer.size, true);

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &self.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase
                .can_scroll_down() => self.scrollbase.scroll_down(1),
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        self.last_size.is_none()
    }

    fn get_min_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<commit_msg>Add `TextView::append_content`<commit_after>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;

use unicode_width::UnicodeWidthStr;

use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{SizeCache, View, ScrollBase, ScrollStrategy};

/// A simple view showing a fixed text
pub struct TextView {
    content: String,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Option<XY<SizeCache>>,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &str) -> &str {
    if content.ends_with('\n') {
        &content[..content.len() - 1]
    } else {
        content
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        let content = content.into();
        TextView {
            content: content,
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: None,
            width: None,
        }
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let content = content.into();
        self.content = content;
        self.invalidate();
    }

    /// Append content to the end of a TextView.
    pub fn append_content(&mut self, content: &str) {
        self.content.push_str(content);
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    // Apply the scrolling strategy to the current scroll position.
    //
    // Called when computing rows and when applying a new strategy.
    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        self.last_size = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        // First attempt: naively hope that we won't need a scrollbar_width
        // (This means we try to use the entire available width for text).
        self.rows = LinesIterator::new(strip_last_newline(&self.content),
                                       size.x)
            .collect();

        // Width taken by the scrollbar. Without a scrollbar, it's 0.
        let mut scrollbar_width = 0;

        if self.scrollable && self.rows.len() > size.y {
            // We take 1 column for the bar itself + 1 spacing column
            scrollbar_width = 2;

            if size.x < scrollbar_width {
                // Again, this is a lost cause.
                return;
            }

            // If we're too high, include a scrollbar_width
            let available = size.x - scrollbar_width;
            self.rows = LinesIterator::new(&self.content, available).collect();

            if self.rows.is_empty() && !self.content.is_empty() {
                // We have some content, we we didn't find any row for it?
                // This probably means we couldn't even make a single row
                // (for instance we only have 1 column and we have a wide character).
                return;
            }
        }

        // Desired width, including the scrollbar_width.
        self.width = self.rows
            .iter()
            .map(|row| row.width)
            .max()
            .map(|w| w + scrollbar_width);

        // The entire "virtual" size (includes all rows)
        let mut my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // If we're scrolling, cap the the available size.
        if self.scrollable && my_size.y > size.y {
            my_size.y = size.y;
        }

        // Build a fresh cache.
        self.last_size = Some(SizeCache::build(my_size, size));

        // Adjust scrolling, in case we're sticking to the bottom for instance.
        self.scrollbase.set_heights(size.y, self.rows.len());
        self.adjust_scroll();
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        self.last_size = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {

        let h = self.rows.len();
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer =
            &printer.sub_printer(Vec2::new(0, offset), printer.size, true);

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &self.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase
                .can_scroll_down() => self.scrollbase.scroll_down(1),
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        self.last_size.is_none()
    }

    fn get_min_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<|endoftext|>


<commit_before>
pub use from::{Table, RcTable};
pub use field::{NamedField, Field, RcField};
pub use select_query::{SelectQuery, LimitMany};
pub use expression::{Expression, UntypedExpression, RcExpression};

#[deriving(Clone)]
pub enum InsertValue<T> {
    ExpressionValue {
        expression: RcExpression
    },
    DefaultValue
}

impl<T> InsertValue<T> {
    pub fn new(exp: &Expression<T>) -> InsertValue<T> {
        ExpressionValue {
            expression: exp.upcast_expression()
        }
    }
}

#[deriving(Clone)]
pub enum InsertValueUntyped {
    ExpressionValueUntyped {
        expression: RcExpression
    },
    DefaultValueUntyped
}

#[allow(dead_code)]
#[deriving(Clone)]
pub enum Insert<T, V, M> {
    InsertDefaultValues,
    InsertValues(Vec<V>),
    InsertUntypedValues(Vec<Vec<RcExpression>>),
    InsertFromSelect(SelectQuery<T, LimitMany, M>)
}

#[allow(dead_code)]
#[deriving(Clone)]
pub struct InsertQuery<T, V, M> {
    into: RcTable,
    cols: Option<Vec<RcField>>,
    values: Insert<T, V, M>
}

macro_rules! insert(
    ($name:ident, $(($t:ident, $arg:ident)),+) => (
        // FIXME: Make this public after https://github.com/rust-lang/rust/issues/17635:
        //        Impossible to have a macro expand to `pub` method
        fn $name<$($t:Clone,)+>(&self, $($arg: &NamedField<$t>,)+) -> InsertQuery<($($t,)+), ($(InsertValue<$t>,)+), M> {
            let mut cols = vec![];
            $(cols.push((*$arg).upcast_field());)+
            let mut query = InsertQuery::new(self);
            query.cols = Some(cols);
            query
        }
    )
)

macro_rules! insertable(
    () => (
        pub trait Insertable<M: Clone>: Table {
            // FIXME: It doesn't work for now because of https://github.com/rust-lang/rust/issues/11403:
            //        Cannot use Macros in Trait Bodies
            // FIXME: Rewrite after https://github.com/rust-lang/rfcs/issues/376:
            //        Draft RFC: variadic generics
            // insert!(insert_1, (T0, _t0))
            // insert!(insert_2, (T0, _t0), (T1, _t1))
            // insert!(insert_3, (T0, _t0), (T1, _t1), (T2, _t2))
            // insert!(insert_4, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3))
            // insert!(insert_5, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4))
            // insert!(insert_6, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5))
            // insert!(insert_7, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6))
            // insert!(insert_8, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7))
            // insert!(insert_9, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8))
            // insert!(insert_10, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9))
            // insert!(insert_11, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9), (T10, _t10))
            // insert!(insert_12, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9), (T10, _t10), (T11, _t11))

            fn insert_all(&self) -> InsertQuery<(), (), M> {
                 InsertQuery::new(self)
            }

            fn insert_fields(&self, fields: &[&Field]) -> InsertQuery<(), (), M> {
                let mut cols = vec![];
                for field in fields.iter() {
                    cols.push(field.upcast_field())
                }
                InsertQuery::new_with_cols(self, cols)
            }
        }
    )
)

insertable!()

#[allow(dead_code)]
impl<T: Clone, V: Clone, M: Clone> InsertQuery<T, V, M> {

    pub fn new(into: &Table) -> InsertQuery<T, V, M> {
        InsertQuery {
            into: into.upcast_table(),
            cols: None,
            values: InsertDefaultValues
        }
    }

    pub fn new_with_cols(into: &Table, cols: Vec<RcField>) -> InsertQuery<T, V, M> {
        InsertQuery {
            into: into.upcast_table(),
            cols: Some(cols),
            values: InsertDefaultValues
        }
    }

    pub fn get_into(&self) -> &RcTable { &self.into }
    pub fn get_cols(&self) -> &Option<Vec<RcField>> { &self.cols }
    pub fn get_values(&self) -> &Insert<T, V, M> { &self.values }

    pub fn push(&mut self, value: V) {

        let mut reassign = false;
        match &self.values {
            &InsertDefaultValues | &InsertFromSelect(_) => {
                reassign = true;
            },
            _ => ()
        }

        if reassign {
            self.values = InsertValues(vec![value])
        } else {
            match &mut self.values {
                &InsertValues(ref mut values) => {
                    values.push(value)
                },
                _ => ()
            }
        }
    }

    pub fn push_untyped(&mut self, values: &[&UntypedExpression]) {
        let mut reassign = false;
        match &self.values {
            &InsertDefaultValues | &InsertFromSelect(_) => {
                reassign = true;
            },
            _ => ()
        }

        let values_vec = values.iter().map(|e| e.upcast_expression()).collect();

        if reassign {
            self.values = InsertUntypedValues(vec![values_vec])
        } else {
            match &mut self.values {
                &InsertUntypedValues(ref mut values) => {
                    values.push(values_vec)
                },
                _ => ()
            }
        }
    }

    pub fn from_select(&self, select: SelectQuery<T, LimitMany, M>) -> InsertQuery<T, V, M> {
        with_clone!(self, query, query.values = InsertFromSelect(select))
    }

}
<commit_msg>feat: improve fixme comments<commit_after>
pub use from::{Table, RcTable};
pub use field::{NamedField, Field, RcField};
pub use select_query::{SelectQuery, LimitMany};
pub use expression::{Expression, UntypedExpression, RcExpression};

#[deriving(Clone)]
pub enum InsertValue<T> {
    ExpressionValue {
        expression: RcExpression
    },
    DefaultValue
}

impl<T> InsertValue<T> {
    pub fn new(exp: &Expression<T>) -> InsertValue<T> {
        ExpressionValue {
            expression: exp.upcast_expression()
        }
    }
}

#[deriving(Clone)]
pub enum InsertValueUntyped {
    ExpressionValueUntyped {
        expression: RcExpression
    },
    DefaultValueUntyped
}

#[allow(dead_code)]
#[deriving(Clone)]
pub enum Insert<T, V, M> {
    InsertDefaultValues,
    InsertValues(Vec<V>),
    InsertUntypedValues(Vec<Vec<RcExpression>>),
    InsertFromSelect(SelectQuery<T, LimitMany, M>)
}

#[allow(dead_code)]
#[deriving(Clone)]
pub struct InsertQuery<T, V, M> {
    into: RcTable,
    cols: Option<Vec<RcField>>,
    values: Insert<T, V, M>
}

macro_rules! insert(
    ($name:ident, $(($t:ident, $arg:ident)),+) => (
        // FIXME: Make this public after https://github.com/rust-lang/rust/issues/17635
        fn $name<$($t:Clone,)+>(&self, $($arg: &NamedField<$t>,)+) -> InsertQuery<($($t,)+), ($(InsertValue<$t>,)+), M> {
            let mut cols = vec![];
            $(cols.push((*$arg).upcast_field());)+
            let mut query = InsertQuery::new(self);
            query.cols = Some(cols);
            query
        }
    )
)

macro_rules! insertable(
    () => (
        pub trait Insertable<M: Clone>: Table {
            // FIXME: It doesn't work for now because of :
            //        [Cannot use Macros in Trait Bodies](https://github.com/rust-lang/rust/issues/11403)
            //        [Impossible to have a macro expand to `pub` method](https://github.com/rust-lang/rust/issues/17635)
            // FIXME: Rewrite after https://github.com/rust-lang/rfcs/issues/376:
            //        Draft RFC: variadic generics
            // insert!(insert_1, (T0, _t0))
            // insert!(insert_2, (T0, _t0), (T1, _t1))
            // insert!(insert_3, (T0, _t0), (T1, _t1), (T2, _t2))
            // insert!(insert_4, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3))
            // insert!(insert_5, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4))
            // insert!(insert_6, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5))
            // insert!(insert_7, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6))
            // insert!(insert_8, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7))
            // insert!(insert_9, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8))
            // insert!(insert_10, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9))
            // insert!(insert_11, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9), (T10, _t10))
            // insert!(insert_12, (T0, _t0), (T1, _t1), (T2, _t2), (T3, _t3), (T4, _t4), (T5, _t5), (T6, _t6), (T7, _t7), (T8, _t8), (T9, _t9), (T10, _t10), (T11, _t11))

            fn insert_all(&self) -> InsertQuery<(), (), M> {
                 InsertQuery::new(self)
            }

            fn insert_fields(&self, fields: &[&Field]) -> InsertQuery<(), (), M> {
                let mut cols = vec![];
                for field in fields.iter() {
                    cols.push(field.upcast_field())
                }
                InsertQuery::new_with_cols(self, cols)
            }
        }
    )
)

insertable!()

#[allow(dead_code)]
impl<T: Clone, V: Clone, M: Clone> InsertQuery<T, V, M> {

    pub fn new(into: &Table) -> InsertQuery<T, V, M> {
        InsertQuery {
            into: into.upcast_table(),
            cols: None,
            values: InsertDefaultValues
        }
    }

    pub fn new_with_cols(into: &Table, cols: Vec<RcField>) -> InsertQuery<T, V, M> {
        InsertQuery {
            into: into.upcast_table(),
            cols: Some(cols),
            values: InsertDefaultValues
        }
    }

    pub fn get_into(&self) -> &RcTable { &self.into }
    pub fn get_cols(&self) -> &Option<Vec<RcField>> { &self.cols }
    pub fn get_values(&self) -> &Insert<T, V, M> { &self.values }

    pub fn push(&mut self, value: V) {

        let mut reassign = false;
        match &self.values {
            &InsertDefaultValues | &InsertFromSelect(_) => {
                reassign = true;
            },
            _ => ()
        }

        if reassign {
            self.values = InsertValues(vec![value])
        } else {
            match &mut self.values {
                &InsertValues(ref mut values) => {
                    values.push(value)
                },
                _ => ()
            }
        }
    }

    pub fn push_untyped(&mut self, values: &[&UntypedExpression]) {
        let mut reassign = false;
        match &self.values {
            &InsertDefaultValues | &InsertFromSelect(_) => {
                reassign = true;
            },
            _ => ()
        }

        let values_vec = values.iter().map(|e| e.upcast_expression()).collect();

        if reassign {
            self.values = InsertUntypedValues(vec![values_vec])
        } else {
            match &mut self.values {
                &InsertUntypedValues(ref mut values) => {
                    values.push(values_vec)
                },
                _ => ()
            }
        }
    }

    pub fn from_select(&self, select: SelectQuery<T, LimitMany, M>) -> InsertQuery<T, V, M> {
        with_clone!(self, query, query.values = InsertFromSelect(select))
    }

}
<|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;
use std::num::Float;

#[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) / Float::sqrt(a * a + b * b + c * c) > 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();

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

fn clipmany(planes: Vec<Plane>, points: Vec<Point>) -> Vec<Point> {
    let (tx, rx) = channel();
    spawn(move || sendlist(tx, points));
    let mut planes = planes;
    let mut rx = rx;
    loop {
        match planes.pop() {
            None => {break;}
            Some(p) => {
                let (tx2, rx2) = channel();
                spawn(move || clipper(p, 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 example to beta2 + minor changes<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::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);
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

extern crate libc;

pub use raw::libc::{c_char, c_int, c_void, size_t, strcmp, uint32_t};

pub use raw::protocol::{
    wl_compositor,
    wl_compositor_create_surface,
    wl_compositor_destroy,
};
pub use raw::protocol::registry::{
    wl_registry,
    wl_registry_add_listener,
    wl_registry_bind,
    wl_registry_destroy,
    wl_registry_listener,
};
pub use raw::protocol::{
    wl_display_get_registry,
};
pub use raw::protocol::{
    wl_surface,
    wl_surface_destroy,
};
pub use raw::protocol::{
    wl_region,
    wl_region_destroy,
};

pub use raw::util::{wl_array, wl_interface, wl_list, wl_message};

pub mod protocol;
pub mod util;

#[repr(C)] pub struct wl_display;
#[repr(C)] pub struct wl_event_queue;
#[repr(C)] pub struct wl_proxy;

#[link(name = "wayland-client")]
extern {
    pub static wl_compositor_interface: util::wl_interface;
    pub static wl_region_interface: util::wl_interface;
    pub static wl_registry_interface: util::wl_interface;
    pub static wl_shell_interface: util::wl_interface;
    pub static wl_surface_interface: util::wl_interface;

    pub fn wl_display_connect(name: *const c_char) -> *mut wl_display;
    pub fn wl_display_disconnect(display: *mut wl_display);
    pub fn wl_display_dispatch(display: *mut wl_display) -> c_int;
    pub fn wl_display_dispatch_queue(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_dispatch_queue_pending(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_dispatch_pending(display: *mut wl_display) -> c_int;
    pub fn wl_display_get_error(display: *mut wl_display) -> c_int;
    pub fn wl_display_flush(display: *mut wl_display) -> c_int;
    pub fn wl_display_roundtrip_queue(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_roundtrip(display: *mut wl_display) -> c_int;
    // wl_proxy
    pub fn wl_proxy_add_listener(
        proxy: *mut wl_proxy,
        implementation: *mut extern fn(),
        data: *mut c_void
    ) -> c_int;
    pub fn wl_proxy_destroy(proxy: *mut wl_proxy);
    pub fn wl_proxy_marshal(
        p: *mut wl_proxy,
        opcode: uint32_t,
        ...
    );
    pub fn wl_proxy_marshal_constructor(
        proxy: *mut wl_proxy,
        opcode: uint32_t,
        interface: *const util::wl_interface,
        ...
    ) -> *mut wl_proxy;
    // wl_list
    pub fn wl_list_init(list: *mut wl_list);
    pub fn wl_list_insert(list: *mut wl_list, elm: *mut wl_list);
    pub fn wl_list_remove(elm: *mut wl_list);
    pub fn wl_list_length(elm: *const wl_list) -> c_int;
    pub fn wl_list_empty(elm: *const wl_list) -> c_int;
    pub fn wl_list_insert_list(list: *mut wl_list, other: *mut wl_list);
}
<commit_msg>Filled in the rest of the static variables<commit_after>#![allow(non_camel_case_types)]

extern crate libc;

pub use raw::libc::{c_char, c_int, c_void, size_t, strcmp, uint32_t};

pub use raw::protocol::{
    wl_compositor,
    wl_compositor_create_surface,
    wl_compositor_destroy,
};
pub use raw::protocol::registry::{
    wl_registry,
    wl_registry_add_listener,
    wl_registry_bind,
    wl_registry_destroy,
    wl_registry_listener,
};
pub use raw::protocol::{
    wl_display_get_registry,
};
pub use raw::protocol::{
    wl_surface,
    wl_surface_destroy,
};
pub use raw::protocol::{
    wl_region,
    wl_region_destroy,
};

pub use raw::util::{wl_array, wl_interface, wl_list, wl_message};

pub mod protocol;
pub mod util;

#[repr(C)]
pub struct wl_display;

#[repr(C)]
pub struct wl_event_queue;

#[repr(C)]
pub struct wl_proxy;

#[link(name = "wayland-client")]
extern {
    pub static wl_buffer_interface: wl_interface;
    pub static wl_callback_interface: wl_interface;
    pub static wl_compositor_interface: wl_interface;
    pub static wl_data_device_interface: wl_interface;
    pub static wl_data_device_manager_interface: wl_interface;
    pub static wl_data_offer_interface: wl_interface;
    pub static wl_data_source_interface: wl_interface;
    pub static wl_display_interface: wl_interface;
    pub static wl_keyboard_interface: wl_interface;
    pub static wl_output_interface: wl_interface;
    pub static wl_pointer_interface: wl_interface;
    pub static wl_region_interface: wl_interface;
    pub static wl_registry_interface: wl_interface;
    pub static wl_shell_interface: wl_interface;
    pub static wl_shell_surface_interface: wl_interface;
    pub static wl_shm_interface: wl_interface;
    pub static wl_shm_pool_interface: wl_interface;
    pub static wl_subcompositor_interface: wl_interface;
    pub static wl_subsurface_interface: wl_interface;
    pub static wl_surface_interface: wl_interface;
    pub static wl_touch_interface: wl_interface;

    pub fn wl_display_connect(name: *const c_char) -> *mut wl_display;
    pub fn wl_display_disconnect(display: *mut wl_display);
    pub fn wl_display_dispatch(display: *mut wl_display) -> c_int;
    pub fn wl_display_dispatch_queue(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_dispatch_queue_pending(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_dispatch_pending(display: *mut wl_display) -> c_int;
    pub fn wl_display_get_error(display: *mut wl_display) -> c_int;
    pub fn wl_display_flush(display: *mut wl_display) -> c_int;
    pub fn wl_display_roundtrip_queue(
        display: *mut wl_display,
        queue: *mut wl_event_queue
    ) -> c_int;
    pub fn wl_display_roundtrip(display: *mut wl_display) -> c_int;
    // wl_proxy
    pub fn wl_proxy_add_listener(
        proxy: *mut wl_proxy,
        implementation: *mut extern fn(),
        data: *mut c_void
    ) -> c_int;
    pub fn wl_proxy_destroy(proxy: *mut wl_proxy);
    pub fn wl_proxy_marshal(
        p: *mut wl_proxy,
        opcode: uint32_t,
        ...
    );
    pub fn wl_proxy_marshal_constructor(
        proxy: *mut wl_proxy,
        opcode: uint32_t,
        interface: *const util::wl_interface,
        ...
    ) -> *mut wl_proxy;
    // wl_list
    pub fn wl_list_init(list: *mut wl_list);
    pub fn wl_list_insert(list: *mut wl_list, elm: *mut wl_list);
    pub fn wl_list_remove(elm: *mut wl_list);
    pub fn wl_list_length(elm: *const wl_list) -> c_int;
    pub fn wl_list_empty(elm: *const wl_list) -> c_int;
    pub fn wl_list_insert_list(list: *mut wl_list, other: *mut wl_list);
}
<|endoftext|>


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

#[doc = "Classic Boolean logic reified as ADT"];

export t;
export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;

#[doc = "The type of boolean logic values"]
type t = bool;

#[doc = "Negation/Inverse"]
pure fn not(v: t) -> t { !v }

#[doc = "Conjunction"]
pure fn and(a: t, b: t) -> t { a && b }

#[doc = "Disjunction"]
pure fn or(a: t, b: t) -> t { a || b }

#[doc = "Exclusive or, i.e. `or(and(a, not(b)), and(not(a), b))`"]
pure fn xor(a: t, b: t) -> t { (a && !b) || (!a && b) }

#[doc = "Implication in the logic, i.e. from `a` follows `b`"]
pure fn implies(a: t, b: t) -> t { !a || b }

#[doc = "
true if truth values `a` and `b` are indistinguishable in the logic
"]
pure fn eq(a: t, b: t) -> bool { a == b }

#[doc = "true if truth values `a` and `b` are distinguishable in the logic"]
pure fn ne(a: t, b: t) -> bool { a != b }

#[doc = "true if `v` represents truth in the logic"]
pure fn is_true(v: t) -> bool { v }

#[doc = "true if `v` represents falsehood in the logic"]
pure fn is_false(v: t) -> bool { !v }

#[doc = "Parse logic value from `s`"]
pure fn from_str(s: str) -> option<t> {
    alt check s {
      "true" { some(true) }
      "false" { some(false) }
      _ { none }
    }
}

#[doc = "Convert `v` into a string"]
pure fn to_str(v: t) -> str { if v { "true" } else { "false" } }

#[doc = "
Iterates over all truth values by passing them to `blk` in an unspecified
order
"]
fn all_values(blk: fn(v: t)) {
    blk(true);
    blk(false);
}

#[doc = "converts truth value to an 8 bit byte"]
pure fn to_bit(v: t) -> u8 { if v { 1u8 } else { 0u8 } }

#[test]
fn test_bool_from_str() {
    all_values { |v|
        assert some(v) == from_str(bool::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() {
    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>core: Cleanup bool module<commit_after>// -*- rust -*-

#[doc = "Boolean logic"];

export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;

#[doc = "Negation / inverse"]
pure fn not(v: bool) -> bool { !v }

#[doc = "Conjunction"]
pure fn and(a: bool, b: bool) -> bool { a && b }

#[doc = "Disjunction"]
pure fn or(a: bool, b: bool) -> bool { a || b }

#[doc = "
Exclusive or

Identical to `or(and(a, not(b)), and(not(a), b))`
"]
pure fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

#[doc = "Implication in the logic, i.e. from `a` follows `b`"]
pure fn implies(a: bool, b: bool) -> bool { !a || b }

#[doc = "
true if truth values `a` and `b` are indistinguishable in the logic
"]
pure fn eq(a: bool, b: bool) -> bool { a == b }

#[doc = "true if truth values `a` and `b` are distinguishable in the logic"]
pure fn ne(a: bool, b: bool) -> bool { a != b }

#[doc = "true if `v` represents truth in the logic"]
pure fn is_true(v: bool) -> bool { v }

#[doc = "true if `v` represents falsehood in the logic"]
pure fn is_false(v: bool) -> bool { !v }

#[doc = "Parse logic value from `s`"]
pure fn from_str(s: str) -> option<bool> {
    alt check s {
      "true" { some(true) }
      "false" { some(false) }
      _ { none }
    }
}

#[doc = "Convert `v` into a string"]
pure fn to_str(v: bool) -> str { if v { "true" } else { "false" } }

#[doc = "
Iterates over all truth values by passing them to `blk` in an unspecified
order
"]
fn all_values(blk: fn(v: bool)) {
    blk(true);
    blk(false);
}

#[doc = "converts truth value to an 8 bit byte"]
pure fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[test]
fn test_bool_from_str() {
    all_values { |v|
        assert some(v) == from_str(bool::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() {
    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:
<|endoftext|>


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

// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

//! Boolean logic

use cmp::Eq;

export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;

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

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

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

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

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

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

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

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

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

/// Parse logic value from `s`
pure 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
pure 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
 */
fn all_values(blk: fn(v: bool)) {
    blk(true);
    blk(false);
}

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

impl bool : cmp::Eq {
    pure fn eq(other: &bool) -> bool { self == (*other) }
    pure fn ne(other: &bool) -> bool { self != (*other) }
}

#[test]
fn test_bool_from_str() {
    do all_values |v| {
        assert Some(v) == from_str(bool::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 };
    }
}

// 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>libcore: De-export bool<commit_after>// -*- rust -*-

// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

//! Boolean logic

use cmp::Eq;

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

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

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

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

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

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

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

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

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

/// Parse logic value from `s`
pub pure 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 pure 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 pure fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

impl bool : cmp::Eq {
    pure fn eq(other: &bool) -> bool { self == (*other) }
    pure fn ne(other: &bool) -> bool { self != (*other) }
}

#[test]
pub fn test_bool_from_str() {
    do all_values |v| {
        assert Some(v) == from_str(bool::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:
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

//! Types that provide interior mutability.

use clone::Clone;
use cmp::Eq;
use kinds::{marker, Copy};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Copy` data.
pub struct Cell<T> {
    value: Unsafe<T>,
    noshare: marker::NoShare,
}

impl<T:Copy> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe::new(value),
            noshare: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Copy> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Copy> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    value: Unsafe<T>,
    borrow: Cell<BorrowFlag>,
    nocopy: marker::NoCopy,
    noshare: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            value: Unsafe::new(value),
            borrow: Cell::new(UNUSED),
            nocopy: marker::NoCopy,
            noshare: marker::NoShare,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        debug_assert!(self.borrow.get() == UNUSED);
        unsafe{self.value.unwrap()}
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow.get() {
            WRITING => None,
            borrow => {
                self.borrow.set(borrow + 1);
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow.get() {
            UNUSED => {
                self.borrow.set(WRITING);
                Some(RefMut { parent: self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        RefCell::new(self.borrow().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        *self.borrow() == *other.borrow()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow != WRITING && borrow != UNUSED);
        self.parent.borrow.set(borrow - 1);
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

/// Copy a `Ref`.
///
/// The `RefCell` is already immutably borrowed, so this cannot fail.
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
    // Since this Ref exists, we know the borrow flag
    // is not set to WRITING.
    let borrow = orig.parent.borrow.get();
    debug_assert!(borrow != WRITING && borrow != UNUSED);
    orig.parent.borrow.set(borrow + 1);

    Ref {
        parent: orig.parent,
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow == WRITING);
        self.parent.borrow.set(UNUSED);
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert!(x == Cell::new(10));
        assert!(x.get() == 10);
        x.set(20);
        assert!(x == Cell::new(20));
        assert!(x.get() == 20);

        let y = Cell::new((30, 40));
        assert!(y == Cell::new((30, 40)));
        assert!(y.get() == (30, 40));
    }

    #[test]
    fn cell_has_sensible_show() {
        use str::StrSlice;

        let x = Cell::new("foo bar");
        assert!(format!("{}", x).contains(x.get()));

        x.set("baz qux");
        assert!(format!("{}", x).contains(x.get()));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }

    #[test]
    fn clone_ref_updates_flag() {
        let x = RefCell::new(0);
        {
            let b1 = x.borrow();
            assert!(x.try_borrow_mut().is_none());
            {
                let _b2 = clone_ref(&b1);
                assert!(x.try_borrow_mut().is_none());
            }
            assert!(x.try_borrow_mut().is_none());
        }
        assert!(x.try_borrow_mut().is_some());
    }
}
<commit_msg>core: Improve docs for cell<commit_after>// Copyright 2012-2013 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.

//! Sharable mutable containers.
//!
//! Values of the `Cell` and `RefCell` types may be mutated through
//! shared references (i.e. the common `&T` type), whereas most Rust
//! types can only be mutated through unique (`&mut T`) references. We
//! say that `Cell` and `RefCell` provide *interior mutability*, in
//! contrast with typical Rust types that exhibit *inherited
//! mutability*.
//!
//! Cell types come in two flavors: `Cell` and `RefCell`. `Cell`
//! provides `get` and `set` methods that change the
//! interior value with a single method call. `Cell` though is only
//! compatible with types that implement `Copy`. For other types,
//! one must use the `RefCell` type, acquiring a write lock before
//! mutating.
//!
//! `RefCell` uses Rust's lifetimes to implement *dynamic borrowing*,
//! a process whereby one can claim temporary, exclusive, mutable
//! access to the inner value. Borrows for `RefCell`s are tracked *at
//! runtime*, unlike Rust's native reference types which are entirely
//! tracked statically, at compile time. Because `RefCell` borrows are
//! dynamic it is possible to attempt to borrow a value that is
//! already mutably borrowed; when this happens it results in task
//! failure.
//!
//! # When to choose interior mutability
//!
//! The more common inherited mutability, where one must have unique
//! access to mutate a value, is one of the key language elements that
//! enables Rust to reason strongly about pointer aliasing, statically
//! preventing crash bugs. Because of that, inherited mutability is
//! preferred, and interior mutability is something of a last
//! resort. Since cell types enable mutation where it would otherwise
//! be disallowed though, there are occassions when interior
//! mutability might be appropriate, or even *must* be used, e.g.
//!
//! * Introducing inherited mutability roots to shared types.
//! * Implementation details of logically-immutable methods.
//! * Mutating implementations of `clone`.
//!
//! ## Introducing inherited mutability roots to shared types
//!
//! Shared smart pointer types, including `Rc` and `Arc`, provide
//! containers that can be cloned and shared between multiple parties.
//! Because the contained values may be multiply-aliased, they can
//! only be borrowed as shared references, not mutable references.
//! Without cells then it would be impossible to mutate data inside of
//! shared boxes at all!
//!
//! It's very common then to put a `RefCell` inside shared pointer
//! types to reintroduce mutability:
//!
//! ```
//! extern crate collections;
//!
//! use collections::HashMap;
//! use std::cell::RefCell;
//! use std::rc::Rc;
//!
//! fn main() {
//!     let shared_map: Rc<RefCell<_>> = Rc::new(RefCell::new(HashMap::new()));
//!     shared_map.borrow_mut().insert("africa", 92388);
//!     shared_map.borrow_mut().insert("kyoto", 11837);
//!     shared_map.borrow_mut().insert("piccadilly", 11826);
//!     shared_map.borrow_mut().insert("marbles", 38);
//! }
//! ```
//!
//! ## Implementation details of logically-immutable methods
//!
//! Occasionally it may be desirable not to expose in an API that
//! there is mutation happening "under the hood". This may be because
//! logically the operation is immutable, but e.g. caching forces the
//! implementation to perform mutation; or because you must employ
//! mutation to implement a trait method that was originally defined
//! to take `&self`.
//!
//! ```
//! extern crate collections;
//!
//! use collections::HashMap;
//! use std::cell::RefCell;
//!
//! struct Graph {
//!     edges: HashMap<uint, uint>,
//!     span_tree_cache: RefCell<Option<Vec<(uint, uint)>>>
//! }
//!
//! impl Graph {
//!     fn minimum_spanning_tree(&self) -> Vec<(uint, uint)> {
//!         // Create a new scope to contain the lifetime of the
//!         // dynamic borrow
//!         {
//!             // Take a reference to the inside of cache cell
//!             let mut cache = self.span_tree_cache.borrow_mut();
//!             if cache.is_some() {
//!                 return cache.take_unwrap().clone();
//!             }
//!
//!             let span_tree = self.calc_span_tree();
//!             *cache = Some(span_tree);
//!         }
//!
//!         // Recursive call to return the just-cached value.
//!         // Note that if we had not let the previous borrow
//!         // of the cache fall out of scope then the subsequent
//!         // recursive borrow would cause a dynamic task failure.
//!         // This is the major hazard of using `RefCell`.
//!         self.minimum_spanning_tree()
//!     }
//! #   fn calc_span_tree(&self) -> Vec<(uint, uint)> { vec!() }
//! }
//! # fn main() { }
//! ```
//!
//! ## Mutating implementations of `clone`
//!
//! This is simply a special - bot common - case of the previous:
//! hiding mutability for operations that appear to be immutable.
//! The `clone` method is expected to not change the source value, and
//! is declared to take `&self`, not `&mut self`. Therefore any
//! mutation that happens in the `clone` method must use cell
//! types. For example, `Rc` maintains its reference counts within a
//! `Cell`.
//!
//! ```
//! use std::cell::Cell;
//!
//! struct Rc<T> {
//!     ptr: *mut RcBox<T>
//! }
//!
//! struct RcBox<T> {
//!     value: T,
//!     refcount: Cell<uint>
//! }
//!
//! impl<T> Clone for Rc<T> {
//!     fn clone(&self) -> Rc<T> {
//!         unsafe {
//!             (*self.ptr).refcount.set((*self.ptr).refcount.get() + 1);
//!             Rc { ptr: self.ptr }
//!         }
//!     }
//! }
//! ```
//!
// TODO: Explain difference between Cell and RefCell
// TODO: Downsides to interior mutability
// TODO: Can't be shared between threads. Dynamic borrows
// TODO: Relationship to Atomic types and RWLock

use clone::Clone;
use cmp::Eq;
use kinds::{marker, Copy};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Copy` data.
pub struct Cell<T> {
    value: Unsafe<T>,
    noshare: marker::NoShare,
}

impl<T:Copy> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe::new(value),
            noshare: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Copy> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Copy> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    value: Unsafe<T>,
    borrow: Cell<BorrowFlag>,
    nocopy: marker::NoCopy,
    noshare: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            value: Unsafe::new(value),
            borrow: Cell::new(UNUSED),
            nocopy: marker::NoCopy,
            noshare: marker::NoShare,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        debug_assert!(self.borrow.get() == UNUSED);
        unsafe{self.value.unwrap()}
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow.get() {
            WRITING => None,
            borrow => {
                self.borrow.set(borrow + 1);
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow.get() {
            UNUSED => {
                self.borrow.set(WRITING);
                Some(RefMut { parent: self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        RefCell::new(self.borrow().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        *self.borrow() == *other.borrow()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow != WRITING && borrow != UNUSED);
        self.parent.borrow.set(borrow - 1);
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

/// Copy a `Ref`.
///
/// The `RefCell` is already immutably borrowed, so this cannot fail.
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
    // Since this Ref exists, we know the borrow flag
    // is not set to WRITING.
    let borrow = orig.parent.borrow.get();
    debug_assert!(borrow != WRITING && borrow != UNUSED);
    orig.parent.borrow.set(borrow + 1);

    Ref {
        parent: orig.parent,
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow == WRITING);
        self.parent.borrow.set(UNUSED);
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert!(x == Cell::new(10));
        assert!(x.get() == 10);
        x.set(20);
        assert!(x == Cell::new(20));
        assert!(x.get() == 20);

        let y = Cell::new((30, 40));
        assert!(y == Cell::new((30, 40)));
        assert!(y.get() == (30, 40));
    }

    #[test]
    fn cell_has_sensible_show() {
        use str::StrSlice;

        let x = Cell::new("foo bar");
        assert!(format!("{}", x).contains(x.get()));

        x.set("baz qux");
        assert!(format!("{}", x).contains(x.get()));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }

    #[test]
    fn clone_ref_updates_flag() {
        let x = RefCell::new(0);
        {
            let b1 = x.borrow();
            assert!(x.try_borrow_mut().is_none());
            {
                let _b2 = clone_ref(&b1);
                assert!(x.try_borrow_mut().is_none());
            }
            assert!(x.try_borrow_mut().is_none());
        }
        assert!(x.try_borrow_mut().is_some());
    }
}
<|endoftext|>