<commit_before>// nesting analysis.
// this is a post-processing engine after tokenization, to give useful information to
// the autocompletion engine and parser (for error recovery).

use std::cmp;
use std::cell::Cell;

use kailua_env::Spanned;
use super::{Tok, Punct, Keyword};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Nesting {
    // implicitly starts, ends with the EOF
    // used to simplify the handling of EOF
    Top,
    // starts with meta token, ends with newline or other meta token (opens another nesting)
    Meta,
    // starts with `(`, ends with `)`
    Paren,
    // starts with `{`, ends with `}`
    Brace,
    // starts with `[`, ends with `]`
    Bracket,
    // starts with `for` or `while`, ends with `do`; normally inside Nesting::End
    Do,
    // starts with `if` or `elseif`, ends with `then`; normally inside Nesting::Else
    Then,
    // starts with `if` or `elseif`, ends with `elseif` or `else`; normally inside Nesting::End
    Else,
    // starts with any block statement, ends with `end`
    End,
    // starts with `repeat`, ends with `until`
    Until,
}

impl Nesting {
    fn is_stmt_level(&self) -> bool {
        match *self {
            Nesting::Top | Nesting::Meta |
            Nesting::Do | Nesting::Then | Nesting::Else | Nesting::End | Nesting::Until => true,
            _ => false,
        }
    }
}

// the major category of the current nesting, most commonly used for autocompletion
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum NestingCategory {
    Expr = 0,
    Meta = 1,
}

// a monotonically increasing serial number, only incremented when the nesting changes.
// the exact number has no meaning, only useful for the comparison.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct NestingSerial(u32);

impl NestingSerial {
    pub fn dummy() -> NestingSerial { NestingSerial(0) }

    pub fn to_usize(&self) -> usize { self.0 as usize }
}

#[derive(Clone, PartialEq, Debug)]
pub struct NestedToken {
    pub tok: Spanned<Tok>,

    // conceptually this nesting information applies to the token and following whitespaces
    pub depth: u16,
    pub category: NestingCategory,
    pub serial: NestingSerial,
}

pub struct Nest<'a> {
    iter: &'a mut Iterator<Item=Spanned<Tok>>,
    open_nestings: Vec<(Nesting, u32)>,
    next_serial: u32,
    meta_idx: Option<usize>, // invariant: if not None, open_nestings[meta] == Nesting::Meta
}

impl<'a> Nest<'a> {
    pub fn new(iter: &'a mut Iterator<Item=Spanned<Tok>>) -> Nest<'a> {
        Nest {
            iter: iter,
            open_nestings: vec![(Nesting::Top, 1)],
            next_serial: 2,
            meta_idx: None,
        }
    }

    fn update_nestings(&mut self, tok: &Tok) {
        enum Action {
            None,
            // push one nesting
            Push(Nesting),
            // push two nestings in this order
            Push2(Nesting, Nesting),
            // push three nestings in this order
            Push3(Nesting, Nesting, Nesting),
            // pop until a particular nesting appears; do nothing if no match
            Pop(Nesting),
            // pop until a particular nestings appears,
            // then push another nesting in place of the popped nesting; do nothing if no match
            PopAndPush(Nesting, Nesting),
            // pop until the first nesting appears; push the second nesting if no match
            PopOrPush(Nesting, Nesting),
            // same to `Pop(Nesting::Meta)` followed by `Push(Nesting::Meta)`,
            // but additionally marks a new meta block
            ReplaceMeta,
        }

        let next_serial = Cell::new(self.next_serial);
        let gen_serial = || {
            let serial = next_serial.get();
            // to avoid panic on overflow (very, very unlikely)
            next_serial.set(serial.wrapping_add(1));
            serial
        };

        // `pop_non_stmt` is a statement-level flag; it will always pop any punctuation-delimted
        // nestings before actually executing an action (even if it would be a no-op).
        let meta = self.meta_idx.is_some();
        let (pop_non_stmt, action) = match (meta, tok) {
            // natural delimiters
            // no angle brackets, hard to distinguish comparison ops from delimiters
            (_, &Tok::Punct(Punct::LParen)) => (false, Action::Push(Nesting::Paren)),
            (_, &Tok::Punct(Punct::LBrace)) => (false, Action::Push(Nesting::Brace)),
            (_, &Tok::Punct(Punct::LBracket)) => (false, Action::Push(Nesting::Bracket)),
            (_, &Tok::Punct(Punct::RParen)) => (false, Action::Pop(Nesting::Paren)),
            (_, &Tok::Punct(Punct::RBrace)) => (false, Action::Pop(Nesting::Brace)),
            (_, &Tok::Punct(Punct::RBracket)) => (false, Action::Pop(Nesting::Bracket)),

            // meta blocks
            // Newline token is only generated inside a meta block by the lexer
            // Meta can be nested (sometimes), but closes the prior open Meta nesting
            (_, &Tok::Punct(Punct::DashDashV)) =>
                // `--v` can appear in an expression (in front of a function literal)
                (false, Action::ReplaceMeta),
            (_, &Tok::Punct(Punct::DashDashHash)) |
            (_, &Tok::Punct(Punct::DashDashColon)) |
            (_, &Tok::Punct(Punct::DashDashGt)) =>
                (true, Action::ReplaceMeta),
            (_, &Tok::Punct(Punct::Newline)) =>
                (true, Action::Pop(Nesting::Meta)),

            // while, for and do blocks
            //
            // while/for ... do ... end
            // -----------End----------
            // -------Do-------
            //
            // do ... end
            // ----End---
            (false, &Tok::Keyword(Keyword::While)) |
            (false, &Tok::Keyword(Keyword::For)) =>
                (true, Action::Push2(Nesting::End, Nesting::Do)),
            (false, &Tok::Keyword(Keyword::Do)) =>
                (true, Action::PopOrPush(Nesting::Do, Nesting::End)),

            // function block
            //
            // function [NAME] ( ... ) ... end
            // -------------End-------------
            //                 -Paren-
            (false, &Tok::Keyword(Keyword::Function)) =>
                (false, Action::Push(Nesting::End)), // can appear in an expression

            // if blocks
            //
            // if ... then ... elseif ... then ... elseif ... then ... else ... end
            // --------------------------------End---------------------------------
            // ---------Else---vvvvvv              vvvvvv----Else----------
            //                 ^^^^^^-----Else-----^^^^^^
            // ----Then---     ------Then-----     ------Then-----
            //
            // `elseif` is a particularly complex token to handle.
            // it is conceptually closing the if--else nesting but should open one simultaneously.
            // therefore while the affected nesting does not change per se,
            // we mark the (conceptual) change in the delta so that the caller can recognize it.
            (false, &Tok::Keyword(Keyword::If)) =>
                (true, Action::Push3(Nesting::End, Nesting::Else, Nesting::Then)),
            (false, &Tok::Keyword(Keyword::Then)) =>
                (true, Action::Pop(Nesting::Then)),
            (false, &Tok::Keyword(Keyword::Elseif)) =>
                (true, Action::PopAndPush(Nesting::Else, Nesting::Else)),
            (false, &Tok::Keyword(Keyword::Else)) =>
                (true, Action::Pop(Nesting::Else)),

            // repeat-until block
            //
            // repeat ... until ...
            // -----Until------
            (false, &Tok::Keyword(Keyword::Repeat)) => (true, Action::Push(Nesting::Until)),
            (false, &Tok::Keyword(Keyword::Until)) => (true, Action::Pop(Nesting::Until)),

            // the universal `end` token
            (_, &Tok::Keyword(Keyword::End)) => (!meta, Action::Pop(Nesting::End)),

            // EOF (conceptually forms the top-level nesting)
            (_, &Tok::EOF) => (true, Action::Pop(Nesting::Top)),

            _ => (false, Action::None),
        };

        if pop_non_stmt {
            let stmt = self.open_nestings.iter().rposition(|&(e, _)| e.is_stmt_level());
            let i = stmt.expect("Nest::update_nestings got a corrupted list of nestings") + 1;
            if i < self.open_nestings.len() {
                trace!("token {:?} closed {} non-statement nesting(s)",
                       tok, self.open_nestings.len() - i);
            }
            self.open_nestings.truncate(i);
        }

        let mut min_depth = self.open_nestings.len();
        let mut meta_updated = false;
        match action {
            Action::None => {}

            Action::Push(e) => {
                let e = (e, gen_serial());
                trace!("token {:?} opened a nesting {:?}", tok, e);
                self.open_nestings.push(e);
            }

            Action::Push2(e1, e2) => {
                let e1 = (e1, gen_serial());
                let e2 = (e2, gen_serial());
                trace!("token {:?} opened nestings {:?} and {:?}", tok, e1, e2);
                self.open_nestings.push(e1);
                self.open_nestings.push(e2);
            }

            Action::Push3(e1, e2, e3) => {
                let e1 = (e1, gen_serial());
                let e2 = (e2, gen_serial());
                let e3 = (e3, gen_serial());
                trace!("token {:?} opened nestings {:?}, {:?} and {:?}", tok, e1, e2, e3);
                self.open_nestings.push(e1);
                self.open_nestings.push(e2);
                self.open_nestings.push(e3);
            }

            Action::Pop(epop) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a nesting {:?}", tok, epop);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    trace!("token {:?} tried to close a nesting {:?}", tok, epop);
                }
            }

            Action::PopAndPush(epop, epush) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    let epush = (epush, gen_serial());
                    trace!("token {:?} closed a nesting {:?} and opened a nesting {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    self.open_nestings.push(epush);
                    min_depth = i;
                } else {
                    trace!("token {:?} tried to close a nesting {:?} and open a nesting {:?}",
                           tok, epop, epush);
                }
            }

