<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq, Clone)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    UnaryMinusTypeMismatch(Value),
    BinaryOperatorTypeMismatch(BinaryOperator, Value, Value),
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match *self {
            Expr::Literal(ref l) => l.interpret(),
            Expr::Unary(ref u) => u.interpret(),
            Expr::Binary(ref b) => b.interpret(),
            Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match *self {
            Literal::NilLiteral => Ok(Value::Nil),
            Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::UnaryMinusTypeMismatch(value)),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l - r))
            }
            (&BinaryOperator::Slash, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l / r))
            }
            (&BinaryOperator::Star, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l * r))
            }
            (&BinaryOperator::Plus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l + r))
            }
            (&BinaryOperator::Plus, &Value::String(ref l), &Value::String(ref r)) => {
                let mut result = String::new();
                result.push_str(l);
                result.push_str(r);
                Ok(Value::String(result))
            }
            (&BinaryOperator::Greater, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l > r))
            }
            (&BinaryOperator::Less, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l < r))
            }
            (&BinaryOperator::GreaterEqual, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l >= r))
            }
            (&BinaryOperator::LessEqual, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l <= r))
            }
            (&BinaryOperator::NotEqual, l, r) => Ok(Value::Boolean(l != r)),
            (&BinaryOperator::Equal, l, r) => Ok(Value::Boolean(l == r)),
            _ => {
                Err(RuntimeError::BinaryOperatorTypeMismatch(self.operator,
                                                             left.clone(),
                                                             right.clone()))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let string = String::from("abc");
        let expr = Expr::Literal(Literal::StringLiteral(string.clone()));
        assert_eq!(Value::String(string), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

    #[test]
    fn binary() {
        let expr = BinaryExpr {
            operator: BinaryOperator::Plus,
            left: Expr::Literal(Literal::NumberLiteral(1.0f64)),
            right: Expr::Literal(Literal::NumberLiteral(1.0f64)),
        };
        assert_eq!(Value::Number(2.0f64), expr.interpret().unwrap());
    }

}
<commit_msg>[clippy] deref on all patterns<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq, Clone)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match *self {
            Value::Nil => false,
            Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    UnaryMinusTypeMismatch(Value),
    BinaryOperatorTypeMismatch(BinaryOperator, Value, Value),
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match *self {
            Expr::Literal(ref l) => l.interpret(),
            Expr::Unary(ref u) => u.interpret(),
            Expr::Binary(ref b) => b.interpret(),
            Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match *self {
            Literal::NilLiteral => Ok(Value::Nil),
            Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::UnaryMinusTypeMismatch(value)),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l - r))
            }
            (&BinaryOperator::Slash, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l / r))
            }
            (&BinaryOperator::Star, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l * r))
            }
            (&BinaryOperator::Plus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l + r))
            }
            (&BinaryOperator::Plus, &Value::String(ref l), &Value::String(ref r)) => {
                let mut result = String::new();
                result.push_str(l);
                result.push_str(r);
                Ok(Value::String(result))
            }
            (&BinaryOperator::Greater, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l > r))
            }
            (&BinaryOperator::Less, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l < r))
            }
            (&BinaryOperator::GreaterEqual, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l >= r))
            }
            (&BinaryOperator::LessEqual, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Boolean(l <= r))
            }
            (&BinaryOperator::NotEqual, l, r) => Ok(Value::Boolean(l != r)),
            (&BinaryOperator::Equal, l, r) => Ok(Value::Boolean(l == r)),
            _ => {
                Err(RuntimeError::BinaryOperatorTypeMismatch(self.operator,
                                                             left.clone(),
                                                             right.clone()))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let string = String::from("abc");
        let expr = Expr::Literal(Literal::StringLiteral(string.clone()));
        assert_eq!(Value::String(string), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

    #[test]
    fn binary() {
        let expr = BinaryExpr {
            operator: BinaryOperator::Plus,
            left: Expr::Literal(Literal::NumberLiteral(1.0f64)),
            right: Expr::Literal(Literal::NumberLiteral(1.0f64)),
        };
        assert_eq!(Value::Number(2.0f64), expr.interpret().unwrap());
    }

}
<|endoftext|>


<commit_before>//FIXME: Check unicode support

use log::{Log, Change, LogEntry};

use gapbuffer::GapBuffer;

use std::cmp;
use std::collections::HashMap;
use std::io::{File, Reader, BufferedReader};

#[deriving(Copy, PartialEq, Eq, Hash, Show)]
pub enum Mark {
    Cursor(uint),           //For keeping track of cursors.
    DisplayMark(uint),      //For using in determining some display of characters.
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub enum Direction {
    Up(uint), Down(uint), Left(uint), Right(uint),
    LineStart, LineEnd,
}

pub struct Buffer {
    text: GapBuffer<u8>,                    //Actual text data being edited.
    marks: HashMap<Mark, (uint, uint)>,     //Table of marked indices in the text.
                                            // KEY: mark id => VALUE : (absolute index, line index)
    log: Log,                               //History of undoable transactions.
    pub file_path: Option<Path>,            //TODO: replace with a general metadata table
}

impl Buffer {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    /// Constructor for empty buffer.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            text: GapBuffer::new(),
            marks: HashMap::new(),
            log: Log::new(),
        }
    }

    /// Constructor for buffer from reader.
    pub fn new_from_reader<R: Reader>(reader: R) -> Buffer {
        let mut buff = Buffer::new();
        if let Ok(contents) = BufferedReader::new(reader).read_to_string() {
            buff.text.extend(contents.bytes());
        }
        buff
    }

    /// Constructor for buffer from file.
    pub fn new_from_file(path: Path) -> Buffer {
        if let Ok(file) = File::open(&path) {
            let mut buff = Buffer::new_from_reader(file);
            buff.file_path = Some(path);
            buff
        } else { Buffer::new() }
    }

    //----- ACCESSORS ------------------------------------------------------------------------------

    ///Length of the text stored in this buffer.
    pub fn len(&self) -> uint {
        self.text.len() + 1
    }

    ///The x,y coordinates of a mark within the file. None if not a valid mark.
    pub fn get_mark_coords(&self, mark: Mark) -> Option<(uint, uint)> {
        if let Some(idx) = self.get_mark_idx(mark) {
            if let Some(line) = get_line(idx, &self.text) {
                Some((idx - line, range(0, idx).filter(|i| -> bool { self.text[*i] == b'\n' })
                                               .fold(0, |a, _| a + 1)))
            } else { None }
        } else { None }
    }

    ///The absolute index of a mark within the file. None if not a valid mark.
    pub fn get_mark_idx(&self, mark: Mark) -> Option<uint> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(idx)
            } else { None }
        } else { None }
    }

    ///Creates an iterator on the text by lines.
    pub fn lines(&self) -> Lines {
        Lines {
            buffer: self.text[],
            tail: 0,
            head: self.len()
        }
    }

    ///Creates an iterator on the text by lines that begins at the specified mark.
    pub fn lines_from(&self, mark: Mark) -> Option<Lines> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(Lines {
                    buffer: self.text[idx..],
                    tail: 0,
                    head: self.len() - idx,
                })
            } else { None }
        } else { None }
    }

    ///Returns the status text for this buffer.
    pub fn status_text(&self) -> String {
        match self.file_path {
            Some(ref path)  =>  format!("{}", path.display()),
            None            =>  format!("untitled"),
        }
    }

    //----- MUTATORS -------------------------------------------------------------------------------

    ///Sets the mark to a given absolute index. Adds a new mark or overwrites an existing mark.
    pub fn set_mark(&mut self, mark: Mark, idx: uint) {
        if let Some(line) = get_line(idx, &self.text) {
            if let Some(tuple) = self.marks.get_mut(&mark) {
                *tuple = (idx, idx - line);
                return;
            }
            self.marks.insert(mark, (idx, idx - line));
        }
    }

    //Shift a mark relative to its position according to the direction given.
    pub fn shift_mark(&mut self, mark: Mark, direction: Direction) {
        let last = self.len() - 1;
        let text = &self.text;
        if let Some(tuple) = self.marks.get_mut(&mark) {
            let (idx, line_idx) = *tuple;
            if let (Some(line), Some(line_end)) = (get_line(idx, text), get_line_end(idx, text)) {
                *tuple = match direction {
                    //For every relative motion of a mark, should return this tuple:
                    //  value 0:    the absolute index of the mark in the file
                    //  value 1:    the index of the mark in its line (unchanged by direct verticle
                    //              traversals)
                    Direction::Left(n)      =>  {
                        if idx >= n { (idx - n, idx - n - get_line(idx - n, text).unwrap()) }
                        else { (0, 0) }
                    }
                    Direction::Right(n)     =>  {
                        if idx + n < last { (idx + n, idx + n - get_line(idx + n, text).unwrap()) }
                        else { (last, last - get_line(last, text).unwrap()) }
                    }
                    Direction::Up(n)        =>  {
                        let nlines = range(0, idx).rev().filter(|i| text[*i] == b'\n')
                                                        .take(n + 1)
                                                        .collect::<Vec<uint>>();
                        if n == nlines.len() { (cmp::min(line_idx, nlines[0]), line_idx) }
                        else if n > nlines.len() { (0, 0) }
                        else { (cmp::min(line_idx + nlines[n] + 1, nlines[n-1]), line_idx) }
                    }
                    Direction::Down(n)      =>  {
                        let nlines = range(idx, text.len()).filter(|i| text[*i] == b'\n')
                                                           .take(n + 1)
                                                           .collect::<Vec<uint>>();
                        if n > nlines.len() { (last, last - get_line(last, text).unwrap())
                        } else if n == nlines.len() {
                            (cmp::min(line_idx + nlines[n-1] + 1, last), line_idx)
                        } else { (cmp::min(line_idx + nlines[n-1] + 1, nlines[n]), line_idx) }
                    }
                    Direction::LineStart    =>  { (line, 0) }
                    Direction::LineEnd      =>  { (line_end, line_end - line) }
                }
            }
        }
    }
    ///Remove the char at the mark.
    pub fn remove_char(&mut self, mark: Mark) -> Option<u8> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if let Some(ch) = self.text.remove(idx) {
                let mut transaction = self.log.start(idx);
                transaction.log(Change::Remove(idx, ch), idx);
                Some(ch)
            } else { None }
        } else { None }
    }

    ///Insert a char at the mark.
    pub fn insert_char(&mut self, mark: Mark, ch: u8) {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            self.text.insert(idx, ch);
            let mut transaction = self.log.start(idx);
            transaction.log(Change::Insert(idx, ch), idx);
        }
    }

    pub fn redo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.redo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

    pub fn undo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.undo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

}

