<commit_before>extern crate termion;
extern crate rustc_serialize;
extern crate hyper;

use rustc_serialize::base64::{self, ToBase64};
use rustc_serialize::hex::FromHex;

use std::fs::File;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Read;

use termion::style;

use self::hyper::Client;
use self::hyper::header::Connection;

fn imgcat(buffer: Vec<u8>, size_key: &str, size_value: usize) -> String {
    let e = buffer.as_slice().to_base64(base64::STANDARD);
    return String::from(format!("\x1b]1337;File=inline=1;{size_key}={size_value};:{code}\x07", size_key = size_key, size_value = size_value, code = e));
}

pub fn imgcatFromPath(path: &str, width: usize) -> String {
    let mut f = match File::open(path) {
        Err(why) => panic!("couldn't open: {}", why),
        Ok(file) => file,
    };
    let mut buffer = Vec::new();
    f.read_to_end(&mut buffer);

    return imgcat(buffer, &"width", width);
}

pub fn imgcatFromUrl(url: &str, height: usize) -> String {
    let mut c = Client::new();
    return match c.get(url).send() {
        Ok(mut resp) => {
                let mut buffer = Vec::new();
                resp.read_to_end(&mut buffer);
                return imgcat(buffer, &"height", height);
            }
        Err(e) => String::from("[IMG FAIL]")
    }
}

pub fn reset_screen() {
    print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
}

pub fn clear_screen () {
    print!("{}", termion::clear::All);
}
<commit_msg>screen common - imgcatFromUrl - load from cache directly<commit_after>extern crate termion;
extern crate rustc_serialize;
extern crate hyper;

use rustc_serialize::base64::{self, ToBase64};
use rustc_serialize::hex::FromHex;

use std::fs::File;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Read;

use termion::style;

use self::hyper::Client;
use self::hyper::header::Connection;

fn imgcat(buffer: Vec<u8>, size_key: &str, size_value: usize) -> String {
    let e = buffer.as_slice().to_base64(base64::STANDARD);
    return String::from(format!("\x1b]1337;File=inline=1;{size_key}={size_value};:{code}\x07", size_key = size_key, size_value = size_value, code = e));
}

pub fn imgcatFromPath(path: &str, width: usize) -> String {
    let mut f = match File::open(path) {
        Err(why) => panic!("couldn't open: {}", why),
        Ok(file) => file,
    };
    let mut buffer = Vec::new();
    f.read_to_end(&mut buffer);

    return imgcat(buffer, &"width", width);
}

pub fn imgcatFromUrl(url: &str, height: usize) -> String {
    let key = url.to_string().into_bytes().to_base64(base64::URL_SAFE);
    let path = format!("data/img/{file_name}", file_name = key);

    return match File::open(path) {
        // Err(why) => String::from(format!("[{url}]", url = url)),
        Err(why) => String::from(format!("[{code}]", code = why)),
        Ok(mut file) => {
            let mut buffer = Vec::new();
            file.read_to_end(&mut buffer);
            return imgcat(buffer, &"height", height);
        },
    };
}

pub fn reset_screen() {
    print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
}

pub fn clear_screen () {
    print!("{}", termion::clear::All);
}
<|endoftext|>


<commit_before>use std::{fmt, iter};
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use geom::{Geom, Point, Size, Matrix};

pub type Hint = Option<u8>;
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Side { In, Out }
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Edge { Line, Cross }

#[derive(Clone, Show, Eq, PartialEq)]
pub struct Board {
    size: Size,
    hint: Matrix<Hint>,
    side: Matrix<Option<Side>>,
    edge_v: Matrix<Option<Edge>>,
    edge_h: Matrix<Option<Edge>>
}

impl Board {
    pub fn new(size: Size) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new_empty(size, None, None);
        let side = Matrix::new_empty(size, Some(Side::Out), None);
        let edge_v = Matrix::new_empty(Size(size.0, size.1 + 1), Some(Edge::Cross), None);
        let edge_h = Matrix::new_empty(Size(size.0 + 1, size.1), Some(Edge::Cross), None);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    fn with_data(size: Size, hint: Vec<Hint>, side: Vec<Option<Side>>,
                 edge_v: Vec<Option<Edge>>, edge_h: Vec<Option<Edge>>) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new(size, None, hint);
        let side = Matrix::new(size, Some(Side::Out), side);
        let edge_v = Matrix::new(Size(size.0, size.1 + 1), Some(Edge::Cross), edge_v);
        let edge_h = Matrix::new(Size(size.0 + 1, size.1), Some(Edge::Cross), edge_h);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    pub fn hint(&self) -> &Matrix<Hint> { &self.hint }
    pub fn side(&self) -> &Matrix<Option<Side>> { &self.side }
    pub fn edge_h(&self) -> &Matrix<Option<Edge>> { &self.edge_h }
    pub fn edge_v(&self) -> &Matrix<Option<Edge>> { &self.edge_v }

    pub fn hint_mut(&mut self) -> &mut Matrix<Hint> { &mut self.hint }
    pub fn side_mut(&mut self) -> &mut Matrix<Option<Side>> { &mut self.side }
    pub fn edge_h_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_h }
    pub fn edge_v_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_v }
}

impl Geom for Board {
    fn size(&self) -> Size { self.size }
}

impl Index<Point> for Board {
    type Output = Hint;

    fn index(&self, p: &Point) -> &Hint {
        &self.hint[*p]
    }
}

impl IndexMut<Point> for Board {
    type Output = Hint;

    fn index_mut(&mut self, p: &Point) -> &mut Hint {
        &mut self.hint[*p]
    }
}

impl FromStr for Board {
    fn from_str(s: &str) -> Option<Board> {
        let mut mat = s.lines()
            .map(|l| l.trim_matches('\n'))
            .map(|l| l.chars().collect::<Vec<_>>())
            .skip_while(|l| l.is_empty())
            .collect::<Vec<_>>();

        while mat.last().map(|l| l.len()) == Some(0) {
            let _ = mat.pop();
        }

        if mat.len() == 0 { return None }

        fn parse_pat1(mat: Vec<Vec<char>>) -> Option<Board> {
            let rows = mat.iter()
                .enumerate()
                .filter(|&(_, cs)| cs[0] == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();
            let cols = mat[rows[0]].iter()
                .enumerate()
                .filter(|&(_, &c)| c == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            for &r in rows.iter() {
                if mat[r].iter().position(|&c| c == '+') != Some(cols[0]) {
                    return None
                }
                if mat[r].iter().rposition(|&c| c == '+') != Some(cols[cols.len() - 1]) {
                    return None
                }
                for &c in cols.iter() {
                    if mat[r].len() <= c {
                        return None
                    }
                    if mat[r][c] != '+' {
                        return None
                    }
                }
            }

            let mut edge_v = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for &c in cols.iter() {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .map(|row| if c < row.len() { row[c] } else { ' ' })
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '|') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_v.push(edge);
                }
            }

            let mut edge_h = vec!{};
            for &r in rows.iter() {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[r][cs + 1 .. ce]
                        .iter()
                        .cloned()
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '-') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_h.push(edge);
                }
            }

            let mut hint = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .flat_map(|row| row[cs + 1 .. ce].iter())
                        .cloned()
                        .collect::<String>();
                    let cell = match s.trim_matches(' ') {
                        "0" => Some(0),
                        "1" => Some(1),
                        "2" => Some(2),
                        "3" => Some(3),
                        _ => None
                    };
                    hint.push(cell);
                }
            }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);
            let side = iter::repeat(None).take((rows.len() - 1) * (cols.len() - 1)).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        fn parse_pat2(mat: Vec<Vec<char>>) -> Option<Board> {
            let row = mat.len();
            if row == 0 { return None }
            let col = mat[0].len();
            if col == 0 { return None }
            if mat[1 ..].iter().any(|r| r.len() != col) { return None }

            let hint = mat.iter().flat_map(|line| {
                line.iter().filter_map(|&c| {
                    match c {
                        '0' => Some(Some(0)),
                        '1' => Some(Some(1)),
                        '2' => Some(Some(2)),
                        '3' => Some(Some(3)),
                        '_' => Some(None),
                        _ => None
                    }
                })
            }).collect::<Vec<_>>();
            if hint.len() != row * col { return None }

            let size = Size(row as i32, col as i32);
            let side = iter::repeat(None).take(row * col).collect();
            let edge_v = iter::repeat(None).take(row * (col + 1)).collect();
            let edge_h = iter::repeat(None).take((row + 1) * col).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        if mat[0].iter().any(|&c| c == '+') {
            parse_pat1(mat)
        } else {
            parse_pat2(mat)
        }
    }
}

struct Cross;
impl fmt::String for Cross {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "+")
    }
}

struct HEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for HEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let HEdge(board, p) = *self;
        match board.edge_h[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "-")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct VEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for VEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let VEdge(board, p) = *self;
        match board.edge_v[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "|")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct EdgeRow<'a>(&'a Board, i32);
impl<'a> fmt::String for EdgeRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let EdgeRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", Cross));
            try!(write!(f, "{}", HEdge(board, p)));
        }
        try!(write!(f, "{}", Cross));
        Ok(())
    }
}

struct CellRow<'a>(&'a Board, i32);
impl<'a> fmt::String for CellRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let CellRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", VEdge(board, p)));
            match board.hint[p] {
                Some(n) => try!(write!(f, "{}", n)),
                None => try!(write!(f, " "))
            }
        }
        try!(write!(f, "{}", VEdge(board, Point(r, board.column()))));
        Ok(())
    }
}

