<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
             data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>Remove StorageBackend::build()<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
             data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>


<commit_before>use super::memory::*;
use super::peripherals::*;

use std::rc::Rc;
use std::cell::RefCell;

#[derive(RustcEncodable, RustcDecodable)]
pub struct Interconnect {
    memory: Rc<RefCell<Memory>>,

    ay: Rc<RefCell<Ay>>,

    ula: Rc<RefCell<Ula>>,

    ula_contention: Vec<u8>,
    ula_contention_no_mreq: Vec<u8>,
}

impl Interconnect {
    pub fn new(memory: Rc<RefCell<Memory>>,
               ay : Rc<RefCell<Ay>>,
               ula : Rc<RefCell<Ula>>) -> Self {

        let ula_contention = include_bytes!("ulacontention.bin");
        let ula_contention_no_mreq = include_bytes!("ulacontention.bin");

        Interconnect {
            memory: memory,
            ay: ay,
            ula: ula,
            ula_contention: ula_contention.to_vec(),
            ula_contention_no_mreq: ula_contention_no_mreq.to_vec(),
        }
    }

    fn is_addr_contended(&self, addr: u16) -> bool {
        (addr >= 0x4000 && addr < 0x8000) ||
        (addr >= 0xC000 && (self.memory.borrow().get_c000_bank() % 2 != 0))
    }

    #[inline(always)]
    pub fn contend_read(&mut self, addr: u16, curr_tcycle: u32, tcycles: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + tcycles
    }

    #[inline(always)]
    pub fn contend_read_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[inline(always)]
    pub fn contend_write_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn read_word(&self, addr: u16, curr_tcycle: u32) -> u8 {
        let val = self.memory.borrow().read_word(addr);
        //println!("{: >5} MR {:04x} {:02x}", curr_tcycle, addr, val);
        val
    }

    pub fn write_word(&mut self, addr: u16, val: u8, curr_tcycle: u32) {
        self.memory.borrow_mut().write_word(addr, val);
        //println!("{: >5} MW {:04x} {:02x}", curr_tcycle, addr, val);
    }