//Returns the index of the first character of the line the mark is in.
//Newline prior to mark (EXCLUSIVE) + 1.
//None iff mark is outside of the len of text.
fn get_line(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(0, mark + 1).filter(|idx| *idx == 0 || text[*idx - 1] == b'\n').max()
    } else { None }
}

//Returns the index of the newline character at the end of the line mark is in.
//Newline after mark (INCLUSIVE).
//None iff mark is outside the len of text.
fn get_line_end(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(mark, text.len() + 1).filter(|idx| *idx == text.len() ||text[*idx] == b'\n').min()
    } else { None }
}

//Performs a transaction on the passed in buffer.
fn commit(transaction: &LogEntry, text: &mut GapBuffer<u8>) {
    for change in transaction.changes.iter() {
        match change {
            &Change::Insert(idx, ch) => {
                text.insert(idx, ch);
            }
            &Change::Remove(idx, _) => {
                text.remove(idx);
            }
        }
    }
}

//----- ITERATE BY LINES ---------------------------------------------------------------------------

pub struct Lines<'a> {
    buffer: &'a [u8],
    tail: uint,
    head: uint,
}

impl<'a> Iterator<&'a [u8]> for Lines<'a> {

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.tail != self.head {

            let old_tail = self.tail;
            //update tail to either the first char after the next \n or to self.head
            self.tail = range(old_tail, self.head).filter(|idx| -> bool {
                *idx + 1 == self.head || self.buffer[*idx] == b'\n'
            }).min().unwrap() + 1;
            if self.tail == self.head { Some(self.buffer[old_tail..self.tail-1]) }
            else { Some(self.buffer[old_tail..self.tail]) }

        } else { None }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        //TODO: this is technically correct but a better estimate could be implemented
        (1, Some(self.head))
    }

}

//----- TESTS --------------------------------------------------------------------------------------

#[cfg(test)]
mod test {

    use buffer::{Buffer, Direction, Mark};

    fn setup_buffer(testcase: &'static str) -> Buffer {
        let mut buffer = Buffer::new();
        buffer.text.extend(testcase.bytes());
        buffer.set_mark(Mark::Cursor(0), 0);
        buffer
    }

    #[test]
    fn test_insert() {
        let mut buffer = setup_buffer("");
        buffer.insert_char(Mark::Cursor(0), b'A');
        assert_eq!(buffer.len(), 2);
        assert_eq!(buffer.lines().next().unwrap(), [b'A']);
    }