            Action::PopOrPush(epop, epush) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a nesting {:?} instead of opening a nesting {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    let epush = (epush, gen_serial());
                    trace!("token {:?} tried to close a nesting {:?} but \
                            opened a nesting {:?} instead", tok, epop, epush);
                    self.open_nestings.push(epush);
                }
            }

            Action::ReplaceMeta => {
                let epush = (Nesting::Meta, gen_serial());
                if let Some(i) = self.meta_idx {
                    assert_eq!(self.open_nestings.get(i).map(|e| e.0), Some(Nesting::Meta));
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a meta block {:?} and reopened a meta block {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    trace!("token {:?} opened a meta block {:?}", tok, epush);
                }
                self.meta_idx = Some(self.open_nestings.len());
                self.open_nestings.push(epush);
                meta_updated = true;
            }
        }

        // check if the prior action has unknowingly destroyed the Meta nesting
        // (Meta can only be introduced by ReplaceMeta)
        if let Some(i) = self.meta_idx {
            if !meta_updated && i >= min_depth {
                self.meta_idx = None;
            }
        }

        self.next_serial = next_serial.get();
    }
}

impl<'a> Iterator for Nest<'a> {
    type Item = NestedToken;

    fn next(&mut self) -> Option<NestedToken> {
        let tok = match self.iter.next() {
            Some(tok) => {
                assert!(self.open_nestings.len() > 0);
                tok
            },
            None => {
                // the final token should be EOF, and Newline has been generated as needed
                assert_eq!(self.open_nestings.len(), 0);
                assert_eq!(self.meta_idx, None);
                return None;
            }
        };

        self.update_nestings(&tok);

        // if depth exceeds u16 range, there is not much point doing AC anyway
        let depth = cmp::min(0xffff, self.open_nestings.len()) as u16;
        let category = match self.meta_idx {
            Some(_) => NestingCategory::Meta,
            None => NestingCategory::Expr,
        };
        let serial = self.open_nestings.last().map_or(0, |e| e.1);
        Some(NestedToken {
            tok: tok, depth: depth, category: category,
            serial: NestingSerial(serial),
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

<commit_msg>Fixed the nesting behavior of meta comments.<commit_after>// nesting analysis.
// this is a post-processing engine after tokenization, to give useful information to
// the autocompletion engine and parser (for error recovery).

use std::cmp;
use std::cell::Cell;

use kailua_env::Spanned;
use super::{Tok, Punct, Keyword};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Nesting {
    // implicitly starts, ends with the EOF
    // used to simplify the handling of EOF
    Top,
    // starts with meta token, ends with newline or other meta token (opens another nesting)
    Meta,
    // starts with `(`, ends with `)`
    Paren,
    // starts with `{`, ends with `}`
    Brace,
    // starts with `[`, ends with `]`
    Bracket,
    // starts with `for` or `while`, ends with `do`; normally inside Nesting::End
    Do,
    // starts with `if` or `elseif`, ends with `then`; normally inside Nesting::Else
    Then,
    // starts with `if` or `elseif`, ends with `elseif` or `else`; normally inside Nesting::End
    Else,
    // starts with any block statement, ends with `end`
    End,
    // starts with `repeat`, ends with `until`
    Until,
}

impl Nesting {
    fn is_stmt_level(&self) -> bool {
        match *self {
            Nesting::Top | Nesting::Meta |
            Nesting::Do | Nesting::Then | Nesting::Else | Nesting::End | Nesting::Until => true,
            _ => false,
        }
    }
}

// the major category of the current nesting, most commonly used for autocompletion
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum NestingCategory {
    Expr = 0,
    Meta = 1,
}

// a monotonically increasing serial number, only incremented when the nesting changes.
// the exact number has no meaning, only useful for the comparison.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct NestingSerial(u32);

impl NestingSerial {
    pub fn dummy() -> NestingSerial { NestingSerial(0) }

    pub fn to_usize(&self) -> usize { self.0 as usize }
}

#[derive(Clone, PartialEq, Debug)]
pub struct NestedToken {
    pub tok: Spanned<Tok>,

    // conceptually this nesting information applies to the token and following whitespaces
    pub depth: u16,
    pub category: NestingCategory,
    pub serial: NestingSerial,
}

pub struct Nest<'a> {
    iter: &'a mut Iterator<Item=Spanned<Tok>>,
    open_nestings: Vec<(Nesting, u32)>,
    next_serial: u32,
    meta_idx: Option<usize>, // invariant: if not None, open_nestings[meta] == Nesting::Meta
}

impl<'a> Nest<'a> {
    pub fn new(iter: &'a mut Iterator<Item=Spanned<Tok>>) -> Nest<'a> {
        Nest {
            iter: iter,
            open_nestings: vec![(Nesting::Top, 1)],
            next_serial: 2,
            meta_idx: None,
        }
    }

    fn update_nestings(&mut self, tok: &Tok) {
        enum Action {
            None,
            // push one nesting
            Push(Nesting),
            // push two nestings in this order
            Push2(Nesting, Nesting),
            // push three nestings in this order
            Push3(Nesting, Nesting, Nesting),
            // pop until a particular nesting appears; do nothing if no match
            Pop(Nesting),
            // pop until a particular nestings appears,
            // then push another nesting in place of the popped nesting; do nothing if no match
            PopAndPush(Nesting, Nesting),
            // pop until the first nesting appears; push the second nesting if no match
            PopOrPush(Nesting, Nesting),
            // same to `Pop(Nesting::Meta)` followed by `Push(Nesting::Meta)`,
            // but additionally marks a new meta block
            ReplaceMeta,
        }

        let next_serial = Cell::new(self.next_serial);
        let gen_serial = || {
            let serial = next_serial.get();
            // to avoid panic on overflow (very, very unlikely)
            next_serial.set(serial.wrapping_add(1));
            serial
        };

        // `pop_non_stmt` is a statement-level flag; it will always pop any punctuation-delimted
        // nestings before actually executing an action (even if it would be a no-op).
        let meta = self.meta_idx.is_some();
        let (pop_non_stmt, action) = match (meta, tok) {
            // natural delimiters
            // no angle brackets, hard to distinguish comparison ops from delimiters
            (_, &Tok::Punct(Punct::LParen)) => (false, Action::Push(Nesting::Paren)),
            (_, &Tok::Punct(Punct::LBrace)) => (false, Action::Push(Nesting::Brace)),
            (_, &Tok::Punct(Punct::LBracket)) => (false, Action::Push(Nesting::Bracket)),
            (_, &Tok::Punct(Punct::RParen)) => (false, Action::Pop(Nesting::Paren)),
            (_, &Tok::Punct(Punct::RBrace)) => (false, Action::Pop(Nesting::Brace)),
            (_, &Tok::Punct(Punct::RBracket)) => (false, Action::Pop(Nesting::Bracket)),

            // meta blocks
            // Newline token is only generated inside a meta block by the lexer
            // Meta can be nested (sometimes), but closes the prior open Meta nesting
            (_, &Tok::Punct(Punct::DashDashV)) |
            (_, &Tok::Punct(Punct::DashDashColon)) =>
                // can appear in the expression context:
                // `--v` before function literals, `--:` inside an argument list (separate nesting)
                // note that `-->` always appear at the statement level due to the positioning
                (false, Action::ReplaceMeta),
            (_, &Tok::Punct(Punct::DashDashGt)) |
            (_, &Tok::Punct(Punct::DashDashHash)) =>
                (true, Action::ReplaceMeta),
            (_, &Tok::Punct(Punct::Newline)) =>
                (false, Action::Pop(Nesting::Meta)),

            // while, for and do blocks
            //
            // while/for ... do ... end
            // -----------End----------
            // -------Do-------
            //
            // do ... end
            // ----End---
            (false, &Tok::Keyword(Keyword::While)) |
            (false, &Tok::Keyword(Keyword::For)) =>
                (true, Action::Push2(Nesting::End, Nesting::Do)),
            (false, &Tok::Keyword(Keyword::Do)) =>
                (true, Action::PopOrPush(Nesting::Do, Nesting::End)),

            // function block
            //
            // function [NAME] ( ... ) ... end
            // -------------End-------------
            //                 -Paren-
            (false, &Tok::Keyword(Keyword::Function)) =>
                (false, Action::Push(Nesting::End)), // can appear in an expression

            // if blocks
            //
            // if ... then ... elseif ... then ... elseif ... then ... else ... end
            // --------------------------------End---------------------------------
            // ---------Else---vvvvvv              vvvvvv----Else----------
            //                 ^^^^^^-----Else-----^^^^^^
            // ----Then---     ------Then-----     ------Then-----
            //
            // `elseif` is a particularly complex token to handle.
            // it is conceptually closing the if--else nesting but should open one simultaneously.
            // therefore while the affected nesting does not change per se,
            // we mark the (conceptual) change in the delta so that the caller can recognize it.
            (false, &Tok::Keyword(Keyword::If)) =>
                (true, Action::Push3(Nesting::End, Nesting::Else, Nesting::Then)),
            (false, &Tok::Keyword(Keyword::Then)) =>
                (true, Action::Pop(Nesting::Then)),
            (false, &Tok::Keyword(Keyword::Elseif)) =>
                (true, Action::PopAndPush(Nesting::Else, Nesting::Else)),
            (false, &Tok::Keyword(Keyword::Else)) =>
                (true, Action::Pop(Nesting::Else)),

            // repeat-until block
            //
            // repeat ... until ...
            // -----Until------
            (false, &Tok::Keyword(Keyword::Repeat)) => (true, Action::Push(Nesting::Until)),
            (false, &Tok::Keyword(Keyword::Until)) => (true, Action::Pop(Nesting::Until)),

            // the universal `end` token
            (_, &Tok::Keyword(Keyword::End)) => (!meta, Action::Pop(Nesting::End)),

            // EOF (conceptually forms the top-level nesting)
            (_, &Tok::EOF) => (true, Action::Pop(Nesting::Top)),

            _ => (false, Action::None),
        };

        if pop_non_stmt {
            let stmt = self.open_nestings.iter().rposition(|&(e, _)| e.is_stmt_level());
            let i = stmt.expect("Nest::update_nestings got a corrupted list of nestings") + 1;
            if i < self.open_nestings.len() {
                trace!("token {:?} closed {} non-statement nesting(s)",
                       tok, self.open_nestings.len() - i);
            }
            self.open_nestings.truncate(i);
        }

        let mut min_depth = self.open_nestings.len();
        let mut meta_updated = false;
        match action {
            Action::None => {}

            Action::Push(e) => {
                let e = (e, gen_serial());
                trace!("token {:?} opened a nesting {:?}", tok, e);
                self.open_nestings.push(e);
            }

            Action::Push2(e1, e2) => {
                let e1 = (e1, gen_serial());
                let e2 = (e2, gen_serial());
                trace!("token {:?} opened nestings {:?} and {:?}", tok, e1, e2);
                self.open_nestings.push(e1);
                self.open_nestings.push(e2);
            }

            Action::Push3(e1, e2, e3) => {
                let e1 = (e1, gen_serial());
                let e2 = (e2, gen_serial());
                let e3 = (e3, gen_serial());
                trace!("token {:?} opened nestings {:?}, {:?} and {:?}", tok, e1, e2, e3);
                self.open_nestings.push(e1);
                self.open_nestings.push(e2);
                self.open_nestings.push(e3);
            }

            Action::Pop(epop) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a nesting {:?}", tok, epop);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    trace!("token {:?} tried to close a nesting {:?}", tok, epop);
                }
            }

            Action::PopAndPush(epop, epush) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    let epush = (epush, gen_serial());
                    trace!("token {:?} closed a nesting {:?} and opened a nesting {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    self.open_nestings.push(epush);
                    min_depth = i;
                } else {
                    trace!("token {:?} tried to close a nesting {:?} and open a nesting {:?}",
                           tok, epop, epush);
                }
            }

            Action::PopOrPush(epop, epush) => {
                if let Some(i) = self.open_nestings.iter().rposition(|&(e, _)| e == epop) {
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a nesting {:?} instead of opening a nesting {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    let epush = (epush, gen_serial());
                    trace!("token {:?} tried to close a nesting {:?} but \
                            opened a nesting {:?} instead", tok, epop, epush);
                    self.open_nestings.push(epush);
                }
            }

            Action::ReplaceMeta => {
                let epush = (Nesting::Meta, gen_serial());
                if let Some(i) = self.meta_idx {
                    assert_eq!(self.open_nestings.get(i).map(|e| e.0), Some(Nesting::Meta));
                    let epop = self.open_nestings[i];
                    trace!("token {:?} closed a meta block {:?} and reopened a meta block {:?}",
                           tok, epop, epush);
                    self.open_nestings.truncate(i);
                    min_depth = i;
                } else {
                    trace!("token {:?} opened a meta block {:?}", tok, epush);
                }
                self.meta_idx = Some(self.open_nestings.len());
                self.open_nestings.push(epush);
                meta_updated = true;
            }
        }

        // check if the prior action has unknowingly destroyed the Meta nesting
        // (Meta can only be introduced by ReplaceMeta)
        if let Some(i) = self.meta_idx {
            if !meta_updated && i >= min_depth {
                self.meta_idx = None;
            }
        }

        self.next_serial = next_serial.get();
    }
}

impl<'a> Iterator for Nest<'a> {
    type Item = NestedToken;

    fn next(&mut self) -> Option<NestedToken> {
        let tok = match self.iter.next() {
            Some(tok) => {
                assert!(self.open_nestings.len() > 0);
                tok
            },
            None => {
                // the final token should be EOF, and Newline has been generated as needed
                assert_eq!(self.open_nestings.len(), 0);
                assert_eq!(self.meta_idx, None);
                return None;
            }
        };

        self.update_nestings(&tok);

        // if depth exceeds u16 range, there is not much point doing AC anyway
        let depth = cmp::min(0xffff, self.open_nestings.len()) as u16;
        let category = match self.meta_idx {
            Some(_) => NestingCategory::Meta,
            None => NestingCategory::Expr,
        };
        let serial = self.open_nestings.last().map_or(0, |e| e.1);
        Some(NestedToken {
            tok: tok, depth: depth, category: category,
            serial: NestingSerial(serial),
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

<|endoftext|>


<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use futures;
use futures::future::{FutureObj, LocalFutureObj};
use futures::prelude::*;
use futures::task::{
    Context, LocalSpawn, Poll, RawWaker, RawWakerVTable, Spawn, SpawnError, Waker,
};
use get_thread_id;
use glib_sys;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use translate::{from_glib_full, from_glib_none, mut_override, ToGlib};

use MainContext;
use MainLoop;
use Priority;
use Source;

// We can't use an enum here because we want to store this in an atomic variable
const INIT: usize = 0;
const NOT_READY: usize = 1;
const READY: usize = 2;
const DONE: usize = 3;

#[allow(clippy::type_complexity)]
#[repr(C)]
struct TaskSource {
    source: glib_sys::GSource,
    future: Option<FutureObj<'static, ()>>,
    thread: Option<usize>,
    state: AtomicUsize,
}

static TASK_SOURCE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
    TaskSource::clone_raw,
    TaskSource::wake_raw,
    TaskSource::wake_by_ref_raw,
    TaskSource::drop_raw,
);

impl TaskSource {
    unsafe fn clone_raw(waker: *const ()) -> RawWaker {
        let waker = &*(waker as *const TaskSource);
        glib_sys::g_source_ref(mut_override(&waker.source));
        RawWaker::new(waker as *const Self as *const (), &TASK_SOURCE_WAKER_VTABLE)
    }
    unsafe fn wake_raw(waker: *const ()) {
        Self::wake_by_ref_raw(waker);
        Self::drop_raw(waker);
    }

    unsafe fn wake_by_ref_raw(waker: *const ()) {
        let waker = &*(waker as *const TaskSource);
        if waker
            .state
            .compare_and_swap(NOT_READY, READY, Ordering::SeqCst)
            == NOT_READY
        {
            glib_sys::g_source_set_ready_time(mut_override(&waker.source), 0);
        }
    }

    unsafe fn drop_raw(waker: *const ()) {
        let waker = &*(waker as *const TaskSource);
        glib_sys::g_source_unref(mut_override(&waker.source));
    }

    fn as_waker(&self) -> Waker {
        unsafe { Waker::from_raw(Self::clone_raw(self as *const Self as *const ())) }
    }
}

unsafe extern "C" fn prepare(
    source: *mut glib_sys::GSource,
    timeout: *mut i32,
) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);

    *timeout = -1;

    let mut cur = source
        .state
        .compare_and_swap(INIT, NOT_READY, Ordering::SeqCst);
    if cur == INIT {
        // XXX: This is not actually correct, we should not dispatch the
        // GSource here already but we need to know its current status so
        // that if it is not ready yet something can register to the waker
        if let Poll::Ready(()) = source.poll() {
            source.state.store(DONE, Ordering::SeqCst);
            cur = DONE;
        } else {
            cur = NOT_READY;
        }
    }

    if cur == READY || cur == DONE {
        glib_sys::GTRUE
    } else {
        glib_sys::GFALSE
    }
}

unsafe extern "C" fn check(source: *mut glib_sys::GSource) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);

    let cur = source.state.load(Ordering::SeqCst);
    if cur == READY || cur == DONE {
        glib_sys::GTRUE
    } else {
        glib_sys::GFALSE
    }
}

unsafe extern "C" fn dispatch(
    source: *mut glib_sys::GSource,
    callback: glib_sys::GSourceFunc,
    _user_data: glib_sys::gpointer,
) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);
    assert!(callback.is_none());

    glib_sys::g_source_set_ready_time(mut_override(&source.source), -1);
    let mut cur = source
        .state
        .compare_and_swap(READY, NOT_READY, Ordering::SeqCst);
    if cur == READY {
        if let Poll::Ready(()) = source.poll() {
            source.state.store(DONE, Ordering::SeqCst);
            cur = DONE;
        } else {
            cur = NOT_READY;
        }
    }

    if cur == DONE {
        glib_sys::G_SOURCE_REMOVE
    } else {
        glib_sys::G_SOURCE_CONTINUE
    }
}

