<commit_before>use ::arch::cpu;
use ::arch::debug;
use ::arch::isr::{self,DropIrqHandler};
use ::phys_mem::PhysicalBitmap;
use ::process::Process;
use ::thread::{Deferred,Promise,Scheduler};
use ::virt_mem::VirtualTree;
use spin::Mutex;
use std::char;
use std::cmp;
use std::collections::VecDeque;
use std::mem;
use std::slice::bytes;
use std::sync::Arc;

//                  S    C    C+S  AGr  AGr+S
pub struct Key(u32, u32, u32, u32, u32, u32);

pub mod keys {
    // "bucky bits"
    bitflags! {
        flags Bucky: u32 {
            const BUCKY_RELEASE =   0x01000000, // Key was released
            const BUCKY_ALT =       0x02000000, // Alt is pressed
            const BUCKY_CTRL =      0x04000000, // Ctrl is pressed
            const BUCKY_SHIFT =     0x08000000, // Shift is pressed
            const BUCKY_CAPS =      0x10000000, // CapsLock is on
            const BUCKY_NUM =       0x20000000, // NumLock is on
            const BUCKY_SCRL =      0x40000000, // ScrollLock is on
            const BUCKY_ALTGR =     0x80000000  // AltGr is pressed
        }
    }

    impl Bucky {
        pub fn set(&mut self, other: Bucky, set: bool) {
            if set {
                self.insert(other)
            } else {
                self.remove(other)
            }
        }
    }

    // "ASCII" values for non-ASCII keys. All of these are user-defined.
    // function keys:
    pub const F1: u32 =      0xE000;
    pub const F2: u32 =      F1 + 1;
    pub const F3: u32 =      F2 + 1;
    pub const F4: u32 =      F3 + 1;
    pub const F5: u32 =      F4 + 1;
    pub const F6: u32 =      F5 + 1;
    pub const F7: u32 =      F6 + 1;
    pub const F8: u32 =      F7 + 1;
    pub const F9: u32 =      F8 + 1;
    pub const F10: u32 =     F9 + 1;
    pub const F11: u32 =     F10 + 1;
    pub const F12: u32 =     F11 + 1;  // 0x10B
    // cursor keys
    pub const INS: u32 =     F12 + 1;  // 0x10C
    pub const DEL: u32 =     INS + 1;
    pub const HOME: u32 =    DEL + 1;
    pub const END: u32 =     HOME + 1;
    pub const PGUP: u32 =    END + 1;
    pub const PGDN: u32 =    PGUP + 1;
    pub const LEFT: u32 =    PGDN + 1;
    pub const UP: u32 =      LEFT + 1;
    pub const DOWN: u32 =    UP + 1;
    pub const RIGHT: u32 =   DOWN + 1;  // 0x115
    // print screen/sys rq and pause/break
    pub const PRTSC: u32 =   RIGHT + 1; // 0x116
    pub const PAUSE: u32 =   PRTSC + 1; // 0x117
    // these return a value but they could also act as additional bucky keys
    pub const LWIN: u32 =    PAUSE + 1; // 0x118
    pub const RWIN: u32 =    LWIN + 1;
    pub const MENU: u32 =    RWIN + 1;  // 0x11A

    pub const SYSR: u32 =    BUCKY_ALT.bits | PRTSC;
}

impl Key {
    pub fn pick(&self, keys: keys::Bucky) -> u32 {
        if keys.contains(keys::BUCKY_SHIFT | keys::BUCKY_ALTGR) {
            self.5
        } else if keys.contains(keys::BUCKY_SHIFT | keys::BUCKY_CTRL) {
            self.3
        } else if keys.contains(keys::BUCKY_ALTGR) {
            self.4
        } else if keys.contains(keys::BUCKY_CTRL) {
            self.2
        } else if keys.contains(keys::BUCKY_SHIFT) {
            self.1
        } else {
            self.0
        }
    }
}

const RAW_LEFT_CTRL: u16 =   0x1D;
const RAW_LEFT_SHIFT: u16 =  0x2A;
//const RAW_CAPS_LOCK: u16 =   0x3A;
const RAW_LEFT_ALT: u16 =    0x38;
const RAW_RIGHT_ALT: u16 =   0x6038;
const RAW_RIGHT_CTRL: u16 =  0x601D;
const RAW_RIGHT_SHIFT: u16 = 0x36;
//const RAW_SCROLL_LOCK: u16 = 0x46;
//const RAW_NUM_LOCK: u16 =    0x45;
const RAW_NUM7: u16 =        0x47;
//const RAW_NUM8: u16 =        0x48;
//const RAW_NUM9: u16 =        0x49;
//const RAW_NUM4: u16 =        0x4b;
//const RAW_NUM5: u16 =        0x4c;
//const RAW_NUM6: u16 =        0x4d;
//const RAW_NUM1: u16 =        0x4f;
//const RAW_NUM2: u16 =        0x50;
//const RAW_NUM3: u16 =        0x51;
const RAW_NUM0: u16 =        0x52;

struct KeyboardState {
    extended: bool,
    keys: keys::Bucky,
    compose: u32,
}

impl KeyboardState {
    pub fn new() -> KeyboardState {
        KeyboardState {
            extended: false,
            keys: keys::Bucky::empty(),
            compose: 0
        }
    }

    pub fn decode(&mut self, scancode: u8) -> u32 {
        static KEYPAD: &'static [Option<u8>; (RAW_NUM0 - RAW_NUM7 + 1) as usize] = &[
            Some(7), Some(8), Some(9), None,
            Some(4), Some(5), Some(6), None,
            Some(1), Some(2), Some(3),
            Some(0)
        ];

        let down = (scancode & 0x80) == 0;
        let mut code = (scancode & !0x80) as u16;
        let mut key: u32 = 0;

        if code == 0x60 {
            self.extended = true;
            return 0;
        } else if self.extended {
            code |= 0x6000;
            self.extended = false;
        }