    #[test]
    fn test_remove() {
        let mut buffer = setup_buffer("ABCD");
        buffer.remove_char(Mark::Cursor(0));

        assert_eq!(buffer.len(), 4);
        assert_eq!(buffer.lines().next().unwrap(), [b'B', b'C', b'D']);
    }

    #[test]
    fn test_set_mark() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 2);
    }

    #[test]
    fn test_shift_down() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Down(2));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (2, 2));
    }

    #[test]
    fn test_shift_right() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::Right(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_up() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 10);
        buffer.shift_mark(Mark::Cursor(0), Direction::Up(1));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (1, 1));
    }

    #[test]
    fn test_shift_left() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_linestart() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::LineStart);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 0);
    }

    #[test]
    fn test_shift_lineend() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::LineEnd);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 4);
    }

    #[test]
    fn test_to_lines() {
        let buffer = setup_buffer("Test\nA\nTest");
        let mut lines = buffer.lines();

        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'A',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn test_to_lines_from() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 6);
        let mut lines = buffer.lines_from(Mark::Cursor(0)).unwrap();

        assert_eq!(lines.next().unwrap(), [b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn move_from_final_position() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 4);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 3);
    }

}
<commit_msg>Added the line count back to the status line.<commit_after>//FIXME: Check unicode support

use log::{Log, Change, LogEntry};

use gapbuffer::GapBuffer;

use std::cmp;
use std::collections::HashMap;
use std::io::{File, Reader, BufferedReader};

#[deriving(Copy, PartialEq, Eq, Hash, Show)]
pub enum Mark {
    Cursor(uint),           //For keeping track of cursors.
    DisplayMark(uint),      //For using in determining some display of characters.
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub enum Direction {
    Up(uint), Down(uint), Left(uint), Right(uint),
    LineStart, LineEnd,
}

pub struct Buffer {
    text: GapBuffer<u8>,                    //Actual text data being edited.
    marks: HashMap<Mark, (uint, uint)>,     //Table of marked indices in the text.
                                            // KEY: mark id => VALUE : (absolute index, line index)
    log: Log,                               //History of undoable transactions.
    pub file_path: Option<Path>,            //TODO: replace with a general metadata table
}

impl Buffer {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    /// Constructor for empty buffer.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            text: GapBuffer::new(),
            marks: HashMap::new(),
            log: Log::new(),
        }
    }

    /// Constructor for buffer from reader.
    pub fn new_from_reader<R: Reader>(reader: R) -> Buffer {
        let mut buff = Buffer::new();
        if let Ok(contents) = BufferedReader::new(reader).read_to_string() {
            buff.text.extend(contents.bytes());
        }
        buff
    }

    /// Constructor for buffer from file.
    pub fn new_from_file(path: Path) -> Buffer {
        if let Ok(file) = File::open(&path) {
            let mut buff = Buffer::new_from_reader(file);
            buff.file_path = Some(path);
            buff
        } else { Buffer::new() }
    }

    //----- ACCESSORS ------------------------------------------------------------------------------

    ///Length of the text stored in this buffer.
    pub fn len(&self) -> uint {
        self.text.len() + 1
    }

    ///The x,y coordinates of a mark within the file. None if not a valid mark.
    pub fn get_mark_coords(&self, mark: Mark) -> Option<(uint, uint)> {
        if let Some(idx) = self.get_mark_idx(mark) {
            if let Some(line) = get_line(idx, &self.text) {
                Some((idx - line, range(0, idx).filter(|i| -> bool { self.text[*i] == b'\n' })
                                               .fold(0, |a, _| a + 1)))
            } else { None }
        } else { None }
    }

    ///The absolute index of a mark within the file. None if not a valid mark.
    pub fn get_mark_idx(&self, mark: Mark) -> Option<uint> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(idx)
            } else { None }
        } else { None }
    }

    ///Creates an iterator on the text by lines.
    pub fn lines(&self) -> Lines {
        Lines {
            buffer: self.text[],
            tail: 0,
            head: self.len()
        }
    }

    ///Creates an iterator on the text by lines that begins at the specified mark.
    pub fn lines_from(&self, mark: Mark) -> Option<Lines> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(Lines {
                    buffer: self.text[idx..],
                    tail: 0,
                    head: self.len() - idx,
                })
            } else { None }
        } else { None }
    }

    ///Returns the status text for this buffer.
    pub fn status_text(&self) -> String {
        match self.file_path {
            Some(ref path)  =>  format!("{}, lines: {} ", path.display(),
                                    self.lines().fold(0, |a, _| -> uint {a + 1})),
            None            =>  format!("untitled, lines: {} ",
                                    self.lines().fold(0, |a, _| -> uint {a + 1})),
        }
    }

    //----- MUTATORS -------------------------------------------------------------------------------

    ///Sets the mark to a given absolute index. Adds a new mark or overwrites an existing mark.
    pub fn set_mark(&mut self, mark: Mark, idx: uint) {
        if let Some(line) = get_line(idx, &self.text) {
            if let Some(tuple) = self.marks.get_mut(&mark) {
                *tuple = (idx, idx - line);
                return;
            }
            self.marks.insert(mark, (idx, idx - line));
        }
    }

    //Shift a mark relative to its position according to the direction given.
    pub fn shift_mark(&mut self, mark: Mark, direction: Direction) {
        let last = self.len() - 1;
        let text = &self.text;
        if let Some(tuple) = self.marks.get_mut(&mark) {
            let (idx, line_idx) = *tuple;
            if let (Some(line), Some(line_end)) = (get_line(idx, text), get_line_end(idx, text)) {
                *tuple = match direction {
                    //For every relative motion of a mark, should return this tuple:
                    //  value 0:    the absolute index of the mark in the file
                    //  value 1:    the index of the mark in its line (unchanged by direct verticle
                    //              traversals)
                    Direction::Left(n)      =>  {
                        if idx >= n { (idx - n, idx - n - get_line(idx - n, text).unwrap()) }
                        else { (0, 0) }
                    }
                    Direction::Right(n)     =>  {
                        if idx + n < last { (idx + n, idx + n - get_line(idx + n, text).unwrap()) }
                        else { (last, last - get_line(last, text).unwrap()) }
                    }
                    Direction::Up(n)        =>  {
                        let nlines = range(0, idx).rev().filter(|i| text[*i] == b'\n')
                                                        .take(n + 1)
                                                        .collect::<Vec<uint>>();
                        if n == nlines.len() { (cmp::min(line_idx, nlines[0]), line_idx) }
                        else if n > nlines.len() { (0, 0) }
                        else { (cmp::min(line_idx + nlines[n] + 1, nlines[n-1]), line_idx) }
                    }
                    Direction::Down(n)      =>  {
                        let nlines = range(idx, text.len()).filter(|i| text[*i] == b'\n')
                                                           .take(n + 1)
                                                           .collect::<Vec<uint>>();
                        if n > nlines.len() { (last, last - get_line(last, text).unwrap())
                        } else if n == nlines.len() {
                            (cmp::min(line_idx + nlines[n-1] + 1, last), line_idx)
                        } else { (cmp::min(line_idx + nlines[n-1] + 1, nlines[n]), line_idx) }
                    }
                    Direction::LineStart    =>  { (line, 0) }
                    Direction::LineEnd      =>  { (line_end, line_end - line) }
                }
            }
        }
    }

    ///Remove the char at the mark.
    pub fn remove_char(&mut self, mark: Mark) -> Option<u8> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if let Some(ch) = self.text.remove(idx) {
                let mut transaction = self.log.start(idx);
                transaction.log(Change::Remove(idx, ch), idx);
                Some(ch)
            } else { None }
        } else { None }
    }

    ///Insert a char at the mark.
    pub fn insert_char(&mut self, mark: Mark, ch: u8) {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            self.text.insert(idx, ch);
            let mut transaction = self.log.start(idx);
            transaction.log(Change::Insert(idx, ch), idx);
        }
    }

    ///Redo most recently undone action.
    pub fn redo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.redo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

    ///Undo most recently performed action.
    pub fn undo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.undo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

}