unsafe extern "C" fn finalize(source: *mut glib_sys::GSource) {
    let source = source as *mut TaskSource;
    let _ = (*source).future.take();
}

static SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
    check: Some(check),
    prepare: Some(prepare),
    dispatch: Some(dispatch),
    finalize: Some(finalize),
    closure_callback: None,
    closure_marshal: None,
};

unsafe impl Send for TaskSource {}
unsafe impl Sync for TaskSource {}

impl TaskSource {
    #[allow(clippy::new_ret_no_self)]
    fn new(priority: Priority, thread: Option<usize>, future: FutureObj<'static, ()>) -> Source {
        unsafe {
            let source = glib_sys::g_source_new(
                mut_override(&SOURCE_FUNCS),
                mem::size_of::<TaskSource>() as u32,
            );
            {
                let source = &mut *(source as *mut TaskSource);
                ptr::write(&mut source.future, Some(future));
                source.thread = thread;
                source.state = AtomicUsize::new(INIT);
            }

            glib_sys::g_source_set_priority(source, priority.to_glib());

            from_glib_full(source)
        }
    }

    fn poll(&mut self) -> Poll<()> {
        // Make sure that the first time we're polled that the current thread is remembered
        // and from there one we ensure that we're always polled from exactly the same thread.
        //
        // In theory a GMainContext can be first run from one thread and later from another
        // thread, but we allow spawning non-Send futures and must not ever use them from
        // any other thread.
        match &mut self.thread {
            thread @ &mut None => {
                *thread = Some(get_thread_id());
            }
            &mut Some(thread_id) => {
                assert_eq!(
                    get_thread_id(),
                    thread_id,
                    "Task polled on a different thread than before"
                );
            }
        }

        let waker = self.as_waker();
        let source = &self.source as *const _;
        if let Some(ref mut future) = self.future {
            let executor: MainContext =
                unsafe { from_glib_none(glib_sys::g_source_get_context(mut_override(source))) };

            assert!(
                executor.is_owner(),
                "Polling futures only allowed if the thread is owning the MainContext"
            );

            // Clone that we store in the task local data so that
            // it can be retrieved as needed
            executor.push_thread_default();

            let res = {
                let enter = futures::executor::enter().unwrap();
                let mut context = Context::from_waker(&waker);

                let res = future.poll_unpin(&mut context);

                drop(enter);

                res
            };

            executor.pop_thread_default();
            res
        } else {
            Poll::Ready(())
        }
    }
}