        match code {
            RAW_LEFT_CTRL | RAW_RIGHT_CTRL => {
                self.keys.set(keys::BUCKY_CTRL, down);
            },

            RAW_LEFT_ALT => {
                if down && self.keys.contains(keys::BUCKY_ALT) {
                    self.compose = 0;
                } else if !down && self.keys.contains(keys::BUCKY_ALT) {
                    key =
                        if self.compose != 0 {
                            self.compose
                        } else {
                            (keys::BUCKY_ALT | keys::BUCKY_RELEASE).bits()
                        };
                }

                self.keys.set(keys::BUCKY_ALT, down);
            },

            RAW_RIGHT_ALT => {
                self.keys.set(keys::BUCKY_ALTGR, down);
            },

            RAW_LEFT_SHIFT | RAW_RIGHT_SHIFT => {
                self.keys.set(keys::BUCKY_SHIFT, down);
            },

            _ => {
                code &= !0x6000;
                if code >= RAW_NUM7 && code <= RAW_NUM0 && code != 0x4a && code != 0x4e {
                    match KEYPAD[(code - RAW_NUM7) as usize] {
                        Some(n) => {
                            if self.keys.contains(keys::BUCKY_ALT) {
                                if down {
                                    self.compose *= 10;
                                    self.compose += n as u32;
                                }
                            } else if self.keys.contains(keys::BUCKY_NUM) {
                                key = '0' as u32 + n as u32;
                            }
                        },

                        None => {
                            key = british::KEYS[code as usize].pick(keys::Bucky::empty());
                        }
                    }
                } else {
                    key = british::KEYS[code as usize].pick(self.keys);
                }

                /* if self.keys.contains(keys::BUCKY_CAPS) {
                    if (iswupper(key)) {
                        key = towlower(key);
                    } else if (iswlower(key)) {
                        key = towupper(key);
                    }
                } */

                if !down {
                    key |= keys::BUCKY_RELEASE.bits();
                }
            }
        }

        key | self.keys.bits()
    }
}

mod british;

pub trait Device {
    fn read_async(&self, buf: Vec<u8>) -> Deferred<Result<(Vec<u8>, usize), &'static str>>;
}

pub struct IoRequest {
    buf: Vec<u8>,
    d: Deferred<Result<(Vec<u8>, usize), &'static str>>,
    current: usize
}

impl IoRequest {
    pub fn new(buf: Vec<u8>, d: Deferred<Result<(Vec<u8>, usize), &'static str>>) -> IoRequest {
        IoRequest {
            buf: buf,
            d: d,
            current: 0
        }
    }

    pub fn fulfil(mut self, data: &mut &[u8]) -> Option<IoRequest> {
        {
            let len = cmp::min(self.buf.len(), data.len());
            let (data1, data2) = data.split_at(len);
            *data = data2;

            let buf1 = &mut self.buf[self.current .. self.current + len];
            bytes::copy_memory(data1, buf1);
            self.current += len;
        }

        if self.current >= self.buf.len() {
            self.d.resolve(Ok((self.buf, self.current)));
            None
        } else {
            Some(self)
        }
    }
}

pub struct Keyboard {
    _drop_irq_handler: DropIrqHandler,
    scheduler: Arc<Scheduler>,
    requests: Arc<Mutex<VecDeque<IoRequest>>>
}

impl Keyboard {
    pub fn new(scheduler: Arc<Scheduler>) -> Keyboard {
        let requests = Arc::new(Mutex::new(VecDeque::new()));
        let state = Mutex::new(KeyboardState::new());

        let handler = {
            let requests = requests.clone();
            move || {
                let data: [u8; 4] = {
                    let scancode = unsafe { cpu::inb(0x60) };
                    let key = lock!(state).decode(scancode);
                    unsafe { mem::transmute(key) }
                };

                let mut slice: &[u8] = &data;
                loop {
                    if slice.len() == 0 {
                        break;
                    }

                    let mut requests = lock!(requests);
                    let request: IoRequest =
                        match requests.pop_front() {
                            Some(request) => request,
                            None => { break; }
                        };

                    if let Some(request) = request.fulfil(&mut slice) {
                        requests.push_front(request);
                    }
                }
            }
        };

        Keyboard {
            _drop_irq_handler: isr::register_irq_handler(1, handler),
            scheduler: scheduler,
            requests: requests
        }
    }
}

impl<'a> Device for Keyboard {
    fn read_async(&self, buf: Vec<u8>) -> Deferred<Result<(Vec<u8>, usize), &'static str>> {
        let d = Deferred::new(self.scheduler.clone());
        lock!(self.requests).push_back(IoRequest::new(buf, d.clone()));
        d
    }
}

test! {
    fn can_read_key() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p));
        let keyboard = Keyboard::new(scheduler);
        log!("Type something and press Enter");

        loop {
            let d = keyboard.read_async(vec![0; 4]);
            let c: u32;
            loop {
                if let Some(result) = d.try_get() {
                    let (keys, _) = result.unwrap();
                    let p = keys[0..4].as_ptr() as *const u32;
                    c = unsafe { *p };
                    break;
                } else {
                    unsafe { asm!("hlt") };
                }
            }

            if let Some(c) = char::from_u32(c & !keys::BUCKY_SHIFT.bits()) {
                if c == '\n' {
                    break;
                } else if c != '\0' {
                    let mut s = String::new();
                    s.push(c);
                    debug::puts(&s);
                }
            }
        }
    }
}
<commit_msg>Caps lock<commit_after>use ::arch::cpu;
use ::arch::debug;
use ::arch::isr::{self,DropIrqHandler};
use ::phys_mem::PhysicalBitmap;
use ::process::Process;
use ::thread::{Deferred,Promise,Scheduler};
use ::virt_mem::VirtualTree;
use spin::Mutex;
use std::char;
use std::cmp;
use std::collections::VecDeque;
use std::mem;
use std::slice::bytes;
use std::sync::Arc;

//                  S    C    C+S  AGr  AGr+S
pub struct Key(u32, u32, u32, u32, u32, u32);

pub mod keys {
    // "bucky bits"
    bitflags! {
        flags Bucky: u32 {
            const BUCKY_RELEASE =   0x01000000, // Key was released
            const BUCKY_ALT =       0x02000000, // Alt is pressed
            const BUCKY_CTRL =      0x04000000, // Ctrl is pressed
            const BUCKY_SHIFT =     0x08000000, // Shift is pressed
            const BUCKY_CAPS =      0x10000000, // CapsLock is on
            const BUCKY_NUM =       0x20000000, // NumLock is on
            const BUCKY_SCRL =      0x40000000, // ScrollLock is on
            const BUCKY_ALTGR =     0x80000000  // AltGr is pressed
        }
    }

    impl Bucky {
        pub fn set(&mut self, other: Bucky, set: bool) {
            if set {
                self.insert(other)
            } else {
                self.remove(other)
            }
        }
    }