//Returns the index of the first character of the line the mark is in.
//Newline prior to mark (EXCLUSIVE) + 1.
//None iff mark is outside of the len of text.
fn get_line(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(0, mark + 1).filter(|idx| *idx == 0 || text[*idx - 1] == b'\n').max()
    } else { None }
}

//Returns the index of the newline character at the end of the line mark is in.
//Newline after mark (INCLUSIVE).
//None iff mark is outside the len of text.
fn get_line_end(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(mark, text.len() + 1).filter(|idx| *idx == text.len() ||text[*idx] == b'\n').min()
    } else { None }
}

//Performs a transaction on the passed in buffer.
fn commit(transaction: &LogEntry, text: &mut GapBuffer<u8>) {
    for change in transaction.changes.iter() {
        match change {
            &Change::Insert(idx, ch) => {
                text.insert(idx, ch);
            }
            &Change::Remove(idx, _) => {
                text.remove(idx);
            }
        }
    }
}

//----- ITERATE BY LINES ---------------------------------------------------------------------------

pub struct Lines<'a> {
    buffer: &'a [u8],
    tail: uint,
    head: uint,
}

impl<'a> Iterator<&'a [u8]> for Lines<'a> {

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.tail != self.head {

            let old_tail = self.tail;
            //update tail to either the first char after the next \n or to self.head
            self.tail = range(old_tail, self.head).filter(|idx| -> bool {
                *idx + 1 == self.head || self.buffer[*idx] == b'\n'
            }).min().unwrap() + 1;
            if self.tail == self.head { Some(self.buffer[old_tail..self.tail-1]) }
            else { Some(self.buffer[old_tail..self.tail]) }

        } else { None }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        //TODO: this is technically correct but a better estimate could be implemented
        (1, Some(self.head))
    }

}

//----- TESTS --------------------------------------------------------------------------------------

#[cfg(test)]
mod test {

    use buffer::{Buffer, Direction, Mark};

    fn setup_buffer(testcase: &'static str) -> Buffer {
        let mut buffer = Buffer::new();
        buffer.text.extend(testcase.bytes());
        buffer.set_mark(Mark::Cursor(0), 0);
        buffer
    }

    #[test]
    fn test_insert() {
        let mut buffer = setup_buffer("");
        buffer.insert_char(Mark::Cursor(0), b'A');
        assert_eq!(buffer.len(), 2);
        assert_eq!(buffer.lines().next().unwrap(), [b'A']);
    }

    #[test]
    fn test_remove() {
        let mut buffer = setup_buffer("ABCD");
        buffer.remove_char(Mark::Cursor(0));

        assert_eq!(buffer.len(), 4);
        assert_eq!(buffer.lines().next().unwrap(), [b'B', b'C', b'D']);
    }

    #[test]
    fn test_set_mark() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 2);
    }

    #[test]
    fn test_shift_down() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Down(2));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (2, 2));
    }

    #[test]
    fn test_shift_right() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::Right(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_up() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 10);
        buffer.shift_mark(Mark::Cursor(0), Direction::Up(1));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (1, 1));
    }

    #[test]
    fn test_shift_left() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_linestart() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::LineStart);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 0);
    }

    #[test]
    fn test_shift_lineend() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::LineEnd);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 4);
    }

    #[test]
    fn test_to_lines() {
        let buffer = setup_buffer("Test\nA\nTest");
        let mut lines = buffer.lines();

        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'A',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn test_to_lines_from() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 6);
        let mut lines = buffer.lines_from(Mark::Cursor(0)).unwrap();

        assert_eq!(lines.next().unwrap(), [b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn move_from_final_position() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 4);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 3);
    }

}
<|endoftext|>


