<commit_before>use futures::{self, Async, BoxFuture, Future, Poll};
use libc;
use nom::IResult;
use std::borrow::Cow;
use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{Error, ErrorKind};
use std::str;
use tokio_core::easy::{EasyBuf, EasyFramed, Parse, Serialize};
use tokio_core::io::Io;

use framed;

pub enum AuthMode {
    External,
}

pub type AuthFuture<T> = BoxFuture<T, AuthError>;

#[derive(Debug)]
pub enum AuthError {
    Io(Error),
    Rejected,
    ServerError,
}

impl Display for AuthError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            AuthError::Io(ref err) => write!(f, "D-Bus IO error: {}", err),
            _ => f.write_str(error::Error::description(self)),
        }
    }
}

impl error::Error for AuthError {
    fn description(&self) -> &str {
        match *self {
            AuthError::Io(ref err) => err.description(),
            AuthError::Rejected => "D-Bus server rejected the authentication attempt",
            AuthError::ServerError => "D-Bus server reported an authentication error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            AuthError::Io(ref err) => Some(err),
            AuthError::ServerError | AuthError::Rejected => None,
        }
    }
}

impl From<Error> for AuthError {
    fn from(err: Error) -> Self {
        AuthError::Io(err)
    }
}

impl From<AuthError> for Error {
    fn from(err: AuthError) -> Self {
        match err {
            AuthError::Io(err) => err,
            AuthError::Rejected => {
                Error::new(ErrorKind::PermissionDenied, error::Error::description(&err))
            }
            AuthError::ServerError => {
                Error::new(ErrorKind::InvalidInput, error::Error::description(&err))
            }
        }
    }
}

pub fn authenticate<T>(upstream: T, auth_mode: AuthMode) -> AuthFuture<T>
    where T: Io + Send + 'static
{
    let auth_stream = AuthStream::new(upstream);
    let auth = match auth_mode {
        AuthMode::External => auth_external(auth_stream),
    };
    let pack = auth.map(AuthStream::into_upstream);

    pack.boxed()
}

fn get_uid_str() -> String {
    unsafe { libc::getuid().to_string() }
}

fn auth_external<T>(auth_stream: AuthStream<T>) -> AuthFuture<AuthStream<T>>
    where T: Io + Send + 'static
{
    let send = auth_stream.send(ClientCommand::Auth {
        mechanism: "EXTERNAL".into(),
        initial_response: Some(get_uid_str().into()),
    });
    let recv = send.and_then(|auth_stream| auth_stream.recv());
    let begin = recv.and_then(|(auth_stream, cmd)| {
        match cmd {
            ServerCommand::Ok => auth_stream.send(ClientCommand::Begin),
            ServerCommand::Rejected => futures::failed(AuthError::Rejected).boxed(),
            ServerCommand::Error => futures::failed(AuthError::ServerError).boxed(),
            // _ => futures::failed(AuthError::from(unexpected_response())).boxed(),
        }
    });

    begin.boxed()
}

#[derive(Debug)]
enum ClientCommand {
    Auth {
        mechanism: Cow<'static, str>,
        initial_response: Option<Cow<'static, str>>,
    },
    Begin,
}

#[derive(Debug)]
enum ServerCommand {
    Ok,
    Rejected,
    Error,
}

struct AuthStream<T> {
    inner: EasyFramed<T, ServerCommandParser, ClientCommandSerializer>,
}

impl<T> AuthStream<T>
    where T: Io + Send + 'static
{
    pub fn new(upstream: T) -> Self {
        AuthStream {
            inner: EasyFramed::new(upstream, ServerCommandParser, ClientCommandSerializer),
        }
    }

    pub fn into_upstream(self) -> T {
        self.inner.into_upstream()
    }

    pub fn recv(self) -> AuthFuture<(Self, ServerCommand)> {
        let AuthStream { inner } = self;

        let read = framed::read(inner);
        let unwrap = read.and_then(|(inner, cmd)| {
            match cmd {
                Some(cmd) => Ok((inner, cmd)),
                None => Err(connection_reset()),
            }
        });
        let pack = unwrap.map(|(inner, cmd)| (AuthStream { inner: inner }, cmd))
            .map_err(AuthError::from);

        pack.boxed()
    }

    pub fn send(self, cmd: ClientCommand) -> AuthFuture<Self> {
        let AuthStream { inner } = self;

        let write = framed::write(inner, cmd);
        let flush = write.and_then(framed::flush);
        let pack = flush.map(|inner| AuthStream { inner: inner }).map_err(AuthError::from);

        pack.boxed()
    }
}

struct ClientCommandSerializer;

static HEX_CHARS: &'static [u8] = b"0123456789abcdef";

fn hex_encoded_len(src: &str) -> usize {
    2 * src.len()
}

fn extend_from_hex_encoded(buf: &mut Vec<u8>, src: &str) {
    for byte in src.as_bytes() {
        buf.push(HEX_CHARS[(byte >> 4) as usize]);
        buf.push(HEX_CHARS[(byte & 0xf) as usize]);
    }
}

impl Serialize for ClientCommandSerializer {
    type In = ClientCommand;

    fn serialize(&mut self, msg: &Self::In, buf: &mut Vec<u8>) {
        match *msg {
            ClientCommand::Auth { ref mechanism, ref initial_response } => {
                buf.reserve(8 + initial_response.as_ref().map_or(0, |s| 1 + hex_encoded_len(&s)));

                buf.extend_from_slice("\0AUTH ".as_bytes());
                buf.extend_from_slice(mechanism.as_bytes());

                match *initial_response {
                    None => {}
                    Some(ref initial_response) => {
                        buf.push(' ' as u8);
                        extend_from_hex_encoded(buf, &initial_response);
                    }
                }

                buf.extend_from_slice("\r\n".as_bytes());
            }
            ClientCommand::Begin => buf.extend_from_slice("BEGIN\r\n".as_bytes()),
        }
    }
}

struct ServerCommandParser;

named!(parse_server_cmd<&[u8], ServerCommand>,
    chain!(
        cmd: alt!(parse_server_cmd_ok | parse_server_cmd_rejected | parse_server_cmd_error) ~
        tag!("\r\n"),
        || { cmd }
    )
);

named!(parse_server_cmd_ok<&[u8], ServerCommand>,
    value!(ServerCommand::Ok, preceded!(tag!("OK "), take_until!("\r\n")))
);

named!(parse_server_cmd_rejected<&[u8], ServerCommand>,
    value!(ServerCommand::Rejected, preceded!(tag!("REJECTED "), take_until!("\r\n")))
);

named!(parse_server_cmd_error<&[u8], ServerCommand>,
    value!(ServerCommand::Error, tag!("ERROR"))
);

impl Parse for ServerCommandParser {
    type Out = ServerCommand;

    fn parse(&mut self, buf: &mut EasyBuf) -> Poll<Self::Out, Error> {
        let (result, consumed) = match parse_server_cmd(buf.as_slice()) {
            IResult::Done(remaining, cmd) => (Ok(Async::Ready(cmd)), buf.len() - remaining.len()),
            IResult::Incomplete(_) => return Ok(Async::NotReady),
            IResult::Error(_) => return Err(unexpected_response()),
        };
        buf.drain_to(consumed);
        result
    }
}

fn connection_reset() -> Error {
    Error::new(ErrorKind::ConnectionReset, "D-Bus connection reset")
}

fn unexpected_response() -> Error {
    Error::new(ErrorKind::InvalidData, "unexpected D-Bus auth response")
}
<commit_msg>Fix rust-clippy nits<commit_after>use futures::{self, Async, BoxFuture, Future, Poll};
use libc;
use nom::IResult;
use std::borrow::Cow;
use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{Error, ErrorKind};
use std::str;
use tokio_core::easy::{EasyBuf, EasyFramed, Parse, Serialize};
use tokio_core::io::Io;

use framed;

pub enum AuthMode {
    External,
}

pub type AuthFuture<T> = BoxFuture<T, AuthError>;

#[derive(Debug)]
pub enum AuthError {
    Io(Error),
    Rejected,
    ServerError,
}

impl Display for AuthError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            AuthError::Io(ref err) => write!(f, "D-Bus IO error: {}", err),
            _ => f.write_str(error::Error::description(self)),
        }
    }
}

impl error::Error for AuthError {
    fn description(&self) -> &str {
        match *self {
            AuthError::Io(ref err) => err.description(),
            AuthError::Rejected => "D-Bus server rejected the authentication attempt",
            AuthError::ServerError => "D-Bus server reported an authentication error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            AuthError::Io(ref err) => Some(err),
            AuthError::ServerError | AuthError::Rejected => None,
        }
    }
}