    // "ASCII" values for non-ASCII keys. All of these are user-defined.
    // function keys:
    pub const F1: u32 =      0xE000;
    pub const F2: u32 =      F1 + 1;
    pub const F3: u32 =      F2 + 1;
    pub const F4: u32 =      F3 + 1;
    pub const F5: u32 =      F4 + 1;
    pub const F6: u32 =      F5 + 1;
    pub const F7: u32 =      F6 + 1;
    pub const F8: u32 =      F7 + 1;
    pub const F9: u32 =      F8 + 1;
    pub const F10: u32 =     F9 + 1;
    pub const F11: u32 =     F10 + 1;
    pub const F12: u32 =     F11 + 1;  // 0x10B
    // cursor keys
    pub const INS: u32 =     F12 + 1;  // 0x10C
    pub const DEL: u32 =     INS + 1;
    pub const HOME: u32 =    DEL + 1;
    pub const END: u32 =     HOME + 1;
    pub const PGUP: u32 =    END + 1;
    pub const PGDN: u32 =    PGUP + 1;
    pub const LEFT: u32 =    PGDN + 1;
    pub const UP: u32 =      LEFT + 1;
    pub const DOWN: u32 =    UP + 1;
    pub const RIGHT: u32 =   DOWN + 1;  // 0x115
    // print screen/sys rq and pause/break
    pub const PRTSC: u32 =   RIGHT + 1; // 0x116
    pub const PAUSE: u32 =   PRTSC + 1; // 0x117
    // these return a value but they could also act as additional bucky keys
    pub const LWIN: u32 =    PAUSE + 1; // 0x118
    pub const RWIN: u32 =    LWIN + 1;
    pub const MENU: u32 =    RWIN + 1;  // 0x11A

    pub const SYSR: u32 =    BUCKY_ALT.bits | PRTSC;
}

impl Key {
    pub fn pick(&self, keys: keys::Bucky) -> u32 {
        if keys.contains(keys::BUCKY_SHIFT | keys::BUCKY_ALTGR) {
            self.5
        } else if keys.contains(keys::BUCKY_SHIFT | keys::BUCKY_CTRL) {
            self.3
        } else if keys.contains(keys::BUCKY_ALTGR) {
            self.4
        } else if keys.contains(keys::BUCKY_CTRL) {
            self.2
        } else if keys.contains(keys::BUCKY_SHIFT) {
            self.1
        } else {
            self.0
        }
    }
}

const RAW_LEFT_CTRL: u16 =   0x1D;
const RAW_LEFT_SHIFT: u16 =  0x2A;
const RAW_CAPS_LOCK: u16 =   0x3A;
const RAW_LEFT_ALT: u16 =    0x38;
const RAW_RIGHT_ALT: u16 =   0x6038;
const RAW_RIGHT_CTRL: u16 =  0x601D;
const RAW_RIGHT_SHIFT: u16 = 0x36;
const RAW_SCROLL_LOCK: u16 = 0x46;
const RAW_NUM_LOCK: u16 =    0x45;
const RAW_NUM7: u16 =        0x47;
const RAW_NUM0: u16 =        0x52;

struct KeyboardState {
    extended: bool,
    keys: keys::Bucky,
    compose: u32,
}

enum Keypress {
    Char(u32),
    Scancode(keys::Bucky, u8, bool),
    Leds(u8)
}

impl KeyboardState {
    pub fn new() -> KeyboardState {
        KeyboardState {
            extended: false,
            keys: keys::Bucky::empty(),
            compose: 0
        }
    }

    pub fn decode(&mut self, scancode: u8) -> Option<Keypress> {
        static KEYPAD: &'static [Option<u8>; (RAW_NUM0 - RAW_NUM7 + 1) as usize] = &[
            Some(7), Some(8), Some(9), None,
            Some(4), Some(5), Some(6), None,
            Some(1), Some(2), Some(3),
            Some(0)
        ];

        let down = (scancode & 0x80) == 0;
        let mut code = (scancode & !0x80) as u16;

        if code == 0x60 {
            self.extended = true;
            return None;
        } else if self.extended {
            code |= 0x6000;
            self.extended = false;
        }

        match code {
            RAW_LEFT_CTRL | RAW_RIGHT_CTRL => {
                self.keys.set(keys::BUCKY_CTRL, down);
                None
            },

            RAW_LEFT_ALT => {
                self.keys.set(keys::BUCKY_ALT, down);

                if down && self.keys.contains(keys::BUCKY_ALT) {
                    self.compose = 0;
                    None
                } else if !down && self.keys.contains(keys::BUCKY_ALT) {
                    if self.compose != 0 {
                        Some(Keypress::Char(self.compose))
                    } else {
                        None
                    }
                } else {
                    None
                }
            },

            RAW_RIGHT_ALT => {
                self.keys.set(keys::BUCKY_ALTGR, down);
                None
            },

            RAW_LEFT_SHIFT | RAW_RIGHT_SHIFT => {
                self.keys.set(keys::BUCKY_SHIFT, down);
                None
            },

            RAW_NUM_LOCK | RAW_CAPS_LOCK | RAW_SCROLL_LOCK => {
                if down {
                    let k =
                        match code {
                            RAW_NUM_LOCK => keys::BUCKY_NUM,
                            RAW_CAPS_LOCK => keys::BUCKY_CAPS,
                            _ => keys::BUCKY_SCRL
                        };

                    self.keys.toggle(k);

                    let mut flags = 0;
                    if self.keys.contains(keys::BUCKY_SCRL) {
                        flags |= 1;
                    }

                    if self.keys.contains(keys::BUCKY_NUM) {
                        flags |= 2;
                    }

                    if self.keys.contains(keys::BUCKY_CAPS) {
                        flags |= 4;
                    }

                    Some(Keypress::Leds(flags))
                } else {
                    None
                }
            },

            _ => {
                if code >= RAW_NUM7 && code <= RAW_NUM0 && code != 0x4a && code != 0x4e {
                    match KEYPAD[(code - RAW_NUM7) as usize] {
                        Some(n) => {
                            if self.keys.contains(keys::BUCKY_ALT) {
                                if down {
                                    self.compose *= 10;
                                    self.compose += n as u32;
                                }
                                None
                            } else if self.keys.contains(keys::BUCKY_NUM) {
                                Some(Keypress::Scancode(self.keys, '0' as u8 + n, down))
                            } else {
                                Some(Keypress::Scancode(self.keys, code as u8, down))
                            }
                        },

                        None => Some(Keypress::Scancode(self.keys, code as u8, down))
                    }
                } else {
                    Some(Keypress::Scancode(self.keys, code as u8, down))
                }
            }
        }
    }
}

pub trait Device {
    fn read_async(&self, buf: Vec<u8>) -> Deferred<Result<(Vec<u8>, usize), &'static str>>;
}