    pub fn contend_port_early(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if self.is_addr_contended(port) {
            //println!("{: >5} PC {:04x}", curr_tcycle, port);
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn contend_port_late(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if (port & 0x0001) == 0 {
            //println!("{: >5} PC {:04x}", curr_tcycle, port);
            (self.ula_contention_no_mreq[curr_tcycle as usize] as u32) + 2
        } else {
            if self.is_addr_contended(port) {
                let mut delay: u32 = 0;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32;
                delay
            } else {
                2
            }
        };
        delay + 1
    }

    pub fn read_port(&mut self, port: u16, curr_tcycle: u32) -> u8 {
        let val = match port {
            port if port & 0x0001 == 0 => self.ula.borrow().read_port(port),
            0x7ffd => self.memory.borrow().read_port(port),
            0xfffd | 0xbffd => self.ay.borrow().read_port(port),
            _ => 0,
        };
        //println!("{: >5} PR {:04x} {:02x}", curr_tcycle, port, val);
        val
    }

    pub fn write_port(&mut self, port: u16, val: u8, curr_tcycle: u32) {
        //println!("{: >5} PW {:04x} {:02x}", curr_tcycle, port, val);
        match port {
            port if port & 0x0001 == 0 => self.ula.borrow_mut().write_port(port, val),
            0x7ffd => self.memory.borrow_mut().write_port(port, val),
            0xfffd | 0xbffd => self.ay.borrow_mut().write_port(port, val),
            _ => (),
        };
    }

    pub fn reset(&mut self) {
        self.memory.borrow_mut().clear();
    }
}
<commit_msg>Suppress unused variable warnings<commit_after>use super::memory::*;
use super::peripherals::*;

use std::rc::Rc;
use std::cell::RefCell;

#[derive(RustcEncodable, RustcDecodable)]
pub struct Interconnect {
    memory: Rc<RefCell<Memory>>,

    ay: Rc<RefCell<Ay>>,

    ula: Rc<RefCell<Ula>>,

    ula_contention: Vec<u8>,
    ula_contention_no_mreq: Vec<u8>,
}

impl Interconnect {
    pub fn new(memory: Rc<RefCell<Memory>>,
               ay : Rc<RefCell<Ay>>,
               ula : Rc<RefCell<Ula>>) -> Self {

        let ula_contention = include_bytes!("ulacontention.bin");
        let ula_contention_no_mreq = include_bytes!("ulacontention.bin");

        Interconnect {
            memory: memory,
            ay: ay,
            ula: ula,
            ula_contention: ula_contention.to_vec(),
            ula_contention_no_mreq: ula_contention_no_mreq.to_vec(),
        }
    }

    fn is_addr_contended(&self, addr: u16) -> bool {
        (addr >= 0x4000 && addr < 0x8000) ||
        (addr >= 0xC000 && (self.memory.borrow().get_c000_bank() % 2 != 0))
    }

    #[inline(always)]
    pub fn contend_read(&mut self, addr: u16, curr_tcycle: u32, tcycles: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + tcycles
    }

    #[inline(always)]
    pub fn contend_read_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    #[inline(always)]
    pub fn contend_write_no_mreq(&mut self, addr: u16, curr_tcycle: u32) -> u32 {
        //println!("{: >5} MC {:04x}", curr_tcycle, addr);
        let delay = if self.is_addr_contended(addr) {
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn read_word(&self, addr: u16, _curr_tcycle: u32) -> u8 {
        let val = self.memory.borrow().read_word(addr);
        //println!("{: >5} MR {:04x} {:02x}", _curr_tcycle, addr, val);
        val
    }

    pub fn write_word(&mut self, addr: u16, val: u8, _curr_tcycle: u32) {
        self.memory.borrow_mut().write_word(addr, val);
        //println!("{: >5} MW {:04x} {:02x}", _curr_tcycle, addr, val);
    }

    pub fn contend_port_early(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if self.is_addr_contended(port) {
            //println!("{: >5} PC {:04x}", curr_tcycle, port);
            self.ula_contention_no_mreq[curr_tcycle as usize] as u32
        } else {
            0
        };
        delay + 1
    }

    pub fn contend_port_late(&mut self, port: u16, curr_tcycle: u32) -> u32 {
        let delay = if (port & 0x0001) == 0 {
            //println!("{: >5} PC {:04x}", curr_tcycle, port);
            (self.ula_contention_no_mreq[curr_tcycle as usize] as u32) + 2
        } else {
            if self.is_addr_contended(port) {
                let mut delay: u32 = 0;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += (self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32) + 1;
                //println!("{: >5} PC {:04x}", curr_tcycle + delay, port);
                delay += self.ula_contention_no_mreq[(curr_tcycle + delay) as usize] as u32;
                delay
            } else {
                2
            }
        };
        delay + 1
    }

    pub fn read_port(&mut self, port: u16, _curr_tcycle: u32) -> u8 {
        let val = match port {
            port if port & 0x0001 == 0 => self.ula.borrow().read_port(port),
            0x7ffd => self.memory.borrow().read_port(port),
            0xfffd | 0xbffd => self.ay.borrow().read_port(port),
            _ => 0,
        };
        //println!("{: >5} PR {:04x} {:02x}", _curr_tcycle, port, val);
        val
    }

    pub fn write_port(&mut self, port: u16, val: u8, _curr_tcycle: u32) {
        //println!("{: >5} PW {:04x} {:02x}", _curr_tcycle, port, val);
        match port {
            port if port & 0x0001 == 0 => self.ula.borrow_mut().write_port(port, val),
            0x7ffd => self.memory.borrow_mut().write_port(port, val),
            0xfffd | 0xbffd => self.ay.borrow_mut().write_port(port, val),
            _ => (),
        };
    }

    pub fn reset(&mut self) {
        self.memory.borrow_mut().clear();
    }
}
<|endoftext|>


<commit_before>/* Copyright 2017 Christopher Bacher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use super::super::*;

/// Takes a list of matchers for the same type combines them conjunctively.
#[macro_export]
macro_rules! all_of {
    ( $matcher: expr ) => {
        Box::new(All::of($matcher))
    };
    ( $matcher: expr, $($matchers: expr),* ) => {
        Box::new(All::of($matcher)$(.and($matchers))*)
    };
}

pub fn box_all<'a,T:'a>(combinator: Any<'a,T>) -> Box<Matcher<&'a T> + 'a> {
    Box::new(move |actual: &'a T| combinator.check(actual))
}

/// A `Matcher` struct which joins multiple `Matcher`s conjunctively.
///
/// Use `of()` to create a new `Matcher` and `and()` to add further `Matcher`s.
pub struct All<'a, T:'a> {
    pub matcher: Box<Matcher<&'a T> + 'a>,
    pub next: Option<Box<All<'a,T>>>
}

impl<'a,T:'a> All<'a, T> {
    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
    pub fn of(matcher: Box<Matcher<&'a T> + 'a>) -> All<'a,T> {
        All {
            matcher: matcher,
            next: None
        }
    }

    /// Adds the given `Matcher` conjunctively.
    pub fn and(self, matcher: Box<Matcher<&'a T> + 'a>) -> All<'a,T> {
        All {
            matcher: matcher,
            next: Some(Box::new(self))
        }
    }
}

impl<'a,T:'a> Matcher<&'a T> for All<'a,T> {
    fn check(&self, actual: &'a T) -> MatchResult {
        match self.matcher.check(actual) {
            x@MatchResult::Matched {..} => {
                match self.next {
                    None => x,
                    Some(ref next) => next.check(actual)
                }
            },
            x@MatchResult::Failed {..} => x
        }
    }
}

/// Takes a list of matchers for the same type combines them disjunctively.
#[macro_export]
macro_rules! any_of {
    ( $matcher: expr ) => {
        Box::new(Any::of($matcher))
    };
    ( $matcher: expr, $($matchers: expr),* ) => {
        Box::new(Any::of($matcher)$(.or($matchers))*)
    };
}

pub fn box_any<'a,T:'a>(combinator: Any<'a,T>) -> Box<Matcher<&'a T> + 'a> {
    Box::new(move |actual: &'a T| combinator.check(actual))
}

/// A `Matcher` struct which joins multiple `Matcher`s disjunctively.
///
/// Use `of()` to create a new `Matcher` and `or()` to add further `Matcher`s.
pub struct Any<'a, T:'a> {
    pub matcher: Box<Matcher<&'a T> + 'a>,
    pub next: Option<Box<Any<'a,T>>>
}

impl<'a,T:'a> Any<'a, T> {
    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
    pub fn of(matcher: Box<Matcher<&'a T> + 'a>) -> Any<'a,T> {
        Any {
            matcher: matcher,
            next: None
        }
    }

    /// Adds the given `Matcher` disjunctively.
    pub fn or(self, matcher: Box<Matcher<&'a T> + 'a>) -> Any<'a,T> {
        Any {
            matcher: matcher,
            next: Some(Box::new(self))
        }
    }
}

impl<'a,T:'a> Matcher<&'a T> for Any<'a,T> {
    fn check(&self, actual: &'a T) -> MatchResult {
        match self.matcher.check(actual) {
            MatchResult::Matched {..} => MatchResult::Matched { name: "any_of".to_owned() },
            x@MatchResult::Failed {..} => match self.next {
                None => x,
                Some(ref next) => next.check(actual)
            }
        }
    }
}
<commit_msg>remove unnecessary functions<commit_after>/* Copyright 2017 Christopher Bacher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use super::super::*;

/// Takes a list of matchers for the same type combines them conjunctively.
#[macro_export]
macro_rules! all_of {
    ( $matcher: expr ) => {
        Box::new(All::of($matcher))
    };
    ( $matcher: expr, $($matchers: expr),* ) => {
        Box::new(All::of($matcher)$(.and($matchers))*)
    };
}

/// A `Matcher` struct which joins multiple `Matcher`s conjunctively.
///
/// Use `of()` to create a new `Matcher` and `and()` to add further `Matcher`s.
pub struct All<'a, T:'a> {
    pub matcher: Box<Matcher<&'a T> + 'a>,
    pub next: Option<Box<All<'a,T>>>
}

impl<'a,T:'a> All<'a, T> {
    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
    pub fn of(matcher: Box<Matcher<&'a T> + 'a>) -> All<'a,T> {
        All {
            matcher: matcher,
            next: None
        }
    }

    /// Adds the given `Matcher` conjunctively.
    pub fn and(self, matcher: Box<Matcher<&'a T> + 'a>) -> All<'a,T> {
        All {
            matcher: matcher,
            next: Some(Box::new(self))
        }
    }
}

impl<'a,T:'a> Matcher<&'a T> for All<'a,T> {
    fn check(&self, actual: &'a T) -> MatchResult {
        match self.matcher.check(actual) {
            x@MatchResult::Matched {..} => {
                match self.next {
                    None => x,
                    Some(ref next) => next.check(actual)
                }
            },
            x@MatchResult::Failed {..} => x
        }
    }
}

/// Takes a list of matchers for the same type combines them disjunctively.
#[macro_export]
macro_rules! any_of {
    ( $matcher: expr ) => {
        Box::new(Any::of($matcher))
    };
    ( $matcher: expr, $($matchers: expr),* ) => {
        Box::new(Any::of($matcher)$(.or($matchers))*)
    };
}

/// A `Matcher` struct which joins multiple `Matcher`s disjunctively.
///
/// Use `of()` to create a new `Matcher` and `or()` to add further `Matcher`s.
pub struct Any<'a, T:'a> {
    pub matcher: Box<Matcher<&'a T> + 'a>,
    pub next: Option<Box<Any<'a,T>>>
}

impl<'a,T:'a> Any<'a, T> {
    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
    pub fn of(matcher: Box<Matcher<&'a T> + 'a>) -> Any<'a,T> {
        Any {
            matcher: matcher,
            next: None
        }
    }

    /// Adds the given `Matcher` disjunctively.
    pub fn or(self, matcher: Box<Matcher<&'a T> + 'a>) -> Any<'a,T> {
        Any {
            matcher: matcher,
            next: Some(Box::new(self))
        }
    }
}

impl<'a,T:'a> Matcher<&'a T> for Any<'a,T> {
    fn check(&self, actual: &'a T) -> MatchResult {
        match self.matcher.check(actual) {
            MatchResult::Matched {..} => MatchResult::Matched { name: "any_of".to_owned() },
            x@MatchResult::Failed {..} => match self.next {
                None => x,
                Some(ref next) => next.check(actual)
            }
        }
    }
}
<|endoftext|>


<commit_before>use ncurses::*;

use irc::client::prelude::*;

pub struct DisplayArea {
    window: WINDOW,
}

impl DisplayArea {
    pub fn new() -> DisplayArea {
        let mut w = 0;
        let mut h = 0;
        getmaxyx(stdscr, &mut h, &mut w);
        let window = subwin(stdscr, h - 2, w, 0, 0);
        scrollok(window, true);
        syncok(window, true);
        DisplayArea {
            window: window,
        }
    }

    pub fn display_message(&self, message: Message) {
        use irc::client::data::Command::*;
        let from = message.source_nickname().unwrap_or("");
        let message = match message.command {
            PRIVMSG(ref target, ref msg) => format!("{} <{}> {}", target, from, msg),
            JOIN(ref chanlist, _, _) => format!("{} has joined {}", from, chanlist),
            NICK(ref nick) => format!("{} is now known as {}", from, nick),
            _ => return,
        };
        waddstr(self.window, &message);
        waddch(self.window, '\n' as u64);
    }
}
<commit_msg>Make full use of the display area.<commit_after>use ncurses::*;

use irc::client::prelude::*;

pub struct DisplayArea {
    window: WINDOW,
}

impl DisplayArea {
    pub fn new() -> DisplayArea {
        let mut w = 0;
        let mut h = 0;
        getmaxyx(stdscr, &mut h, &mut w);
        let window = subwin(stdscr, h - 1, w, 0, 0);
        scrollok(window, true);
        syncok(window, true);
        DisplayArea {
            window: window,
        }
    }

    pub fn display_message(&self, message: Message) {
        use irc::client::data::Command::*;
        let from = message.source_nickname().unwrap_or("");
        let message = match message.command {
            PRIVMSG(ref target, ref msg) => format!("{} <{}> {}", target, from, msg),
            JOIN(ref chanlist, _, _) => format!("{} has joined {}", from, chanlist),
            NICK(ref nick) => format!("{} is now known as {}", from, nick),
            _ => return,
        };
        if getcury(self.window) != 0 {
            waddch(self.window, '\n' as u64);
        }
        waddstr(self.window, &message);
    }
}
<|endoftext|>


<commit_before>//! LSIF (language server index format) generator

use std::collections::HashMap;
use std::env;
use std::time::Instant;

use ide::{
    Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex,
    StaticIndexedFile, TokenId, TokenStaticData,
};
use ide_db::LineIndexDatabase;

use ide_db::base_db::salsa::{self, ParallelDatabase};
use lsp_types::{self, lsif};
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
use vfs::{AbsPathBuf, Vfs};

use crate::cli::{
    flags,
    load_cargo::{load_workspace, LoadCargoConfig},
    Result,
};
use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
use crate::to_proto;

/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap<DB>(DB);
impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
        Snap(self.0.snapshot())
    }
}

struct LsifManager<'a> {
    count: i32,
    token_map: HashMap<TokenId, Id>,
    range_map: HashMap<FileRange, Id>,
    file_map: HashMap<FileId, Id>,
    package_map: HashMap<PackageInformation, Id>,
    analysis: &'a Analysis,
    db: &'a RootDatabase,
    vfs: &'a Vfs,
}

#[derive(Clone, Copy)]
struct Id(i32);

impl From<Id> for lsp_types::NumberOrString {
    fn from(Id(x): Id) -> Self {
        lsp_types::NumberOrString::Number(x)
    }
}

impl LsifManager<'_> {
    fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
        LsifManager {
            count: 0,
            token_map: HashMap::default(),
            range_map: HashMap::default(),
            file_map: HashMap::default(),
            package_map: HashMap::default(),
            analysis,
            db,
            vfs,
        }
    }

    fn add(&mut self, data: lsif::Element) -> Id {
        let id = Id(self.count);
        self.emit(&serde_json::to_string(&lsif::Entry { id: id.into(), data }).unwrap());
        self.count += 1;
        id
    }

    fn add_vertex(&mut self, vertex: lsif::Vertex) -> Id {
        self.add(lsif::Element::Vertex(vertex))
    }

    fn add_edge(&mut self, edge: lsif::Edge) -> Id {
        self.add(lsif::Element::Edge(edge))
    }

    // FIXME: support file in addition to stdout here
    fn emit(&self, data: &str) {
        println!("{}", data);
    }

    fn get_token_id(&mut self, id: TokenId) -> Id {
        if let Some(x) = self.token_map.get(&id) {
            return *x;
        }
        let result_set_id = self.add_vertex(lsif::Vertex::ResultSet(lsif::ResultSet { key: None }));
        self.token_map.insert(id, result_set_id);
        result_set_id
    }

    fn get_package_id(&mut self, package_information: PackageInformation) -> Id {
        if let Some(x) = self.package_map.get(&package_information) {
            return *x;
        }
        let pi = package_information.clone();
        let result_set_id =
            self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation {
                name: pi.name,
                manager: "cargo".to_string(),
                uri: None,
                content: None,
                repository: Some(lsif::Repository {
                    url: pi.repo,
                    r#type: "git".to_string(),
                    commit_id: None,
                }),
                version: Some(pi.version),
            }));
        self.package_map.insert(package_information, result_set_id);
        result_set_id
    }

    fn get_range_id(&mut self, id: FileRange) -> Id {
        if let Some(x) = self.range_map.get(&id) {
            return *x;
        }
        let file_id = id.file_id;
        let doc_id = self.get_file_id(file_id);
        let line_index = self.db.line_index(file_id);
        let line_index = LineIndex {
            index: line_index,
            encoding: OffsetEncoding::Utf16,
            endings: LineEndings::Unix,
        };
        let range_id = self.add_vertex(lsif::Vertex::Range {
            range: to_proto::range(&line_index, id.range),
            tag: None,
        });
        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
            in_vs: vec![range_id.into()],
            out_v: doc_id.into(),
        }));
        range_id
    }

    fn get_file_id(&mut self, id: FileId) -> Id {
        if let Some(x) = self.file_map.get(&id) {
            return *x;
        }
        let path = self.vfs.file_path(id);
        let path = path.as_path().unwrap();
        let doc_id = self.add_vertex(lsif::Vertex::Document(lsif::Document {
            language_id: "rust".to_string(),
            uri: lsp_types::Url::from_file_path(path).unwrap(),
        }));
        self.file_map.insert(id, doc_id);
        doc_id
    }

    fn add_token(&mut self, id: TokenId, token: TokenStaticData) {
        let result_set_id = self.get_token_id(id);
        if let Some(hover) = token.hover {
            let hover_id = self.add_vertex(lsif::Vertex::HoverResult {
                result: lsp_types::Hover {
                    contents: lsp_types::HoverContents::Markup(to_proto::markup_content(
                        hover.markup,
                        ide::HoverDocFormat::Markdown,
                    )),
                    range: None,
                },
            });
            self.add_edge(lsif::Edge::Hover(lsif::EdgeData {
                in_v: hover_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if let Some(moniker) = token.moniker {
            let package_id = self.get_package_id(moniker.package_information);
            let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
                scheme: "rust-analyzer".to_string(),
                identifier: moniker.identifier.to_string(),
                unique: lsp_types::UniquenessLevel::Scheme,
                kind: Some(match moniker.kind {
                    MonikerKind::Import => lsp_types::MonikerKind::Import,
                    MonikerKind::Export => lsp_types::MonikerKind::Export,
                }),
            }));
            self.add_edge(lsif::Edge::PackageInformation(lsif::EdgeData {
                in_v: package_id.into(),
                out_v: moniker_id.into(),
            }));
            self.add_edge(lsif::Edge::Moniker(lsif::EdgeData {
                in_v: moniker_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if let Some(def) = token.definition {
            let result_id = self.add_vertex(lsif::Vertex::DefinitionResult);
            let def_vertex = self.get_range_id(def);
            self.add_edge(lsif::Edge::Item(lsif::Item {
                document: (*self.file_map.get(&def.file_id).unwrap()).into(),
                property: None,
                edge_data: lsif::EdgeDataMultiIn {
                    in_vs: vec![def_vertex.into()],
                    out_v: result_id.into(),
                },
            }));
            self.add_edge(lsif::Edge::Definition(lsif::EdgeData {
                in_v: result_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if !token.references.is_empty() {
            let result_id = self.add_vertex(lsif::Vertex::ReferenceResult);
            self.add_edge(lsif::Edge::References(lsif::EdgeData {
                in_v: result_id.into(),
                out_v: result_set_id.into(),
            }));
            let edges = token.references.iter().fold(
                HashMap::<_, Vec<lsp_types::NumberOrString>>::new(),
                |mut edges, x| {
                    let entry =
                        edges.entry((x.range.file_id, x.is_definition)).or_insert_with(Vec::new);
                    entry.push((*self.range_map.get(&x.range).unwrap()).into());
                    edges
                },
            );
            for ((file_id, is_definition), vertices) in edges.into_iter() {
                self.add_edge(lsif::Edge::Item(lsif::Item {
                    document: (*self.file_map.get(&file_id).unwrap()).into(),
                    property: Some(if is_definition {
                        lsif::ItemKind::Definitions
                    } else {
                        lsif::ItemKind::References
                    }),
                    edge_data: lsif::EdgeDataMultiIn { in_vs: vertices, out_v: result_id.into() },
                }));
            }
        }
    }

    fn add_file(&mut self, file: StaticIndexedFile) {
        let StaticIndexedFile { file_id, tokens, folds, .. } = file;
        let doc_id = self.get_file_id(file_id);
        let text = self.analysis.file_text(file_id).unwrap();
        let line_index = self.db.line_index(file_id);
        let line_index = LineIndex {
            index: line_index,
            encoding: OffsetEncoding::Utf16,
            endings: LineEndings::Unix,
        };
        let result = folds
            .into_iter()
            .map(|it| to_proto::folding_range(&*text, &line_index, false, it))
            .collect();
        let folding_id = self.add_vertex(lsif::Vertex::FoldingRangeResult { result });
        self.add_edge(lsif::Edge::FoldingRange(lsif::EdgeData {
            in_v: folding_id.into(),
            out_v: doc_id.into(),
        }));
        let tokens_id = tokens
            .into_iter()
            .map(|(range, id)| {
                let range_id = self.add_vertex(lsif::Vertex::Range {
                    range: to_proto::range(&line_index, range),
                    tag: None,
                });
                self.range_map.insert(FileRange { file_id, range }, range_id);
                let result_set_id = self.get_token_id(id);
                self.add_edge(lsif::Edge::Next(lsif::EdgeData {
                    in_v: result_set_id.into(),
                    out_v: range_id.into(),
                }));
                range_id.into()
            })
            .collect();
        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
            in_vs: tokens_id,
            out_v: doc_id.into(),
        }));
    }
}

impl flags::Lsif {
    pub fn run(self) -> Result<()> {
        eprintln!("Generating LSIF started...");
        let now = Instant::now();
        let cargo_config = CargoConfig::default();
        let no_progress = &|_| ();
        let load_cargo_config = LoadCargoConfig {
            load_out_dirs_from_check: true,
            with_proc_macro: true,
            prefill_caches: false,
        };
        let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
        let manifest = ProjectManifest::discover_single(&path)?;

        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;

        let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
        let db = host.raw_database();
        let analysis = host.analysis();

        let si = StaticIndex::compute(&analysis);

        let mut lsif = LsifManager::new(&analysis, db, &vfs);
        lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData {
            version: String::from("0.5.0"),
            project_root: lsp_types::Url::from_file_path(path).unwrap(),
            position_encoding: lsif::Encoding::Utf16,
            tool_info: Some(lsp_types::lsif::ToolInfo {
                name: "rust-analyzer".to_string(),
                args: vec![],
                version: Some(env!("REV").to_string()),
            }),
        }));
        for file in si.files {
            lsif.add_file(file);
        }
        for (id, token) in si.tokens.iter() {
            lsif.add_token(id, token);
        }
        eprintln!("Generating LSIF finished in {:?}", now.elapsed());
        Ok(())
    }
}
<commit_msg>Preserve order when grouping references.<commit_after>//! LSIF (language server index format) generator

use std::collections::HashMap;
use std::env;
use std::time::Instant;

use ide::{
    Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex,
    StaticIndexedFile, TokenId, TokenStaticData,
};
use ide_db::LineIndexDatabase;

use ide_db::base_db::salsa::{self, ParallelDatabase};
use lsp_types::{self, lsif};
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
use vfs::{AbsPathBuf, Vfs};

use crate::cli::{
    flags,
    load_cargo::{load_workspace, LoadCargoConfig},
    Result,
};
use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
use crate::to_proto;

/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap<DB>(DB);
impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
        Snap(self.0.snapshot())
    }
}

struct LsifManager<'a> {
    count: i32,
    token_map: HashMap<TokenId, Id>,
    range_map: HashMap<FileRange, Id>,
    file_map: HashMap<FileId, Id>,
    package_map: HashMap<PackageInformation, Id>,
    analysis: &'a Analysis,
    db: &'a RootDatabase,
    vfs: &'a Vfs,
}

#[derive(Clone, Copy)]
struct Id(i32);

impl From<Id> for lsp_types::NumberOrString {
    fn from(Id(x): Id) -> Self {
        lsp_types::NumberOrString::Number(x)
    }
}

impl LsifManager<'_> {
    fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
        LsifManager {
            count: 0,
            token_map: HashMap::default(),
            range_map: HashMap::default(),
            file_map: HashMap::default(),
            package_map: HashMap::default(),
            analysis,
            db,
            vfs,
        }
    }

    fn add(&mut self, data: lsif::Element) -> Id {
        let id = Id(self.count);
        self.emit(&serde_json::to_string(&lsif::Entry { id: id.into(), data }).unwrap());
        self.count += 1;
        id
    }

    fn add_vertex(&mut self, vertex: lsif::Vertex) -> Id {
        self.add(lsif::Element::Vertex(vertex))
    }

    fn add_edge(&mut self, edge: lsif::Edge) -> Id {
        self.add(lsif::Element::Edge(edge))
    }

    // FIXME: support file in addition to stdout here
    fn emit(&self, data: &str) {
        println!("{}", data);
    }

    fn get_token_id(&mut self, id: TokenId) -> Id {
        if let Some(x) = self.token_map.get(&id) {
            return *x;
        }
        let result_set_id = self.add_vertex(lsif::Vertex::ResultSet(lsif::ResultSet { key: None }));
        self.token_map.insert(id, result_set_id);
        result_set_id
    }

    fn get_package_id(&mut self, package_information: PackageInformation) -> Id {
        if let Some(x) = self.package_map.get(&package_information) {
            return *x;
        }
        let pi = package_information.clone();
        let result_set_id =
            self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation {
                name: pi.name,
                manager: "cargo".to_string(),
                uri: None,
                content: None,
                repository: Some(lsif::Repository {
                    url: pi.repo,
                    r#type: "git".to_string(),
                    commit_id: None,
                }),
                version: Some(pi.version),
            }));
        self.package_map.insert(package_information, result_set_id);
        result_set_id
    }

    fn get_range_id(&mut self, id: FileRange) -> Id {
        if let Some(x) = self.range_map.get(&id) {
            return *x;
        }
        let file_id = id.file_id;
        let doc_id = self.get_file_id(file_id);
        let line_index = self.db.line_index(file_id);
        let line_index = LineIndex {
            index: line_index,
            encoding: OffsetEncoding::Utf16,
            endings: LineEndings::Unix,
        };
        let range_id = self.add_vertex(lsif::Vertex::Range {
            range: to_proto::range(&line_index, id.range),
            tag: None,
        });
        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
            in_vs: vec![range_id.into()],
            out_v: doc_id.into(),
        }));
        range_id
    }

    fn get_file_id(&mut self, id: FileId) -> Id {
        if let Some(x) = self.file_map.get(&id) {
            return *x;
        }
        let path = self.vfs.file_path(id);
        let path = path.as_path().unwrap();
        let doc_id = self.add_vertex(lsif::Vertex::Document(lsif::Document {
            language_id: "rust".to_string(),
            uri: lsp_types::Url::from_file_path(path).unwrap(),
        }));
        self.file_map.insert(id, doc_id);
        doc_id
    }

    fn add_token(&mut self, id: TokenId, token: TokenStaticData) {
        let result_set_id = self.get_token_id(id);
        if let Some(hover) = token.hover {
            let hover_id = self.add_vertex(lsif::Vertex::HoverResult {
                result: lsp_types::Hover {
                    contents: lsp_types::HoverContents::Markup(to_proto::markup_content(
                        hover.markup,
                        ide::HoverDocFormat::Markdown,
                    )),
                    range: None,
                },
            });
            self.add_edge(lsif::Edge::Hover(lsif::EdgeData {
                in_v: hover_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if let Some(moniker) = token.moniker {
            let package_id = self.get_package_id(moniker.package_information);
            let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
                scheme: "rust-analyzer".to_string(),
                identifier: moniker.identifier.to_string(),
                unique: lsp_types::UniquenessLevel::Scheme,
                kind: Some(match moniker.kind {
                    MonikerKind::Import => lsp_types::MonikerKind::Import,
                    MonikerKind::Export => lsp_types::MonikerKind::Export,
                }),
            }));
            self.add_edge(lsif::Edge::PackageInformation(lsif::EdgeData {
                in_v: package_id.into(),
                out_v: moniker_id.into(),
            }));
            self.add_edge(lsif::Edge::Moniker(lsif::EdgeData {
                in_v: moniker_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if let Some(def) = token.definition {
            let result_id = self.add_vertex(lsif::Vertex::DefinitionResult);
            let def_vertex = self.get_range_id(def);
            self.add_edge(lsif::Edge::Item(lsif::Item {
                document: (*self.file_map.get(&def.file_id).unwrap()).into(),
                property: None,
                edge_data: lsif::EdgeDataMultiIn {
                    in_vs: vec![def_vertex.into()],
                    out_v: result_id.into(),
                },
            }));
            self.add_edge(lsif::Edge::Definition(lsif::EdgeData {
                in_v: result_id.into(),
                out_v: result_set_id.into(),
            }));
        }
        if !token.references.is_empty() {
            let result_id = self.add_vertex(lsif::Vertex::ReferenceResult);
            self.add_edge(lsif::Edge::References(lsif::EdgeData {
                in_v: result_id.into(),
                out_v: result_set_id.into(),
            }));
            let mut edges = token.references.iter().fold(
                HashMap::<_, Vec<lsp_types::NumberOrString>>::new(),
                |mut edges, x| {
                    let entry =
                        edges.entry((x.range.file_id, x.is_definition)).or_insert_with(Vec::new);
                    entry.push((*self.range_map.get(&x.range).unwrap()).into());
                    edges
                },
            );
            for x in token.references {
                if let Some(vertices) = edges.remove(&(x.range.file_id, x.is_definition)) {
                    self.add_edge(lsif::Edge::Item(lsif::Item {
                        document: (*self.file_map.get(&x.range.file_id).unwrap()).into(),
                        property: Some(if x.is_definition {
                            lsif::ItemKind::Definitions
                        } else {
                            lsif::ItemKind::References
                        }),
                        edge_data: lsif::EdgeDataMultiIn {
                            in_vs: vertices,
                            out_v: result_id.into(),
                        },
                    }));
                }
            }
        }
    }

    fn add_file(&mut self, file: StaticIndexedFile) {
        let StaticIndexedFile { file_id, tokens, folds, .. } = file;
        let doc_id = self.get_file_id(file_id);
        let text = self.analysis.file_text(file_id).unwrap();
        let line_index = self.db.line_index(file_id);
        let line_index = LineIndex {
            index: line_index,
            encoding: OffsetEncoding::Utf16,
            endings: LineEndings::Unix,
        };
        let result = folds
            .into_iter()
            .map(|it| to_proto::folding_range(&*text, &line_index, false, it))
            .collect();
        let folding_id = self.add_vertex(lsif::Vertex::FoldingRangeResult { result });
        self.add_edge(lsif::Edge::FoldingRange(lsif::EdgeData {
            in_v: folding_id.into(),
            out_v: doc_id.into(),
        }));
        let tokens_id = tokens
            .into_iter()
            .map(|(range, id)| {
                let range_id = self.add_vertex(lsif::Vertex::Range {
                    range: to_proto::range(&line_index, range),
                    tag: None,
                });
                self.range_map.insert(FileRange { file_id, range }, range_id);
                let result_set_id = self.get_token_id(id);
                self.add_edge(lsif::Edge::Next(lsif::EdgeData {
                    in_v: result_set_id.into(),
                    out_v: range_id.into(),
                }));
                range_id.into()
            })
            .collect();
        self.add_edge(lsif::Edge::Contains(lsif::EdgeDataMultiIn {
            in_vs: tokens_id,
            out_v: doc_id.into(),
        }));
    }
}

impl flags::Lsif {
    pub fn run(self) -> Result<()> {
        eprintln!("Generating LSIF started...");
        let now = Instant::now();
        let cargo_config = CargoConfig::default();
        let no_progress = &|_| ();
        let load_cargo_config = LoadCargoConfig {
            load_out_dirs_from_check: true,
            with_proc_macro: true,
            prefill_caches: false,
        };
        let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
        let manifest = ProjectManifest::discover_single(&path)?;

        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;

        let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
        let db = host.raw_database();
        let analysis = host.analysis();

        let si = StaticIndex::compute(&analysis);

        let mut lsif = LsifManager::new(&analysis, db, &vfs);
        lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData {
            version: String::from("0.5.0"),
            project_root: lsp_types::Url::from_file_path(path).unwrap(),
            position_encoding: lsif::Encoding::Utf16,
            tool_info: Some(lsp_types::lsif::ToolInfo {
                name: "rust-analyzer".to_string(),
                args: vec![],
                version: Some(env!("REV").to_string()),
            }),
        }));
        for file in si.files {
            lsif.add_file(file);
        }
        for (id, token) in si.tokens.iter() {
            lsif.add_token(id, token);
        }
        eprintln!("Generating LSIF finished in {:?}", now.elapsed());
        Ok(())
    }
}
<|endoftext|>


<commit_before>use libc::c_int;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wl_display, wlr_compositor, wlr_xwayland, wlr_xwayland_create,
                  wlr_xwayland_destroy, pid_t, wl_client};

use super::{XWaylandManager, XWaylandManagerHandler};

pub struct XWaylandServer {
    xwayland: *mut wlr_xwayland,
    manager: Box<XWaylandManager>
}

impl XWaylandServer {
    pub(crate) unsafe fn new(display: *mut wl_display,
                             compositor: *mut wlr_compositor,
                             manager: Box<XWaylandManagerHandler>)
                             -> Self {
        let xwayland = wlr_xwayland_create(display, compositor);
        let mut manager = XWaylandManager::new(manager);
        wl_signal_add(&mut (*xwayland).events.ready as *mut _ as _,
                      manager.on_ready_listener() as *mut _ as _);
        wl_signal_add(&mut (*xwayland).events.new_surface as *mut _ as _,
                      manager.new_surface_listener() as *mut _ as _);
        if xwayland.is_null() {
            panic!("Could not start XWayland server")
        }
        XWaylandServer { xwayland, manager }
    }

    /// Get the PID of the XWayland server.
    pub fn pid(&self) -> pid_t {
        unsafe { (*self.xwayland).pid }
    }

    pub fn display(&self) -> c_int {
        unsafe { (*self.xwayland).display }
    }

    pub fn x_fd(&self) -> [c_int; 2] {
        unsafe { (*self.xwayland).x_fd }
    }

    pub fn wl_fd(&self) -> [c_int; 2] {
        unsafe { (*self.xwayland).wl_fd }
    }

    pub fn wm_fd(&self) -> [c_int; 2] {
        unsafe {(*self.xwayland).wm_fd }
    }

    pub fn wl_client(&self) -> *mut wl_client {
        unsafe { (*self.xwayland).client }
    }
}

impl Drop for XWaylandServer {
    fn drop(&mut self) {
        unsafe { wlr_xwayland_destroy(self.xwayland) }
    }
}
<commit_msg>Fixed possible segfault<commit_after>use libc::c_int;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{pid_t, wl_client, wl_display, wlr_compositor, wlr_xwayland, wlr_xwayland_create,
                  wlr_xwayland_destroy};

use super::{XWaylandManager, XWaylandManagerHandler};

pub struct XWaylandServer {
    xwayland: *mut wlr_xwayland,
    manager: Box<XWaylandManager>
}

impl XWaylandServer {
    pub(crate) unsafe fn new(display: *mut wl_display,
                             compositor: *mut wlr_compositor,
                             manager: Box<XWaylandManagerHandler>)
                             -> Self {
        let xwayland = wlr_xwayland_create(display, compositor);
        if xwayland.is_null() {
            panic!("Could not start XWayland server")
        }
        let mut manager = XWaylandManager::new(manager);
        wl_signal_add(&mut (*xwayland).events.ready as *mut _ as _,
                      manager.on_ready_listener() as *mut _ as _);
        wl_signal_add(&mut (*xwayland).events.new_surface as *mut _ as _,
                      manager.new_surface_listener() as *mut _ as _);
        XWaylandServer { xwayland, manager }
    }

    /// Get the PID of the XWayland server.
    pub fn pid(&self) -> pid_t {
        unsafe { (*self.xwayland).pid }
    }

    pub fn display(&self) -> c_int {
        unsafe { (*self.xwayland).display }
    }

    pub fn x_fd(&self) -> [c_int; 2] {
        unsafe { (*self.xwayland).x_fd }
    }

    pub fn wl_fd(&self) -> [c_int; 2] {
        unsafe { (*self.xwayland).wl_fd }
    }

    pub fn wm_fd(&self) -> [c_int; 2] {
        unsafe { (*self.xwayland).wm_fd }
    }

    pub fn wl_client(&self) -> *mut wl_client {
        unsafe { (*self.xwayland).client }
    }
}

impl Drop for XWaylandServer {
    fn drop(&mut self) {
        unsafe { wlr_xwayland_destroy(self.xwayland) }
    }
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum Player {
    A,
    B,
    C,
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let mut cards: Vec<u8> = Vec::new();
    // print sorted cards
    for n in 0..32 {
        cards.push(n);
    }
    for n in 0..8 {
        print_card(n);
    };
    println!("");
    for n in 8..16 {
        print_card(n);
    }
    println!("");
    for n in 16..24 {
        print_card(n);
    };
    println!("");
    for n in 24..32 {
        print_card(n);
    };
    println!("");
    println!("");
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // print shuffled cards (per player plus Skat)
    for n in 0..10 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 10..20 {
        print_card(shuffled[n]);
    }
    println!("");
    for n in 20..30 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_number: u8 = rand::thread_rng().gen_range(0, 3);
    match player_number {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_number),
    }
    loop {
        // player player_number is dealing
        deal(player_number);
        // bid
        let (player, bid) = bid(player_number);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<commit_msg>Rename Player into PlayerId but don't use it (yet).<commit_after>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let mut cards: Vec<u8> = Vec::new();
    // print sorted cards
    for n in 0..32 {
        cards.push(n);
    }
    for n in 0..8 {
        print_card(n);
    };
    println!("");
    for n in 8..16 {
        print_card(n);
    }
    println!("");
    for n in 16..24 {
        print_card(n);
    };
    println!("");
    for n in 24..32 {
        print_card(n);
    };
    println!("");
    println!("");
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // print shuffled cards (per player plus Skat)
    for n in 0..10 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 10..20 {
        print_card(shuffled[n]);
    }
    println!("");
    for n in 20..30 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    match player_id {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_id),
    }
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Slight refactoring<commit_after><|endoftext|>


<commit_before>#![cfg(unix)]

extern crate rexpect;

use rexpect::spawn;
use rexpect::session::PtySession;
use rexpect::errors::*;

macro_rules! test {
    ($b: block) => {
        if ::std::env::var("GLUON_PATH").is_err() {
            ::std::env::set_var("GLUON_PATH", "..");
        }

        || -> Result<()> {
            $b
            Ok(())
        }().unwrap_or_else(|err| panic!("{}", err));
    };
}

struct REPL {
    session: PtySession,
    prompt: &'static str,
}

impl REPL {
    /// Defines the command, timeout, and prompt settings.
    /// Wraps a rexpect::session::PtySession. expecting the prompt after launch.
    fn new() -> Result<REPL> {
        let command = "../target/debug/gluon -i";
        let timeout: u64 = 10_000;
        let prompt: &'static str = "> ";

        let mut session = spawn(command, Some(timeout))?;
        session.exp_string(prompt)?;

        Ok(REPL { session, prompt })
    }

    /// Ensures certain lines are expected to reduce race conditions.
    /// If no ouput is expected or desired to be tested, pass it an Option::None,
    /// causing rexpect to wait for the next prompt.
    fn test(&mut self, send: &str, expect: Option<&str>) -> Result<()> {
        self.session.send_line(send)?;
        self.session.exp_string(send)?;

        if let Some(string) = expect {
            self.session.exp_string(string)?;
        }

        self.session.exp_string(self.prompt)?;
        Ok(())
    }

    fn quit(&mut self) -> Result<()> {
        let line: &'static str = ":q";
        self.session.send_line(line)?;
        self.session.exp_string(line)?;
        self.session.exp_eof()?;
        Ok(())
    }
}

#[test]
fn prompt() {
    test!({
        let mut repl = REPL::new()?;
        repl.test(repl.prompt, None)?;
    });
}

#[test]
fn exit() {
    test!({
        let mut repl = REPL::new()?;
        repl.quit()?;
    });
}

#[test]
fn hello_world() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let io = import! std.io", None)?;
        repl.test("io.println \"Hello world\"", Some("Hello world"))?;
    });
}

#[test]
fn expression_types() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(":t 5", Some("Int"))?;
        // repl.test(":t 5 + 5", Some("Int -> Int"))?;
        repl.test(":t \"gluon\"", Some("String"))?;
    });
}

#[test]
fn names() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(
            ":i std.prelude.show",
            Some("std.prelude.show: forall a . [std.prelude.Show a] -> a -> String"),
        )?;
    });
}

#[test]
fn comments() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("1 + 2 // Calls the + function on 1 and 2", Some("3"))?;
        repl.test("1 + 2 /* Calls the + function on 1 and 2 */", Some("3"))?;
    });
}

#[test]
fn if_expressions() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("if True then 1 else 0", Some("1"))?;
        repl.test("if False then 1 else 0", Some("0"))?;
    });
}