impl From<Error> for AuthError {
    fn from(err: Error) -> Self {
        AuthError::Io(err)
    }
}

impl From<AuthError> for Error {
    fn from(err: AuthError) -> Self {
        match err {
            AuthError::Io(err) => err,
            AuthError::Rejected => {
                Error::new(ErrorKind::PermissionDenied, error::Error::description(&err))
            }
            AuthError::ServerError => {
                Error::new(ErrorKind::InvalidInput, error::Error::description(&err))
            }
        }
    }
}

pub fn authenticate<T>(upstream: T, auth_mode: AuthMode) -> AuthFuture<T>
    where T: Io + Send + 'static
{
    let auth_stream = AuthStream::new(upstream);
    let auth = match auth_mode {
        AuthMode::External => auth_external(auth_stream),
    };
    let pack = auth.map(AuthStream::into_upstream);

    pack.boxed()
}

fn get_uid_str() -> String {
    unsafe { libc::getuid().to_string() }
}

fn auth_external<T>(auth_stream: AuthStream<T>) -> AuthFuture<AuthStream<T>>
    where T: Io + Send + 'static
{
    let send = auth_stream.send(ClientCommand::Auth {
        mechanism: "EXTERNAL".into(),
        initial_response: Some(get_uid_str().into()),
    });
    let recv = send.and_then(|auth_stream| auth_stream.recv());
    let begin = recv.and_then(|(auth_stream, cmd)| {
        match cmd {
            ServerCommand::Ok => auth_stream.send(ClientCommand::Begin),
            ServerCommand::Rejected => futures::failed(AuthError::Rejected).boxed(),
            ServerCommand::Error => futures::failed(AuthError::ServerError).boxed(),
            // _ => futures::failed(AuthError::from(unexpected_response())).boxed(),
        }
    });

    begin.boxed()
}

#[derive(Debug)]
enum ClientCommand {
    Auth {
        mechanism: Cow<'static, str>,
        initial_response: Option<Cow<'static, str>>,
    },
    Begin,
}

#[derive(Debug)]
enum ServerCommand {
    Ok,
    Rejected,
    Error,
}

struct AuthStream<T> {
    inner: EasyFramed<T, ServerCommandParser, ClientCommandSerializer>,
}

impl<T> AuthStream<T>
    where T: Io + Send + 'static
{
    pub fn new(upstream: T) -> Self {
        AuthStream {
            inner: EasyFramed::new(upstream, ServerCommandParser, ClientCommandSerializer),
        }
    }

    pub fn into_upstream(self) -> T {
        self.inner.into_upstream()
    }

    pub fn recv(self) -> AuthFuture<(Self, ServerCommand)> {
        let AuthStream { inner } = self;

        let read = framed::read(inner);
        let unwrap = read.and_then(|(inner, cmd)| {
            match cmd {
                Some(cmd) => Ok((inner, cmd)),
                None => Err(connection_reset()),
            }
        });
        let pack = unwrap.map(|(inner, cmd)| (AuthStream { inner: inner }, cmd))
            .map_err(AuthError::from);

        pack.boxed()
    }

    pub fn send(self, cmd: ClientCommand) -> AuthFuture<Self> {
        let AuthStream { inner } = self;

        let write = framed::write(inner, cmd);
        let flush = write.and_then(framed::flush);
        let pack = flush.map(|inner| AuthStream { inner: inner }).map_err(AuthError::from);

        pack.boxed()
    }
}

struct ClientCommandSerializer;

static HEX_CHARS: &'static [u8] = b"0123456789abcdef";

fn hex_encoded_len(src: &str) -> usize {
    2 * src.len()
}

fn extend_from_hex_encoded(buf: &mut Vec<u8>, src: &str) {
    for byte in src.as_bytes() {
        buf.push(HEX_CHARS[(byte >> 4) as usize]);
        buf.push(HEX_CHARS[(byte & 0xf) as usize]);
    }
}

impl Serialize for ClientCommandSerializer {
    type In = ClientCommand;

    fn serialize(&mut self, msg: &Self::In, buf: &mut Vec<u8>) {
        match *msg {
            ClientCommand::Auth { ref mechanism, ref initial_response } => {
                buf.reserve(8 + initial_response.as_ref().map_or(0, |s| 1 + hex_encoded_len(s)));

                buf.extend_from_slice(b"\0AUTH ");
                buf.extend_from_slice(mechanism.as_bytes());

                match *initial_response {
                    None => {}
                    Some(ref initial_response) => {
                        buf.push(b' ');
                        extend_from_hex_encoded(buf, initial_response);
                    }
                }

                buf.extend_from_slice(b"\r\n");
            }
            ClientCommand::Begin => buf.extend_from_slice(b"BEGIN\r\n"),
        }
    }
}

struct ServerCommandParser;

named!(parse_server_cmd<&[u8], ServerCommand>,
    chain!(
        cmd: alt!(parse_server_cmd_ok | parse_server_cmd_rejected | parse_server_cmd_error) ~
        tag!("\r\n"),
        || { cmd }
    )
);

named!(parse_server_cmd_ok<&[u8], ServerCommand>,
    value!(ServerCommand::Ok, preceded!(tag!("OK "), take_until!("\r\n")))
);

named!(parse_server_cmd_rejected<&[u8], ServerCommand>,
    value!(ServerCommand::Rejected, preceded!(tag!("REJECTED "), take_until!("\r\n")))
);

named!(parse_server_cmd_error<&[u8], ServerCommand>,
    value!(ServerCommand::Error, tag!("ERROR"))
);

impl Parse for ServerCommandParser {
    type Out = ServerCommand;

    fn parse(&mut self, buf: &mut EasyBuf) -> Poll<Self::Out, Error> {
        let (result, consumed) = match parse_server_cmd(buf.as_slice()) {
            IResult::Done(remaining, cmd) => (Ok(Async::Ready(cmd)), buf.len() - remaining.len()),
            IResult::Incomplete(_) => return Ok(Async::NotReady),
            IResult::Error(_) => return Err(unexpected_response()),
        };
        buf.drain_to(consumed);
        result
    }
}

fn connection_reset() -> Error {
    Error::new(ErrorKind::ConnectionReset, "D-Bus connection reset")
}

fn unexpected_response() -> Error {
    Error::new(ErrorKind::InvalidData, "unexpected D-Bus auth response")
}
<|endoftext|>


<commit_before>use std::io::TcpStream;
use std::io::{Buffer, BufferedStream};
use std::str::StrSlice;

use user::User;

pub struct ClientConn {
    stream: BufferedStream<TcpStream>,
    user: Option<User>,
    // folder: Folder
}

impl ClientConn {
    pub fn new(stream: BufferedStream<TcpStream>) -> ClientConn {
        ClientConn {
            stream: stream,
            user: None
        }
    }
    pub fn handle(&mut self) {
        loop {
            match self.stream.read_line() {
                Ok(command) => {
                    if command.len() == 0 {
                        return;
                    }
                    let res = self.interpret(command.as_slice());
                    match self.stream.write(res.as_bytes()) {
                        Ok(_) => {}
                        Err(_) => { return; }
                    }
                    match self.stream.flush() {
                        Ok(_) => {}
                        Err(_) => { return; }
                    }
                }
                Err(_) => { return; }
            }
        }
    }
    fn interpret(&mut self, command: &str) -> String {
        let mut args = command.split(' ');
        match args.nth(0) {
            Some(cmd) => {
                if cmd == "hello" {
                    return "OK\n".to_string()
                }
            }
            None => {}
        }
        "BAD Invalid command\n".to_string()
    }
}
<commit_msg>OK, so I can pattern match on commands. Neat.<commit_after>use std::io::TcpStream;
use std::io::{Buffer, BufferedStream};
use std::str::StrSlice;
use std::ascii::AsciiStr;

use user::User;

pub struct ClientConn {
    stream: BufferedStream<TcpStream>,
    user: Option<User>,
    // folder: Folder
}

impl ClientConn {
    pub fn new(stream: BufferedStream<TcpStream>) -> ClientConn {
        ClientConn {
            stream: stream,
            user: None
        }
    }
    pub fn handle(&mut self) {
        loop {
            match self.stream.read_line() {
                Ok(command) => {
                    if command.len() == 0 {
                        return;
                    }
                    let res = self.interpret(command.as_slice());
                    match self.stream.write(res.as_bytes()) {
                        Ok(_) => {}
                        Err(_) => { return; }
                    }
                    match self.stream.flush() {
                        Ok(_) => {}
                        Err(_) => { return; }
                    }
                }
                Err(_) => { return; }
            }
        }
    }
    fn interpret(&mut self, command: &str) -> String {
        let mut args = command.split(' ');
        match args.nth(0) {
            Some(cmd) if cmd.len() == "login".len() && cmd.to_ascii().eq_ignore_case("login".to_ascii()) => {
                return "OK\n".to_string()
            }
            Some(_) => {}
            None => {}
        }
        "BAD Invalid command\n".to_string()
    }
}
<|endoftext|>