pub struct IoRequest {
    buf: Vec<u8>,
    d: Deferred<Result<(Vec<u8>, usize), &'static str>>,
    current: usize
}

impl IoRequest {
    pub fn new(buf: Vec<u8>, d: Deferred<Result<(Vec<u8>, usize), &'static str>>) -> IoRequest {
        IoRequest {
            buf: buf,
            d: d,
            current: 0
        }
    }

    pub fn fulfil(mut self, data: &mut &[u8]) -> Option<IoRequest> {
        {
            let len = cmp::min(self.buf.len(), data.len());
            let (data1, data2) = data.split_at(len);
            *data = data2;

            let buf1 = &mut self.buf[self.current .. self.current + len];
            bytes::copy_memory(data1, buf1);
            self.current += len;
        }

        if self.current >= self.buf.len() {
            self.d.resolve(Ok((self.buf, self.current)));
            None
        } else {
            Some(self)
        }
    }
}

mod british;

pub struct Keyboard {
    _drop_irq_handler: DropIrqHandler,
    scheduler: Arc<Scheduler>,
    requests: Arc<Mutex<VecDeque<IoRequest>>>
}

impl Keyboard {
    pub fn new(scheduler: Arc<Scheduler>) -> Keyboard {
        let requests = Arc::new(Mutex::new(VecDeque::new()));
        let state = Mutex::new(KeyboardState::new());

        let handler = {
            let requests = requests.clone();
            move || {
                let key = {
                    let scancode = unsafe { cpu::inb(0x60) };
                    lock!(state).decode(scancode)
                };

                let c =
                    match key {
                        Some(Keypress::Char(c)) => c,

                        Some(Keypress::Scancode(mut keys, scan, down)) => {
                            keys.set(keys::BUCKY_RELEASE, !down);
                            if let Some(key) = british::KEYS.get(scan as usize) {
                                let c = key.pick(keys);

                                let c =
                                    match char::from_u32(c) {
                                        Some(c) if keys.contains(keys::BUCKY_CAPS) => c.to_uppercase().next().unwrap_or(c) as u32,
                                        _ => c
                                    };

                                keys.bits() | c
                            } else {
                                return;
                            }
                        },

                        Some(Keypress::Leds(flags)) => {
                            unsafe {
                                cpu::outb(0x60, 0xed);
                                cpu::outb(0x60, flags);
                            }
                            return;
                        },

                        None => { return; }
                    };

                let data: [u8; 4] = unsafe { mem::transmute(c) };
                let mut slice: &[u8] = &data;
                loop {
                    if slice.len() == 0 {
                        break;
                    }

                    let mut requests = lock!(requests);
                    let request: IoRequest =
                        match requests.pop_front() {
                            Some(request) => request,
                            None => { break; }
                        };

                    if let Some(request) = request.fulfil(&mut slice) {
                        requests.push_front(request);
                    }
                }
            }
        };

        Keyboard {
            _drop_irq_handler: isr::register_irq_handler(1, handler),
            scheduler: scheduler,
            requests: requests
        }
    }
}

impl<'a> Device for Keyboard {
    fn read_async(&self, buf: Vec<u8>) -> Deferred<Result<(Vec<u8>, usize), &'static str>> {
        let d = Deferred::new(self.scheduler.clone());
        lock!(self.requests).push_back(IoRequest::new(buf, d.clone()));
        d
    }
}