<commit_before>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::{Item, ItemAncestors};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// Template declaration (and such declaration's template parameters) related
/// methods.
///
/// This trait's methods distinguish between `None` and `Some([])` for
/// declarations that are not templates and template declarations with zero
/// parameters, in general.
///
/// Consider this example:
///
/// ```c++
/// template <typename T, typename U>
/// class Foo {
///     T use_of_t;
///     U use_of_u;
///
///     template <typename V>
///     using Bar = V*;
///
///     class Inner {
///         T        x;
///         U        y;
///         Bar<int> z;
///     };
///
///     template <typename W>
///     class Lol {
///         // No use of W, but here's a use of T.
///         T t;
///     };
///
///     template <typename X>
///     class Wtf {
///         // X is not used because W is not used.
///         Lol<X> lololol;
///     };
/// };
///
/// class Qux {
///     int y;
/// };
/// ```
///
/// The following table depicts the results of each trait method when invoked on
/// each of the declarations above:
///
/// +------+----------------------+--------------------------+------------------------+----
/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
/// +------+----------------------+--------------------------+------------------------+----
/// |Foo   | Some([T, U])         | Some(2)                  | Some([T, U])           | ...
/// |Bar   | Some([V])            | Some(1)                  | Some([T, U, V])        | ...
/// |Inner | None                 | None                     | Some([T, U])           | ...
/// |Lol   | Some([W])            | Some(1)                  | Some([T, U, W])        | ...
/// |Wtf   | Some([X])            | Some(1)                  | Some([T, U, X])        | ...
/// |Qux   | None                 | None                     | None                   | ...
/// +------+----------------------+--------------------------+------------------------+----
///
/// ----+------+-----+----------------------+
/// ... |Decl. | ... | used_template_params |
/// ----+------+-----+----------------------+
/// ... |Foo   | ... | Some([T, U])         |
/// ... |Bar   | ... | Some([V])            |
/// ... |Inner | ... | None                 |
/// ... |Lol   | ... | Some([T])            |
/// ... |Wtf   | ... | Some([T])            |
/// ... |Qux   | ... | None                 |
/// ----+------+-----+----------------------+
pub trait TemplateParameters {
    /// Get the set of `ItemId`s that make up this template declaration's free
    /// template parameters.
    ///
    /// Note that these might *not* all be named types: C++ allows
    /// constant-value template parameters as well as template-template
    /// parameters. Of course, Rust does not allow generic parameters to be
    /// anything but types, so we must treat them as opaque, and avoid
    /// instantiating them.
    fn self_template_params(&self,
                            ctx: &BindgenContext)
                            -> Option<Vec<ItemId>>;

    /// Get the number of free template parameters this template declaration
    /// has.
    ///
    /// Implementations *may* return `Some` from this method when
    /// `template_params` returns `None`. This is useful when we only have
    /// partial information about the template declaration, such as when we are
    /// in the middle of parsing it.
    fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
        self.self_template_params(ctx).map(|params| params.len())
    }

    /// Get the complete set of template parameters that can affect this
    /// declaration.
    ///
    /// Note that this item doesn't need to be a template declaration itself for
    /// `Some` to be returned here (in contrast to `self_template_params`). If
    /// this item is a member of a template declaration, then the parent's
    /// template parameters are included here.
    ///
    /// In the example above, `Inner` depends on both of the `T` and `U` type
    /// parameters, even though it is not itself a template declaration and
    /// therefore has no type parameters itself. Perhaps it helps to think about
    /// how we would fully reference such a member type in C++:
    /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
    /// arguments before we can gain access to the `Inner` member type.
    fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
        where Self: ItemAncestors,
    {
        let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
            .filter_map(|id| id.self_template_params(ctx))
            .collect();
        if each_self_params.is_empty() {
            None
        } else {
            Some(each_self_params.into_iter()
                .rev()
                .flat_map(|params| params)
                .collect())
        }
    }

    /// Get only the set of template parameters that this item uses. This is a
    /// subset of `all_template_params` and does not necessarily contain any of
    /// `self_template_params`.
    fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
        where Self: AsRef<ItemId>,
    {
        assert!(ctx.in_codegen_phase(),
                "template parameter usage is not computed until codegen");

        let id = *self.as_ref();
        ctx.resolve_item(id)
            .all_template_params(ctx)
            .map(|all_params| {
                all_params.into_iter()
                    .filter(|p| ctx.uses_template_parameter(id, *p))
                    .collect()
            })
    }
}

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                args.filter(|t| t.kind() != CXType_Invalid)
                    .map(|t| {
                        Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                    })
                    .collect()
            });

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            });

        let definition = match definition {
            Some(def) => def,
            None => {
                if !ty.declaration().is_builtin() {
                    warn!("Could not find template definition for template \
                           instantiation");
                }
                return None
            }
        };

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx)
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<commit_msg>Auto merge of #694 - emilio:finally, r=fitzgen<commit_after>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::{Item, ItemAncestors};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// Template declaration (and such declaration's template parameters) related
/// methods.
///
/// This trait's methods distinguish between `None` and `Some([])` for
/// declarations that are not templates and template declarations with zero
/// parameters, in general.
///
/// Consider this example:
///
/// ```c++
/// template <typename T, typename U>
/// class Foo {
///     T use_of_t;
///     U use_of_u;
///
///     template <typename V>
///     using Bar = V*;
///
///     class Inner {
///         T        x;
///         U        y;
///         Bar<int> z;
///     };
///
///     template <typename W>
///     class Lol {
///         // No use of W, but here's a use of T.
///         T t;
///     };
///
///     template <typename X>
///     class Wtf {
///         // X is not used because W is not used.
///         Lol<X> lololol;
///     };
/// };
///
/// class Qux {
///     int y;
/// };
/// ```
///
/// The following table depicts the results of each trait method when invoked on
/// each of the declarations above:
///
/// +------+----------------------+--------------------------+------------------------+----
/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
/// +------+----------------------+--------------------------+------------------------+----
/// |Foo   | Some([T, U])         | Some(2)                  | Some([T, U])           | ...
/// |Bar   | Some([V])            | Some(1)                  | Some([T, U, V])        | ...
/// |Inner | None                 | None                     | Some([T, U])           | ...
/// |Lol   | Some([W])            | Some(1)                  | Some([T, U, W])        | ...
/// |Wtf   | Some([X])            | Some(1)                  | Some([T, U, X])        | ...
/// |Qux   | None                 | None                     | None                   | ...
/// +------+----------------------+--------------------------+------------------------+----
///
/// ----+------+-----+----------------------+
/// ... |Decl. | ... | used_template_params |
/// ----+------+-----+----------------------+
/// ... |Foo   | ... | Some([T, U])         |
/// ... |Bar   | ... | Some([V])            |
/// ... |Inner | ... | None                 |
/// ... |Lol   | ... | Some([T])            |
/// ... |Wtf   | ... | Some([T])            |
/// ... |Qux   | ... | None                 |
/// ----+------+-----+----------------------+
pub trait TemplateParameters {
    /// Get the set of `ItemId`s that make up this template declaration's free
    /// template parameters.
    ///
    /// Note that these might *not* all be named types: C++ allows
    /// constant-value template parameters as well as template-template
    /// parameters. Of course, Rust does not allow generic parameters to be
    /// anything but types, so we must treat them as opaque, and avoid
    /// instantiating them.
    fn self_template_params(&self,
                            ctx: &BindgenContext)
                            -> Option<Vec<ItemId>>;