<commit_before>use std::result::Result;

use super::script::*;
use super::super::lex::lex_tool::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

///
/// Parses a parse_command
///
/// Syntax '<expression>', '<expression> <expression>'
///
pub fn parse_command<'a>(input: &'a [LexerMatch]) -> Result<(Script, &'a [LexerMatch]), ParseError> {
    unimplemented!();
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<commit_msg>Parse tool should work in terms of script tokens<commit_after>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

///
/// Looks ahead to the next syntactically relevant lexer match
///
fn lookahead<'a>(input: &'a [ScriptToken]) -> (Option<ScriptToken>, &'a [ScriptToken]) {
    unimplemented!();
}

///
/// Parses a statement
///
pub fn parse_statement<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
    unimplemented!();
}

///
/// Parses a command
///
/// Syntax '<expression>', '<expression> <expression>'
///
pub fn parse_command<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
    unimplemented!();
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        self.i += self.regs[idx] as u16;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        println!("ld_vi x: {}", x);

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }

        // TODO: is this really important?
        // self.i += x as u16 + 1;
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }

        // TODO: is this really important?
        // self.i += x as u16 + 1;
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        if self.key != 0 {
            self.regs[self.inst.x] = self.key;
            key_pressed = true;
        }

        if !key_pressed {
            // TODO: create pc_dec
            self.pc -= 2;
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<commit_msg>fixed ADD IV instruction due to arithmetic overflow<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        println!("ld_vi x: {}", x);

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }

        // TODO: is this really important?
        // self.i += x as u16 + 1;
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }

        // TODO: is this really important?
        // self.i += x as u16 + 1;
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        if self.key != 0 {
            self.regs[self.inst.x] = self.key;
            key_pressed = true;
        }

        if !key_pressed {
            // TODO: create pc_dec
            self.pc -= 2;
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<|endoftext|>


<commit_before>use std::num::Float;

use super::{Item, ItemSchedData};
use time::now_utc;

static INITIAL_FF: f64 = 3.0;
static STEP_1_IRI: f64: 2.0;
static STEP_2_IRI: f64: 4.0;

fn days_to_seconds(days: f64) -> i64 {
    (days * 86400.0).round() as i64
}

pub fn init_item() -> ItemSchedData {
    ItemSchedData {
        last_reviewed: now_utc().to_timespec(),
        ff: INITIAL_FF,
        int_step: 1,
        iri: STEP_1_IRI,
    }
}

pub fn assess_item(data: &ItemSchedData, fam: u8) -> ItemSchedData {
    let int_step = if fam < 2 {
        1
    } else {
        data.int_step + 1
    };

    let iri = match int_step {
        1 => STEP_1_IRI,
        2 => STEP_2_IRI,
        _ => data.iri + data.ff
    };

    // SM-2 algorithm says only to adjust if familiar was above a certain
    // threshold. haven't thought about what effect this has yet.
    // TODO: revisit

    let mut ff = data.ff + match fam {
        0 => 0.,
        1 => 0.,
        2 => -0.32,
        3 => -0.14,
        4 => 0.,
        5 => 0.1,
        _ => unreachable!("Internal error: managed to reach unreachable code. I'm impressed.")
    };

    if ff < 1.3 {
        ff = 1.3;
    }

    ItemSchedData {
        last_reviewed: now_utc().to_timespec(),
        ff: ff,
        int_step: int_step,
        iri: iri,
    }
}

pub fn list_display_item(item: Item) -> String {
    format!("{:3} : {}", item.id, item.desc)
}

pub fn full_display_item(item: Item) -> String {
    let dur = now_utc().to_timespec() - item.data.last_reviewed;
    format!("{:3} : {}\nLast reviewed: {} hours ago\nFF: {}\nint_step: {}\nIRI: {}",
            item.id, item.desc, dur.num_hours(), item.data.ff,
            item.data.int_step, item.data.iri)
}

// Given a vector of items, returns a new vector with only the items
// that are in need of review
pub fn filter_unreviewed_items(items: Vec<Item>) -> Vec<Item> {
    let curr_time = now_utc().to_timespec();

    items.into_iter()
         .filter(|i| (curr_time - i.data.last_reviewed).num_seconds() > days_to_seconds(i.data.iri))
         .collect()
}

fn sort_review_items(mut items: Vec<Item>) -> Vec<Item> {
    let curr_time = now_utc().to_timespec();

    let exceeded_by = |it: &Item| -> i64 {
        (curr_time - it.data.last_reviewed).num_seconds() - days_to_seconds(it.data.iri)
    };

    items.sort_by(|a, b| exceeded_by(b).cmp(&exceeded_by(a)));
    items
}

pub fn prepare_review_items(items: Vec<Item>) -> Vec<Item> {
    sort_review_items(filter_unreviewed_items(items))
}

pub fn review_display_item(review_num: usize, item: &Item) -> String {
    format!("\n{:3} - {} (id: {})\n\n0-5 or 's' to skip item or 'q' to quit > ",
            review_num, item.desc, item.id)
}
<commit_msg>Fix syntax errors in the new static variables for IRI<commit_after>use std::num::Float;

use super::{Item, ItemSchedData};
use time::now_utc;

static INITIAL_FF: f64 = 3.0;
static STEP_1_IRI: f64 = 2.0;
static STEP_2_IRI: f64 = 4.0;

fn days_to_seconds(days: f64) -> i64 {
    (days * 86400.0).round() as i64
}

pub fn init_item() -> ItemSchedData {
    ItemSchedData {
        last_reviewed: now_utc().to_timespec(),
        ff: INITIAL_FF,
        int_step: 1,
        iri: STEP_1_IRI,
    }
}

pub fn assess_item(data: &ItemSchedData, fam: u8) -> ItemSchedData {
    let int_step = if fam < 2 {
        1
    } else {
        data.int_step + 1
    };

    let iri = match int_step {
        1 => STEP_1_IRI,
        2 => STEP_2_IRI,
        _ => data.iri + data.ff
    };

    // SM-2 algorithm says only to adjust if familiar was above a certain
    // threshold. haven't thought about what effect this has yet.
    // TODO: revisit

    let mut ff = data.ff + match fam {
        0 => 0.,
        1 => 0.,
        2 => -0.32,
        3 => -0.14,
        4 => 0.,
        5 => 0.1,
        _ => unreachable!("Internal error: managed to reach unreachable code. I'm impressed.")
    };

    if ff < 1.3 {
        ff = 1.3;
    }

    ItemSchedData {
        last_reviewed: now_utc().to_timespec(),
        ff: ff,
        int_step: int_step,
        iri: iri,
    }
}

pub fn list_display_item(item: Item) -> String {
    format!("{:3} : {}", item.id, item.desc)
}

pub fn full_display_item(item: Item) -> String {
    let dur = now_utc().to_timespec() - item.data.last_reviewed;
    format!("{:3} : {}\nLast reviewed: {} hours ago\nFF: {}\nint_step: {}\nIRI: {}",
            item.id, item.desc, dur.num_hours(), item.data.ff,
            item.data.int_step, item.data.iri)
}

// Given a vector of items, returns a new vector with only the items
// that are in need of review
pub fn filter_unreviewed_items(items: Vec<Item>) -> Vec<Item> {
    let curr_time = now_utc().to_timespec();

    items.into_iter()
         .filter(|i| (curr_time - i.data.last_reviewed).num_seconds() > days_to_seconds(i.data.iri))
         .collect()
}

fn sort_review_items(mut items: Vec<Item>) -> Vec<Item> {
    let curr_time = now_utc().to_timespec();

    let exceeded_by = |it: &Item| -> i64 {
        (curr_time - it.data.last_reviewed).num_seconds() - days_to_seconds(it.data.iri)
    };

    items.sort_by(|a, b| exceeded_by(b).cmp(&exceeded_by(a)));
    items
}

pub fn prepare_review_items(items: Vec<Item>) -> Vec<Item> {
    sort_review_items(filter_unreviewed_items(items))
}

pub fn review_display_item(review_num: usize, item: &Item) -> String {
    format!("\n{:3} - {} (id: {})\n\n0-5 or 's' to skip item or 'q' to quit > ",
            review_num, item.desc, item.id)
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::*;
use punctuated::Punctuated;

ast_struct! {
    /// An enum variant.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Variant {
        /// Attributes tagged on the variant.
        pub attrs: Vec<Attribute>,

        /// Name of the variant.
        pub ident: Ident,

        /// Content stored in the variant.
        pub fields: Fields,

        /// Explicit discriminant: `Variant = 1`
        pub discriminant: Option<(Token![=], Expr)>,
    }
}

ast_enum_of_structs! {
    /// Data stored within an enum variant or struct.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Fields {
        /// Named fields of a struct or struct variant such as `Point { x: f64,
        /// y: f64 }`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Named(FieldsNamed {
            pub brace_token: token::Brace,
            pub named: Punctuated<Field, Token![,]>,
        }),

        /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Unnamed(FieldsUnnamed {
            pub paren_token: token::Paren,
            pub unnamed: Punctuated<Field, Token![,]>,
        }),

        /// Unit struct or unit variant such as `None`.
        pub Unit,
    }
}