test! {
    fn can_read_key() {
        let phys = Arc::new(PhysicalBitmap::parse_multiboot());
        let kernel_virt = Arc::new(VirtualTree::new());
        let p = Arc::new(Process::new(phys, kernel_virt).unwrap());
        let scheduler = Arc::new(Scheduler::new(p));
        let keyboard = Keyboard::new(scheduler);
        log!("Type something and press Enter");

        loop {
            let d = keyboard.read_async(vec![0; 4]);
            let c: u32;
            loop {
                if let Some(result) = d.try_get() {
                    let (keys, _) = result.unwrap();
                    let p = keys[0..4].as_ptr() as *const u32;
                    c = unsafe { *p };
                    break;
                } else {
                    unsafe { asm!("hlt") };
                }
            }

            let keys = keys::Bucky::from_bits_truncate(c);
            if !keys.intersects(keys::BUCKY_RELEASE | keys::BUCKY_CTRL | keys::BUCKY_ALT | keys::BUCKY_ALTGR) {
                let c = c & !keys.bits();
                if let Some(c) = char::from_u32(c) {
                    if c == '\n' {
                        break;
                    } else if c != '\0' {
                        let mut s = String::new();
                        s.push(c);
                        debug::puts(&s);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::env;
use std::io::Write;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark(keyword: &str) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
"#,
            ME,
            keyword,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this")
    }
    fn end_mark() -> String {
        Self::base_mark("up to here")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!("^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$", Self::start_mark(), Self::end_mark());
        let re    = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        try!(self.delete(&current_dir));

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(ref time, ref command)| {
                let line = format!("{}\tcd {} && kic {}\n", time, current_dir, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) -> Result<(), RegexError> {
        let re = try!(Regex::new(&format!(r".*cd\s+{}\s+&&\s+kic.*\n", dir.as_ref())));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(())
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}
<commit_msg>[Test] Create tests for Cron.my_area_is_empty()<commit_after>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::env;
use std::io::Write;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark(keyword: &str) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
"#,
            ME,
            keyword,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this")
    }
    fn end_mark() -> String {
        Self::base_mark("up to here")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!("^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$", Self::start_mark(), Self::end_mark());
        let re    = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        try!(self.delete(&current_dir));

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(ref time, ref command)| {
                let line = format!("{}\tcd {} && kic {}\n", time, current_dir, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) -> Result<(), RegexError> {
        let re = try!(Regex::new(&format!(r".*cd\s+{}\s+&&\s+kic.*\n", dir.as_ref())));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(())
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}

#[test]
fn my_area_is_empty_return_true() {
    let empties = [
        "",
        " ",
        "\t",
        "\r",
        "\n",
        " \t\r\n ",
    ];

    for empty in &empties {
        let cron = Cron {
            upper: "".to_string(),
            my_area: empty.to_string(),
            lower: "".to_string()
        };
        assert!(cron.my_area_is_empty());
    }
}
#[test]
fn my_area_is_empty_return_false() {
    let non_empties = [
        "a",
        "ab",
        " ab",
        "a b",
        "ab ",
        "\tab",
        "a\tb",
        "ab\t",
        "\rab",
        "a\rb",
        "ab\r",
        "\nab",
        "a\nb",
        "ab\n",
        " \t\r\nab",
        "a \t\r\nb",
        "ab \t\r\n",
    ];

    for non_empty in &non_empties {
        let cron = Cron {
            upper: "".to_string(),
            my_area: non_empty.to_string(),
            lower: "".to_string()
        };
        assert!(!cron.my_area_is_empty());
    }
}
<|endoftext|>


<commit_before>/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use crate::mir::*;
use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::layout::VariantIdx;
use crate::hir;
use crate::ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
    pub ty: Ty<'tcx>,
    /// Downcast to a particular variant of an enum, if included.
    pub variant_index: Option<VariantIdx>,
}

// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PlaceTy<'_>, 16);

impl<'tcx> PlaceTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
        PlaceTy { ty, variant_index: None }
    }

    /// `place_ty.field_ty(tcx, f)` computes the type at a given field
    /// of a record or enum-variant. (Most clients of `PlaceTy` can
    /// instead just extract the relevant type directly from their
    /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
    /// not carry a `Ty` for `T`.)
    ///
    /// Note that the resulting type has not been normalized.
    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
        let answer = match self.ty.sty {
            ty::Adt(adt_def, substs) => {
                let variant_def = match self.variant_index {
                    None => adt_def.non_enum_variant(),
                    Some(variant_index) => {
                        assert!(adt_def.is_enum());
                        &adt_def.variants[variant_index]
                    }
                };
                let field_def = &variant_def.fields[f.index()];
                field_def.ty(tcx, substs)
            }
            ty::Tuple(ref tys) => tys[f.index()].expect_ty(),
            _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
        };
        debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
        answer
    }

    /// Convenience wrapper around `projection_ty_core` for
    /// `PlaceElem`, where we can just use the `Ty` that is already
    /// stored inline on field projection elems.
    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
        self.projection_ty_core(tcx, elem, |_, _, ty| ty)
    }

    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
    /// projects `place_ty` onto `elem`, returning the appropriate
    /// `Ty` or downcast variant corresponding to that projection.
    /// The `handle_field` callback must map a `Field` to its `Ty`,
    /// (which should be trivial when `T` = `Ty`).
    pub fn projection_ty_core<V, T>(
        self,
        tcx: TyCtxt<'tcx>,
        elem: &ProjectionElem<V, T>,
        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
    ) -> PlaceTy<'tcx>
    where
        V: ::std::fmt::Debug,
        T: ::std::fmt::Debug,
    {
        let answer = match *elem {
            ProjectionElem::Deref => {
                let ty = self.ty
                             .builtin_deref(true)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                PlaceTy::from_ty(ty)
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
            ProjectionElem::Subslice { from, to } => {
                PlaceTy::from_ty(match self.ty.sty {
                    ty::Array(inner, size) => {
                        let size = size.unwrap_usize(tcx);
                        let len = size - (from as u64) - (to as u64);
                        tcx.mk_array(inner, len)
                    }
                    ty::Slice(..) => self.ty,
                    _ => {
                        bug!("cannot subslice non-array type: `{:?}`", self)
                    }
                })
            }
            ProjectionElem::Downcast(_name, index) =>
                PlaceTy { ty: self.ty, variant_index: Some(index) },
            ProjectionElem::Field(ref f, ref fty) =>
                PlaceTy::from_ty(handle_field(&self, f, fty)),
        };
        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
        answer
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
        ty,
        variant_index,
    }
}

impl<'tcx> Place<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match *self {
            Place::Base(PlaceBase::Local(index)) =>
                PlaceTy::from_ty(local_decls.local_decls()[index].ty),
            Place::Base(PlaceBase::Static(ref data)) =>
                PlaceTy::from_ty(data.ty),
            Place::Projection(ref proj) =>
                proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
        }
    }
}

pub enum RvalueInitializationState {
    Shallow,
    Deep
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, count) => {
                tcx.mk_array(operand.ty(local_decls, tcx), count)
            }
            Rvalue::Ref(reg, bk, ref place) => {
                let place_ty = place.ty(local_decls, tcx).ty;
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: place_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool])
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref place) => {
                let ty = place.ty(local_decls, tcx).ty;
                match ty.sty {
                    ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
                    ty::Generator(_, substs, _) => substs.discr_ty(tcx),
                    _ => {
                        // This can only be `0`, for now, so `u8` will suffice.
                        tcx.types.u8
                    }
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len() as u64)
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
                    }
                    AggregateKind::Adt(def, _, substs, _, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure(did, substs)
                    }
                    AggregateKind::Generator(did, substs, movability) => {
                        tcx.mk_generator(did, substs, movability)
                    }
                }
            }
        }
    }

    #[inline]
    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
    /// whether its only shallowly initialized (`Rvalue::Box`).
    pub fn initialization_state(&self) -> RvalueInitializationState {
        match *self {
            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
            _ => RvalueInitializationState::Deep
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match self {
            &Operand::Copy(ref l) |
            &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
            &Operand::Constant(ref c) => c.ty,
        }
    }
}

impl<'tcx> BinOp {
    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut { .. } => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,

            // We have no type corresponding to a shallow borrow, so use
            // `&` as an approximation.
            BorrowKind::Shallow => hir::MutImmutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOpKind {
        match self {
            BinOp::Add => hir::BinOpKind::Add,
            BinOp::Sub => hir::BinOpKind::Sub,
            BinOp::Mul => hir::BinOpKind::Mul,
            BinOp::Div => hir::BinOpKind::Div,
            BinOp::Rem => hir::BinOpKind::Rem,
            BinOp::BitXor => hir::BinOpKind::BitXor,
            BinOp::BitAnd => hir::BinOpKind::BitAnd,
            BinOp::BitOr => hir::BinOpKind::BitOr,
            BinOp::Shl => hir::BinOpKind::Shl,
            BinOp::Shr => hir::BinOpKind::Shr,
            BinOp::Eq => hir::BinOpKind::Eq,
            BinOp::Ne => hir::BinOpKind::Ne,
            BinOp::Lt => hir::BinOpKind::Lt,
            BinOp::Gt => hir::BinOpKind::Gt,
            BinOp::Le => hir::BinOpKind::Le,
            BinOp::Ge => hir::BinOpKind::Ge,
            BinOp::Offset => unreachable!()
        }
    }
}
<commit_msg>Rollup merge of #61940 - spastorino:place-ty-iterate, r=oli-obk<commit_after>/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use crate::mir::*;
use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::layout::VariantIdx;
use crate::hir;
use crate::ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
    pub ty: Ty<'tcx>,
    /// Downcast to a particular variant of an enum, if included.
    pub variant_index: Option<VariantIdx>,
}

// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PlaceTy<'_>, 16);

impl<'tcx> PlaceTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
        PlaceTy { ty, variant_index: None }
    }

    /// `place_ty.field_ty(tcx, f)` computes the type at a given field
    /// of a record or enum-variant. (Most clients of `PlaceTy` can
    /// instead just extract the relevant type directly from their
    /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
    /// not carry a `Ty` for `T`.)
    ///
    /// Note that the resulting type has not been normalized.
    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
        let answer = match self.ty.sty {
            ty::Adt(adt_def, substs) => {
                let variant_def = match self.variant_index {
                    None => adt_def.non_enum_variant(),
                    Some(variant_index) => {
                        assert!(adt_def.is_enum());
                        &adt_def.variants[variant_index]
                    }
                };
                let field_def = &variant_def.fields[f.index()];
                field_def.ty(tcx, substs)
            }
            ty::Tuple(ref tys) => tys[f.index()].expect_ty(),
            _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
        };
        debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
        answer
    }

    /// Convenience wrapper around `projection_ty_core` for
    /// `PlaceElem`, where we can just use the `Ty` that is already
    /// stored inline on field projection elems.
    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
        self.projection_ty_core(tcx, elem, |_, _, ty| ty)
    }

    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
    /// projects `place_ty` onto `elem`, returning the appropriate
    /// `Ty` or downcast variant corresponding to that projection.
    /// The `handle_field` callback must map a `Field` to its `Ty`,
    /// (which should be trivial when `T` = `Ty`).
    pub fn projection_ty_core<V, T>(
        self,
        tcx: TyCtxt<'tcx>,
        elem: &ProjectionElem<V, T>,
        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
    ) -> PlaceTy<'tcx>
    where
        V: ::std::fmt::Debug,
        T: ::std::fmt::Debug,
    {
        let answer = match *elem {
            ProjectionElem::Deref => {
                let ty = self.ty
                             .builtin_deref(true)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                PlaceTy::from_ty(ty)
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
            ProjectionElem::Subslice { from, to } => {
                PlaceTy::from_ty(match self.ty.sty {
                    ty::Array(inner, size) => {
                        let size = size.unwrap_usize(tcx);
                        let len = size - (from as u64) - (to as u64);
                        tcx.mk_array(inner, len)
                    }
                    ty::Slice(..) => self.ty,
                    _ => {
                        bug!("cannot subslice non-array type: `{:?}`", self)
                    }
                })
            }
            ProjectionElem::Downcast(_name, index) =>
                PlaceTy { ty: self.ty, variant_index: Some(index) },
            ProjectionElem::Field(ref f, ref fty) =>
                PlaceTy::from_ty(handle_field(&self, f, fty)),
        };
        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
        answer
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
        ty,
        variant_index,
    }
}

impl<'tcx> Place<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        self.iterate(|place_base, place_projections| {
            let mut place_ty = place_base.ty(local_decls);

            for proj in place_projections {
                place_ty = place_ty.projection_ty(tcx, &proj.elem);
            }

            place_ty
        })
    }
}

impl<'tcx> PlaceBase<'tcx> {
    pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match self {
            PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
            PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
        }
    }
}

pub enum RvalueInitializationState {
    Shallow,
    Deep
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, count) => {
                tcx.mk_array(operand.ty(local_decls, tcx), count)
            }
            Rvalue::Ref(reg, bk, ref place) => {
                let place_ty = place.ty(local_decls, tcx).ty;
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: place_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool])
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref place) => {
                let ty = place.ty(local_decls, tcx).ty;
                match ty.sty {
                    ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
                    ty::Generator(_, substs, _) => substs.discr_ty(tcx),
                    _ => {
                        // This can only be `0`, for now, so `u8` will suffice.
                        tcx.types.u8
                    }
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len() as u64)
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
                    }
                    AggregateKind::Adt(def, _, substs, _, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure(did, substs)
                    }
                    AggregateKind::Generator(did, substs, movability) => {
                        tcx.mk_generator(did, substs, movability)
                    }
                }
            }
        }
    }

    #[inline]
    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
    /// whether its only shallowly initialized (`Rvalue::Box`).
    pub fn initialization_state(&self) -> RvalueInitializationState {
        match *self {
            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
            _ => RvalueInitializationState::Deep
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match self {
            &Operand::Copy(ref l) |
            &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
            &Operand::Constant(ref c) => c.ty,
        }
    }
}

impl<'tcx> BinOp {
    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut { .. } => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,

            // We have no type corresponding to a shallow borrow, so use
            // `&` as an approximation.
            BorrowKind::Shallow => hir::MutImmutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOpKind {
        match self {
            BinOp::Add => hir::BinOpKind::Add,
            BinOp::Sub => hir::BinOpKind::Sub,
            BinOp::Mul => hir::BinOpKind::Mul,
            BinOp::Div => hir::BinOpKind::Div,
            BinOp::Rem => hir::BinOpKind::Rem,
            BinOp::BitXor => hir::BinOpKind::BitXor,
            BinOp::BitAnd => hir::BinOpKind::BitAnd,
            BinOp::BitOr => hir::BinOpKind::BitOr,
            BinOp::Shl => hir::BinOpKind::Shl,
            BinOp::Shr => hir::BinOpKind::Shr,
            BinOp::Eq => hir::BinOpKind::Eq,
            BinOp::Ne => hir::BinOpKind::Ne,
            BinOp::Lt => hir::BinOpKind::Lt,
            BinOp::Gt => hir::BinOpKind::Gt,
            BinOp::Le => hir::BinOpKind::Le,
            BinOp::Ge => hir::BinOpKind::Ge,
            BinOp::Offset => unreachable!()
        }
    }
}
<|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.

// rustpkg unit tests

use context::Ctx;
use core::hashmap::HashMap;
use core::path::Path;
use std::tempfile::mkdtemp;
use util::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace,
               target_test_in_workspace, target_bench_in_workspace,
               make_dir_rwx, u_rwx};
use core::os::mkdir_recursive;

fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
    Ctx {
        sysroot_opt: sysroot_opt,
        json: false,
        dep_cache: @mut HashMap::new()
    }
}

fn fake_pkg() -> PkgId {
    PkgId {
        path: Path(~"bogus"),
        version: default_version()
    }
}

fn remote_pkg() -> PkgId {
    PkgId {
        path: Path(~"github.com/catamorphism/test-pkg"),
        version: default_version()
    }
}