impl MainContext {
    /// Spawn a new infallible `Future` on the main context.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn<F: Future<Output = ()> + Send + 'static>(&self, f: F) {
        self.spawn_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local<F: Future<Output = ()> + 'static>(&self, f: F) {
        self.spawn_local_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn_with_priority<F: Future<Output = ()> + Send + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        let f = FutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, None, f);
        source.attach(Some(&*self));
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local_with_priority<F: Future<Output = ()> + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        assert!(
            self.is_owner(),
            "Spawning local futures only allowed on the thread owning the MainContext"
        );
        unsafe {
            let f = LocalFutureObj::new(Box::new(f));
            // We ensure here that we only ever run the future on this very task
            // and that the futures executor is running on this task. Otherwise
            // we will panic later.
            // As such we can add the Send impl here safely
            let f = f.into_future_obj();
            let source = TaskSource::new(priority, Some(get_thread_id()), f);
            source.attach(Some(&*self));
        }
    }

    /// Runs a new, infallible `Future` on the main context and block until it finished, returning
    /// the result of the `Future`.
    ///
    /// The given `Future` does not have to be `Send` or `'static`.
    ///
    /// This must only be called if no `MainLoop` or anything else is running on this specific main
    /// context.
    #[allow(clippy::transmute_ptr_to_ptr)]
    pub fn block_on<F: Future>(&self, f: F) -> F::Output {
        let mut res = None;
        let l = MainLoop::new(Some(&*self), false);
        let l_clone = l.clone();

        unsafe {
            let f = f.then(|r| {
                res = Some(r);
                l_clone.quit();
                future::ready(())
            });

            // Super-unsafe: We transmute here to get rid of the 'static lifetime
            let f = LocalFutureObj::new(Box::new(f));
            let f: (LocalFutureObj<'static, ()>) = mem::transmute(f);

            // And ensure that we are only ever running on this very thread.
            let f = f.into_future_obj();

            let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), f);
            source.attach(Some(&*self));
        }

        l.run();

        res.unwrap()
    }
}

impl Spawn for MainContext {
    fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, None, f);
        source.attach(Some(&*self));
        Ok(())
    }
}

impl LocalSpawn for MainContext {
    fn spawn_local_obj(&mut self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), unsafe {
            f.into_future_obj()
        });
        source.attach(Some(&*self));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::channel::oneshot;
    use std::sync::mpsc;
    use std::thread;

    #[test]
    fn test_spawn() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        let (sender, receiver) = mpsc::channel();
        let (o_sender, o_receiver) = oneshot::channel();

        let l_clone = l.clone();
        c.spawn(
            o_receiver
                .and_then(move |()| {
                    sender.send(()).unwrap();
                    l_clone.quit();

                    future::ok(())
                })
                .then(|res| future::ready(res.unwrap())),
        );

        thread::spawn(move || {
            l.run();
        });

        o_sender.send(()).unwrap();

        let _ = receiver.recv().unwrap();
    }

    #[test]
    fn test_spawn_local() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        c.push_thread_default();
        let l_clone = l.clone();
        c.spawn_local(future::lazy(move |_ctx| {
            l_clone.quit();
        }));

        l.run();

        c.pop_thread_default();
    }

    #[test]
    fn test_block_on() {
        let c = MainContext::new();

        let mut v = None;
        {
            let v = &mut v;

            let future = future::lazy(|_ctx| {
                *v = Some(123);
                Ok::<i32, ()>(123)
            });

            let res = c.block_on(future);
            assert_eq!(res, Ok(123));
        }

        assert_eq!(v, Some(123));
    }
}
<commit_msg>Implement futures-0.3 `Spawn` for `&MainContext`<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use futures;
use futures::future::{FutureObj, LocalFutureObj};
use futures::prelude::*;
use futures::task::{
    Context, LocalSpawn, Poll, RawWaker, RawWakerVTable, Spawn, SpawnError, Waker,
};
use get_thread_id;
use glib_sys;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use translate::{from_glib_full, from_glib_none, mut_override, ToGlib};

use MainContext;
use MainLoop;
use Priority;
use Source;

// We can't use an enum here because we want to store this in an atomic variable
const INIT: usize = 0;
const NOT_READY: usize = 1;
const READY: usize = 2;
const DONE: usize = 3;

#[allow(clippy::type_complexity)]
#[repr(C)]
struct TaskSource {
    source: glib_sys::GSource,
    future: Option<FutureObj<'static, ()>>,
    thread: Option<usize>,
    state: AtomicUsize,
}

static TASK_SOURCE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
    TaskSource::clone_raw,
    TaskSource::wake_raw,
    TaskSource::wake_by_ref_raw,
    TaskSource::drop_raw,
);

impl TaskSource {
    unsafe fn clone_raw(waker: *const ()) -> RawWaker {
        let waker = &*(waker as *const TaskSource);
        glib_sys::g_source_ref(mut_override(&waker.source));
        RawWaker::new(waker as *const Self as *const (), &TASK_SOURCE_WAKER_VTABLE)
    }
    unsafe fn wake_raw(waker: *const ()) {
        Self::wake_by_ref_raw(waker);
        Self::drop_raw(waker);
    }

    unsafe fn wake_by_ref_raw(waker: *const ()) {
        let waker = &*(waker as *const TaskSource);
        if waker
            .state
            .compare_and_swap(NOT_READY, READY, Ordering::SeqCst)
            == NOT_READY
        {
            glib_sys::g_source_set_ready_time(mut_override(&waker.source), 0);
        }
    }

    unsafe fn drop_raw(waker: *const ()) {
        let waker = &*(waker as *const TaskSource);
        glib_sys::g_source_unref(mut_override(&waker.source));
    }

    fn as_waker(&self) -> Waker {
        unsafe { Waker::from_raw(Self::clone_raw(self as *const Self as *const ())) }
    }
}