impl Fields {
    /// Get an iterator over the borrowed [`Field`] items in this object. This
    /// iterator can be used to iterate over a named or unnamed struct or
    /// variant's fields uniformly.
    ///
    /// [`Field`]: struct.Field.html
    pub fn iter(&self) -> punctuated::Iter<Field> {
        match *self {
            Fields::Unit => punctuated::Iter::private_empty(),
            Fields::Named(ref f) => f.named.iter(),
            Fields::Unnamed(ref f) => f.unnamed.iter(),
        }
    }

    /// Get an iterator over the mutably borrowed [`Field`] items in this
    /// object. This iterator can be used to iterate over a named or unnamed
    /// struct or variant's fields uniformly.
    ///
    /// [`Field`]: struct.Field.html
    pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
        match *self {
            Fields::Unit => punctuated::IterMut::private_empty(),
            Fields::Named(ref mut f) => f.named.iter_mut(),
            Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(),
        }
    }
}

impl<'a> IntoIterator for &'a Fields {
    type Item = &'a Field;
    type IntoIter = punctuated::Iter<'a, Field>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for &'a mut Fields {
    type Item = &'a mut Field;
    type IntoIter = punctuated::IterMut<'a, Field>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

ast_struct! {
    /// A field of a struct or enum variant.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Field {
        /// Attributes tagged on the field.
        pub attrs: Vec<Attribute>,

        /// Visibility of the field.
        pub vis: Visibility,

        /// Name of the field, if any.
        ///
        /// Fields of tuple structs have no names.
        pub ident: Option<Ident>,

        pub colon_token: Option<Token![:]>,

        /// Type of the field.
        pub ty: Type,
    }
}

ast_enum_of_structs! {
    /// The visibility level of an item: inherited or `pub` or
    /// `pub(restricted)`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Visibility {
        /// A public visibility level: `pub`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Public(VisPublic {
            pub pub_token: Token![pub],
        }),

        /// A crate-level visibility: `crate`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Crate(VisCrate {
            pub crate_token: Token![crate],
        }),

        /// A visibility level restricted to some path: `pub(self)` or
        /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Restricted(VisRestricted {
            pub pub_token: Token![pub],
            pub paren_token: token::Paren,
            pub in_token: Option<Token![in]>,
            pub path: Box<Path>,
        }),

        /// An inherited visibility, which usually means private.
        pub Inherited,
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use synom::Synom;

    impl Synom for Variant {
        named!(parse -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            id: syn!(Ident) >>
            fields: alt!(
                syn!(FieldsNamed) => { Fields::Named }
                |
                syn!(FieldsUnnamed) => { Fields::Unnamed }
                |
                epsilon!() => { |_| Fields::Unit }
            ) >>
            disr: option!(tuple!(punct!(=), syn!(Expr))) >>
            (Variant {
                ident: id,
                attrs: attrs,
                fields: fields,
                discriminant: disr,
            })
        ));

        fn description() -> Option<&'static str> {
            Some("enum variant")
        }
    }

    impl Synom for FieldsNamed {
        named!(parse -> Self, map!(
            braces!(call!(Punctuated::parse_terminated_with, Field::parse_named)),
            |(brace, fields)| FieldsNamed {
                brace_token: brace,
                named: fields,
            }
        ));

        fn description() -> Option<&'static str> {
            Some("named fields in a struct or struct variant")
        }
    }

    impl Synom for FieldsUnnamed {
        named!(parse -> Self, map!(
            parens!(call!(Punctuated::parse_terminated_with, Field::parse_unnamed)),
            |(paren, fields)| FieldsUnnamed {
                paren_token: paren,
                unnamed: fields,
            }
        ));

        fn description() -> Option<&'static str> {
            Some("unnamed fields in a tuple struct or tuple variant")
        }
    }

    impl Field {
        named!(pub parse_named -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            vis: syn!(Visibility) >>
            id: syn!(Ident) >>
            colon: punct!(:) >>
            ty: syn!(Type) >>
            (Field {
                ident: Some(id),
                vis: vis,
                attrs: attrs,
                ty: ty,
                colon_token: Some(colon),
            })
        ));

        named!(pub parse_unnamed -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            vis: syn!(Visibility) >>
            ty: syn!(Type) >>
            (Field {
                ident: None,
                colon_token: None,
                vis: vis,
                attrs: attrs,
                ty: ty,
            })
        ));
    }

    impl Synom for Visibility {
        named!(parse -> Self, alt!(
            do_parse!(
                pub_token: keyword!(pub) >>
                other: parens!(keyword!(crate)) >>
                (Visibility::Restricted(VisRestricted {
                    pub_token: pub_token,
                    paren_token: other.0,
                    in_token: None,
                    path: Box::new(other.1.into()),
                }))
            )
            |
            do_parse!(
                crate_token: keyword!(crate) >>
                not!(punct!(::)) >>
                (Visibility::Crate(VisCrate {
                    crate_token: crate_token,
                }))
            )
            |
            do_parse!(
                pub_token: keyword!(pub) >>
                other: parens!(keyword!(self)) >>
                (Visibility::Restricted(VisRestricted {
                    pub_token: pub_token,
                    paren_token: other.0,
                    in_token: None,
                    path: Box::new(other.1.into()),
                }))
            )
            |
            do_parse!(
                pub_token: keyword!(pub) >>
                other: parens!(keyword!(super)) >>
                (Visibility::Restricted(VisRestricted {
                    pub_token: pub_token,
                    paren_token: other.0,
                    in_token: None,
                    path: Box::new(other.1.into()),
                }))
            )
            |
            do_parse!(
                pub_token: keyword!(pub) >>
                other: parens!(do_parse!(
                    in_tok: keyword!(in) >>
                    restricted: call!(Path::parse_mod_style) >>
                    (in_tok, restricted)
                )) >>
                (Visibility::Restricted(VisRestricted {
                    pub_token: pub_token,
                    paren_token: other.0,
                    in_token: Some((other.1).0),
                    path: Box::new((other.1).1),
                }))
            )
            |
            keyword!(pub) => { |tok| {
                Visibility::Public(VisPublic {
                    pub_token: tok,
                })
            } }
            |
            epsilon!() => { |_| Visibility::Inherited }
        ));

        fn description() -> Option<&'static str> {
            Some("visibility qualifier such as `pub`")
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Variant {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.ident.to_tokens(tokens);
            self.fields.to_tokens(tokens);
            if let Some((ref eq_token, ref disc)) = self.discriminant {
                eq_token.to_tokens(tokens);
                disc.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for FieldsNamed {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                self.named.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for FieldsUnnamed {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.paren_token.surround(tokens, |tokens| {
                self.unnamed.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for Field {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            if let Some(ref ident) = self.ident {
                ident.to_tokens(tokens);
                TokensOrDefault(&self.colon_token).to_tokens(tokens);
            }
            self.ty.to_tokens(tokens);
        }
    }

    impl ToTokens for VisPublic {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.pub_token.to_tokens(tokens)
        }
    }

    impl ToTokens for VisCrate {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.crate_token.to_tokens(tokens);
        }
    }

    impl ToTokens for VisRestricted {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.pub_token.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                // XXX: If we have a path which is not "self" or "super" or
                // "crate", automatically add the "in" token.
                self.in_token.to_tokens(tokens);
                self.path.to_tokens(tokens);
            });
        }
    }
}
<commit_msg>Migrate syn::Visibility to new trait<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::*;
use punctuated::Punctuated;

ast_struct! {
    /// An enum variant.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Variant {
        /// Attributes tagged on the variant.
        pub attrs: Vec<Attribute>,

        /// Name of the variant.
        pub ident: Ident,

        /// Content stored in the variant.
        pub fields: Fields,

        /// Explicit discriminant: `Variant = 1`
        pub discriminant: Option<(Token![=], Expr)>,
    }
}