    /// Get the number of free template parameters this template declaration
    /// has.
    ///
    /// Implementations *may* return `Some` from this method when
    /// `template_params` returns `None`. This is useful when we only have
    /// partial information about the template declaration, such as when we are
    /// in the middle of parsing it.
    fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
        self.self_template_params(ctx).map(|params| params.len())
    }

    /// Get the complete set of template parameters that can affect this
    /// declaration.
    ///
    /// Note that this item doesn't need to be a template declaration itself for
    /// `Some` to be returned here (in contrast to `self_template_params`). If
    /// this item is a member of a template declaration, then the parent's
    /// template parameters are included here.
    ///
    /// In the example above, `Inner` depends on both of the `T` and `U` type
    /// parameters, even though it is not itself a template declaration and
    /// therefore has no type parameters itself. Perhaps it helps to think about
    /// how we would fully reference such a member type in C++:
    /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
    /// arguments before we can gain access to the `Inner` member type.
    fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
        where Self: ItemAncestors,
    {
        let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
            .filter_map(|id| id.self_template_params(ctx))
            .collect();
        if each_self_params.is_empty() {
            None
        } else {
            Some(each_self_params.into_iter()
                .rev()
                .flat_map(|params| params)
                .collect())
        }
    }

    /// Get only the set of template parameters that this item uses. This is a
    /// subset of `all_template_params` and does not necessarily contain any of
    /// `self_template_params`.
    fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
        where Self: AsRef<ItemId>,
    {
        assert!(ctx.in_codegen_phase(),
                "template parameter usage is not computed until codegen");

        let id = *self.as_ref();
        ctx.resolve_item(id)
            .all_template_params(ctx)
            .map(|all_params| {
                all_params.into_iter()
                    .filter(|p| ctx.uses_template_parameter(id, *p))
                    .collect()
            })
    }
}

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                match ty.canonical_type().template_args() {
                    Some(canonical_args) => {
                        let arg_count = args.len();
                        args.chain(canonical_args.skip(arg_count))
                            .filter(|t| t.kind() != CXType_Invalid)
                            .map(|t| {
                                Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                            }).collect()
                    }
                    None => {
                        args.filter(|t| t.kind() != CXType_Invalid)
                            .map(|t| {
                                Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                            }).collect()
                    }
                }
            });

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            });

        let definition = match definition {
            Some(def) => def,
            None => {
                if !ty.declaration().is_builtin() {
                    warn!("Could not find template definition for template \
                           instantiation");
                }
                return None
            }
        };

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx)
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<|endoftext|>


<commit_before>//#[derive(PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq)]
pub enum SegmentType {
    // BuildState is really simple state tracker to prevent misuse of api
    ObjectKey,
    Array,
    Word,
    DocSeq,
}

#[derive(Debug)]
struct Segment {
    type_: SegmentType,
    offset: usize,
}

#[derive(Debug)]
pub struct KeyBuilder {
    array_depth: usize,
    segments: Vec<Segment>,
    fullkey: String,
}

impl KeyBuilder {
    pub fn new() -> KeyBuilder {
        let mut kb = KeyBuilder{
            array_depth: 0,
             // Magic reserve numbers that are completely arbitrary
            segments: Vec::with_capacity(10),
            fullkey: String::with_capacity(100),
        };
        // First char is keyspace identifier. W means Word keyspace
        kb.fullkey.push('W');
        return kb;
    }

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

    pub fn key(&self) -> String {
        self.fullkey.clone()
    }

    pub fn push_object_key(&mut self, key: String) {
        debug_assert!(self.segments.len() == 0 ||
                      self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::ObjectKey, offset: self.fullkey.len() });
        self.fullkey.push('.');
        for cc in key.chars() {
            // Escape chars that conflict with delimiters
            if "\\$.!#".contains(cc) {
                self.fullkey.push('\\');
            }
            self.fullkey.push(cc);
        }
    }

    pub fn push_array(&mut self) {
        debug_assert!(self.segments.len() == 0 ||
                      self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::Array, offset: self.fullkey.len() });
        self.fullkey.push('$');
        self.array_depth += 1;
    }

    pub fn push_word(&mut self, stemmed_word: String) {
        debug_assert!(self.segments.len() > 0);
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::Word, offset: self.fullkey.len() });
        self.fullkey.push('!');
        self.fullkey += stemmed_word.as_str();
        self.fullkey.push('#');
    }

    pub fn push_doc_seq(&mut self, seq: u64) {
        debug_assert!(self.segments.len() > 0);
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Word);
        self.segments.push(Segment{ type_: SegmentType::DocSeq, offset: self.fullkey.len() });
        self.fullkey.push_str(seq.to_string().as_str());
    }

    pub fn pop_object_key(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::ObjectKey);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn pop_array(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Array);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.array_depth -= 1;
        self.segments.pop();
    }

    pub fn pop_word(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Word);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn pop_doc_seq(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::DocSeq);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn last_pushed_segment_type(&self) -> Option<SegmentType> {
        self.segments.last().and_then(|segment| Some(segment.type_.clone()))
    }
}

#[cfg(test)]
mod tests {
    use super::{KeyBuilder, SegmentType};

    #[test]
    fn test_new_key_builder() {
        let kb = KeyBuilder::new();
        assert_eq!(kb.key(), "W", "Initial value is set");
    }

    #[test]
    fn test_segments_push() {
        let mut kb = KeyBuilder::new();
        assert_eq!(kb.segments_count(), 0, "No segments so far");
        assert_eq!(kb.key(), "W", "Key for segments is correct");

        kb.push_object_key("first".to_string());
        assert_eq!(kb.segments_count(), 1, "One segment");
        assert_eq!(kb.key(), "W.first", "Key for one segments is correct");

        kb.push_object_key("second".to_string());
        assert_eq!(kb.segments_count(), 2, "Two segments");
        assert_eq!(kb.key(), "W.first.second", "Key for two segments is correct");

        kb.push_array();
        assert_eq!(kb.segments_count(), 3, "Three segments ");
        assert_eq!(kb.key(), "W.first.second$", "Key for three segments is correct");

        kb.push_word("astemmedword".to_string());
        assert_eq!(kb.segments_count(), 4, "Four segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#", "Key for four segments is correct");

        kb.push_doc_seq(123);
        assert_eq!(kb.segments_count(), 5, "Five segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#123",
                   "Key for five segments is correct");
    }

    #[test]
    #[should_panic(expected = "assertion failed: self.segments.len() > 0")]
    fn test_segments_push_doc_seq_panic() {
        let mut kb = KeyBuilder::new();
        kb.push_doc_seq(456);
    }