impl fmt::String for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for r in (0 .. self.row()) {
            try!(writeln!(f, "{}", EdgeRow(self, r)));
            try!(writeln!(f, "{}", CellRow(self, r)));
        }
        try!(writeln!(f, "{}", EdgeRow(self, self.row())));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::Board;
    use geom::{Geom, Size, Point};

    #[test]
    fn parse() {
        let input = "123___
______
3_____
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Size(3, 6), hint.size());
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
        assert_eq!(None, hint[Point(0, 3)]);
        assert_eq!(None, hint[Point(0, 4)]);
        assert_eq!(None, hint[Point(0, 5)]);
        assert_eq!(None, hint[Point(1, 0)]);
        assert_eq!(None, hint[Point(1, 1)]);
        assert_eq!(None, hint[Point(1, 2)]);
        assert_eq!(None, hint[Point(1, 3)]);
        assert_eq!(None, hint[Point(1, 4)]);
        assert_eq!(None, hint[Point(1, 5)]);
        assert_eq!(Some(3), hint[Point(2, 0)]);
        assert_eq!(None, hint[Point(2, 1)]);
        assert_eq!(None, hint[Point(2, 2)]);
        assert_eq!(None, hint[Point(2, 3)]);
        assert_eq!(None, hint[Point(2, 4)]);
        assert_eq!(None, hint[Point(2, 5)]);

        assert_eq!(Some(&hint), hint.to_string().parse::<Board>().as_ref());

        assert_eq!(None, "1243".parse::<Board>());

        let input = "
+--+ +-+!!+asdf
+  + + +  +
|  |1|    |
|  | |  2 |
+  + + +  +
";
        let output = "+-+ +-+ +

+ + + + +
| |1|  2|
+ + + + +
";

        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(1, 1)]);
        assert_eq!(Some(2), hint[Point(1, 3)]);
        assert_eq!(output, hint.to_string());

        assert_eq!(None, "".parse::<Board>());

        let input = "
+ + + +
 1 2 3
+ + + +
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
    }
}
<commit_msg>board: Support hyphens<commit_after>use std::{fmt, iter};
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use geom::{Geom, Point, Size, Matrix};

pub type Hint = Option<u8>;
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Side { In, Out }
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Edge { Line, Cross }

#[derive(Clone, Show, Eq, PartialEq)]
pub struct Board {
    size: Size,
    hint: Matrix<Hint>,
    side: Matrix<Option<Side>>,
    edge_v: Matrix<Option<Edge>>,
    edge_h: Matrix<Option<Edge>>
}

impl Board {
    pub fn new(size: Size) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new_empty(size, None, None);
        let side = Matrix::new_empty(size, Some(Side::Out), None);
        let edge_v = Matrix::new_empty(Size(size.0, size.1 + 1), Some(Edge::Cross), None);
        let edge_h = Matrix::new_empty(Size(size.0 + 1, size.1), Some(Edge::Cross), None);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    fn with_data(size: Size, hint: Vec<Hint>, side: Vec<Option<Side>>,
                 edge_v: Vec<Option<Edge>>, edge_h: Vec<Option<Edge>>) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new(size, None, hint);
        let side = Matrix::new(size, Some(Side::Out), side);
        let edge_v = Matrix::new(Size(size.0, size.1 + 1), Some(Edge::Cross), edge_v);
        let edge_h = Matrix::new(Size(size.0 + 1, size.1), Some(Edge::Cross), edge_h);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    pub fn hint(&self) -> &Matrix<Hint> { &self.hint }
    pub fn side(&self) -> &Matrix<Option<Side>> { &self.side }
    pub fn edge_h(&self) -> &Matrix<Option<Edge>> { &self.edge_h }
    pub fn edge_v(&self) -> &Matrix<Option<Edge>> { &self.edge_v }

    pub fn hint_mut(&mut self) -> &mut Matrix<Hint> { &mut self.hint }
    pub fn side_mut(&mut self) -> &mut Matrix<Option<Side>> { &mut self.side }
    pub fn edge_h_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_h }
    pub fn edge_v_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_v }
}

impl Geom for Board {
    fn size(&self) -> Size { self.size }
}

impl Index<Point> for Board {
    type Output = Hint;

    fn index(&self, p: &Point) -> &Hint {
        &self.hint[*p]
    }
}

impl IndexMut<Point> for Board {
    type Output = Hint;

    fn index_mut(&mut self, p: &Point) -> &mut Hint {
        &mut self.hint[*p]
    }
}

impl FromStr for Board {
    fn from_str(s: &str) -> Option<Board> {
        let mut mat = s.lines()
            .map(|l| l.trim_matches('\n'))
            .map(|l| l.chars().collect::<Vec<_>>())
            .skip_while(|l| l.is_empty())
            .collect::<Vec<_>>();

        while mat.last().map(|l| l.len()) == Some(0) {
            let _ = mat.pop();
        }

        if mat.len() == 0 { return None }

        fn parse_pat1(mat: Vec<Vec<char>>) -> Option<Board> {
            let rows = mat.iter()
                .enumerate()
                .filter(|&(_, cs)| cs[0] == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();
            let cols = mat[rows[0]].iter()
                .enumerate()
                .filter(|&(_, &c)| c == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            for &r in rows.iter() {
                if mat[r].iter().position(|&c| c == '+') != Some(cols[0]) {
                    return None
                }
                if mat[r].iter().rposition(|&c| c == '+') != Some(cols[cols.len() - 1]) {
                    return None
                }
                for &c in cols.iter() {
                    if mat[r].len() <= c {
                        return None
                    }
                    if mat[r][c] != '+' {
                        return None
                    }
                }
            }

            let mut edge_v = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for &c in cols.iter() {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .map(|row| if c < row.len() { row[c] } else { ' ' })
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '|') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_v.push(edge);
                }
            }

            let mut edge_h = vec!{};
            for &r in rows.iter() {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[r][cs + 1 .. ce]
                        .iter()
                        .cloned()
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '-') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_h.push(edge);
                }
            }

            let mut hint = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .flat_map(|row| row[cs + 1 .. ce].iter())
                        .cloned()
                        .collect::<String>();
                    let cell = match s.trim_matches(' ') {
                        "0" => Some(0),
                        "1" => Some(1),
                        "2" => Some(2),
                        "3" => Some(3),
                        _ => None
                    };
                    hint.push(cell);
                }
            }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);
            let side = iter::repeat(None).take((rows.len() - 1) * (cols.len() - 1)).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        fn parse_pat2(mat: Vec<Vec<char>>) -> Option<Board> {
            let row = mat.len();
            if row == 0 { return None }
            let col = mat[0].len();
            if col == 0 { return None }
            if mat[1 ..].iter().any(|r| r.len() != col) { return None }

            let hint = mat.iter().flat_map(|line| {
                line.iter().filter_map(|&c| {
                    match c {
                        '0' => Some(Some(0)),
                        '1' => Some(Some(1)),
                        '2' => Some(Some(2)),
                        '3' => Some(Some(3)),
                        '_' | '-' => Some(None),
                        _ => None
                    }
                })
            }).collect::<Vec<_>>();
            if hint.len() != row * col { return None }

            let size = Size(row as i32, col as i32);
            let side = iter::repeat(None).take(row * col).collect();
            let edge_v = iter::repeat(None).take(row * (col + 1)).collect();
            let edge_h = iter::repeat(None).take((row + 1) * col).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        if mat[0].iter().any(|&c| c == '+') {
            parse_pat1(mat)
        } else {
            parse_pat2(mat)
        }
    }
}

struct Cross;
impl fmt::String for Cross {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "+")
    }
}

struct HEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for HEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let HEdge(board, p) = *self;
        match board.edge_h[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "-")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct VEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for VEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let VEdge(board, p) = *self;
        match board.edge_v[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "|")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct EdgeRow<'a>(&'a Board, i32);
impl<'a> fmt::String for EdgeRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let EdgeRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", Cross));
            try!(write!(f, "{}", HEdge(board, p)));
        }
        try!(write!(f, "{}", Cross));
        Ok(())
    }
}

struct CellRow<'a>(&'a Board, i32);
impl<'a> fmt::String for CellRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let CellRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", VEdge(board, p)));
            match board.hint[p] {
                Some(n) => try!(write!(f, "{}", n)),
                None => try!(write!(f, " "))
            }
        }
        try!(write!(f, "{}", VEdge(board, Point(r, board.column()))));
        Ok(())
    }
}

impl fmt::String for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for r in (0 .. self.row()) {
            try!(writeln!(f, "{}", EdgeRow(self, r)));
            try!(writeln!(f, "{}", CellRow(self, r)));
        }
        try!(writeln!(f, "{}", EdgeRow(self, self.row())));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::Board;
    use geom::{Geom, Size, Point};

    #[test]
    fn parse() {
        let input = "123___
______
3_____
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Size(3, 6), hint.size());
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
        assert_eq!(None, hint[Point(0, 3)]);
        assert_eq!(None, hint[Point(0, 4)]);
        assert_eq!(None, hint[Point(0, 5)]);
        assert_eq!(None, hint[Point(1, 0)]);
        assert_eq!(None, hint[Point(1, 1)]);
        assert_eq!(None, hint[Point(1, 2)]);
        assert_eq!(None, hint[Point(1, 3)]);
        assert_eq!(None, hint[Point(1, 4)]);
        assert_eq!(None, hint[Point(1, 5)]);
        assert_eq!(Some(3), hint[Point(2, 0)]);
        assert_eq!(None, hint[Point(2, 1)]);
        assert_eq!(None, hint[Point(2, 2)]);
        assert_eq!(None, hint[Point(2, 3)]);
        assert_eq!(None, hint[Point(2, 4)]);
        assert_eq!(None, hint[Point(2, 5)]);

        assert_eq!(Some(&hint), hint.to_string().parse::<Board>().as_ref());

        assert_eq!(None, "1243".parse::<Board>());

        let input = "