ast_enum_of_structs! {
    /// Data stored within an enum variant or struct.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Fields {
        /// Named fields of a struct or struct variant such as `Point { x: f64,
        /// y: f64 }`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Named(FieldsNamed {
            pub brace_token: token::Brace,
            pub named: Punctuated<Field, Token![,]>,
        }),

        /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Unnamed(FieldsUnnamed {
            pub paren_token: token::Paren,
            pub unnamed: Punctuated<Field, Token![,]>,
        }),

        /// Unit struct or unit variant such as `None`.
        pub Unit,
    }
}

impl Fields {
    /// Get an iterator over the borrowed [`Field`] items in this object. This
    /// iterator can be used to iterate over a named or unnamed struct or
    /// variant's fields uniformly.
    ///
    /// [`Field`]: struct.Field.html
    pub fn iter(&self) -> punctuated::Iter<Field> {
        match *self {
            Fields::Unit => punctuated::Iter::private_empty(),
            Fields::Named(ref f) => f.named.iter(),
            Fields::Unnamed(ref f) => f.unnamed.iter(),
        }
    }

    /// Get an iterator over the mutably borrowed [`Field`] items in this
    /// object. This iterator can be used to iterate over a named or unnamed
    /// struct or variant's fields uniformly.
    ///
    /// [`Field`]: struct.Field.html
    pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
        match *self {
            Fields::Unit => punctuated::IterMut::private_empty(),
            Fields::Named(ref mut f) => f.named.iter_mut(),
            Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(),
        }
    }
}

impl<'a> IntoIterator for &'a Fields {
    type Item = &'a Field;
    type IntoIter = punctuated::Iter<'a, Field>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> IntoIterator for &'a mut Fields {
    type Item = &'a mut Field;
    type IntoIter = punctuated::IterMut<'a, Field>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

ast_struct! {
    /// A field of a struct or enum variant.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Field {
        /// Attributes tagged on the field.
        pub attrs: Vec<Attribute>,

        /// Visibility of the field.
        pub vis: Visibility,

        /// Name of the field, if any.
        ///
        /// Fields of tuple structs have no names.
        pub ident: Option<Ident>,

        pub colon_token: Option<Token![:]>,

        /// Type of the field.
        pub ty: Type,
    }
}

ast_enum_of_structs! {
    /// The visibility level of an item: inherited or `pub` or
    /// `pub(restricted)`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    ///
    /// # Syntax tree enum
    ///
    /// This type is a [syntax tree enum].
    ///
    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
    pub enum Visibility {
        /// A public visibility level: `pub`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Public(VisPublic {
            pub pub_token: Token![pub],
        }),

        /// A crate-level visibility: `crate`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Crate(VisCrate {
            pub crate_token: Token![crate],
        }),

        /// A visibility level restricted to some path: `pub(self)` or
        /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
        ///
        /// *This type is available if Syn is built with the `"derive"` or
        /// `"full"` feature.*
        pub Restricted(VisRestricted {
            pub pub_token: Token![pub],
            pub paren_token: token::Paren,
            pub in_token: Option<Token![in]>,
            pub path: Box<Path>,
        }),

        /// An inherited visibility, which usually means private.
        pub Inherited,
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use parse::{Parse, ParseStream, Result};
    use synom::ext::IdentExt;
    use synom::Synom;

    impl Synom for Variant {
        named!(parse -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            id: syn!(Ident) >>
            fields: alt!(
                syn!(FieldsNamed) => { Fields::Named }
                |
                syn!(FieldsUnnamed) => { Fields::Unnamed }
                |
                epsilon!() => { |_| Fields::Unit }
            ) >>
            disr: option!(tuple!(punct!(=), syn!(Expr))) >>
            (Variant {
                ident: id,
                attrs: attrs,
                fields: fields,
                discriminant: disr,
            })
        ));

        fn description() -> Option<&'static str> {
            Some("enum variant")
        }
    }

    impl Synom for FieldsNamed {
        named!(parse -> Self, map!(
            braces!(call!(Punctuated::parse_terminated_with, Field::parse_named)),
            |(brace, fields)| FieldsNamed {
                brace_token: brace,
                named: fields,
            }
        ));

        fn description() -> Option<&'static str> {
            Some("named fields in a struct or struct variant")
        }
    }

    impl Synom for FieldsUnnamed {
        named!(parse -> Self, map!(
            parens!(call!(Punctuated::parse_terminated_with, Field::parse_unnamed)),
            |(paren, fields)| FieldsUnnamed {
                paren_token: paren,
                unnamed: fields,
            }
        ));

        fn description() -> Option<&'static str> {
            Some("unnamed fields in a tuple struct or tuple variant")
        }
    }

    impl Field {
        named!(pub parse_named -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            vis: syn!(Visibility) >>
            id: syn!(Ident) >>
            colon: punct!(:) >>
            ty: syn!(Type) >>
            (Field {
                ident: Some(id),
                vis: vis,
                attrs: attrs,
                ty: ty,
                colon_token: Some(colon),
            })
        ));

        named!(pub parse_unnamed -> Self, do_parse!(
            attrs: many0!(Attribute::parse_outer) >>
            vis: syn!(Visibility) >>
            ty: syn!(Type) >>
            (Field {
                ident: None,
                colon_token: None,
                vis: vis,
                attrs: attrs,
                ty: ty,
            })
        ));
    }

    impl Parse for Visibility {
        fn parse(input: ParseStream) -> Result<Self> {
            if input.peek(Token![pub]) {
                Self::parse_pub(input)
            } else if input.peek(Token![crate]) {
                Self::parse_crate(input)
            } else {
                Ok(Visibility::Inherited)
            }
        }
    }

    impl Visibility {
        fn parse_pub(input: ParseStream) -> Result<Self> {
            let pub_token = input.parse::<Token![pub]>()?;

            if input.peek(token::Paren) {
                let ahead = input.fork();
                let mut content;
                parenthesized!(content in ahead);

                if content.peek(Token![crate])
                    || content.peek(Token![self])
                    || content.peek(Token![super])
                {
                    return Ok(Visibility::Restricted(VisRestricted {
                        pub_token: pub_token,
                        paren_token: parenthesized!(content in input),
                        in_token: None,
                        path: Box::new(Path::from(content.parse_synom(Ident::parse_any)?)),
                    }));
                } else if content.peek(Token![in]) {
                    return Ok(Visibility::Restricted(VisRestricted {
                        pub_token: pub_token,
                        paren_token: parenthesized!(content in input),
                        in_token: Some(content.parse()?),
                        path: Box::new(content.parse_synom(Path::parse_mod_style)?),
                    }));
                }
            }

            Ok(Visibility::Public(VisPublic {
                pub_token: pub_token,
            }))
        }

        fn parse_crate(input: ParseStream) -> Result<Self> {
            let followed_by_colons = {
                let ahead = input.fork();
                ahead.parse::<Token![crate]>()?;
                ahead.peek(Token![::])
            };

            if followed_by_colons {
                Ok(Visibility::Inherited)
            } else {
                Ok(Visibility::Crate(VisCrate {
                    crate_token: input.parse()?,
                }))
            }
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Variant {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.ident.to_tokens(tokens);
            self.fields.to_tokens(tokens);
            if let Some((ref eq_token, ref disc)) = self.discriminant {
                eq_token.to_tokens(tokens);
                disc.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for FieldsNamed {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                self.named.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for FieldsUnnamed {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.paren_token.surround(tokens, |tokens| {
                self.unnamed.to_tokens(tokens);
            });
        }
    }

    impl ToTokens for Field {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            if let Some(ref ident) = self.ident {
                ident.to_tokens(tokens);
                TokensOrDefault(&self.colon_token).to_tokens(tokens);
            }
            self.ty.to_tokens(tokens);
        }
    }

    impl ToTokens for VisPublic {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.pub_token.to_tokens(tokens)
        }
    }

    impl ToTokens for VisCrate {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.crate_token.to_tokens(tokens);
        }
    }

    impl ToTokens for VisRestricted {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.pub_token.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                // XXX: If we have a path which is not "self" or "super" or
                // "crate", automatically add the "in" token.
                self.in_token.to_tokens(tokens);
                self.path.to_tokens(tokens);
            });
        }
    }
}
<|endoftext|>


<commit_before>//! Helper methods for colors

use types::{Color, ColorComponent};

/// White color.
pub const WHITE: Color = [1.0; 4];
/// Black color.
pub const BLACK: Color = [0.0, 0.0, 0.0, 1.0];
/// Transparent color.
pub const TRANSPARENT: Color = [0.0; 4];

/// Returns a grey color
pub fn grey(f: ColorComponent) -> Color {
    [f, f, f, 1.0]
}