unsafe extern "C" fn prepare(
    source: *mut glib_sys::GSource,
    timeout: *mut i32,
) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);

    *timeout = -1;

    let mut cur = source
        .state
        .compare_and_swap(INIT, NOT_READY, Ordering::SeqCst);
    if cur == INIT {
        // XXX: This is not actually correct, we should not dispatch the
        // GSource here already but we need to know its current status so
        // that if it is not ready yet something can register to the waker
        if let Poll::Ready(()) = source.poll() {
            source.state.store(DONE, Ordering::SeqCst);
            cur = DONE;
        } else {
            cur = NOT_READY;
        }
    }

    if cur == READY || cur == DONE {
        glib_sys::GTRUE
    } else {
        glib_sys::GFALSE
    }
}

unsafe extern "C" fn check(source: *mut glib_sys::GSource) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);

    let cur = source.state.load(Ordering::SeqCst);
    if cur == READY || cur == DONE {
        glib_sys::GTRUE
    } else {
        glib_sys::GFALSE
    }
}

unsafe extern "C" fn dispatch(
    source: *mut glib_sys::GSource,
    callback: glib_sys::GSourceFunc,
    _user_data: glib_sys::gpointer,
) -> glib_sys::gboolean {
    let source = &mut *(source as *mut TaskSource);
    assert!(callback.is_none());

    glib_sys::g_source_set_ready_time(mut_override(&source.source), -1);
    let mut cur = source
        .state
        .compare_and_swap(READY, NOT_READY, Ordering::SeqCst);
    if cur == READY {
        if let Poll::Ready(()) = source.poll() {
            source.state.store(DONE, Ordering::SeqCst);
            cur = DONE;
        } else {
            cur = NOT_READY;
        }
    }

    if cur == DONE {
        glib_sys::G_SOURCE_REMOVE
    } else {
        glib_sys::G_SOURCE_CONTINUE
    }
}

unsafe extern "C" fn finalize(source: *mut glib_sys::GSource) {
    let source = source as *mut TaskSource;
    let _ = (*source).future.take();
}

static SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
    check: Some(check),
    prepare: Some(prepare),
    dispatch: Some(dispatch),
    finalize: Some(finalize),
    closure_callback: None,
    closure_marshal: None,
};

unsafe impl Send for TaskSource {}
unsafe impl Sync for TaskSource {}

impl TaskSource {
    #[allow(clippy::new_ret_no_self)]
    fn new(priority: Priority, thread: Option<usize>, future: FutureObj<'static, ()>) -> Source {
        unsafe {
            let source = glib_sys::g_source_new(
                mut_override(&SOURCE_FUNCS),
                mem::size_of::<TaskSource>() as u32,
            );
            {
                let source = &mut *(source as *mut TaskSource);
                ptr::write(&mut source.future, Some(future));
                source.thread = thread;
                source.state = AtomicUsize::new(INIT);
            }

            glib_sys::g_source_set_priority(source, priority.to_glib());

            from_glib_full(source)
        }
    }

    fn poll(&mut self) -> Poll<()> {
        // Make sure that the first time we're polled that the current thread is remembered
        // and from there one we ensure that we're always polled from exactly the same thread.
        //
        // In theory a GMainContext can be first run from one thread and later from another
        // thread, but we allow spawning non-Send futures and must not ever use them from
        // any other thread.
        match &mut self.thread {
            thread @ &mut None => {
                *thread = Some(get_thread_id());
            }
            &mut Some(thread_id) => {
                assert_eq!(
                    get_thread_id(),
                    thread_id,
                    "Task polled on a different thread than before"
                );
            }
        }

        let waker = self.as_waker();
        let source = &self.source as *const _;
        if let Some(ref mut future) = self.future {
            let executor: MainContext =
                unsafe { from_glib_none(glib_sys::g_source_get_context(mut_override(source))) };

            assert!(
                executor.is_owner(),
                "Polling futures only allowed if the thread is owning the MainContext"
            );

            // Clone that we store in the task local data so that
            // it can be retrieved as needed
            executor.push_thread_default();

            let res = {
                let enter = futures::executor::enter().unwrap();
                let mut context = Context::from_waker(&waker);

                let res = future.poll_unpin(&mut context);

                drop(enter);

                res
            };

            executor.pop_thread_default();
            res
        } else {
            Poll::Ready(())
        }
    }
}

impl MainContext {
    /// Spawn a new infallible `Future` on the main context.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn<F: Future<Output = ()> + Send + 'static>(&self, f: F) {
        self.spawn_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local<F: Future<Output = ()> + 'static>(&self, f: F) {
        self.spawn_local_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn_with_priority<F: Future<Output = ()> + Send + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        let f = FutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, None, f);
        source.attach(Some(&*self));
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local_with_priority<F: Future<Output = ()> + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        assert!(
            self.is_owner(),
            "Spawning local futures only allowed on the thread owning the MainContext"
        );
        unsafe {
            let f = LocalFutureObj::new(Box::new(f));
            // We ensure here that we only ever run the future on this very task
            // and that the futures executor is running on this task. Otherwise
            // we will panic later.
            // As such we can add the Send impl here safely
            let f = f.into_future_obj();
            let source = TaskSource::new(priority, Some(get_thread_id()), f);
            source.attach(Some(&*self));
        }
    }

    /// Runs a new, infallible `Future` on the main context and block until it finished, returning
    /// the result of the `Future`.
    ///
    /// The given `Future` does not have to be `Send` or `'static`.
    ///
    /// This must only be called if no `MainLoop` or anything else is running on this specific main
    /// context.
    #[allow(clippy::transmute_ptr_to_ptr)]
    pub fn block_on<F: Future>(&self, f: F) -> F::Output {
        let mut res = None;
        let l = MainLoop::new(Some(&*self), false);
        let l_clone = l.clone();

        unsafe {
            let f = f.then(|r| {
                res = Some(r);
                l_clone.quit();
                future::ready(())
            });

            // Super-unsafe: We transmute here to get rid of the 'static lifetime
            let f = LocalFutureObj::new(Box::new(f));
            let f: (LocalFutureObj<'static, ()>) = mem::transmute(f);

            // And ensure that we are only ever running on this very thread.
            let f = f.into_future_obj();

            let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), f);
            source.attach(Some(&*self));
        }

        l.run();

        res.unwrap()
    }
}

impl Spawn for MainContext {
    fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
        (&*self).spawn_obj(f)
    }
}

/// Implementing `Spawn` for a _reference_ of `MainContext` allows to convert it to a futures-0.1 `Executor`,
/// using the futures-0.1 compatibility layer.
///
/// See https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.16/src/futures_util/compat/executor.rs.html#85
impl Spawn for &MainContext {
    fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, None, f);
        source.attach(Some(&*self));
        Ok(())
    }
}

impl LocalSpawn for MainContext {
    fn spawn_local_obj(&mut self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), unsafe {
            f.into_future_obj()
        });
        source.attach(Some(&*self));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::channel::oneshot;
    use std::sync::mpsc;
    use std::thread;

    #[test]
    fn test_spawn() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        let (sender, receiver) = mpsc::channel();
        let (o_sender, o_receiver) = oneshot::channel();

        let l_clone = l.clone();
        c.spawn(
            o_receiver
                .and_then(move |()| {
                    sender.send(()).unwrap();
                    l_clone.quit();

                    future::ok(())
                })
                .then(|res| future::ready(res.unwrap())),
        );

        thread::spawn(move || {
            l.run();
        });

        o_sender.send(()).unwrap();

        let _ = receiver.recv().unwrap();
    }

    #[test]
    fn test_spawn_local() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        c.push_thread_default();
        let l_clone = l.clone();
        c.spawn_local(future::lazy(move |_ctx| {
            l_clone.quit();
        }));

        l.run();

        c.pop_thread_default();
    }

    #[test]
    fn test_block_on() {
        let c = MainContext::new();

        let mut v = None;
        {
            let v = &mut v;

            let future = future::lazy(|_ctx| {
                *v = Some(123);
                Ok::<i32, ()>(123)
            });

            let res = c.block_on(future);
            assert_eq!(res, Ok(123));
        }

        assert_eq!(v, Some(123));
    }
}
<|endoftext|>


<commit_before>//! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs)
//!
//!

//!
//!
//!
//!
//!
//!
//!

//!