+--+ +-+!!+asdf
+  + + +  +
|  |1|    |
|  | |  2 |
+  + + +  +
";
        let output = "+-+ +-+ +

+ + + + +
| |1|  2|
+ + + + +
";

        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(1, 1)]);
        assert_eq!(Some(2), hint[Point(1, 3)]);
        assert_eq!(output, hint.to_string());

        assert_eq!(None, "".parse::<Board>());

        let input = "
+ + + +
 1 2 3
+ + + +
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
    }
}
<|endoftext|>


<commit_before>
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use std::collections::HashMap;
use std::time::{Instant, Duration};

pub struct Registry<Id> {
    /// A worker-specific identifier.
    id: Id,
    /// A map from names to typed loggers.
    map: HashMap<String, (Box<Any>, Box<Flush>)>,
    /// An instant common to all logging statements.
    time: Instant,
}

impl<Id: Clone+'static> Registry<Id> {
    /// Binds a log name to an action on log event batches.
    ///
    /// This method also returns any pre-installed action, rather than overwriting it
    /// and pivoting the logging destination mid-stream. New loggers with this name will
    /// use the new destination, and existing loggers will use the old destination.
    ///
    /// The action should respond to a sequence of events with non-decreasing timestamps
    /// (Durations) and well as a timestamp that lower bounds the next event that could be
    /// seen (likely greater or equal to the timestamp of the last event). The end of a
    /// logging stream is indicated only by dropping the associated action, which can be
    /// accomplished with `remove` (or a call to insert, though this is not recommended).
    pub fn insert<T: 'static, F: FnMut(&Duration, &mut Vec<(Duration, Id, T)>)+'static>(
        &mut self,
        name: &str,
        action: F) -> Option<Box<Any>>
    {
        let logger = Logger::<T, Id>::new(self.time.clone(), self.id.clone(), action);
        self.map.insert(name.to_owned(), (Box::new(logger.clone()), Box::new(logger))).map(|x| x.0)
    }

    /// Removes a bound logger.
    ///
    /// This is intended primarily to close a logging stream and let the associated writer
    /// communicate that the stream is closed to any consumers. If a binding is not removed,
    /// then the stream cannot be complete as in principle anyone could acquire a handle to
    /// the logger and start further logging.
    pub fn remove(&mut self, name: &str) -> Option<Box<Any>> {
        self.map.remove(name).map(|x| x.0)
    }

    /// Retrieves a shared logger, if one has been inserted.
    pub fn get<T: 'static>(&self, name: &str) -> Option<Logger<T, Id>> {
        self.map
            .get(name)
            .and_then(|entry| entry.0.downcast_ref::<Logger<T, Id>>())
            .map(|x| (*x).clone())
    }

    /// Creates a new logger registry.
    pub fn new(time: Instant, id: Id) -> Self {
        Registry {
            id,
            time,
            map: HashMap::new(),
        }
    }

    /// Flushes all registered logs.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

impl<Id> Flush for Registry<Id> {
    fn flush(&mut self) {
        for value in self.map.values_mut() {
            value.1.flush();
        }
    }
}

/// A buffering logger.
pub struct Logger<T, E> {
    id:     E,
    time:   Instant,                                                    // common instant used for all loggers.
    action: Rc<RefCell<FnMut(&Duration, &mut Vec<(Duration, E, T)>)>>,  // action to take on full log buffers.
    buffer: Rc<RefCell<Vec<(Duration, E, T)>>>,                         // shared buffer; not obviously best design.
}

impl<T, E: Clone> Clone for Logger<T, E> {
    fn clone(&self) -> Self {
        Logger {
            id: self.id.clone(),
            time: self.time,
            action: self.action.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

impl<T, E: Clone> Logger<T, E> {
    /// Allocates a new shareable logger bound to a write destination.
    pub fn new<F>(time: Instant, id: E, action: F) -> Self
    where
        F: FnMut(&Duration, &mut Vec<(Duration, E, T)>)+'static
    {
        Logger {
            id,
            time,
            action: Rc::new(RefCell::new(action)),
            buffer: Rc::new(RefCell::new(Vec::with_capacity(1024))),
        }
    }

    /// Logs an event.
    ///
    /// The event has its timestamp recorded at the moment of logging, but it may be delayed
    /// due to buffering. It will be written when the logger is next flushed, either due to
    /// the buffer reaching capacity or a direct call to flush.
    ///
    /// This implementation borrows a shared (but thread-local) buffer of log events, to ensure
    /// that the `action` only sees one stream of events with increasing timestamps. This may
    /// have a cost that we don't entirely understand.
    pub fn log<S: Into<T>>(&self, event: S) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.push((self.time.elapsed(), self.id.clone(), event.into()));
        if buffer.len() == buffer.capacity() {
            // Would call `self.flush()`, but for `RefCell` panic.
            let mut action = self.action.borrow_mut();
            let action = &mut *action;
            (*action)(&self.time.elapsed(), &mut *buffer);
            buffer.clear();
            buffer.reserve(1024);
        }
    }

    /// Flushes logged messages and communicates the new minimal timestamp.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

/// Bit weird, because we only have to flush on the *last* drop, but this should be ok.
impl<T, E> Drop for Logger<T, E> {
    fn drop(&mut self) { self.flush(); }
}

/// Types that can be flushed.
trait Flush {
    /// Flushes buffered data.
    fn flush(&mut self);
}

impl<T, E> Flush for Logger<T, E> {
    fn flush(&mut self) {
        let mut buffer = self.buffer.borrow_mut();
        let mut action = self.action.borrow_mut();
        let action = &mut *action;
        (*action)(&self.time.elapsed(), &mut *buffer);
        buffer.clear();
        buffer.reserve(1024);
    }
}<commit_msg>Add logging::Registry::insert_logger<commit_after>
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use std::collections::HashMap;
use std::time::{Instant, Duration};

pub struct Registry<Id> {
    /// A worker-specific identifier.
    id: Id,
    /// A map from names to typed loggers.
    map: HashMap<String, (Box<Any>, Box<Flush>)>,
    /// An instant common to all logging statements.
    time: Instant,
}

impl<Id: Clone+'static> Registry<Id> {
    /// Binds a log name to an action on log event batches. See
    /// `insert_closure`.
    pub fn insert<T: 'static, F: FnMut(&Duration, &mut Vec<(Duration, Id, T)>)+'static>(
        &mut self,
        name: &str,
        action: F) -> Option<Box<Any>>
    {
        self.insert_closure(name, action)
    }

    /// Binds a log name to an action on log event batches.
    ///
    /// This method also returns any pre-installed action, rather than overwriting it
    /// and pivoting the logging destination mid-stream. New loggers with this name will
    /// use the new destination, and existing loggers will use the old destination.
    ///
    /// The action should respond to a sequence of events with non-decreasing timestamps
    /// (Durations) and well as a timestamp that lower bounds the next event that could be
    /// seen (likely greater or equal to the timestamp of the last event). The end of a
    /// logging stream is indicated only by dropping the associated action, which can be
    /// accomplished with `remove` (or a call to insert, though this is not recommended).
    pub fn insert_closure<T: 'static, F: FnMut(&Duration, &mut Vec<(Duration, Id, T)>)+'static>(
        &mut self,
        name: &str,
        action: F) -> Option<Box<Any>>
    {
        let logger = Logger::<T, Id>::new(self.time.clone(), self.id.clone(), action);
        self.insert_logger(name, logger)
    }

    /// Binds a log name to a logger.
    pub fn insert_logger<T: 'static>(
        &mut self,
        name: &str,
        logger: Logger<T, Id>) -> Option<Box<Any>>
    {
        self.map.insert(name.to_owned(), (Box::new(logger.clone()), Box::new(logger))).map(|x| x.0)
    }

    /// Removes a bound logger.
    ///
    /// This is intended primarily to close a logging stream and let the associated writer
    /// communicate that the stream is closed to any consumers. If a binding is not removed,
    /// then the stream cannot be complete as in principle anyone could acquire a handle to
    /// the logger and start further logging.
    pub fn remove(&mut self, name: &str) -> Option<Box<Any>> {
        self.map.remove(name).map(|x| x.0)
    }

    /// Retrieves a shared logger, if one has been inserted.
    pub fn get<T: 'static>(&self, name: &str) -> Option<Logger<T, Id>> {
        self.map
            .get(name)
            .and_then(|entry| entry.0.downcast_ref::<Logger<T, Id>>())
            .map(|x| (*x).clone())
    }

    /// Creates a new logger registry.
    pub fn new(time: Instant, id: Id) -> Self {
        Registry {
            id,
            time,
            map: HashMap::new(),
        }
    }