fn writeFile(file_path: &Path, contents: ~str) {
    let out: @io::Writer =
        result::get(&io::file_writer(file_path,
                                     ~[io::Create, io::Truncate]));
    out.write_line(contents);
}

fn mk_temp_workspace(short_name: &Path) -> Path {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let package_dir = workspace.push(~"src").push_rel(short_name);
    assert!(mkdir_recursive(&package_dir, u_rwx));
    // Create main, lib, test, and bench files
    writeFile(&package_dir.push(~"main.rs"),
              ~"fn main() { let _x = (); }");
    writeFile(&package_dir.push(~"lib.rs"),
              ~"pub fn f() { let _x = (); }");
    writeFile(&package_dir.push(~"test.rs"),
              ~"#[test] pub fn f() { (); }");
    writeFile(&package_dir.push(~"bench.rs"),
              ~"#[bench] pub fn f() { (); }");
    workspace
}

fn is_rwx(p: &Path) -> bool {
    use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};

    match p.get_mode() {
        None => return false,
        Some(m) =>
            ((m & S_IRUSR as uint) == S_IRUSR as uint
            && (m & S_IWUSR as uint) == S_IWUSR as uint
            && (m & S_IXUSR as uint) == S_IXUSR as uint)
    }
}

fn test_sysroot() -> Path {
    // Totally gross hack but it's just for test cases.
    // Infer the sysroot from the exe name and tack "stage2"
    // onto it. (Did I mention it was a gross hack?)
    let self_path = os::self_exe_path().expect("Couldn't get self_exe path");
    self_path.pop().push("stage2")
}

#[test]
fn test_make_dir_rwx() {
    let temp = &os::tmpdir();
    let dir = temp.push(~"quux");
    assert!(!os::path_exists(&dir) ||
            os::remove_dir_recursive(&dir));
    debug!("Trying to make %s", dir.to_str());
    assert!(make_dir_rwx(&dir));
    assert!(os::path_is_dir(&dir));
    assert!(is_rwx(&dir));
    assert!(os::remove_dir_recursive(&dir));
}

#[test]
fn test_install_valid() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = fake_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
fn test_install_invalid() {
    use conditions::nonexistent_package::cond;
    use cond1 = conditions::missing_pkg_files::cond;

    let ctxt = fake_ctxt(None);
    let pkgid = fake_pkg();
    let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let mut error_occurred = false;
    let mut error1_occurred = false;
    do cond1.trap(|_| {
        error1_occurred = true;
    }).in {
        do cond.trap(|_| {
            error_occurred = true;
        }).in {
            ctxt.install(&temp_workspace, &pkgid);
        }
    }
    assert!(error_occurred && error1_occurred);
}

#[test]
#[ignore(reason = "install from URL-fragment not yet implemented")]
fn test_install_url() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = remote_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}
<commit_msg>Fix rustpkg tests now that they're in a different location<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.

// rustpkg unit tests

use context::Ctx;
use core::hashmap::HashMap;
use core::path::Path;
use std::tempfile::mkdtemp;
use util::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace,
               target_test_in_workspace, target_bench_in_workspace,
               make_dir_rwx, u_rwx};
use core::os::mkdir_recursive;

fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
    Ctx {
        sysroot_opt: sysroot_opt,
        json: false,
        dep_cache: @mut HashMap::new()
    }
}

fn fake_pkg() -> PkgId {
    PkgId {
        path: Path(~"bogus"),
        version: default_version()
    }
}

fn remote_pkg() -> PkgId {
    PkgId {
        path: Path(~"github.com/catamorphism/test-pkg"),
        version: default_version()
    }
}

fn writeFile(file_path: &Path, contents: ~str) {
    let out: @io::Writer =
        result::get(&io::file_writer(file_path,
                                     ~[io::Create, io::Truncate]));
    out.write_line(contents);
}

fn mk_temp_workspace(short_name: &Path) -> Path {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let package_dir = workspace.push(~"src").push_rel(short_name);
    assert!(mkdir_recursive(&package_dir, u_rwx));
    // Create main, lib, test, and bench files
    writeFile(&package_dir.push(~"main.rs"),
              ~"fn main() { let _x = (); }");
    writeFile(&package_dir.push(~"lib.rs"),
              ~"pub fn f() { let _x = (); }");
    writeFile(&package_dir.push(~"test.rs"),
              ~"#[test] pub fn f() { (); }");
    writeFile(&package_dir.push(~"bench.rs"),
              ~"#[bench] pub fn f() { (); }");
    workspace
}

fn is_rwx(p: &Path) -> bool {
    use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};

    match p.get_mode() {
        None => return false,
        Some(m) =>
            ((m & S_IRUSR as uint) == S_IRUSR as uint
            && (m & S_IWUSR as uint) == S_IWUSR as uint
            && (m & S_IXUSR as uint) == S_IXUSR as uint)
    }
}

fn test_sysroot() -> Path {
    // Totally gross hack but it's just for test cases.
    // Infer the sysroot from the exe name and pray that it's right.
    // (Did I mention it was a gross hack?)
    let self_path = os::self_exe_path().expect("Couldn't get self_exe path");
    self_path.pop()
}

#[test]
fn test_make_dir_rwx() {
    let temp = &os::tmpdir();
    let dir = temp.push(~"quux");
    assert!(!os::path_exists(&dir) ||
            os::remove_dir_recursive(&dir));
    debug!("Trying to make %s", dir.to_str());
    assert!(make_dir_rwx(&dir));
    assert!(os::path_is_dir(&dir));
    assert!(is_rwx(&dir));
    assert!(os::remove_dir_recursive(&dir));
}

#[test]
fn test_install_valid() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = fake_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
fn test_install_invalid() {
    use conditions::nonexistent_package::cond;
    use cond1 = conditions::missing_pkg_files::cond;

    let ctxt = fake_ctxt(None);
    let pkgid = fake_pkg();
    let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let mut error_occurred = false;
    let mut error1_occurred = false;
    do cond1.trap(|_| {
        error1_occurred = true;
    }).in {
        do cond.trap(|_| {
            error_occurred = true;
        }).in {
            ctxt.install(&temp_workspace, &pkgid);
        }
    }
    assert!(error_occurred && error1_occurred);
}

#[test]
#[ignore(reason = "install from URL-fragment not yet implemented")]
fn test_install_url() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = remote_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}
<|endoftext|>


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

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

/// Create a list from a vector
pub fn from_vec<T:Clone + 'static>(v: &[T]) -> @List<T> {
    v.rev_iter().fold(@Nil::<T>, |t, h| @Cons((*h).clone(), t))
}