//!
//! Procedural macro [compile-time] assertions as an extension of
//! [`static_assertions`].
//!
//! # Usage
//!
//! There's two main ways of using this crate: as a direct dependency or
//! indirect dependency (via [`static_assertions`]).
//!
//! ## Direct Dependency
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! proc_static_assertions = "0.0.0"
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```
//! #[macro_use]
//! extern crate proc_static_assertions;
//! # fn main() {}
//! ```
//!
//! ## Indirect Dependency
//!
//! Add the following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! static_assertions = { version = "1.1.0", features = ["proc"] }
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! ```
//!
//! This will also import all macros in `proc_static_assertions`.
//!
//! # Donate
//!
//! This project is made freely available (as in free beer), but unfortunately
//! not all beer is free! So, if you would like to buy me a beer (or coffee or
//! *more*), then consider supporting my work that's benefited your project
//! and thousands of others.
//!
//!
//!
//!
//!
//!
//!
//!
//! [`static_assertions`]: https://github.com/nvzqz/static-assertions-rs
//! [crate]: https://crates.io/crates/static_assertions
//! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [compile-time]: https://en.wikipedia.org/wiki/Compile_time

#![doc(html_root_url = "https://docs.rs/proc_static_assertions/0.0.0")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png")]

#![deny(missing_docs)]

extern crate proc_macro;
use proc_macro::TokenStream;

/// Statically assert aspects of types, traits, and more.
///
/// This currently does nothing. Create an issue if you have ideas for what this
/// could do!
#[proc_macro_attribute]
pub fn assert(_attr: TokenStream, _item: TokenStream) -> TokenStream {
    TokenStream::new()
}
<commit_msg>Ignore import of `static_assertions` in docs<commit_after>//! [![Banner](https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Banner.png)](https://github.com/nvzqz/static-assertions-rs)
//!
//!

//!
//!
//!
//!
//!
//!
//!

//!

//!
//! Procedural macro [compile-time] assertions as an extension of
//! [`static_assertions`].
//!
//! # Usage
//!
//! There's two main ways of using this crate: as a direct dependency or
//! indirect dependency (via [`static_assertions`]).
//!
//! ## Direct Dependency
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! proc_static_assertions = "0.0.0"
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```
//! #[macro_use]
//! extern crate proc_static_assertions;
//! # fn main() {}
//! ```
//!
//! ## Indirect Dependency
//!
//! Add the following to your project's [`Cargo.toml`]:
//!
//! ```toml
//! [dependencies]
//! static_assertions = { version = "1.1.0", features = ["proc"] }
//! ```
//!
//! and this to your crate root (`main.rs` or `lib.rs`):
//!
//! ```ignore
//! #[macro_use]
//! extern crate static_assertions;
//! ```
//!
//! This will also import all macros in `proc_static_assertions`.
//!
//! # Donate
//!
//! This project is made freely available (as in free beer), but unfortunately
//! not all beer is free! So, if you would like to buy me a beer (or coffee or
//! *more*), then consider supporting my work that's benefited your project
//! and thousands of others.
//!
//!
//!
//!
//!
//!
//!
//!
//! [`static_assertions`]: https://github.com/nvzqz/static-assertions-rs
//! [crate]: https://crates.io/crates/static_assertions
//! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [compile-time]: https://en.wikipedia.org/wiki/Compile_time

#![doc(html_root_url = "https://docs.rs/proc_static_assertions/0.0.0")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/nvzqz/static-assertions-rs/assets/Icon.png")]

#![deny(missing_docs)]

extern crate proc_macro;
use proc_macro::TokenStream;

/// Statically assert aspects of types, traits, and more.
///
/// This currently does nothing. Create an issue if you have ideas for what this
/// could do!
#[proc_macro_attribute]
pub fn assert(_attr: TokenStream, _item: TokenStream) -> TokenStream {
    TokenStream::new()
}
<|endoftext|>


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

use syntax::abi::{Abi};
use syntax::ast;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};

use bitslice::BitSlice;

use super::super::gather_moves::MovePath;
use super::{bitwise, Union, Subtract};
use super::BitDenotation;
use super::DataflowResults;
use super::HasMoveData;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Bit=MovePath<'tcx>>, O::Ctxt: HasMoveData<'tcx>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    let blocks = mir.all_basic_blocks();
    'next_block: for bb in blocks {
        let bb_data = mir.basic_block_data(bb);
        let &repr::BasicBlockData { ref statements,
                                    ref terminator,
                                    is_cleanup: _ } = bb_data;

        let (args, span) = if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
            if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
            {
                if let repr::Operand::Constant(ref func) = *oper
                {
                    if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                    {
                        let name = tcx.item_name(def_id);
                        if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                            if name.as_str() == "rustc_peek" {
                                (args, span)
                            } else {
                                continue;
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                } else {
                    continue;
                }
            } else {
                continue;
            }
        } else {
            continue;
        };
        assert!(args.len() == 1);
        let peek_arg_lval = match args[0] {
            repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
                lval
            }
            repr::Operand::Consume(_) => {
                bug!("dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            }
            repr::Operand::Constant(_) => {
                bug!("dataflow::sanity_check cannot feed a constant to rustc_peek.");
            }
        };

        let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
        let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
        let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

        let move_data = flow_ctxt.move_data();

        // Emulate effect of all statements in the block up to (but
        // not including) the assignment to `peek_arg_lval`. Do *not*
        // include terminator (since we are peeking the state of the
        // argument at time immediate preceding Call to `rustc_peek`).

        let mut sets = super::BlockSets { on_entry: &mut entry[..],
                                          gen_set: &mut gen[..],
                                          kill_set: &mut kill[..] };

        for (j, stmt) in statements.iter().enumerate() {
            debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
            let (lvalue, rvalue) = match stmt.kind {
                repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                    (lvalue, rvalue)
                }
            };

            if lvalue == peek_arg_lval {
                if let repr::Rvalue::Ref(_,
                                         repr::BorrowKind::Shared,
                                         ref peeking_at_lval) = *rvalue {
                    // Okay, our search is over.
                    let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
                    let bit_state = sets.on_entry.get_bit(peek_mpi.idx());
                    debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                           lvalue, peeking_at_lval, bit_state);
                    if !bit_state {
                        tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
                    }
                    continue 'next_block;
                } else {
                    // Our search should have been over, but the input
                    // does not match expectations of `rustc_peek` for
                    // this sanity_check.
                    tcx.sess.span_err(span, &format!("rustc_peek: argument expression \
                                                      must be immediate borrow of form `&expr`"));
                }
            }

            enum Effect<'a, 'tcx:'a> { Propagate(&'a repr::Lvalue<'tcx>), Compute }
            let lvalue_effect: Effect = match *rvalue {
                // tmp = rhs
                repr::Rvalue::Use(repr::Operand::Consume(ref rhs_lval)) =>
                    Effect::Propagate(rhs_lval),

                repr::Rvalue::Use(repr::Operand::Constant(_)) =>
                    Effect::Compute,

                _ => {
                    // (fall back to BitDenotation for all other kinds of Rvalues
                    Effect::Compute
                }
            };

            let lhs_mpi = move_data.rev_lookup.find(lvalue);

            if let Effect::Propagate(rhs_lval) = lvalue_effect {
                let rhs_mpi = move_data.rev_lookup.find(rhs_lval);
                let state = sets.on_entry.get_bit(rhs_mpi.idx());
                debug!("rustc_peek: propagate into lvalue {:?} ({:?}) from rhs: {:?} state: {}",
                       lvalue, lhs_mpi, rhs_lval, state);
                if state {
                    sets.on_entry.set_bit(lhs_mpi.idx());
                } else {
                    sets.on_entry.clear_bit(lhs_mpi.idx());
                }
            } else {
                debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
                       lvalue, lhs_mpi, stmt);
                // reset GEN and KILL sets before emulating their effect.
                for e in &mut sets.gen_set[..] { *e = 0; }
                for e in &mut sets.kill_set[..] { *e = 0; }
                results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j);
                bitwise(sets.on_entry, sets.gen_set, &Union);
                bitwise(sets.on_entry, sets.kill_set, &Subtract);
            }
        }

        tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                          anticipated pattern; note that \
                                          rustc_peek expects input of \
                                          form `&expr`"));
    }
}
<commit_msg>`mir::dataflow::sanity_check`: removed hackish `tmp = val` propagation code.<commit_after>// Copyright 2012-2016 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.

use syntax::abi::{Abi};
use syntax::ast;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};

use bitslice::BitSlice;