    /// Flushes all registered logs.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

impl<Id> Flush for Registry<Id> {
    fn flush(&mut self) {
        for value in self.map.values_mut() {
            value.1.flush();
        }
    }
}

/// A buffering logger.
pub struct Logger<T, E> {
    id:     E,
    time:   Instant,                                                    // common instant used for all loggers.
    action: Rc<RefCell<FnMut(&Duration, &mut Vec<(Duration, E, T)>)>>,  // action to take on full log buffers.
    buffer: Rc<RefCell<Vec<(Duration, E, T)>>>,                         // shared buffer; not obviously best design.
}

impl<T, E: Clone> Clone for Logger<T, E> {
    fn clone(&self) -> Self {
        Logger {
            id: self.id.clone(),
            time: self.time,
            action: self.action.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

impl<T, E: Clone> Logger<T, E> {
    /// Allocates a new shareable logger bound to a write destination.
    pub fn new<F>(time: Instant, id: E, action: F) -> Self
    where
        F: FnMut(&Duration, &mut Vec<(Duration, E, T)>)+'static
    {
        Logger {
            id,
            time,
            action: Rc::new(RefCell::new(action)),
            buffer: Rc::new(RefCell::new(Vec::with_capacity(1024))),
        }
    }

    /// Logs an event.
    ///
    /// The event has its timestamp recorded at the moment of logging, but it may be delayed
    /// due to buffering. It will be written when the logger is next flushed, either due to
    /// the buffer reaching capacity or a direct call to flush.
    ///
    /// This implementation borrows a shared (but thread-local) buffer of log events, to ensure
    /// that the `action` only sees one stream of events with increasing timestamps. This may
    /// have a cost that we don't entirely understand.
    pub fn log<S: Into<T>>(&self, event: S) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.push((self.time.elapsed(), self.id.clone(), event.into()));
        if buffer.len() == buffer.capacity() {
            // Would call `self.flush()`, but for `RefCell` panic.
            let mut action = self.action.borrow_mut();
            let action = &mut *action;
            (*action)(&self.time.elapsed(), &mut *buffer);
            buffer.clear();
            buffer.reserve(1024);
        }
    }

    /// Flushes logged messages and communicates the new minimal timestamp.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

/// Bit weird, because we only have to flush on the *last* drop, but this should be ok.
impl<T, E> Drop for Logger<T, E> {
    fn drop(&mut self) { self.flush(); }
}

/// Types that can be flushed.
trait Flush {
    /// Flushes buffered data.
    fn flush(&mut self);
}

impl<T, E> Flush for Logger<T, E> {
    fn flush(&mut self) {
        let mut buffer = self.buffer.borrow_mut();
        let mut action = self.action.borrow_mut();
        let action = &mut *action;
        (*action)(&self.time.elapsed(), &mut *buffer);
        buffer.clear();
        buffer.reserve(1024);
    }
}
<|endoftext|>


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

pub use self::Def::*;

use middle::def_id::DefId;
use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
use util::nodemap::NodeMap;
use syntax::ast;
use rustc_front::hir;

use std::cell::RefCell;

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
    DefFn(DefId, bool /* is_ctor */),
    DefSelfTy(Option<DefId>,                    // trait id
              Option<(ast::NodeId, ast::NodeId)>),   // (impl id, self type id)
    DefMod(DefId),
    DefForeignMod(DefId),
    DefStatic(DefId, bool /* is_mutbl */),
    DefConst(DefId),
    DefAssociatedConst(DefId),
    DefLocal(ast::NodeId),
    DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
    DefTy(DefId, bool /* is_enum */),
    DefAssociatedTy(DefId /* trait */, DefId),
    DefTrait(DefId),
    DefPrimTy(hir::PrimTy),
    DefTyParam(ParamSpace, u32, DefId, ast::Name),
    DefUse(DefId),
    DefUpvar(ast::NodeId,  // id of closed over local
             usize,        // index in the freevars list of the closure
             ast::NodeId), // expr node that creates the closure

    /// Note that if it's a tuple struct's definition, the node id of the DefId
    /// may either refer to the item definition's id or the StructDef.ctor_id.
    ///
    /// The cases that I have encountered so far are (this is not exhaustive):
    /// - If it's a ty_path referring to some tuple struct, then DefMap maps
    ///   it to a def whose id is the item definition's id.
    /// - If it's an ExprPath referring to some tuple struct, then DefMap maps
    ///   it to a def whose id is the StructDef.ctor_id.
    DefStruct(DefId),
    DefLabel(ast::NodeId),
    DefMethod(DefId),
}

/// The result of resolving a path.
/// Before type checking completes, `depth` represents the number of
/// trailing segments which are yet unresolved. Afterwards, if there
/// were no errors, all paths should be fully resolved, with `depth`
/// set to `0` and `base_def` representing the final resolution.
///
///     module::Type::AssocX::AssocY::MethodOrAssocType
///     ^~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///     base_def      depth = 3
///
///     <T as Trait>::AssocX::AssocY::MethodOrAssocType
///           ^~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~
///           base_def        depth = 2
#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
    pub base_def: Def,
    pub last_private: LastPrivate,
    pub depth: usize
}

impl PathResolution {
    /// Get the definition, if fully resolved, otherwise panic.
    pub fn full_def(&self) -> Def {
        if self.depth != 0 {
            panic!("path not fully resolved: {:?}", self);
        }
        self.base_def
    }

    /// Get the DefId, if fully resolved, otherwise panic.
    pub fn def_id(&self) -> DefId {
        self.full_def().def_id()
    }

    pub fn new(base_def: Def,
               last_private: LastPrivate,
               depth: usize)
               -> PathResolution {
        PathResolution {
            base_def: base_def,
            last_private: last_private,
            depth: depth,
        }
    }
}

// Definition mapping
pub type DefMap = RefCell<NodeMap<PathResolution>>;
// This is the replacement export map. It maps a module to all of the exports
// within.
pub type ExportMap = NodeMap<Vec<Export>>;

#[derive(Copy, Clone)]
pub struct Export {
    pub name: ast::Name,    // The name of the target.
    pub def_id: DefId, // The definition of the target.
}

impl Def {
    pub fn var_id(&self) -> ast::NodeId {
        match *self {
            DefLocal(id) |
            DefUpvar(id, _, _) => {
                id
            }

            DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
            DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
            DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) |
            DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
            DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => {
                panic!("attempted .def_id() on invalid {:?}", self)
            }
        }
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
            DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
            DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
            DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
            DefSelfTy(Some(id), None)=> {
                id
            }

            DefLocal(id) |
            DefUpvar(id, _, _) |
            DefLabel(id)  |
            DefSelfTy(_, Some((_, id))) => {
                DefId::xxx_local(id) // TODO, clearly
            }

            DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"),
            DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"),
        }
    }

    pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
        match *self {
            DefVariant(enum_id, var_id, _) => {
                Some((enum_id, var_id))
            }
            _ => None
        }
    }
}
<commit_msg>Move DefLabel out from the def_id() results<commit_after>// Copyright 2014 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.

pub use self::Def::*;

use middle::def_id::DefId;
use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
use util::nodemap::NodeMap;
use syntax::ast;
use rustc_front::hir;

use std::cell::RefCell;

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
    DefFn(DefId, bool /* is_ctor */),
    DefSelfTy(Option<DefId>,                    // trait id
              Option<(ast::NodeId, ast::NodeId)>),   // (impl id, self type id)
    DefMod(DefId),
    DefForeignMod(DefId),
    DefStatic(DefId, bool /* is_mutbl */),
    DefConst(DefId),
    DefAssociatedConst(DefId),
    DefLocal(ast::NodeId),
    DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
    DefTy(DefId, bool /* is_enum */),
    DefAssociatedTy(DefId /* trait */, DefId),
    DefTrait(DefId),
    DefPrimTy(hir::PrimTy),
    DefTyParam(ParamSpace, u32, DefId, ast::Name),
    DefUse(DefId),
    DefUpvar(ast::NodeId,  // id of closed over local
             usize,        // index in the freevars list of the closure
             ast::NodeId), // expr node that creates the closure

    /// Note that if it's a tuple struct's definition, the node id of the DefId
    /// may either refer to the item definition's id or the StructDef.ctor_id.
    ///
    /// The cases that I have encountered so far are (this is not exhaustive):
    /// - If it's a ty_path referring to some tuple struct, then DefMap maps
    ///   it to a def whose id is the item definition's id.
    /// - If it's an ExprPath referring to some tuple struct, then DefMap maps
    ///   it to a def whose id is the StructDef.ctor_id.
    DefStruct(DefId),
    DefLabel(ast::NodeId),
    DefMethod(DefId),
}

/// The result of resolving a path.
/// Before type checking completes, `depth` represents the number of
/// trailing segments which are yet unresolved. Afterwards, if there
/// were no errors, all paths should be fully resolved, with `depth`
/// set to `0` and `base_def` representing the final resolution.
///
///     module::Type::AssocX::AssocY::MethodOrAssocType
///     ^~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///     base_def      depth = 3
///
///     <T as Trait>::AssocX::AssocY::MethodOrAssocType
///           ^~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~
///           base_def        depth = 2
#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
    pub base_def: Def,
    pub last_private: LastPrivate,
    pub depth: usize
}

impl PathResolution {
    /// Get the definition, if fully resolved, otherwise panic.
    pub fn full_def(&self) -> Def {
        if self.depth != 0 {
            panic!("path not fully resolved: {:?}", self);
        }
        self.base_def
    }

    /// Get the DefId, if fully resolved, otherwise panic.
    pub fn def_id(&self) -> DefId {
        self.full_def().def_id()
    }