        #[test]
    #[should_panic(expected = "assertion failed: self.segments.len() > 0")]
    fn test_segments_push_word_panic() {
        let mut kb = KeyBuilder::new();
        kb.push_word("astemmedword".to_string());
    }

    #[test]
    fn test_segments_pop() {
        let mut kb = KeyBuilder::new();
        kb.push_object_key("first".to_string());
        kb.push_object_key("second".to_string());
        kb.push_array();
        kb.push_word("astemmedword".to_string());
        kb.push_doc_seq(123);
        assert_eq!(kb.segments_count(), 5, "Five segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#123",
                   "Key for five segments is correct");

        kb.pop_doc_seq();
        assert_eq!(kb.segments_count(), 4, "Four segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#", "Key for four segments is correct");

        kb.pop_word();
        assert_eq!(kb.segments_count(), 3, "Three segments ");
        assert_eq!(kb.key(), "W.first.second$", "Key for three segments is correct");

        kb.pop_array();
        assert_eq!(kb.segments_count(), 2, "Two segments");
        assert_eq!(kb.key(), "W.first.second", "Key for two segments is correct");

        kb.pop_object_key();
        assert_eq!(kb.segments_count(), 1, "One segment");
        assert_eq!(kb.key(), "W.first", "Key for one segments is correct");

        kb.pop_object_key();
        assert_eq!(kb.segments_count(), 0, "No segments so far");
        assert_eq!(kb.key(), "W", "Key for segments is correct");
    }

    #[test]
    fn test_last_pushed_segment_type() {
        let mut kb = KeyBuilder::new();
        assert_eq!(kb.last_pushed_segment_type(), None, "No segments");

        kb.push_object_key("first".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::ObjectKey),
                   "Last segment is an object key");

        kb.push_object_key("second".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::ObjectKey),
                   "Last segment is an object key");

        kb.push_array();
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::Array),
                   "Last segment is an array");

        kb.push_word("astemmedword".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::Word),
                   "Last segment is a word");

        kb.push_doc_seq(123);
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::DocSeq),
                   "Last segment is a doc sequence");
    }
}
<commit_msg>Remove trailing whitespace from keybuilder<commit_after>//#[derive(PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq)]
pub enum SegmentType {
    // BuildState is really simple state tracker to prevent misuse of api
    ObjectKey,
    Array,
    Word,
    DocSeq,
}

#[derive(Debug)]
struct Segment {
    type_: SegmentType,
    offset: usize,
}

#[derive(Debug)]
pub struct KeyBuilder {
    array_depth: usize,
    segments: Vec<Segment>,
    fullkey: String,
}

impl KeyBuilder {
    pub fn new() -> KeyBuilder {
        let mut kb = KeyBuilder{
            array_depth: 0,
             // Magic reserve numbers that are completely arbitrary
            segments: Vec::with_capacity(10),
            fullkey: String::with_capacity(100),
        };
        // First char is keyspace identifier. W means Word keyspace
        kb.fullkey.push('W');
        return kb;
    }

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

    pub fn key(&self) -> String {
        self.fullkey.clone()
    }

    pub fn push_object_key(&mut self, key: String) {
        debug_assert!(self.segments.len() == 0 ||
                      self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::ObjectKey, offset: self.fullkey.len() });
        self.fullkey.push('.');
        for cc in key.chars() {
            // Escape chars that conflict with delimiters
            if "\\$.!#".contains(cc) {
                self.fullkey.push('\\');
            }
            self.fullkey.push(cc);
        }
    }

    pub fn push_array(&mut self) {
        debug_assert!(self.segments.len() == 0 ||
                      self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::Array, offset: self.fullkey.len() });
        self.fullkey.push('$');
        self.array_depth += 1;
    }

    pub fn push_word(&mut self, stemmed_word: String) {
        debug_assert!(self.segments.len() > 0);
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::ObjectKey ||
                      self.segments.last().unwrap().type_ == SegmentType::Array);
        self.segments.push(Segment{ type_: SegmentType::Word, offset: self.fullkey.len() });
        self.fullkey.push('!');
        self.fullkey += stemmed_word.as_str();
        self.fullkey.push('#');
    }

    pub fn push_doc_seq(&mut self, seq: u64) {
        debug_assert!(self.segments.len() > 0);
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Word);
        self.segments.push(Segment{ type_: SegmentType::DocSeq, offset: self.fullkey.len() });
        self.fullkey.push_str(seq.to_string().as_str());
    }

    pub fn pop_object_key(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::ObjectKey);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn pop_array(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Array);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.array_depth -= 1;
        self.segments.pop();
    }

    pub fn pop_word(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::Word);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn pop_doc_seq(&mut self) {
        debug_assert!(self.segments.last().unwrap().type_ == SegmentType::DocSeq);
        self.fullkey.truncate(self.segments.last().unwrap().offset);
        self.segments.pop();
    }

    pub fn last_pushed_segment_type(&self) -> Option<SegmentType> {
        self.segments.last().and_then(|segment| Some(segment.type_.clone()))
    }
}

#[cfg(test)]
mod tests {
    use super::{KeyBuilder, SegmentType};

    #[test]
    fn test_new_key_builder() {
        let kb = KeyBuilder::new();
        assert_eq!(kb.key(), "W", "Initial value is set");
    }

    #[test]
    fn test_segments_push() {
        let mut kb = KeyBuilder::new();
        assert_eq!(kb.segments_count(), 0, "No segments so far");
        assert_eq!(kb.key(), "W", "Key for segments is correct");

        kb.push_object_key("first".to_string());
        assert_eq!(kb.segments_count(), 1, "One segment");
        assert_eq!(kb.key(), "W.first", "Key for one segments is correct");

        kb.push_object_key("second".to_string());
        assert_eq!(kb.segments_count(), 2, "Two segments");
        assert_eq!(kb.key(), "W.first.second", "Key for two segments is correct");

        kb.push_array();
        assert_eq!(kb.segments_count(), 3, "Three segments ");
        assert_eq!(kb.key(), "W.first.second$", "Key for three segments is correct");

        kb.push_word("astemmedword".to_string());
        assert_eq!(kb.segments_count(), 4, "Four segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#", "Key for four segments is correct");

        kb.push_doc_seq(123);
        assert_eq!(kb.segments_count(), 5, "Five segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#123",
                   "Key for five segments is correct");
    }

    #[test]
    #[should_panic(expected = "assertion failed: self.segments.len() > 0")]
    fn test_segments_push_doc_seq_panic() {
        let mut kb = KeyBuilder::new();
        kb.push_doc_seq(456);
    }