/// Returns a semi-transparent white color
pub fn alpha(f: ColorComponent) -> Color {
    [1.0, 1.0, 1.0, f]
}

/// Converts from hexadecimal color format
pub fn hex(hex: &str) -> Color {
    use read_color::rgb_maybe_a;

    let (rgb, a) = rgb_maybe_a(&mut hex.chars()).unwrap();
    let color = match a {
        None => [rgb[0], rgb[1], rgb[2], 255],
        Some(a) => [rgb[0], rgb[1], rgb[2], a],
    };
    let inv_255 = 1.0f32 / 255.0f32;
    [color[0] as f32 * inv_255,
     color[1] as f32 * inv_255,
     color[2] as f32 * inv_255,
     color[3] as f32 * inv_255]
}

#[inline(always)]
fn component_srgb_to_linear(f: ColorComponent) -> ColorComponent {
    if f <= 0.04045 {
        f / 12.92
    } else {
        ((f + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts gamma (brightness) from sRGB to linear color space.
///
/// sRGB is the default color space for image editors, pictures, internet etc.
/// Linear gamma yields better results when doing math with colors.
pub fn gamma_srgb_to_linear(c: Color) -> Color {
    [component_srgb_to_linear(c[0]),
     component_srgb_to_linear(c[1]),
     component_srgb_to_linear(c[2]),
     c[3]]
}

#[inline(always)]
fn component_linear_to_srgb(f: ColorComponent) -> ColorComponent {
    if f <= 0.0031308 {
        f * 12.92
    } else {
        1.055 * f.powf(1.0 / 2.4) - 0.055
    }
}

/// Converts gamma (brightness) of a color from linear color space to sRGB.
///
/// sRGB is the default color space for image editors, pictures, internet etc.
/// Linear gamma yields better results when doing math with colors.
pub fn gamma_linear_to_srgb(c: Color) -> Color {
    [component_linear_to_srgb(c[0]),
     component_linear_to_srgb(c[1]),
     component_linear_to_srgb(c[2]),
     c[3]]
}
<commit_msg>Add additional convience colors<commit_after>//! Helper methods for colors

use types::{Color, ColorComponent};

/// Black color.
pub const BLACK: Color = [0.0, 0.0, 0.0, 1.0];
/// Blue color.
pub const BLUE: Color = [0.0, 0.0, 255.0, 1.0];
/// Cyan color.
pub const CYAN: Color = [0.0, 255.0, 255.0, 1.0];
/// Gray color.
pub const GRAY: Color = [128.0, 128.0, 128.0, 1.0];
/// Green color.
pub const GREEN: Color = [0.0, 128.0, 0.0, 1.0];
/// Lime color.
pub const LIME: Color = [0.0, 255.0, 0.0, 1.0];
/// Magenta color.
pub const MAGENTA: Color = [255.0, 0.0, 255.0, 1.0];
/// Maroon color.
pub const MAROON: Color = [128.0, 0.0, 0.0, 1.0];
/// Navy color.
pub const NAVY: Color = [0.0, 0.0, 128.0, 1.0];
/// Olive color.
pub const OLIVE: Color = [128.0, 128.0, 0.0, 1.0];
/// Purple color.
pub const PURPLE: Color = [128.0, 0.0, 128.0, 1.0];
/// Red color.
pub const RED: Color = [255.0, 0.0, 0.0, 1.0];
/// Silver color.
pub const SILVER: Color = [192.0, 192.0, 192.0, 1.0];
/// Teal color.
pub const TEAL: Color = [0.0, 128.0, 128.0, 1.0];
/// White color.
pub const WHITE: Color = [255.0, 255.0, 255.0, 1.0];
/// Yellow color.
pub const YELLOW: Color = [255.0, 255.0, 0.0, 1.0];
/// Transparent color.
pub const TRANSPARENT: Color = [0.0; 4];

/// Returns a grey color
pub fn grey(f: ColorComponent) -> Color {
    [f, f, f, 1.0]
}

/// Returns a semi-transparent white color
pub fn alpha(f: ColorComponent) -> Color {
    [1.0, 1.0, 1.0, f]
}

/// Converts from hexadecimal color format
pub fn hex(hex: &str) -> Color {
    use read_color::rgb_maybe_a;

    let (rgb, a) = rgb_maybe_a(&mut hex.chars()).unwrap();
    let color = match a {
        None => [rgb[0], rgb[1], rgb[2], 255],
        Some(a) => [rgb[0], rgb[1], rgb[2], a],
    };
    let inv_255 = 1.0f32 / 255.0f32;
    [color[0] as f32 * inv_255,
     color[1] as f32 * inv_255,
     color[2] as f32 * inv_255,
     color[3] as f32 * inv_255]
}

#[inline(always)]
fn component_srgb_to_linear(f: ColorComponent) -> ColorComponent {
    if f <= 0.04045 {
        f / 12.92
    } else {
        ((f + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts gamma (brightness) from sRGB to linear color space.
///
/// sRGB is the default color space for image editors, pictures, internet etc.
/// Linear gamma yields better results when doing math with colors.
pub fn gamma_srgb_to_linear(c: Color) -> Color {
    [component_srgb_to_linear(c[0]),
     component_srgb_to_linear(c[1]),
     component_srgb_to_linear(c[2]),
     c[3]]
}

#[inline(always)]
fn component_linear_to_srgb(f: ColorComponent) -> ColorComponent {
    if f <= 0.0031308 {
        f * 12.92
    } else {
        1.055 * f.powf(1.0 / 2.4) - 0.055
    }
}

/// Converts gamma (brightness) of a color from linear color space to sRGB.
///
/// sRGB is the default color space for image editors, pictures, internet etc.
/// Linear gamma yields better results when doing math with colors.
pub fn gamma_linear_to_srgb(c: Color) -> Color {
    [component_linear_to_srgb(c[0]),
     component_linear_to_srgb(c[1]),
     component_linear_to_srgb(c[2]),
     c[3]]
}
<|endoftext|>


<commit_before>use bytecodec;
use fibers::sync::oneshot::MonitorError;
use fibers_transport;
use std::io;
use std::sync::mpsc::SendError;
use stun_codec::rfc5389::attributes::ErrorCode;
use stun_codec::AttributeType;
use trackable::error::{self, ErrorKindExt, TrackableError};

/// This crate specific `Error` type.
#[derive(Debug, Clone)]
pub struct Error(TrackableError<ErrorKind>);
derive_traits_for_trackable_error_newtype!(Error, ErrorKind);
impl From<MonitorError<Error>> for Error {
    fn from(f: MonitorError<Error>) -> Self {
        f.unwrap_or_else(|| {
            ErrorKind::Other
                .cause("Monitor channel has disconnected")
                .into()
        })
    }
}
impl From<io::Error> for Error {
    fn from(f: io::Error) -> Self {
        ErrorKind::Other.cause(f).into()
    }
}
impl<T> From<SendError<T>> for Error {
    fn from(_: SendError<T>) -> Self {
        ErrorKind::Other.cause("Receiver has terminated").into()
    }
}
impl From<bytecodec::Error> for Error {
    fn from(f: bytecodec::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            bytecodec::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
            _ => ErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}
impl From<MessageError> for Error {
    fn from(f: MessageError) -> Self {
        ErrorKind::InvalidMessage(f.kind().clone())
            .takes_over(f)
            .into()
    }
}
impl From<ErrorCode> for Error {
    fn from(f: ErrorCode) -> Self {
        ErrorKind::Other
            .cause(format!("STUN error response: {:?}", f))
            .into()
    }
}
impl From<fibers_transport::Error> for Error {
    fn from(f: fibers_transport::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            fibers_transport::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
            _ => ErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}

/// Possible error kinds.
#[derive(Debug, Clone)]
pub enum ErrorKind {
    /// Input is invalid.
    InvalidInput,

    /// A message is invalid.
    ///
    /// This error does not affect the overall execution of a channel/client/server.
    InvalidMessage(MessageErrorKind),

    /// Other errors.
    Other,
}
impl error::ErrorKind for ErrorKind {}

/// Message level error.
#[derive(Debug, Clone)]
pub struct MessageError(TrackableError<MessageErrorKind>);
derive_traits_for_trackable_error_newtype!(MessageError, MessageErrorKind);
impl From<MonitorError<MessageError>> for MessageError {
    fn from(f: MonitorError<MessageError>) -> Self {
        f.unwrap_or_else(|| {
            MessageErrorKind::Other
                .cause("`Channel` instance has dropped")
                .into()
        })
    }
}
impl From<Error> for MessageError {
    fn from(f: Error) -> Self {
        let original_error_kind = f.kind().clone();
        track!(MessageErrorKind::Other.takes_over(f); original_error_kind).into()
    }
}
impl From<fibers_transport::Error> for MessageError {
    fn from(f: fibers_transport::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            fibers_transport::ErrorKind::InvalidInput => MessageErrorKind::InvalidInput,
            _ => MessageErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}

/// Possible error kinds.
#[derive(Debug, Clone)]
pub enum MessageErrorKind {
    /// Unexpected response message.
    UnexpectedResponse,

    /// There are some malformed attributes in a message.
    MalformedAttribute,

    /// There are unknown comprehension-required attributes.
    ///
    /// If a server receives a message that contains unknown comprehension-required attributes,
    /// it should reply an `ErrorResponse` message that has the [`UnknownAttribute`] error code and
    /// an [`UnknownAttributes`] attribute.
    ///
    /// [`UnknownAttribute`]: https://docs.rs/stun_codec/0.1/stun_codec/rfc5389/errors/struct.UnknownAttribute.html
    /// [`UnknownAttributes`]: https://docs.rs/stun_codec/0.1/stun_codec/rfc5389/attributes/struct.UnknownAttributes.html
    UnknownAttributes(Vec<AttributeType>),

    /// Input is invalid.
    InvalidInput,

    /// Operation timed out.
    Timeout,

    /// Other errors.
    Other,
}
impl error::ErrorKind for MessageErrorKind {}
<commit_msg>Use `TrackableError` derive macro<commit_after>use bytecodec;
use fibers::sync::oneshot::MonitorError;
use fibers_transport;
use std::io;
use std::sync::mpsc::SendError;
use stun_codec::rfc5389::attributes::ErrorCode;
use stun_codec::AttributeType;
use trackable::error::{self, ErrorKindExt, TrackableError};

/// This crate specific `Error` type.
#[derive(Debug, Clone, TrackableError)]
pub struct Error(TrackableError<ErrorKind>);
impl From<MonitorError<Error>> for Error {
    fn from(f: MonitorError<Error>) -> Self {
        f.unwrap_or_else(|| {
            ErrorKind::Other
                .cause("Monitor channel has disconnected")
                .into()
        })
    }
}
impl From<io::Error> for Error {
    fn from(f: io::Error) -> Self {
        ErrorKind::Other.cause(f).into()
    }
}
impl<T> From<SendError<T>> for Error {
    fn from(_: SendError<T>) -> Self {
        ErrorKind::Other.cause("Receiver has terminated").into()
    }
}
impl From<bytecodec::Error> for Error {
    fn from(f: bytecodec::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            bytecodec::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
            _ => ErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}
impl From<MessageError> for Error {
    fn from(f: MessageError) -> Self {
        ErrorKind::InvalidMessage(f.kind().clone())
            .takes_over(f)
            .into()
    }
}
impl From<ErrorCode> for Error {
    fn from(f: ErrorCode) -> Self {
        ErrorKind::Other
            .cause(format!("STUN error response: {:?}", f))
            .into()
    }
}
impl From<fibers_transport::Error> for Error {
    fn from(f: fibers_transport::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            fibers_transport::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
            _ => ErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}

/// Possible error kinds.
#[derive(Debug, Clone)]
pub enum ErrorKind {
    /// Input is invalid.
    InvalidInput,

    /// A message is invalid.
    ///
    /// This error does not affect the overall execution of a channel/client/server.
    InvalidMessage(MessageErrorKind),

    /// Other errors.
    Other,
}
impl error::ErrorKind for ErrorKind {}

/// Message level error.
#[derive(Debug, Clone)]
pub struct MessageError(TrackableError<MessageErrorKind>);
derive_traits_for_trackable_error_newtype!(MessageError, MessageErrorKind);
impl From<MonitorError<MessageError>> for MessageError {
    fn from(f: MonitorError<MessageError>) -> Self {
        f.unwrap_or_else(|| {
            MessageErrorKind::Other
                .cause("`Channel` instance has dropped")
                .into()
        })
    }
}
impl From<Error> for MessageError {
    fn from(f: Error) -> Self {
        let original_error_kind = f.kind().clone();
        track!(MessageErrorKind::Other.takes_over(f); original_error_kind).into()
    }
}
impl From<fibers_transport::Error> for MessageError {
    fn from(f: fibers_transport::Error) -> Self {
        let original_error_kind = *f.kind();
        let kind = match original_error_kind {
            fibers_transport::ErrorKind::InvalidInput => MessageErrorKind::InvalidInput,
            _ => MessageErrorKind::Other,
        };
        track!(kind.takes_over(f); original_error_kind).into()
    }
}

/// Possible error kinds.
#[derive(Debug, Clone)]
pub enum MessageErrorKind {
    /// Unexpected response message.
    UnexpectedResponse,

    /// There are some malformed attributes in a message.
    MalformedAttribute,

    /// There are unknown comprehension-required attributes.
    ///
    /// If a server receives a message that contains unknown comprehension-required attributes,
    /// it should reply an `ErrorResponse` message that has the [`UnknownAttribute`] error code and
    /// an [`UnknownAttributes`] attribute.
    ///
    /// [`UnknownAttribute`]: https://docs.rs/stun_codec/0.1/stun_codec/rfc5389/errors/struct.UnknownAttribute.html
    /// [`UnknownAttributes`]: https://docs.rs/stun_codec/0.1/stun_codec/rfc5389/attributes/struct.UnknownAttributes.html
    UnknownAttributes(Vec<AttributeType>),

    /// Input is invalid.
    InvalidInput,

    /// Operation timed out.
    Timeout,

    /// Other errors.
    Other,
}
impl error::ErrorKind for MessageErrorKind {}
<|endoftext|>


<commit_before>error_chain! {
    // The type defined for this error. These are the conventional
    // and recommended names, but they can be arbitrarily chosen.
    types {
        Error, ErrorKind, ChainErr, Result;
    }

    // Automatic conversions between this error chain and other
    // error chains. In this case, it will e.g. generate an
    // `ErrorKind` variant called `Dist` which in turn contains
    // the `rustup_dist::ErrorKind`, with conversions from
    // `rustup_dist::Error`.
    //
    // This section can be empty.
    links {
    }

    // Automatic conversions between this error chain and other
    // error types not defined by the `error_chain!`. These will be
    // boxed as the error cause and wrapped in a new error with,
    // in this case, the `ErrorKind::Temp` variant.
    //
    // This section can be empty.
    foreign_links {
    }

    // Define additional `ErrorKind` variants. The syntax here is
    // the same as `quick_error!`, but the `from()` and `cause()`
    // syntax is not supported.
    errors {
    }
}
<commit_msg>Less is more: remove unnecessary error macro code<commit_after>error_chain! {}
<|endoftext|>


<commit_before>//! Errors for `frippy` crate using `failure`.

use failure::Fail;

pub fn log_error(e: &FrippyError) {
    let text = e.causes()
        .fold(format!("{}", e), |acc, err| format!("{}: {}", acc, err));
    error!("{}", text);
}

/// The main crate-wide error type.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
#[error = "FrippyError"]
pub enum ErrorKind {
    /// Connection error
    #[fail(display = "A connection error occured")]
    Connection,

    /// Thread spawn error
    #[fail(display = "Failed to spawn thread")]
    ThreadSpawn,

    /// A Url error
    #[fail(display = "A Url error has occured")]
    Url,

    /// A Tell error
    #[fail(display = "A Tell error has occured")]
    Tell,

    /// A Factoids error
    #[fail(display = "A Factoids error has occured")]
    Factoids,

    /// A Remind error
    #[fail(display = "A Remind error has occured")]
    Remind,
}
<commit_msg>Errors: Fix accidental double printing<commit_after>//! Errors for `frippy` crate using `failure`.

use failure::Fail;

pub fn log_error(e: &FrippyError) {
    let text = e.causes()
        .skip(1)
        .fold(format!("{}", e), |acc, err| format!("{}: {}", acc, err));
    error!("{}", text);
}

/// The main crate-wide error type.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
#[error = "FrippyError"]
pub enum ErrorKind {
    /// Connection error
    #[fail(display = "A connection error occured")]
    Connection,

    /// Thread spawn error
    #[fail(display = "Failed to spawn thread")]
    ThreadSpawn,

    /// A Url error
    #[fail(display = "A Url error has occured")]
    Url,

    /// A Tell error
    #[fail(display = "A Tell error has occured")]
    Tell,

    /// A Factoids error
    #[fail(display = "A Factoids error has occured")]
    Factoids,

    /// A Remind error
    #[fail(display = "A Remind error has occured")]
    Remind,
}
<|endoftext|>


<commit_before>use crate::std::fmt;

/// A general error that can occur when working with UUIDs.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error(pub(crate) ErrorKind);

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(crate) enum ErrorKind {
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    Char { character: char, index: usize },
    /// A simple [`Uuid`] didn't contain 32 characters.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    SimpleLength { len: usize },
    /// A byte array didn't contain 16 bytes
    #[allow(dead_code)]
    ByteLength { len: usize },
    /// A hyphenated [`Uuid`] didn't contain 5 groups
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupCount { count: usize },
    /// A hyphenated [`Uuid`] had a group that wasn't the right length
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupLength {
        group: usize,
        len: usize,
        index: usize,
    },
    /// Some other error occurred.
    #[allow(dead_code)]
    Other,
}

/// A string that is guaranteed to fail to parse to a [`Uuid`].
///
/// This type acts as a lightweight error indicator, suggesting
/// that the string cannot be parsed but offering no error
/// details. To get details, use `InvalidUuid::into_err`.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct InvalidUuid<'a>(pub(crate) &'a str);

impl<'a> InvalidUuid<'a> {
    /// Converts the lightweight error type into detailed diagnostics.
    pub fn into_err(self) -> Error {
        let (s, offset, simple) = match self.0.as_bytes() {
            [b'{', s @ .., b'}'] => (s, 1, false),
            [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..] => {
                (s, "urn:uuid:".len(), false)
            }
            s => (s, 0, true),
        };

        let mut hyphen_count = 0;
        let mut group_bounds = [0; 4];

        // SAFETY: the byte array came from a valid utf8 string,
        // and is aligned along char boundries.
        let string = unsafe { std::str::from_utf8_unchecked(s) };

        for (index, character) in string.char_indices() {
            let byte = character as u8;
            if character as u32 - byte as u32 > 0 {
                // Multibyte char
                return Error(ErrorKind::Char {
                    character,
                    index: index + offset + 1,
                });
            } else if byte == b'-' {
                // While we search, also count group breaks
                if hyphen_count < 4 {
                    group_bounds[hyphen_count] = index;
                }
                hyphen_count += 1;
            } else if !matches!(byte, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F') {
                // Non-hex char
                return Error(ErrorKind::Char {
                    character: byte as char,
                    index: index + offset + 1,
                });
            }
        }

        if hyphen_count == 0 && simple {
            // This means that we tried and failed to parse a simple uuid.
            // Since we verified that all the characters are valid, this means
            // that it MUST have an invalid length.
            Error(ErrorKind::SimpleLength { len: s.len() })
        } else if hyphen_count != 4 {
            // We tried to parse a hyphenated variant, but there weren't
            // 5 groups (4 hyphen splits).
            Error(ErrorKind::GroupCount {
                count: hyphen_count + 1,
            })
        } else {
            // There are 5 groups, one of them has an incorrect length
            const BLOCK_STARTS: [usize; 5] = [0, 9, 14, 19, 24];
            for i in 0..4 {
                if group_bounds[i] != BLOCK_STARTS[i + 1] - 1 {
                    return Error(ErrorKind::GroupLength {
                        group: i,
                        len: group_bounds[i] - BLOCK_STARTS[i],
                        index: offset + BLOCK_STARTS[i] + 1,
                    });
                }
            }

            // The last group must be too long
            Error(ErrorKind::GroupLength {
                group: 4,
                len: s.len() - BLOCK_STARTS[4],
                index: offset + BLOCK_STARTS[4] + 1,
            })
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            ErrorKind::Char {
                character, index, ..
            } => {
                write!(f, "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `{}` at {}", character, index)
            }
            ErrorKind::SimpleLength { len } => {
                write!(
                    f,
                    "invalid length: expected length 32 for simple format, found {}",
                    len
                )
            }
            ErrorKind::ByteLength { len } => {
                write!(f, "invalid length: expected 16 bytes, found {}", len)
            }
            ErrorKind::GroupCount { count } => {
                write!(f, "invalid group count: expected 5, found {}", count)
            }
            ErrorKind::GroupLength { group, len, .. } => {
                let expected = [8, 4, 4, 4, 12][group];
                write!(
                    f,
                    "invalid group length in group {}: expected {}, found {}",
                    group, expected, len
                )
            }
            ErrorKind::Other => write!(f, "failed to parse a UUID"),
        }
    }
}

#[cfg(feature = "std")]
mod std_support {
    use super::*;
    use crate::std::error;

    impl error::Error for Error {}
}
<commit_msg>some more dead code lints<commit_after>use crate::std::fmt;

/// A general error that can occur when working with UUIDs.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error(pub(crate) ErrorKind);

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(crate) enum ErrorKind {
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    Char { character: char, index: usize },
    /// A simple [`Uuid`] didn't contain 32 characters.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    SimpleLength { len: usize },
    /// A byte array didn't contain 16 bytes
    ByteLength { len: usize },
    /// A hyphenated [`Uuid`] didn't contain 5 groups
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupCount { count: usize },
    /// A hyphenated [`Uuid`] had a group that wasn't the right length
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupLength {
        group: usize,
        len: usize,
        index: usize,
    },
    /// Some other error occurred.
    Other,
}

/// A string that is guaranteed to fail to parse to a [`Uuid`].
///
/// This type acts as a lightweight error indicator, suggesting
/// that the string cannot be parsed but offering no error
/// details. To get details, use `InvalidUuid::into_err`.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct InvalidUuid<'a>(pub(crate) &'a str);

impl<'a> InvalidUuid<'a> {
    /// Converts the lightweight error type into detailed diagnostics.
    pub fn into_err(self) -> Error {
        let (s, offset, simple) = match self.0.as_bytes() {
            [b'{', s @ .., b'}'] => (s, 1, false),
            [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..] => {
                (s, "urn:uuid:".len(), false)
            }
            s => (s, 0, true),
        };

        let mut hyphen_count = 0;
        let mut group_bounds = [0; 4];

        // SAFETY: the byte array came from a valid utf8 string,
        // and is aligned along char boundries.
        let string = unsafe { std::str::from_utf8_unchecked(s) };

        for (index, character) in string.char_indices() {
            let byte = character as u8;
            if character as u32 - byte as u32 > 0 {
                // Multibyte char
                return Error(ErrorKind::Char {
                    character,
                    index: index + offset + 1,
                });
            } else if byte == b'-' {
                // While we search, also count group breaks
                if hyphen_count < 4 {
                    group_bounds[hyphen_count] = index;
                }
                hyphen_count += 1;
            } else if !matches!(byte, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F') {
                // Non-hex char
                return Error(ErrorKind::Char {
                    character: byte as char,
                    index: index + offset + 1,
                });
            }
        }

        if hyphen_count == 0 && simple {
            // This means that we tried and failed to parse a simple uuid.
            // Since we verified that all the characters are valid, this means
            // that it MUST have an invalid length.
            Error(ErrorKind::SimpleLength { len: s.len() })
        } else if hyphen_count != 4 {
            // We tried to parse a hyphenated variant, but there weren't
            // 5 groups (4 hyphen splits).
            Error(ErrorKind::GroupCount {
                count: hyphen_count + 1,
            })
        } else {
            // There are 5 groups, one of them has an incorrect length
            const BLOCK_STARTS: [usize; 5] = [0, 9, 14, 19, 24];
            for i in 0..4 {
                if group_bounds[i] != BLOCK_STARTS[i + 1] - 1 {
                    return Error(ErrorKind::GroupLength {
                        group: i,
                        len: group_bounds[i] - BLOCK_STARTS[i],
                        index: offset + BLOCK_STARTS[i] + 1,
                    });
                }
            }

            // The last group must be too long
            Error(ErrorKind::GroupLength {
                group: 4,
                len: s.len() - BLOCK_STARTS[4],
                index: offset + BLOCK_STARTS[4] + 1,
            })
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            ErrorKind::Char {
                character, index, ..
            } => {
                write!(f, "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `{}` at {}", character, index)
            }
            ErrorKind::SimpleLength { len } => {
                write!(
                    f,
                    "invalid length: expected length 32 for simple format, found {}",
                    len
                )
            }
            ErrorKind::ByteLength { len } => {
                write!(f, "invalid length: expected 16 bytes, found {}", len)
            }
            ErrorKind::GroupCount { count } => {
                write!(f, "invalid group count: expected 5, found {}", count)
            }
            ErrorKind::GroupLength { group, len, .. } => {
                let expected = [8, 4, 4, 4, 12][group];
                write!(
                    f,
                    "invalid group length in group {}: expected {}, found {}",
                    group, expected, len
                )
            }
            ErrorKind::Other => write!(f, "failed to parse a UUID"),
        }
    }
}

#[cfg(feature = "std")]
mod std_support {
    use super::*;
    use crate::std::error;

    impl error::Error for Error {}
}
<|endoftext|>