    pub fn new(base_def: Def,
               last_private: LastPrivate,
               depth: usize)
               -> PathResolution {
        PathResolution {
            base_def: base_def,
            last_private: last_private,
            depth: depth,
        }
    }
}

// Definition mapping
pub type DefMap = RefCell<NodeMap<PathResolution>>;
// This is the replacement export map. It maps a module to all of the exports
// within.
pub type ExportMap = NodeMap<Vec<Export>>;

#[derive(Copy, Clone)]
pub struct Export {
    pub name: ast::Name,    // The name of the target.
    pub def_id: DefId, // The definition of the target.
}

impl Def {
    pub fn var_id(&self) -> ast::NodeId {
        match *self {
            DefLocal(id) |
            DefUpvar(id, _, _) => {
                id
            }

            DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
            DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
            DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) |
            DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
            DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => {
                panic!("attempted .def_id() on invalid {:?}", self)
            }
        }
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
            DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
            DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
            DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
            DefSelfTy(Some(id), None)=> {
                id
            }

            DefLocal(id) |
            DefUpvar(id, _, _) |
            DefSelfTy(_, Some((_, id))) => {
                DefId::xxx_local(id) // TODO, clearly
            }

            DefLabel(..)  |
            DefPrimTy(..) |
            DefSelfTy(..) => {
                panic!("attempted .def_id() on invalid def: {:?}", self)
            }
        }
    }

    pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
        match *self {
            DefVariant(enum_id, var_id, _) => {
                Some((enum_id, var_id))
            }
            _ => None
        }
    }
}
<|endoftext|>


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

//! Access to a single thread-local pointer.
//!
//! The runtime will use this for storing ~Task.
//!
//! XXX: Add runtime checks for usage of inconsistent pointer types.
//! and for overwriting an existing pointer.

#[allow(dead_code)];

use cast;
use ops::Drop;
use ptr::RawPtr;

#[cfg(windows)]               // mingw-w32 doesn't like thread_local things
#[cfg(target_os = "android")] // see #10686
pub use self::native::*;

#[cfg(not(windows), not(target_os = "android"))]
pub use self::compiled::*;

/// Encapsulates a borrowed value. When this value goes out of scope, the
/// pointer is returned.
pub struct Borrowed<T> {
    priv val: *(),
}

#[unsafe_destructor]
impl<T> Drop for Borrowed<T> {
    fn drop(&mut self) {
        unsafe {
            if self.val.is_null() {
                rtabort!("Aiee, returning null borrowed object!");
            }
            let val: ~T = cast::transmute(self.val);
            put::<T>(val);
            rtassert!(exists());
        }
    }
}

impl<T> Borrowed<T> {
    pub fn get<'a>(&'a mut self) -> &'a mut T {
        unsafe {
            let val_ptr: &mut ~T = cast::transmute(&mut self.val);
            let val_ptr: &'a mut T = *val_ptr;
            val_ptr
        }
    }
}

/// Borrow the thread-local value from thread-local storage.
/// While the value is borrowed it is not available in TLS.
///
/// # Safety note
///
/// Does not validate the pointer type.
#[inline]
pub unsafe fn borrow<T>() -> Borrowed<T> {
    let val: *() = cast::transmute(take::<T>());
    Borrowed {
        val: val,
    }
}

/// Compiled implementation of accessing the runtime local pointer. This is
/// implemented using LLVM's thread_local attribute which isn't necessarily
/// working on all platforms. This implementation is faster, however, so we use
/// it wherever possible.
#[cfg(not(windows), not(target_os = "android"))]
pub mod compiled {
    use cast;
    use option::{Option, Some, None};
    use ptr::RawPtr;
    #[cfg(not(test))] use libc::c_void;

    #[cfg(test)]
    pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;

    #[cfg(not(test))]
    #[thread_local]
    pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void;

    pub fn init() {}

    pub unsafe fn cleanup() {}

    /// Give a pointer to thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn put<T>(sched: ~T) {
        RT_TLS_PTR = cast::transmute(sched)
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn take<T>() -> ~T {
        let ptr = RT_TLS_PTR;
        rtassert!(!ptr.is_null());
        let ptr: ~T = cast::transmute(ptr);
        // can't use `as`, due to type not matching with `cfg(test)`
        RT_TLS_PTR = cast::transmute(0);
        ptr
    }

    /// Optionally take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn try_take<T>() -> Option<~T> {
        let ptr = RT_TLS_PTR;
        if ptr.is_null() {
            None
        } else {
            let ptr: ~T = cast::transmute(ptr);
            // can't use `as`, due to type not matching with `cfg(test)`
            RT_TLS_PTR = cast::transmute(0);
            Some(ptr)
        }
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    /// Leaves the old pointer in TLS for speed.
    #[inline]
    pub unsafe fn unsafe_take<T>() -> ~T {
        cast::transmute(RT_TLS_PTR)
    }

    /// Check whether there is a thread-local pointer installed.
    pub fn exists() -> bool {
        unsafe {
            RT_TLS_PTR.is_not_null()
        }
    }

    pub unsafe fn unsafe_borrow<T>() -> *mut T {
        if RT_TLS_PTR.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        RT_TLS_PTR as *mut T
    }

    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
        if RT_TLS_PTR.is_null() {
            None
        } else {
            Some(RT_TLS_PTR as *mut T)
        }
    }
}

/// Native implementation of having the runtime thread-local pointer. This
/// implementation uses the `thread_local_storage` module to provide a
/// thread-local value.
pub mod native {
    use cast;
    use libc::c_void;
    use option::{Option, Some, None};
    use ptr;
    use ptr::RawPtr;
    use tls = rt::thread_local_storage;

    static mut RT_TLS_KEY: tls::Key = -1;

    /// Initialize the TLS key. Other ops will fail if this isn't executed
    /// first.
    pub fn init() {
        unsafe {
            tls::create(&mut RT_TLS_KEY);
        }
    }

    pub unsafe fn cleanup() {
        rtassert!(RT_TLS_KEY != -1);
        tls::destroy(RT_TLS_KEY);
    }

    /// Give a pointer to thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn put<T>(sched: ~T) {
        let key = tls_key();
        let void_ptr: *mut c_void = cast::transmute(sched);
        tls::set(key, void_ptr);
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn take<T>() -> ~T {
        let key = tls_key();
        let void_ptr: *mut c_void = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        let ptr: ~T = cast::transmute(void_ptr);
        tls::set(key, ptr::mut_null());
        return ptr;
    }

    /// Optionally take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn try_take<T>() -> Option<~T> {
        match maybe_tls_key() {
            Some(key) => {
                let void_ptr: *mut c_void = tls::get(key);
                if void_ptr.is_null() {
                    None
                } else {
                    let ptr: ~T = cast::transmute(void_ptr);
                    tls::set(key, ptr::mut_null());
                    Some(ptr)
                }
            }
            None => None
        }
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    /// Leaves the old pointer in TLS for speed.
    #[inline]
    pub unsafe fn unsafe_take<T>() -> ~T {
        let key = tls_key();
        let void_ptr: *mut c_void = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        let ptr: ~T = cast::transmute(void_ptr);
        return ptr;
    }

    /// Check whether there is a thread-local pointer installed.
    pub fn exists() -> bool {
        unsafe {
            match maybe_tls_key() {
                Some(key) => tls::get(key).is_not_null(),
                None => false
            }
        }
    }

    /// Borrow a mutable reference to the thread-local value
    ///
    /// # Safety Note
    ///
    /// Because this leaves the value in thread-local storage it is possible
    /// For the Scheduler pointer to be aliased
    pub unsafe fn unsafe_borrow<T>() -> *mut T {
        let key = tls_key();
        let void_ptr = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        void_ptr as *mut T
    }

    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
        match maybe_tls_key() {
            Some(key) => {
                let void_ptr = tls::get(key);
                if void_ptr.is_null() {
                    None
                } else {
                    Some(void_ptr as *mut T)
                }
            }
            None => None
        }
    }

    #[inline]
    fn tls_key() -> tls::Key {
        match maybe_tls_key() {
            Some(key) => key,
            None => rtabort!("runtime tls key not initialized")
        }
    }

    #[inline]
    #[cfg(not(test))]
    pub fn maybe_tls_key() -> Option<tls::Key> {
        unsafe {
            // NB: This is a little racy because, while the key is
            // initalized under a mutex and it's assumed to be initalized
            // in the Scheduler ctor by any thread that needs to use it,
            // we are not accessing the key under a mutex.  Threads that
            // are not using the new Scheduler but still *want to check*
            // whether they are running under a new Scheduler may see a 0
            // value here that is in the process of being initialized in
            // another thread. I think this is fine since the only action
            // they could take if it was initialized would be to check the
            // thread-local value and see that it's not set.
            if RT_TLS_KEY != -1 {
                return Some(RT_TLS_KEY);
            } else {
                return None;
            }
        }
    }

    #[inline] #[cfg(test)]
    pub fn maybe_tls_key() -> Option<tls::Key> {
        use realstd;
        unsafe {
            cast::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key())
        }
    }
}
<commit_msg>Flag all TLS functions as inline(never)<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Access to a single thread-local pointer.
//!
//! The runtime will use this for storing ~Task.
//!
//! XXX: Add runtime checks for usage of inconsistent pointer types.
//! and for overwriting an existing pointer.

#[allow(dead_code)];