use super::super::gather_moves::MovePath;
use super::{bitwise, Union, Subtract};
use super::BitDenotation;
use super::DataflowResults;
use super::HasMoveData;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Bit=MovePath<'tcx>>, O::Ctxt: HasMoveData<'tcx>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    let blocks = mir.all_basic_blocks();
    'next_block: for bb in blocks {
        let bb_data = mir.basic_block_data(bb);
        let &repr::BasicBlockData { ref statements,
                                    ref terminator,
                                    is_cleanup: _ } = bb_data;

        let (args, span) = if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
            if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
            {
                if let repr::Operand::Constant(ref func) = *oper
                {
                    if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                    {
                        let name = tcx.item_name(def_id);
                        if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                            if name.as_str() == "rustc_peek" {
                                (args, span)
                            } else {
                                continue;
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                } else {
                    continue;
                }
            } else {
                continue;
            }
        } else {
            continue;
        };
        assert!(args.len() == 1);
        let peek_arg_lval = match args[0] {
            repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
                lval
            }
            repr::Operand::Consume(_) => {
                bug!("dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            }
            repr::Operand::Constant(_) => {
                bug!("dataflow::sanity_check cannot feed a constant to rustc_peek.");
            }
        };

        let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
        let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
        let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

        let move_data = flow_ctxt.move_data();

        // Emulate effect of all statements in the block up to (but
        // not including) the assignment to `peek_arg_lval`. Do *not*
        // include terminator (since we are peeking the state of the
        // argument at time immediate preceding Call to `rustc_peek`).

        let mut sets = super::BlockSets { on_entry: &mut entry[..],
                                          gen_set: &mut gen[..],
                                          kill_set: &mut kill[..] };

        for (j, stmt) in statements.iter().enumerate() {
            debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
            let (lvalue, rvalue) = match stmt.kind {
                repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                    (lvalue, rvalue)
                }
            };

            if lvalue == peek_arg_lval {
                if let repr::Rvalue::Ref(_,
                                         repr::BorrowKind::Shared,
                                         ref peeking_at_lval) = *rvalue {
                    // Okay, our search is over.
                    let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
                    let bit_state = sets.on_entry.get_bit(peek_mpi.idx());
                    debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                           lvalue, peeking_at_lval, bit_state);
                    if !bit_state {
                        tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
                    }
                    continue 'next_block;
                } else {
                    // Our search should have been over, but the input
                    // does not match expectations of `rustc_peek` for
                    // this sanity_check.
                    tcx.sess.span_err(span, &format!("rustc_peek: argument expression \
                                                      must be immediate borrow of form `&expr`"));
                }
            }

            let lhs_mpi = move_data.rev_lookup.find(lvalue);

            debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
                   lvalue, lhs_mpi, stmt);
            // reset GEN and KILL sets before emulating their effect.
            for e in &mut sets.gen_set[..] { *e = 0; }
            for e in &mut sets.kill_set[..] { *e = 0; }
            results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j);
            bitwise(sets.on_entry, sets.gen_set, &Union);
            bitwise(sets.on_entry, sets.kill_set, &Subtract);
        }

        tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                          anticipated pattern; note that \
                                          rustc_peek expects input of \
                                          form `&expr`"));
    }
}
<|endoftext|>


<commit_before>use libc::{getifaddrs, freeifaddrs, ifaddrs, IFF_UP, IFF_RUNNING, IFF_LOOPBACK};
use std::ptr::null_mut;
use std::ffi::CStr;
use std::os::raw::c_uint;

/// Pcaps Device::list() returns many non-network devices (usb, bluetooth) but we only want to capture network interfaces

/// Test flags whether device is running
fn is_running(flags: c_uint) -> bool {
  !(flags & IFF_LOOPBACK as c_uint != 0) && (flags & IFF_UP as c_uint != 0) && (flags & IFF_RUNNING as c_uint != 0)
}

/// List all network interfaces by Tuple (name, is_running)
pub fn list_network() -> Result<Vec<(String, bool)>, ()> {
    unsafe {
        let mut ifaddrs: *mut ifaddrs = null_mut();
        if getifaddrs(&mut ifaddrs as *mut *mut ifaddrs) != 0 { return Err(()); }

        let mut devices = Vec::new();
        let mut ifa = ifaddrs;
        while ifa != null_mut() {
            let devname = CStr::from_ptr((*ifa).ifa_name).to_string_lossy().into_owned();
            devices.push((devname, is_running((*ifa).ifa_flags)));
            ifa = (*ifa).ifa_next;
        }

        freeifaddrs(ifaddrs);

        Ok(devices)
    }
}
<commit_msg>Delete list_devices.rs (wasn't used in latest versions)<commit_after><|endoftext|>


<commit_before>use toml::Value;

use libimagerror::into::IntoError;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

pub fn commit_interactive(config: &Value) -> bool {
    unimplemented!()
}

pub fn commit_message(config: &Value, action: StoreAction) -> Option<String> {
    if commit_interactive(config) {
        unimplemented!()
    } else {
        unimplemented!()
    }
}

pub fn abort_on_repo_init_err(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "abort_on_repo_init_failure", true, true)
}

pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
}

fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup(name) {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
                warn!("Assuming 'true' now.");
                on_fail
            },
            None => {
                debug!("No key '{}' - Assuming 'true'", name);
                on_fail
            },
        }
    })
    .unwrap_or(on_unavail)
}

<commit_msg>Let the commit_message() helper always return a proper commit msg<commit_after>use toml::Value;

use libimagerror::into::IntoError;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

pub fn commit_interactive(config: &Value) -> bool {
    unimplemented!()
}

pub fn commit_message(config: &Value, action: StoreAction) -> String {
    if commit_interactive(config) {
        unimplemented!()
    } else {
        unimplemented!()
    }
}

pub fn abort_on_repo_init_err(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "abort_on_repo_init_failure", true, true)
}

pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
}

fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup(name) {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
                warn!("Assuming 'true' now.");
                on_fail
            },
            None => {
                debug!("No key '{}' - Assuming 'true'", name);
                on_fail
            },
        }
    })
    .unwrap_or(on_unavail)
}

<|endoftext|>


<commit_before>//! Defines an instance of some piece of geometry in the scene, instances
//! can re-use loaded geometry but apply different transformations and materials
//! to them
//!
//! # Scene Usage Example
//! An instance is an instantion of geometry in your scene. The instance needs to know
//! its type (emitter/receiver), its name along with the geometry to use, material to apply
//! and transformation to place the object in the scene. The instances are specified in the
//! objects list in the scene file.
//!
//! The transform for the object is specified in the order in which the transformations should
//! be applied. For information on emitters see the emitter documentation.
//!
//! ```json
//! "objects": [
//!     {
//!         "name": "back_wall",
//!         "type": "receiver",
//!         "material": "white_wall",
//!         "geometry": {
//!             "type": "plane"
//!         },
//!         "transform": [
//!             {
//!                 "type": "scaling",
//!                 "scaling": 15.0
//!             },
//!             {
//!                 "type": "translate",
//!                 "translation": [0.0, 1.0, 20.]
//!             }
//!         ]
//!     },
//!     ...
//! ]
//! ```

use std::sync::Arc;

use geometry::{Intersection, Boundable, BBox, BoundableGeom, Receiver, Emitter,
               SampleableGeom};
use material::Material;
use linalg::{Transform, Point, Ray};
use film::Colorf;

/// Defines an instance of some geometry with its own transform and material
pub enum Instance {
    Emitter(Emitter),
    Receiver(Receiver),
}

impl Instance {
    /// Create an instance of the geometry in the scene that will only receive light.
    pub fn receiver(geom: Arc<BoundableGeom + Send + Sync>, material: Arc<Material + Send + Sync>,
               transform: Transform, tag: String) -> Instance {
        Instance::Receiver(Receiver::new(geom, material, transform, tag))
    }
    /// Create an instance of the geometry in the scene that will emit and receive light
    pub fn area_light(geom: Arc<SampleableGeom + Send + Sync>, material: Arc<Material + Send + Sync>,
               emission: Colorf, transform: Transform, tag: String) -> Instance {
        Instance::Emitter(Emitter::area(geom, material, emission, transform, tag))
    }
    pub fn point_light(pos: Point, emission: Colorf, tag: String) ->  Instance {
        Instance::Emitter(Emitter::point(pos, emission, tag))
    }
    /// Test the ray for intersection against this insance of geometry.
    /// returns Some(Intersection) if an intersection was found and None if not.
    /// If an intersection is found `ray.max_t` will be set accordingly
    pub fn intersect(&self, ray: &mut Ray) -> Option<Intersection> {
        let hit = match self {
            &Instance::Emitter(ref e) => e.intersect(ray),
            &Instance::Receiver(ref r) => r.intersect(ray),
        };
        match hit {
            Some((dg, mat)) => Some(Intersection::new(dg, self, mat)),
            None => None,
        }
    }
    /// Get the tag for this instance
    pub fn tag(&self) -> &str {
        match self {
            &Instance::Emitter(ref e) => &e.tag[..],
            &Instance::Receiver(ref r) => &r.tag[..],
        }
    }
    /// Get the transform for this instance
    pub fn get_transform(&self) -> &Transform {
        match self {
            &Instance::Emitter(ref e) => e.get_transform(),
            &Instance::Receiver(ref r) => r.get_transform()
        }
    }
    /// Set the transform for this instance
    pub fn set_transform(&mut self, transform: Transform) {
        match self {
            &mut Instance::Emitter(ref mut e) => e.set_transform(transform),
            &mut Instance::Receiver(ref mut r) => r.set_transform(transform)
        }
    }
}

impl Boundable for Instance {
    fn bounds(&self) -> BBox {
        match self {
            &Instance::Emitter(ref e) => e.bounds(),
            &Instance::Receiver(ref r) => r.bounds(),
        }
    }
}