        #[test]
    #[should_panic(expected = "assertion failed: self.segments.len() > 0")]
    fn test_segments_push_word_panic() {
        let mut kb = KeyBuilder::new();
        kb.push_word("astemmedword".to_string());
    }

    #[test]
    fn test_segments_pop() {
        let mut kb = KeyBuilder::new();
        kb.push_object_key("first".to_string());
        kb.push_object_key("second".to_string());
        kb.push_array();
        kb.push_word("astemmedword".to_string());
        kb.push_doc_seq(123);
        assert_eq!(kb.segments_count(), 5, "Five segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#123",
                   "Key for five segments is correct");

        kb.pop_doc_seq();
        assert_eq!(kb.segments_count(), 4, "Four segments");
        assert_eq!(kb.key(), "W.first.second$!astemmedword#", "Key for four segments is correct");

        kb.pop_word();
        assert_eq!(kb.segments_count(), 3, "Three segments ");
        assert_eq!(kb.key(), "W.first.second$", "Key for three segments is correct");

        kb.pop_array();
        assert_eq!(kb.segments_count(), 2, "Two segments");
        assert_eq!(kb.key(), "W.first.second", "Key for two segments is correct");

        kb.pop_object_key();
        assert_eq!(kb.segments_count(), 1, "One segment");
        assert_eq!(kb.key(), "W.first", "Key for one segments is correct");

        kb.pop_object_key();
        assert_eq!(kb.segments_count(), 0, "No segments so far");
        assert_eq!(kb.key(), "W", "Key for segments is correct");
    }

    #[test]
    fn test_last_pushed_segment_type() {
        let mut kb = KeyBuilder::new();
        assert_eq!(kb.last_pushed_segment_type(), None, "No segments");

        kb.push_object_key("first".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::ObjectKey),
                   "Last segment is an object key");

        kb.push_object_key("second".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::ObjectKey),
                   "Last segment is an object key");

        kb.push_array();
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::Array),
                   "Last segment is an array");

        kb.push_word("astemmedword".to_string());
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::Word),
                   "Last segment is a word");

        kb.push_doc_seq(123);
        assert_eq!(kb.last_pushed_segment_type(), Some(SegmentType::DocSeq),
                   "Last segment is a doc sequence");
    }
}
<|endoftext|>


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

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! # #![feature(rustc_private)]
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     write!(t, "hello, ").unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     writeln!(t, "world!").unwrap();
//!
//!     assert!(t.reset().unwrap());
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       html_playground_url = "https://play.rust-lang.org/",
       test(attr(deny(warnings))))]
#![deny(missing_docs)]

#![cfg_attr(windows, feature(libc))]
// Handle rustfmt skips
#![feature(custom_attribute)]
#![allow(unused_attributes)]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stdout terminals.
pub type StdoutTerminal = dyn Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = dyn Terminal<Output = Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout())
        .map(|t| Box::new(t) as Box<StdoutTerminal>)
        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr())
        .map(|t| Box::new(t) as Box<StderrTerminal>)
        .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
}

/// Terminal color definitions
#[allow(missing_docs)]
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK: Color = 0;
    pub const RED: Color = 1;
    pub const GREEN: Color = 2;
    pub const YELLOW: Color = 3;
    pub const BLUE: Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN: Color = 6;
    pub const WHITE: Color = 7;

    pub const BRIGHT_BLACK: Color = 8;
    pub const BRIGHT_RED: Color = 9;
    pub const BRIGHT_GREEN: Color = 10;
    pub const BRIGHT_YELLOW: Color = 11;
    pub const BRIGHT_BLUE: Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN: Color = 14;
    pub const BRIGHT_WHITE: Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color),
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: Attr) -> io::Result<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and colors to their defaults.
    ///
    /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
    /// was an I/O error.
    ///
    /// *Note: This does not flush.*
    ///
    /// That means the reset command may get buffered so, if you aren't planning on doing anything
    /// else that might flush stdout's buffer (e.g. writing a line of text), you should flush after
    /// calling reset.
    fn reset(&mut self) -> io::Result<bool>;

    /// Gets an immutable reference to the stream inside
    fn get_ref(&self) -> &Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut(&mut self) -> &mut Self::Output;

    /// Returns the contained stream, destroying the `Terminal`
    fn into_inner(self) -> Self::Output where Self: Sized;
}
<commit_msg>[nll] libterm: enable feature(nll) for bootstrap<commit_after>// Copyright 2013-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.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! # #![feature(rustc_private)]
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     write!(t, "hello, ").unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     writeln!(t, "world!").unwrap();
//!
//!     assert!(t.reset().unwrap());
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       html_playground_url = "https://play.rust-lang.org/",
       test(attr(deny(warnings))))]
#![deny(missing_docs)]

#![cfg_attr(windows, feature(libc))]
// Handle rustfmt skips
#![feature(custom_attribute)]
#![cfg_attr(not(stage0), feature(nll))]
#![allow(unused_attributes)]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stdout terminals.
pub type StdoutTerminal = dyn Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = dyn Terminal<Output = Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout())
        .map(|t| Box::new(t) as Box<StdoutTerminal>)
        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr())
        .map(|t| Box::new(t) as Box<StderrTerminal>)
        .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
}

/// Terminal color definitions
#[allow(missing_docs)]
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK: Color = 0;
    pub const RED: Color = 1;
    pub const GREEN: Color = 2;
    pub const YELLOW: Color = 3;
    pub const BLUE: Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN: Color = 6;
    pub const WHITE: Color = 7;

    pub const BRIGHT_BLACK: Color = 8;
    pub const BRIGHT_RED: Color = 9;
    pub const BRIGHT_GREEN: Color = 10;
    pub const BRIGHT_YELLOW: Color = 11;
    pub const BRIGHT_BLUE: Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN: Color = 14;
    pub const BRIGHT_WHITE: Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color),
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: Attr) -> io::Result<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and colors to their defaults.
    ///
    /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
    /// was an I/O error.
    ///
    /// *Note: This does not flush.*
    ///
    /// That means the reset command may get buffered so, if you aren't planning on doing anything
    /// else that might flush stdout's buffer (e.g. writing a line of text), you should flush after
    /// calling reset.
    fn reset(&mut self) -> io::Result<bool>;

    /// Gets an immutable reference to the stream inside
    fn get_ref(&self) -> &Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut(&mut self) -> &mut Self::Output;

    /// Returns the contained stream, destroying the `Terminal`
    fn into_inner(self) -> Self::Output where Self: Sized;
}
<|endoftext|>