use cast;
use ops::Drop;
use ptr::RawPtr;

#[cfg(windows)]               // mingw-w32 doesn't like thread_local things
#[cfg(target_os = "android")] // see #10686
pub use self::native::*;

#[cfg(not(windows), not(target_os = "android"))]
pub use self::compiled::*;

/// Encapsulates a borrowed value. When this value goes out of scope, the
/// pointer is returned.
pub struct Borrowed<T> {
    priv val: *(),
}

#[unsafe_destructor]
impl<T> Drop for Borrowed<T> {
    fn drop(&mut self) {
        unsafe {
            if self.val.is_null() {
                rtabort!("Aiee, returning null borrowed object!");
            }
            let val: ~T = cast::transmute(self.val);
            put::<T>(val);
            rtassert!(exists());
        }
    }
}

impl<T> Borrowed<T> {
    pub fn get<'a>(&'a mut self) -> &'a mut T {
        unsafe {
            let val_ptr: &mut ~T = cast::transmute(&mut self.val);
            let val_ptr: &'a mut T = *val_ptr;
            val_ptr
        }
    }
}

/// Borrow the thread-local value from thread-local storage.
/// While the value is borrowed it is not available in TLS.
///
/// # Safety note
///
/// Does not validate the pointer type.
#[inline]
pub unsafe fn borrow<T>() -> Borrowed<T> {
    let val: *() = cast::transmute(take::<T>());
    Borrowed {
        val: val,
    }
}

/// Compiled implementation of accessing the runtime local pointer. This is
/// implemented using LLVM's thread_local attribute which isn't necessarily
/// working on all platforms. This implementation is faster, however, so we use
/// it wherever possible.
#[cfg(not(windows), not(target_os = "android"))]
pub mod compiled {
    use cast;
    use option::{Option, Some, None};
    use ptr::RawPtr;
    #[cfg(not(test))] use libc::c_void;

    #[cfg(test)]
    pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;

    #[cfg(not(test))]
    #[thread_local]
    pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void;

    pub fn init() {}

    pub unsafe fn cleanup() {}

    // Rationale for all of these functions being inline(never)
    //
    // The #[thread_local] annotation gets propagated all the way through to
    // LLVM, meaning the global is specially treated by LLVM to lower it to an
    // efficient sequence of instructions. This also involves dealing with fun
    // stuff in object files and whatnot. Regardless, it turns out this causes
    // trouble with green threads and lots of optimizations turned on. The
    // following case study was done on linux x86_64, but I would imagine that
    // other platforms are similar.
    //
    // On linux, the instruction sequence for loading the tls pointer global
    // looks like:
    //
    //      mov %fs:0x0, %rax
    //      mov -0x8(%rax), %rbx
    //
    // This code leads me to believe that (%fs:0x0) is a table, and then the
    // table contains the TLS values for the process. Hence, the slot at offset
    // -0x8 is the task TLS pointer. This leads us to the conclusion that this
    // table is the actual thread local part of each thread. The kernel sets up
    // the fs segment selector to point at the right region of memory for each
    // thread.
    //
    // Optimizations lead me to believe that this code is lowered to these
    // instructions in the LLVM codegen passes, because you'll see code like
    // this when everything is optimized:
    //
    //      mov %fs:0x0, %r14
    //      mov -0x8(%r14), %rbx
    //      // do something with %rbx, the rust Task pointer
    //
    //      ... // <- do more things
    //
    //      mov -0x8(%r14), %rbx
    //      // do something else with %rbx
    //
    // Note that the optimization done here is that the first load is not
    // duplicated during the lower instructions. This means that the %fs:0x0
    // memory location is only dereferenced once.
    //
    // Normally, this is actually a good thing! With green threads, however,
    // it's very possible for the code labeled "do more things" to context
    // switch to another thread. If this happens, then we *must* re-load %fs:0x0
    // because it's changed (we're on a different thread). If we don't re-load
    // the table location, then we'll be reading the original thread's TLS
    // values, not our thread's TLS values.
    //
    // Hence, we never inline these functions. By never inlining, we're
    // guaranteed that loading the table is a local decision which is forced to
    // *always* happen.

    /// Give a pointer to thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline(never)] // see comments above
    pub unsafe fn put<T>(sched: ~T) {
        RT_TLS_PTR = cast::transmute(sched)
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline(never)] // see comments above
    pub unsafe fn take<T>() -> ~T {
        let ptr = RT_TLS_PTR;
        rtassert!(!ptr.is_null());
        let ptr: ~T = cast::transmute(ptr);
        // can't use `as`, due to type not matching with `cfg(test)`
        RT_TLS_PTR = cast::transmute(0);
        ptr
    }

    /// Optionally take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline(never)] // see comments above
    pub unsafe fn try_take<T>() -> Option<~T> {
        let ptr = RT_TLS_PTR;
        if ptr.is_null() {
            None
        } else {
            let ptr: ~T = cast::transmute(ptr);
            // can't use `as`, due to type not matching with `cfg(test)`
            RT_TLS_PTR = cast::transmute(0);
            Some(ptr)
        }
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    /// Leaves the old pointer in TLS for speed.
    #[inline(never)] // see comments above
    pub unsafe fn unsafe_take<T>() -> ~T {
        cast::transmute(RT_TLS_PTR)
    }

    /// Check whether there is a thread-local pointer installed.
    #[inline(never)] // see comments above
    pub fn exists() -> bool {
        unsafe {
            RT_TLS_PTR.is_not_null()
        }
    }

    #[inline(never)] // see comments above
    pub unsafe fn unsafe_borrow<T>() -> *mut T {
        if RT_TLS_PTR.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        RT_TLS_PTR as *mut T
    }

    #[inline(never)] // see comments above
    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
        if RT_TLS_PTR.is_null() {
            None
        } else {
            Some(RT_TLS_PTR as *mut T)
        }
    }
}

/// Native implementation of having the runtime thread-local pointer. This
/// implementation uses the `thread_local_storage` module to provide a
/// thread-local value.
pub mod native {
    use cast;
    use libc::c_void;
    use option::{Option, Some, None};
    use ptr;
    use ptr::RawPtr;
    use tls = rt::thread_local_storage;

    static mut RT_TLS_KEY: tls::Key = -1;

    /// Initialize the TLS key. Other ops will fail if this isn't executed
    /// first.
    pub fn init() {
        unsafe {
            tls::create(&mut RT_TLS_KEY);
        }
    }

    pub unsafe fn cleanup() {
        rtassert!(RT_TLS_KEY != -1);
        tls::destroy(RT_TLS_KEY);
    }

    /// Give a pointer to thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn put<T>(sched: ~T) {
        let key = tls_key();
        let void_ptr: *mut c_void = cast::transmute(sched);
        tls::set(key, void_ptr);
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn take<T>() -> ~T {
        let key = tls_key();
        let void_ptr: *mut c_void = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        let ptr: ~T = cast::transmute(void_ptr);
        tls::set(key, ptr::mut_null());
        return ptr;
    }

    /// Optionally take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    #[inline]
    pub unsafe fn try_take<T>() -> Option<~T> {
        match maybe_tls_key() {
            Some(key) => {
                let void_ptr: *mut c_void = tls::get(key);
                if void_ptr.is_null() {
                    None
                } else {
                    let ptr: ~T = cast::transmute(void_ptr);
                    tls::set(key, ptr::mut_null());
                    Some(ptr)
                }
            }
            None => None
        }
    }

    /// Take ownership of a pointer from thread-local storage.
    ///
    /// # Safety note
    ///
    /// Does not validate the pointer type.
    /// Leaves the old pointer in TLS for speed.
    #[inline]
    pub unsafe fn unsafe_take<T>() -> ~T {
        let key = tls_key();
        let void_ptr: *mut c_void = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        let ptr: ~T = cast::transmute(void_ptr);
        return ptr;
    }

    /// Check whether there is a thread-local pointer installed.
    pub fn exists() -> bool {
        unsafe {
            match maybe_tls_key() {
                Some(key) => tls::get(key).is_not_null(),
                None => false
            }
        }
    }

    /// Borrow a mutable reference to the thread-local value
    ///
    /// # Safety Note
    ///
    /// Because this leaves the value in thread-local storage it is possible
    /// For the Scheduler pointer to be aliased
    pub unsafe fn unsafe_borrow<T>() -> *mut T {
        let key = tls_key();
        let void_ptr = tls::get(key);
        if void_ptr.is_null() {
            rtabort!("thread-local pointer is null. bogus!");
        }
        void_ptr as *mut T
    }

    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
        match maybe_tls_key() {
            Some(key) => {
                let void_ptr = tls::get(key);
                if void_ptr.is_null() {
                    None
                } else {
                    Some(void_ptr as *mut T)
                }
            }
            None => None
        }
    }

    #[inline]
    fn tls_key() -> tls::Key {
        match maybe_tls_key() {
            Some(key) => key,
            None => rtabort!("runtime tls key not initialized")
        }
    }

    #[inline]
    #[cfg(not(test))]
    pub fn maybe_tls_key() -> Option<tls::Key> {
        unsafe {
            // NB: This is a little racy because, while the key is
            // initalized under a mutex and it's assumed to be initalized
            // in the Scheduler ctor by any thread that needs to use it,
            // we are not accessing the key under a mutex.  Threads that
            // are not using the new Scheduler but still *want to check*
            // whether they are running under a new Scheduler may see a 0
            // value here that is in the process of being initialized in
            // another thread. I think this is fine since the only action
            // they could take if it was initialized would be to check the
            // thread-local value and see that it's not set.
            if RT_TLS_KEY != -1 {
                return Some(RT_TLS_KEY);
            } else {
                return None;
            }
        }
    }

    #[inline] #[cfg(test)]
    pub fn maybe_tls_key() -> Option<tls::Key> {
        use realstd;
        unsafe {
            cast::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key())
        }
    }
}
<|endoftext|>


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