<commit_msg>Add doc for object groups<commit_after>//! Defines an instance of some piece of geometry in the scene, instances
//! can re-use loaded geometry but apply different transformations and materials
//! to them
//!
//! # Scene Usage Example
//! An instance is an instantion of geometry in your scene. The instance needs to know
//! its type (emitter/receiver), its name along with the geometry to use, material to apply
//! and transformation to place the object in the scene. The instances are specified in the
//! objects list in the scene file.
//!
//! The transform for the object is specified in the order in which the transformations should
//! be applied. For information on emitters see the emitter documentation.
//!
//! ```json
//! "objects": [
//!     {
//!         "name": "back_wall",
//!         "type": "receiver",
//!         "material": "white_wall",
//!         "geometry": {
//!             "type": "plane"
//!         },
//!         "transform": [
//!             {
//!                 "type": "scaling",
//!                 "scaling": 15.0
//!             },
//!             {
//!                 "type": "translate",
//!                 "translation": [0.0, 1.0, 20]
//!             }
//!         ]
//!     },
//!     ...
//! ]
//! ```
//!
//! # Object Group Example
//! You can also specify groups of objects to have the same transformation applied to all of them.
//! This is done with a 'group' type object followed by a list of objects in the group. For a full
//! example see `scenes/cornell_box.json`.
//!
//! ```json
//! "objects": [
//!     {
//!         "name": "my_group",
//!         "type": "group",
//!         "transform": [
//!             {
//!                 "type": "translate",
//!                 "translation": [0.0, 1.0, 20]
//!             }
//!         ],
//!         "objects": [
//!             ...
//!         ]
//!     },
//!     ...
//! ]
//! ```
//!

use std::sync::Arc;

use geometry::{Intersection, Boundable, BBox, BoundableGeom, Receiver, Emitter,
               SampleableGeom};
use material::Material;
use linalg::{Transform, Point, Ray};
use film::Colorf;

/// Defines an instance of some geometry with its own transform and material
pub enum Instance {
    Emitter(Emitter),
    Receiver(Receiver),
}

impl Instance {
    /// Create an instance of the geometry in the scene that will only receive light.
    pub fn receiver(geom: Arc<BoundableGeom + Send + Sync>, material: Arc<Material + Send + Sync>,
               transform: Transform, tag: String) -> Instance {
        Instance::Receiver(Receiver::new(geom, material, transform, tag))
    }
    /// Create an instance of the geometry in the scene that will emit and receive light
    pub fn area_light(geom: Arc<SampleableGeom + Send + Sync>, material: Arc<Material + Send + Sync>,
               emission: Colorf, transform: Transform, tag: String) -> Instance {
        Instance::Emitter(Emitter::area(geom, material, emission, transform, tag))
    }
    pub fn point_light(pos: Point, emission: Colorf, tag: String) ->  Instance {
        Instance::Emitter(Emitter::point(pos, emission, tag))
    }
    /// Test the ray for intersection against this insance of geometry.
    /// returns Some(Intersection) if an intersection was found and None if not.
    /// If an intersection is found `ray.max_t` will be set accordingly
    pub fn intersect(&self, ray: &mut Ray) -> Option<Intersection> {
        let hit = match self {
            &Instance::Emitter(ref e) => e.intersect(ray),
            &Instance::Receiver(ref r) => r.intersect(ray),
        };
        match hit {
            Some((dg, mat)) => Some(Intersection::new(dg, self, mat)),
            None => None,
        }
    }
    /// Get the tag for this instance
    pub fn tag(&self) -> &str {
        match self {
            &Instance::Emitter(ref e) => &e.tag[..],
            &Instance::Receiver(ref r) => &r.tag[..],
        }
    }
    /// Get the transform for this instance
    pub fn get_transform(&self) -> &Transform {
        match self {
            &Instance::Emitter(ref e) => e.get_transform(),
            &Instance::Receiver(ref r) => r.get_transform()
        }
    }
    /// Set the transform for this instance
    pub fn set_transform(&mut self, transform: Transform) {
        match self {
            &mut Instance::Emitter(ref mut e) => e.set_transform(transform),
            &mut Instance::Receiver(ref mut r) => r.set_transform(transform)
        }
    }
}

impl Boundable for Instance {
    fn bounds(&self) -> BBox {
        match self {
            &Instance::Emitter(ref e) => e.bounds(),
            &Instance::Receiver(ref r) => r.bounds(),
        }
    }
}

<|endoftext|>


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

// This test checks for namespace pollution by private tests.
// Tests used to marked as public causing name conflicts with normal
// functions only in test builds.

// compile-flags: --test

mod a {
    pub fn foo() -> bool {
        true
    }
}

mod b {
    #[test]
    fn foo() {}
}

use a::*;
use b::*;

fn conflict() {
    let _: bool = foo();
}<commit_msg>Just tidying up<commit_after>// Copyright 2015 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.

// This test checks for namespace pollution by private tests.
// Tests used to marked as public causing name conflicts with normal
// functions only in test builds.

// compile-flags: --test

mod a {
    pub fn foo() -> bool {
        true
    }
}

mod b {
    #[test]
    fn foo() {
        local_name(); // ensure the local name still works
    }

    #[test]
    fn local_name() {}
}

use a::*;
use b::*;

pub fn conflict() {
    let _: bool = foo();
}
<|endoftext|>


<commit_before>use traits::Coord;

#[derive(Debug, PartialEq)]
pub struct GridCoord {
    x: i32,
    y: i32,
}

impl GridCoord {

    #[inline]
    pub fn from_offset(offset: i32, rows: i32, cols: i32) -> GridCoord {
        let col = offset % cols;
        let row = (offset - col) / rows;

        GridCoord {
            x: col,
            y: row,
        }
    }
}

impl Coord for GridCoord {

    fn from_2d(x: i32, y: i32) -> Self {
        GridCoord {
            x: x,
            y: y,
        }
    }

    fn x(&self) -> i32 { self.x }

    fn y(&self) -> i32 { self.y }
}

#[cfg(test)]
mod tests {

    use traits::Coord;
    use traits::Nhood;
    use grid::nhood::MooreNhood;
    use super::GridCoord;

    #[test]
    fn test_from_offset() {
        let c = GridCoord::from_offset(0, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 0);

        let c = GridCoord::from_offset(10, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 1);

        let c = GridCoord::from_offset(100, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 10);
    }

    #[test]
    fn test_with_moore_nhood() {
        // 3 x 3 square grid with Moore's neighborhood

        let nhood: MooreNhood<GridCoord> = MooreNhood::new();

        let center = GridCoord::from_2d(1, 1);

        let neighbors = nhood.neighbors(&center);
        assert_eq!(neighbors.len(), nhood.neighbors_count());

        assert_eq!(neighbors[0], GridCoord::from_2d(0, 0));
        assert_eq!(neighbors[1], GridCoord::from_2d(1, 0));
        assert_eq!(neighbors[2], GridCoord::from_2d(2, 0));
        assert_eq!(neighbors[3], GridCoord::from_2d(0, 1));
        assert_eq!(neighbors[4], GridCoord::from_2d(2, 1));
        assert_eq!(neighbors[5], GridCoord::from_2d(0, 2));
        assert_eq!(neighbors[6], GridCoord::from_2d(1, 2));
        assert_eq!(neighbors[7], GridCoord::from_2d(2, 2));
    }
}<commit_msg>Type inference usage.<commit_after>use traits::Coord;

#[derive(Debug, PartialEq)]
pub struct GridCoord {
    x: i32,
    y: i32,
}

impl GridCoord {

    #[inline]
    pub fn from_offset(offset: i32, rows: i32, cols: i32) -> GridCoord {
        let col = offset % cols;
        let row = (offset - col) / rows;

        GridCoord {
            x: col,
            y: row,
        }
    }
}

impl Coord for GridCoord {

    fn from_2d(x: i32, y: i32) -> Self {
        GridCoord {
            x: x,
            y: y,
        }
    }

    fn x(&self) -> i32 { self.x }

    fn y(&self) -> i32 { self.y }
}

#[cfg(test)]
mod tests {

    use traits::Coord;
    use traits::Nhood;
    use grid::nhood::MooreNhood;
    use super::GridCoord;

    #[test]
    fn test_from_offset() {
        let c = GridCoord::from_offset(0, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 0);

        let c = GridCoord::from_offset(10, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 1);

        let c = GridCoord::from_offset(100, 10, 10);
        assert_eq!(c.x(), 0);
        assert_eq!(c.y(), 10);
    }

    #[test]
    fn test_with_moore_nhood() {
        // 3 x 3 square grid with Moore's neighborhood

        let nhood = MooreNhood::new();

        let center = GridCoord::from_2d(1, 1);

        let neighbors = nhood.neighbors(&center);
        assert_eq!(neighbors.len(), nhood.neighbors_count());

        assert_eq!(neighbors[0], GridCoord::from_2d(0, 0));
        assert_eq!(neighbors[1], GridCoord::from_2d(1, 0));
        assert_eq!(neighbors[2], GridCoord::from_2d(2, 0));
        assert_eq!(neighbors[3], GridCoord::from_2d(0, 1));
        assert_eq!(neighbors[4], GridCoord::from_2d(2, 1));
        assert_eq!(neighbors[5], GridCoord::from_2d(0, 2));
        assert_eq!(neighbors[6], GridCoord::from_2d(1, 2));
        assert_eq!(neighbors[7], GridCoord::from_2d(2, 2));
    }
}<|endoftext|>