/**
 * Left fold
 *
 * Applies `f` to `u` and the first element in the list, then applies `f` to
 * the result of the previous call and the second element, and so on,
 * returning the accumulated result.
 *
 * # Arguments
 *
 * * ls - The list to fold
 * * z - The initial value
 * * f - The function to apply
 */
pub fn foldl<T:Clone,U>(z: T, ls: @List<U>, f: |&T, &U| -> T) -> T {
    let mut accum: T = z;
    iter(ls, |elt| accum = f(&accum, elt));
    accum
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `ls`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(ls: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut ls = ls;
    loop {
        ls = match *ls {
          Cons(ref hd, tl) => {
            if f(hd) { return Some((*hd).clone()); }
            tl
          }
          Nil => return None
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(ls: @List<T>, elt: T) -> bool {
    let mut found = false;
    each(ls, |e| {
        if *e == elt { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(ls: @List<T>) -> bool {
    match *ls {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(ls: @List<T>) -> uint {
    let mut count = 0u;
    iter(ls, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(ls: @List<T>) -> @List<T> {
    match *ls {
        Cons(_, tl) => return tl,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(ls: @List<T>) -> T {
    match *ls {
      Cons(ref hd, _) => (*hd).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(l: @List<T>, m: @List<T>) -> @List<T> {
    match *l {
      Nil => return m,
      Cons(ref x, xs) => {
        let rest = append(xs, m);
        return @Cons((*x).clone(), rest);
      }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(l: @List<T>, f: |&T|) {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            f(hd);
            tl
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(l: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            if !f(hd) { return false; }
            tl
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, from_vec, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = from_vec([]);
        let full1 = from_vec([1]);
        let full2 = from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let l = from_vec([0, 1, 2]);

        assert_eq!(head(l), 0);

        let tail_l = tail(l);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : @list::List<int> = from_vec([]);
        assert_eq!(empty, @list::Nil::<int>);
    }

    #[test]
    fn test_foldl() {
        fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); }
        let l = from_vec([0, 1, 2, 3, 4]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::foldl(0u, l, add), 10u);
        assert_eq!(list::foldl(0u, empty, add), 0u);
    }

    #[test]
    fn test_foldl2() {
        fn sub(a: &int, b: &int) -> int {
            *a - *b
        }
        let l = from_vec([1, 2, 3, 4]);
        assert_eq!(list::foldl(0, l, sub), -10);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let l = from_vec([0, 1, 2]);
        assert_eq!(list::find(l, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(l, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_has() {
        let l = from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(l, 5)));
        assert!((!list::has(l, 7)));
        assert!((list::has(l, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(l), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(from_vec([1,2,3,4])
            == list::append(list::from_vec([1,2]), list::from_vec([3,4])));
    }
}
<commit_msg>auto merge of #12132 : brunoabinader/rust/list-matches-predicate, r=alexcrichton<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

/// Create a list from a vector
pub fn from_vec<T:Clone + 'static>(v: &[T]) -> @List<T> {
    v.rev_iter().fold(@Nil::<T>, |t, h| @Cons((*h).clone(), t))
}

/**
 * Left fold
 *
 * Applies `f` to `u` and the first element in the list, then applies `f` to
 * the result of the previous call and the second element, and so on,
 * returning the accumulated result.
 *
 * # Arguments
 *
 * * ls - The list to fold
 * * z - The initial value
 * * f - The function to apply
 */
pub fn foldl<T:Clone,U>(z: T, ls: @List<U>, f: |&T, &U| -> T) -> T {
    let mut accum: T = z;
    iter(ls, |elt| accum = f(&accum, elt));
    accum
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `ls`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(ls: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut ls = ls;
    loop {
        ls = match *ls {
          Cons(ref hd, tl) => {
            if f(hd) { return Some((*hd).clone()); }
            tl
          }
          Nil => return None
        }
    };
}

/**
 * Returns true if a list contains an element that matches a given predicate
 *
 * Apply function `f` to each element of `ls`, starting from the first.
 * When function `f` returns true then it also returns true. If `f` matches no
 * elements then false is returned.
 */
pub fn any<T>(ls: @List<T>, f: |&T| -> bool) -> bool {
    let mut ls = ls;
    loop {
        ls = match *ls {
            Cons(ref hd, tl) => {
                if f(hd) { return true; }
                tl
            }
            Nil => return false
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(ls: @List<T>, elt: T) -> bool {
    let mut found = false;
    each(ls, |e| {
        if *e == elt { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(ls: @List<T>) -> bool {
    match *ls {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(ls: @List<T>) -> uint {
    let mut count = 0u;
    iter(ls, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(ls: @List<T>) -> @List<T> {
    match *ls {
        Cons(_, tl) => return tl,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(ls: @List<T>) -> T {
    match *ls {
      Cons(ref hd, _) => (*hd).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(l: @List<T>, m: @List<T>) -> @List<T> {
    match *l {
      Nil => return m,
      Cons(ref x, xs) => {
        let rest = append(xs, m);
        return @Cons((*x).clone(), rest);
      }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(l: @List<T>, f: |&T|) {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            f(hd);
            tl
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(l: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            if !f(hd) { return false; }
            tl
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, from_vec, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = from_vec([]);
        let full1 = from_vec([1]);
        let full2 = from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let l = from_vec([0, 1, 2]);

        assert_eq!(head(l), 0);

        let tail_l = tail(l);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : @list::List<int> = from_vec([]);
        assert_eq!(empty, @list::Nil::<int>);
    }

    #[test]
    fn test_foldl() {
        fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); }
        let l = from_vec([0, 1, 2, 3, 4]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::foldl(0u, l, add), 10u);
        assert_eq!(list::foldl(0u, empty, add), 0u);
    }

    #[test]
    fn test_foldl2() {
        fn sub(a: &int, b: &int) -> int {
            *a - *b
        }
        let l = from_vec([1, 2, 3, 4]);
        assert_eq!(list::foldl(0, l, sub), -10);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let l = from_vec([0, 1, 2]);
        assert_eq!(list::find(l, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(l, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::any(l, match_), true);
        assert_eq!(list::any(empty, match_), false);
    }

    #[test]
    fn test_has() {
        let l = from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(l, 5)));
        assert!((!list::has(l, 7)));
        assert!((list::has(l, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(l), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(from_vec([1,2,3,4])
            == list::append(list::from_vec([1,2]), list::from_vec([3,4])));
    }
}
<|endoftext|>