use core::prelude::*;
use io::prelude::*;
use os::unix::prelude::*;

use ffi::{self, CString, OsString, AsOsStr, OsStr};
use io::{self, Error, Seek, SeekFrom};
use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t};
use mem;
use path::{Path, PathBuf};
use ptr;
use rc::Rc;
use sys::fd::FileDesc;
use sys::{c, cvt, cvt_r};
use sys_common::FromInner;
use vec::Vec;

pub struct File(FileDesc);

pub struct FileAttr {
    stat: libc::stat,
}

pub struct ReadDir {
    dirp: *mut libc::DIR,
    root: Rc<PathBuf>,
}

pub struct DirEntry {
    buf: Vec<u8>,
    dirent: *mut libc::dirent_t,
    root: Rc<PathBuf>,
}

#[derive(Clone)]
pub struct OpenOptions {
    flags: c_int,
    read: bool,
    write: bool,
    mode: mode_t,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions { mode: mode_t }

impl FileAttr {
    pub fn is_dir(&self) -> bool {
        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFDIR
    }
    pub fn is_file(&self) -> bool {
        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFREG
    }
    pub fn size(&self) -> u64 { self.stat.st_size as u64 }
    pub fn perm(&self) -> FilePermissions {
        FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
    }

    pub fn accessed(&self) -> u64 {
        self.mktime(self.stat.st_atime as u64, self.stat.st_atime_nsec as u64)
    }
    pub fn modified(&self) -> u64 {
        self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64)
    }

    // times are in milliseconds (currently)
    fn mktime(&self, secs: u64, nsecs: u64) -> u64 {
        secs * 1000 + nsecs / 1000000
    }
}

impl FilePermissions {
    pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
    pub fn set_readonly(&mut self, readonly: bool) {
        if readonly {
            self.mode &= !0o222;
        } else {
            self.mode |= 0o222;
        }
    }
}

impl FromInner<i32> for FilePermissions {
    fn from_inner(mode: i32) -> FilePermissions {
        FilePermissions { mode: mode as mode_t }
    }
}

impl Iterator for ReadDir {
    type Item = io::Result<DirEntry>;

    fn next(&mut self) -> Option<io::Result<DirEntry>> {
        extern {
            fn rust_dirent_t_size() -> c_int;
        }

        let mut buf: Vec<u8> = Vec::with_capacity(unsafe {
            rust_dirent_t_size() as usize
        });
        let ptr = buf.as_mut_ptr() as *mut libc::dirent_t;

        let mut entry_ptr = ptr::null_mut();
        loop {
            if unsafe { libc::readdir_r(self.dirp, ptr, &mut entry_ptr) != 0 } {
                return Some(Err(Error::last_os_error()))
            }
            if entry_ptr.is_null() {
                return None
            }

            let entry = DirEntry {
                buf: buf,
                dirent: entry_ptr,
                root: self.root.clone()
            };
            if entry.name_bytes() == b"." || entry.name_bytes() == b".." {
                buf = entry.buf;
            } else {
                return Some(Ok(entry))
            }
        }
    }
}

impl Drop for ReadDir {
    fn drop(&mut self) {
        let r = unsafe { libc::closedir(self.dirp) };
        debug_assert_eq!(r, 0);
    }
}

impl DirEntry {
    pub fn path(&self) -> PathBuf {
        self.root.join(<OsStr as OsStrExt>::from_byte_slice(self.name_bytes()))
    }

    fn name_bytes(&self) -> &[u8] {
        extern {
            fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
        }
        unsafe {
            let ptr = rust_list_dir_val(self.dirent);
            ffi::c_str_to_bytes(mem::copy_lifetime(self, &ptr))
        }
    }
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            flags: 0,
            read: false,
            write: false,
            mode: libc::S_IRUSR | libc::S_IWUSR,
        }
    }

    pub fn read(&mut self, read: bool) {
        self.read = read;
    }

    pub fn write(&mut self, write: bool) {
        self.write = write;
    }

    pub fn append(&mut self, append: bool) {
        self.flag(libc::O_APPEND, append);
    }

    pub fn truncate(&mut self, truncate: bool) {
        self.flag(libc::O_TRUNC, truncate);
    }

    pub fn create(&mut self, create: bool) {
        self.flag(libc::O_CREAT, create);
    }

    pub fn mode(&mut self, mode: i32) {
        self.mode = mode as mode_t;
    }

    fn flag(&mut self, bit: c_int, on: bool) {
        if on {
            self.flags |= bit;
        } else {
            self.flags &= !bit;
        }
    }
}

impl File {
    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
        let flags = opts.flags | match (opts.read, opts.write) {
            (true, true) => libc::O_RDWR,
            (false, true) => libc::O_WRONLY,
            (true, false) |
            (false, false) => libc::O_RDONLY,
        };
        let path = cstr(path);
        let fd = try!(cvt_r(|| unsafe {
            libc::open(path.as_ptr(), flags, opts.mode)
        }));
        Ok(File(FileDesc::new(fd)))
    }

    pub fn file_attr(&self) -> io::Result<FileAttr> {
        let mut stat: libc::stat = unsafe { mem::zeroed() };
        try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) }));
        Ok(FileAttr { stat: stat })
    }

    pub fn fsync(&self) -> io::Result<()> {
        try!(cvt_r(|| unsafe { libc::fsync(self.0.raw()) }));
        Ok(())
    }

    pub fn datasync(&self) -> io::Result<()> {
        try!(cvt_r(|| unsafe { os_datasync(self.0.raw()) }));
        return Ok(());

        #[cfg(any(target_os = "macos", target_os = "ios"))]
        unsafe fn os_datasync(fd: c_int) -> c_int {
            libc::fcntl(fd, libc::F_FULLFSYNC)
        }
        #[cfg(target_os = "linux")]
        unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
        #[cfg(not(any(target_os = "macos",
                      target_os = "ios",
                      target_os = "linux")))]
        unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
    }

    pub fn truncate(&self, size: u64) -> io::Result<()> {
        try!(cvt_r(|| unsafe {
            libc::ftruncate(self.0.raw(), size as libc::off_t)
        }));
        Ok(())
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn flush(&self) -> io::Result<()> { Ok(()) }

    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
        let (whence, pos) = match pos {
            SeekFrom::Start(off) => (libc::SEEK_SET, off as off_t),
            SeekFrom::End(off) => (libc::SEEK_END, off as off_t),
            SeekFrom::Current(off) => (libc::SEEK_CUR, off as off_t),
        };
        let n = try!(cvt(unsafe { libc::lseek(self.0.raw(), pos, whence) }));
        Ok(n as u64)
    }

    pub fn fd(&self) -> &FileDesc { &self.0 }
}

fn cstr(path: &Path) -> CString {
    CString::from_slice(path.as_os_str().as_byte_slice())
}

pub fn mkdir(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) }));
    Ok(())
}

pub fn readdir(p: &Path) -> io::Result<ReadDir> {
    let root = Rc::new(p.to_path_buf());
    let p = cstr(p);
    unsafe {
        let ptr = libc::opendir(p.as_ptr());
        if ptr.is_null() {
            Err(Error::last_os_error())
        } else {
            Ok(ReadDir { dirp: ptr, root: root })
        }
    }
}

pub fn unlink(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::unlink(p.as_ptr()) }));
    Ok(())
}

pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
    let old = cstr(old);
    let new = cstr(new);
    try!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }));
    Ok(())
}

pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }));
    Ok(())
}

pub fn rmdir(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::rmdir(p.as_ptr()) }));
    Ok(())
}

pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt_r(|| unsafe {
        libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
    }));
    Ok(())
}

pub fn readlink(p: &Path) -> io::Result<PathBuf> {
    let c_path = cstr(p);
    let p = c_path.as_ptr();
    let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
    if len < 0 {
        len = 1024; // FIXME: read PATH_MAX from C ffi?
    }
    let mut buf: Vec<u8> = Vec::with_capacity(len as usize);
    unsafe {
        let n = try!(cvt({
            libc::readlink(p, buf.as_ptr() as *mut c_char, len as size_t)
        }));
        buf.set_len(n as usize);
    }
    let s: OsString = OsStringExt::from_vec(buf);
    Ok(PathBuf::new(&s))
}

pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
    let src = cstr(src);
    let dst = cstr(dst);
    try!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }));
    Ok(())
}

pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
    let src = cstr(src);
    let dst = cstr(dst);
    try!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }));
    Ok(())
}

pub fn stat(p: &Path) -> io::Result<FileAttr> {
    let p = cstr(p);
    let mut stat: libc::stat = unsafe { mem::zeroed() };
    try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }));
    Ok(FileAttr { stat: stat })
}

pub fn lstat(p: &Path) -> io::Result<FileAttr> {
    let p = cstr(p);
    let mut stat: libc::stat = unsafe { mem::zeroed() };
    try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }));
    Ok(FileAttr { stat: stat })
}

pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
    let p = cstr(p);
    let buf = [super::ms_to_timeval(atime), super::ms_to_timeval(mtime)];
    try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }));
    Ok(())
}
<commit_msg>Add read and write rights to group and other when creating file<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;
use io::prelude::*;
use os::unix::prelude::*;

use ffi::{self, CString, OsString, AsOsStr, OsStr};
use io::{self, Error, Seek, SeekFrom};
use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t};
use mem;
use path::{Path, PathBuf};
use ptr;
use rc::Rc;
use sys::fd::FileDesc;
use sys::{c, cvt, cvt_r};
use sys_common::FromInner;
use vec::Vec;

pub struct File(FileDesc);

pub struct FileAttr {
    stat: libc::stat,
}

pub struct ReadDir {
    dirp: *mut libc::DIR,
    root: Rc<PathBuf>,
}

pub struct DirEntry {
    buf: Vec<u8>,
    dirent: *mut libc::dirent_t,
    root: Rc<PathBuf>,
}

#[derive(Clone)]
pub struct OpenOptions {
    flags: c_int,
    read: bool,
    write: bool,
    mode: mode_t,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions { mode: mode_t }

impl FileAttr {
    pub fn is_dir(&self) -> bool {
        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFDIR
    }
    pub fn is_file(&self) -> bool {
        (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFREG
    }
    pub fn size(&self) -> u64 { self.stat.st_size as u64 }
    pub fn perm(&self) -> FilePermissions {
        FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
    }

    pub fn accessed(&self) -> u64 {
        self.mktime(self.stat.st_atime as u64, self.stat.st_atime_nsec as u64)
    }
    pub fn modified(&self) -> u64 {
        self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64)
    }

    // times are in milliseconds (currently)
    fn mktime(&self, secs: u64, nsecs: u64) -> u64 {
        secs * 1000 + nsecs / 1000000
    }
}

impl FilePermissions {
    pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
    pub fn set_readonly(&mut self, readonly: bool) {
        if readonly {
            self.mode &= !0o222;
        } else {
            self.mode |= 0o222;
        }
    }
}

impl FromInner<i32> for FilePermissions {
    fn from_inner(mode: i32) -> FilePermissions {
        FilePermissions { mode: mode as mode_t }
    }
}

impl Iterator for ReadDir {
    type Item = io::Result<DirEntry>;

    fn next(&mut self) -> Option<io::Result<DirEntry>> {
        extern {
            fn rust_dirent_t_size() -> c_int;
        }

        let mut buf: Vec<u8> = Vec::with_capacity(unsafe {
            rust_dirent_t_size() as usize
        });
        let ptr = buf.as_mut_ptr() as *mut libc::dirent_t;

        let mut entry_ptr = ptr::null_mut();
        loop {
            if unsafe { libc::readdir_r(self.dirp, ptr, &mut entry_ptr) != 0 } {
                return Some(Err(Error::last_os_error()))
            }
            if entry_ptr.is_null() {
                return None
            }

            let entry = DirEntry {
                buf: buf,
                dirent: entry_ptr,
                root: self.root.clone()
            };
            if entry.name_bytes() == b"." || entry.name_bytes() == b".." {
                buf = entry.buf;
            } else {
                return Some(Ok(entry))
            }
        }
    }
}

impl Drop for ReadDir {
    fn drop(&mut self) {
        let r = unsafe { libc::closedir(self.dirp) };
        debug_assert_eq!(r, 0);
    }
}

impl DirEntry {
    pub fn path(&self) -> PathBuf {
        self.root.join(<OsStr as OsStrExt>::from_byte_slice(self.name_bytes()))
    }

    fn name_bytes(&self) -> &[u8] {
        extern {
            fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
        }
        unsafe {
            let ptr = rust_list_dir_val(self.dirent);
            ffi::c_str_to_bytes(mem::copy_lifetime(self, &ptr))
        }
    }
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            flags: 0,
            read: false,
            write: false,
            mode: libc::S_IRUSR | libc::S_IWUSR
                | libc::S_IRGRP | libc::S_IWGRP
                | libc::S_IROTH | libc::S_IWOTH,
        }
    }

    pub fn read(&mut self, read: bool) {
        self.read = read;
    }

    pub fn write(&mut self, write: bool) {
        self.write = write;
    }

    pub fn append(&mut self, append: bool) {
        self.flag(libc::O_APPEND, append);
    }

    pub fn truncate(&mut self, truncate: bool) {
        self.flag(libc::O_TRUNC, truncate);
    }

    pub fn create(&mut self, create: bool) {
        self.flag(libc::O_CREAT, create);
    }

    pub fn mode(&mut self, mode: i32) {
        self.mode = mode as mode_t;
    }

    fn flag(&mut self, bit: c_int, on: bool) {
        if on {
            self.flags |= bit;
        } else {
            self.flags &= !bit;
        }
    }
}

impl File {
    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
        let flags = opts.flags | match (opts.read, opts.write) {
            (true, true) => libc::O_RDWR,
            (false, true) => libc::O_WRONLY,
            (true, false) |
            (false, false) => libc::O_RDONLY,
        };
        let path = cstr(path);
        let fd = try!(cvt_r(|| unsafe {
            libc::open(path.as_ptr(), flags, opts.mode)
        }));
        Ok(File(FileDesc::new(fd)))
    }

    pub fn file_attr(&self) -> io::Result<FileAttr> {
        let mut stat: libc::stat = unsafe { mem::zeroed() };
        try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) }));
        Ok(FileAttr { stat: stat })
    }

    pub fn fsync(&self) -> io::Result<()> {
        try!(cvt_r(|| unsafe { libc::fsync(self.0.raw()) }));
        Ok(())
    }

    pub fn datasync(&self) -> io::Result<()> {
        try!(cvt_r(|| unsafe { os_datasync(self.0.raw()) }));
        return Ok(());

        #[cfg(any(target_os = "macos", target_os = "ios"))]
        unsafe fn os_datasync(fd: c_int) -> c_int {
            libc::fcntl(fd, libc::F_FULLFSYNC)
        }
        #[cfg(target_os = "linux")]
        unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
        #[cfg(not(any(target_os = "macos",
                      target_os = "ios",
                      target_os = "linux")))]
        unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
    }

    pub fn truncate(&self, size: u64) -> io::Result<()> {
        try!(cvt_r(|| unsafe {
            libc::ftruncate(self.0.raw(), size as libc::off_t)
        }));
        Ok(())
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    pub fn flush(&self) -> io::Result<()> { Ok(()) }

    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
        let (whence, pos) = match pos {
            SeekFrom::Start(off) => (libc::SEEK_SET, off as off_t),
            SeekFrom::End(off) => (libc::SEEK_END, off as off_t),
            SeekFrom::Current(off) => (libc::SEEK_CUR, off as off_t),
        };
        let n = try!(cvt(unsafe { libc::lseek(self.0.raw(), pos, whence) }));
        Ok(n as u64)
    }

    pub fn fd(&self) -> &FileDesc { &self.0 }
}

fn cstr(path: &Path) -> CString {
    CString::from_slice(path.as_os_str().as_byte_slice())
}

pub fn mkdir(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) }));
    Ok(())
}

pub fn readdir(p: &Path) -> io::Result<ReadDir> {
    let root = Rc::new(p.to_path_buf());
    let p = cstr(p);
    unsafe {
        let ptr = libc::opendir(p.as_ptr());
        if ptr.is_null() {
            Err(Error::last_os_error())
        } else {
            Ok(ReadDir { dirp: ptr, root: root })
        }
    }
}

pub fn unlink(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::unlink(p.as_ptr()) }));
    Ok(())
}

pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
    let old = cstr(old);
    let new = cstr(new);
    try!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }));
    Ok(())
}

pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }));
    Ok(())
}

pub fn rmdir(p: &Path) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt(unsafe { libc::rmdir(p.as_ptr()) }));
    Ok(())
}

pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> {
    let p = cstr(p);
    try!(cvt_r(|| unsafe {
        libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
    }));
    Ok(())
}

pub fn readlink(p: &Path) -> io::Result<PathBuf> {
    let c_path = cstr(p);
    let p = c_path.as_ptr();
    let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
    if len < 0 {
        len = 1024; // FIXME: read PATH_MAX from C ffi?
    }
    let mut buf: Vec<u8> = Vec::with_capacity(len as usize);
    unsafe {
        let n = try!(cvt({
            libc::readlink(p, buf.as_ptr() as *mut c_char, len as size_t)
        }));
        buf.set_len(n as usize);
    }
    let s: OsString = OsStringExt::from_vec(buf);
    Ok(PathBuf::new(&s))
}

pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
    let src = cstr(src);
    let dst = cstr(dst);
    try!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }));
    Ok(())
}

pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
    let src = cstr(src);
    let dst = cstr(dst);
    try!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }));
    Ok(())
}

pub fn stat(p: &Path) -> io::Result<FileAttr> {
    let p = cstr(p);
    let mut stat: libc::stat = unsafe { mem::zeroed() };
    try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }));
    Ok(FileAttr { stat: stat })
}

pub fn lstat(p: &Path) -> io::Result<FileAttr> {
    let p = cstr(p);
    let mut stat: libc::stat = unsafe { mem::zeroed() };
    try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }));
    Ok(FileAttr { stat: stat })
}

pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
    let p = cstr(p);
    let buf = [super::ms_to_timeval(atime), super::ms_to_timeval(mtime)];
    try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }));
    Ok(())
}
<|endoftext|>