#[test]
fn records() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let record = { pi = 3.14, add1 = (+) 1.0 }", None)?;
        repl.test("record.pi", Some("3.14"))?;

        repl.test("let record_2 = {x = 1 .. record }", None)?;
        repl.test("record_2.x", Some("1"))?;
        repl.test("record_2.pi", Some("3.14"))?;
    });
}

#[test]
fn arrays() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let array = import! std.array", None)?;
        repl.test("array.len [1, 2, 3]", Some("3"))?;
    });
}
<commit_msg>Remove extra prompt test.<commit_after>#![cfg(unix)]

extern crate rexpect;

use rexpect::spawn;
use rexpect::session::PtySession;
use rexpect::errors::*;

macro_rules! test {
    ($b: block) => {
        if ::std::env::var("GLUON_PATH").is_err() {
            ::std::env::set_var("GLUON_PATH", "..");
        }

        || -> Result<()> {
            $b
            Ok(())
        }().unwrap_or_else(|err| panic!("{}", err));
    };
}

struct REPL {
    session: PtySession,
    prompt: &'static str,
}

impl REPL {
    /// Defines the command, timeout, and prompt settings.
    /// Wraps a rexpect::session::PtySession. expecting the prompt after launch.
    fn new() -> Result<REPL> {
        let command = "../target/debug/gluon -i";
        let timeout: u64 = 10_000;
        let prompt: &'static str = "> ";

        let mut session = spawn(command, Some(timeout))?;
        session.exp_string(prompt)?;

        Ok(REPL { session, prompt })
    }

    /// Ensures certain lines are expected to reduce race conditions.
    /// If no ouput is expected or desired to be tested, pass it an Option::None,
    /// causing rexpect to wait for the next prompt.
    fn test(&mut self, send: &str, expect: Option<&str>) -> Result<()> {
        self.session.send_line(send)?;
        self.session.exp_string(send)?;

        if let Some(string) = expect {
            self.session.exp_string(string)?;
        }

        self.session.exp_string(self.prompt)?;
        Ok(())
    }

    fn quit(&mut self) -> Result<()> {
        let line: &'static str = ":q";
        self.session.send_line(line)?;
        self.session.exp_string(line)?;
        self.session.exp_eof()?;
        Ok(())
    }
}

#[test]
fn prompt() {
    test!({
        let mut repl = REPL::new()?;
    });
}

#[test]
fn exit() {
    test!({
        let mut repl = REPL::new()?;
        repl.quit()?;
    });
}

#[test]
fn hello_world() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let io = import! std.io", None)?;
        repl.test("io.println \"Hello world\"", Some("Hello world"))?;
    });
}

#[test]
fn expression_types() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(":t 5", Some("Int"))?;
        // repl.test(":t 5 + 5", Some("Int -> Int"))?;
        repl.test(":t \"gluon\"", Some("String"))?;
    });
}

#[test]
fn names() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(
            ":i std.prelude.show",
            Some("std.prelude.show: forall a . [std.prelude.Show a] -> a -> String"),
        )?;
    });
}

#[test]
fn comments() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("1 + 2 // Calls the + function on 1 and 2", Some("3"))?;
        repl.test("1 + 2 /* Calls the + function on 1 and 2 */", Some("3"))?;
    });
}

#[test]
fn if_expressions() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("if True then 1 else 0", Some("1"))?;
        repl.test("if False then 1 else 0", Some("0"))?;
    });
}

#[test]
fn records() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let record = { pi = 3.14, add1 = (+) 1.0 }", None)?;
        repl.test("record.pi", Some("3.14"))?;

        repl.test("let record_2 = {x = 1 .. record }", None)?;
        repl.test("record_2.x", Some("1"))?;
        repl.test("record_2.pi", Some("3.14"))?;
    });
}

#[test]
fn arrays() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let array = import! std.array", None)?;
        repl.test("array.len [1, 2, 3]", Some("3"))?;
    });
}
<|endoftext|>