<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! FFI bindings to advapi32.
#![no_std]
#![experimental]
extern crate winapi;
use winapi::*;
extern "system" {
    pub fn AdjustTokenPrivileges(
        TokenHandle: HANDLE,
        DisableAllPrivileges: BOOL,
        NewState: PTOKEN_PRIVILEGES,
        BufferLength: DWORD,
        PreviousState: PTOKEN_PRIVILEGES,
        ReturnLength: PDWORD,
    ) -> BOOL;
    pub fn OpenProcessToken(
        ProcessHandle: HANDLE,
        DesiredAccess: DWORD,
        TokenHandle: PHANDLE
    ) -> BOOL;
    pub fn RegCloseKey(
        hKey: HKEY
    ) -> LONG;
    pub fn RegConnectRegistryA(
        lpMachineName: LPCSTR,
        hKey: HKEY,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegConnectRegistryW(
        lpMachineName: LPCWSTR,
        hKey: HKEY,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegCopyTreeA(
        hKeySrc: HKEY,
        lpSubKey: LPCSTR,
        hKeyDest: HKEY
    ) -> LONG;
    pub fn RegCopyTreeW(
        hKeySrc: HKEY,
        lpSubKey: LPCWSTR,
        hKeyDest: HKEY
    ) -> LONG;
    pub fn RegCreateKeyExA(
        hKey: HKEY,
        lpSubKey: LPCSTR,
        Reserved: DWORD,
        lpClass: LPCSTR,
        dwOptions: DWORD,
        samDesired: REGSAM,
        lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
        phkResult: PHKEY,
        lpdwDisposition: LPDWORD
    ) -> LONG;
    pub fn RegCreateKeyExW(
        hKey: HKEY,
        lpSubKey: LPCWSTR,
        Reserved: DWORD,
        lpClass: LPCWSTR,
        dwOptions: DWORD,
        samDesired: REGSAM,
        lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
        phkResult: PHKEY,
        lpdwDisposition: LPDWORD
    ) -> LONG;
    pub fn RegDeleteKeyA(
        hKey: HKEY,
        lpSubKey: LPCSTR
    ) -> LONG;
    pub fn RegDeleteKeyW(
        hKey: HKEY,
        lpSubKey: LPCWSTR
    ) -> LONG;
    pub fn RegDeleteKeyExA(
        hKey: HKEY,
        lpSubKey: LPCSTR,
        samDesired: REGSAM,
        Reserved: DWORD
    ) -> LONG;
    pub fn RegDeleteKeyExW(
        hKey: HKEY,
        lpSubKey: LPCWSTR,
        samDesired: REGSAM,
        Reserved: DWORD
    ) -> LONG;
    pub fn RegDeleteKeyValueA(
        hKey: HKEY,
        lpSubKey: LPCSTR,
        lpValueName: LPCSTR
    ) -> LONG;
    pub fn RegDeleteKeyValueW(
        hKey: HKEY,
        lpSubKey: LPCWSTR,
        lpValueName: LPCWSTR
    ) -> LONG;
    pub fn RegDeleteTreeA(
        hKey: HKEY,
        lpSubKey: LPCSTR
    ) -> LONG;
    pub fn RegDeleteTreeW(
        hKey: HKEY,
        lpSubKey: LPCWSTR
    ) -> LONG;
    pub fn RegDeleteValueA(
        hKey: HKEY,
        lpValueName: LPCSTR
    ) -> LONG;
    pub fn RegDeleteValueW(
        hKey: HKEY,
        lpValueName: LPCWSTR
    ) -> LONG;
    pub fn RegDisablePredefinedCache() -> LONG;
    pub fn RegDisablePredefinedCacheEx() -> LONG;
    pub fn RegDisableReflectionKey(
        hBase: HKEY
    ) -> LONG;
    pub fn RegEnableReflectionKey(
        hBase: HKEY
    ) -> LONG;
    pub fn RegEnumKeyExA(
        hKey: HKEY,
        dwIndex: DWORD,
        lpName: LPSTR,
        lpcName: LPDWORD,
        lpReserved: LPDWORD,
        lpClass: LPSTR,
        lpcClass: LPDWORD,
        lpftLastWriteTime: PFILETIME
    ) -> LONG;
    pub fn RegEnumKeyExW(
        hKey: HKEY,
        dwIndex: DWORD,
        lpName: LPWSTR,
        lpcName: LPDWORD,
        lpReserved: LPDWORD,
        lpClass: LPWSTR,
        lpcClass: LPDWORD,
        lpftLastWriteTime: PFILETIME
    ) -> LONG;
    pub fn RegEnumValueA(
        hKey: HKEY,
        dwIndex: DWORD,
        lpValueName: LPSTR,
        lpcchValueName: LPDWORD,
        lpReserved: LPDWORD,
        lpType: LPDWORD,
        lpData: LPBYTE,
        lpcbData: LPDWORD
    ) -> LONG;
    pub fn RegEnumValueW(
        hKey: HKEY,
        dwIndex: DWORD,
        lpValueName: LPWSTR,
        lpcchValueName: LPDWORD,
        lpReserved: LPDWORD,
        lpType: LPDWORD,
        lpData: LPBYTE,
        lpcbData: LPDWORD
    ) -> LONG;
    pub fn RegFlushKey(
        hKey: HKEY
    ) -> LONG;
    pub fn RegGetValueA(
         hkey: HKEY,
         lpSubKey: LPCSTR,
         lpValue: LPCSTR,
         dwFlags: DWORD,
         pdwType: LPDWORD,
         pvData: PVOID,
         pcbData: LPDWORD
    ) -> LONG;
    pub fn RegGetValueW(
         hkey: HKEY,
         lpSubKey: LPCWSTR,
         lpValue: LPCWSTR,
         dwFlags: DWORD,
         pdwType: LPDWORD,
         pvData: PVOID,
         pcbData: LPDWORD
    ) -> LONG;
    pub fn RegLoadMUIStringW(
        hKey: HKEY,
        pszValue: LPCWSTR,
        pszOutBuf: LPWSTR,
        cbOutBuf: DWORD,
        pcbData: LPDWORD,
        Flags: DWORD,
        pszDirectory: LPCWSTR
    ) -> LONG;
    pub fn RegNotifyChangeKeyValue(
        hKey: HKEY,
        bWatchSubtree: BOOL,
        dwNotifyFilter: DWORD,
        hEvent: HANDLE,
        fAsynchronous: BOOL
    ) -> LONG;
    pub fn RegOpenCurrentUser(
        samDesired: REGSAM,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegOpenKeyExA(
        hKey: HKEY,
        lpSubKey: LPCSTR,
        ulOptions: DWORD,
        samDesired: REGSAM,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegOpenKeyExW(
        hKey: HKEY,
        lpSubKey: LPCWSTR,
        ulOptions: DWORD,
        samDesired: REGSAM,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegOpenUserClassesRoot(
        hToken: HANDLE,
        dwOptions: DWORD,
        samDesired: REGSAM,
        phkResult: PHKEY
    ) -> LONG;
    pub fn RegOverridePredefKey(
        hKey: HKEY,
        hNewHKey: HKEY
    ) -> LONG;
    pub fn RegQueryInfoKeyA(
        hKey: HKEY,
        lpClass: LPSTR,
        lpcClass: LPDWORD,
        lpReserved: LPDWORD,
        lpcSubKeys: LPDWORD,
        lpcMaxSubKeyLen: LPDWORD,
        lpcMaxClassLen: LPDWORD,
        lpcValues: LPDWORD,
        lpcMaxValueNameLen: LPDWORD,
        lpcMaxValueLen: LPDWORD,
        lpcbSecurityDescriptor: LPDWORD,
        lpftLastWriteTime: PFILETIME
    ) -> LONG;
    pub fn RegQueryInfoKeyW(
        hKey: HKEY,
        lpClass: LPWSTR,
        lpcClass: LPDWORD,
        lpReserved: LPDWORD,
        lpcSubKeys: LPDWORD,
        lpcMaxSubKeyLen: LPDWORD,
        lpcMaxClassLen: LPDWORD,
        lpcValues: LPDWORD,
        lpcMaxValueNameLen: LPDWORD,
        lpcMaxValueLen: LPDWORD,
        lpcbSecurityDescriptor: LPDWORD,
        lpftLastWriteTime: PFILETIME
    ) -> LONG;
    pub fn RegQueryMultipleValuesA(
        hKey: HKEY,
        val_list: PVALENTA,
        num_vals: DWORD,
        lpValueBuf: LPSTR,
        ldwTotsize: LPDWORD
    ) -> LONG;
    pub fn RegQueryMultipleValuesW(
        hKey: HKEY,
        val_list: PVALENTW,
        num_vals: DWORD,
        lpValueBuf: LPWSTR,
        ldwTotsize: LPDWORD
    ) -> LONG;
    pub fn RegQueryReflectionKey(
        hBase: HKEY,
        bIsReflectionDisabled: PBOOL
    ) -> LONG;
    pub fn RegQueryValueExA(
        hKey: HKEY,
        lpValueName: LPCSTR,
        lpReserved: LPDWORD,
        lpType: LPDWORD,
        lpData: LPBYTE,
        lpcbData: LPDWORD
    ) -> LONG;
    pub fn RegQueryValueExW(
        hKey: HKEY,
        lpValueName: LPCWSTR,
        lpReserved: LPDWORD,
        lpType: LPDWORD,
        lpData: LPBYTE,
        lpcbData: LPDWORD
    ) -> LONG;
    pub fn RegSetKeyValueA(
        hKey: HKEY,
        lpSubKey: LPCSTR,
        lpValueName: LPCSTR,
        dwType: DWORD,
        lpData: LPCVOID,
        cbData: DWORD
    ) -> LONG;
    pub fn RegSetKeyValueW(
        hKey: HKEY,
        lpSubKey: LPCWSTR,
        lpValueName: LPCWSTR,
        dwType: DWORD,
        lpData: LPCVOID,
        cbData: DWORD
    ) -> LONG;
    pub fn RegSetValueExA(
        hKey: HKEY,
        lpValueName: LPCSTR,
        Reserved: DWORD,
        dwType: DWORD,
        lpData: *const BYTE,
        cbData: DWORD
    ) -> LONG;
    pub fn RegSetValueExW(
        hKey: HKEY,
        lpValueName: LPCWSTR,
        Reserved: DWORD,
        dwType: DWORD,
        lpData: *const BYTE,
        cbData: DWORD
    ) -> LONG;
}<commit_msg>Reformat code.<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! FFI bindings to advapi32.
#![no_std]
#![experimental]
extern crate winapi;
use winapi::*;
extern "system" {
    pub fn AdjustTokenPrivileges(
        TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES,
        BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD,
    ) -> BOOL;
    pub fn OpenProcessToken(
        ProcessHandle: HANDLE, DesiredAccess: DWORD, TokenHandle: PHANDLE,
    ) -> BOOL;
    pub fn RegCloseKey(hKey: HKEY) -> LONG;
    pub fn RegConnectRegistryA(lpMachineName: LPCSTR, hKey: HKEY, phkResult: PHKEY) -> LONG;
    pub fn RegConnectRegistryW(lpMachineName: LPCWSTR, hKey: HKEY, phkResult: PHKEY) -> LONG;
    pub fn RegCopyTreeA(hKeySrc: HKEY, lpSubKey: LPCSTR, hKeyDest: HKEY) -> LONG;
    pub fn RegCopyTreeW(hKeySrc: HKEY, lpSubKey: LPCWSTR, hKeyDest: HKEY) -> LONG;
    pub fn RegCreateKeyExA(
        hKey: HKEY, lpSubKey: LPCSTR, Reserved: DWORD, lpClass: LPCSTR, dwOptions: DWORD,
        samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY,
        lpdwDisposition: LPDWORD,
    ) -> LONG;
    pub fn RegCreateKeyExW(
        hKey: HKEY, lpSubKey: LPCWSTR, Reserved: DWORD, lpClass: LPCWSTR, dwOptions: DWORD,
        samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY,
        lpdwDisposition: LPDWORD,
    ) -> LONG;
    pub fn RegDeleteKeyA(hKey: HKEY, lpSubKey: LPCSTR) -> LONG;
    pub fn RegDeleteKeyW(hKey: HKEY, lpSubKey: LPCWSTR) -> LONG;
    pub fn RegDeleteKeyExA(
        hKey: HKEY, lpSubKey: LPCSTR, samDesired: REGSAM, Reserved: DWORD,
    ) -> LONG;
    pub fn RegDeleteKeyExW(
        hKey: HKEY, lpSubKey: LPCWSTR, samDesired: REGSAM, Reserved: DWORD,
    ) -> LONG;
    pub fn RegDeleteKeyValueA(hKey: HKEY, lpSubKey: LPCSTR, lpValueName: LPCSTR) -> LONG;
    pub fn RegDeleteKeyValueW(hKey: HKEY, lpSubKey: LPCWSTR, lpValueName: LPCWSTR) -> LONG;
    pub fn RegDeleteTreeA(hKey: HKEY, lpSubKey: LPCSTR) -> LONG;
    pub fn RegDeleteTreeW(hKey: HKEY, lpSubKey: LPCWSTR) -> LONG;
    pub fn RegDeleteValueA(hKey: HKEY, lpValueName: LPCSTR) -> LONG;
    pub fn RegDeleteValueW(hKey: HKEY, lpValueName: LPCWSTR) -> LONG;
    pub fn RegDisablePredefinedCache() -> LONG;
    pub fn RegDisablePredefinedCacheEx() -> LONG;
    pub fn RegDisableReflectionKey(hBase: HKEY) -> LONG;
    pub fn RegEnableReflectionKey(hBase: HKEY) -> LONG;
    pub fn RegEnumKeyExA(
        hKey: HKEY, dwIndex: DWORD, lpName: LPSTR, lpcName: LPDWORD, lpReserved: LPDWORD,
        lpClass: LPSTR, lpcClass: LPDWORD, lpftLastWriteTime: PFILETIME,
    ) -> LONG;
    pub fn RegEnumKeyExW(
        hKey: HKEY, dwIndex: DWORD, lpName: LPWSTR, lpcName: LPDWORD, lpReserved: LPDWORD,
        lpClass: LPWSTR, lpcClass: LPDWORD, lpftLastWriteTime: PFILETIME,
    ) -> LONG;
    pub fn RegEnumValueA(
        hKey: HKEY, dwIndex: DWORD, lpValueName: LPSTR, lpcchValueName: LPDWORD,
        lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,
    ) -> LONG;
    pub fn RegEnumValueW(
        hKey: HKEY, dwIndex: DWORD, lpValueName: LPWSTR, lpcchValueName: LPDWORD,
        lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,
    ) -> LONG;
    pub fn RegFlushKey(hKey: HKEY) -> LONG;
    pub fn RegGetValueA(
        hkey: HKEY, lpSubKey: LPCSTR, lpValue: LPCSTR, dwFlags: DWORD, pdwType: LPDWORD,
        pvData: PVOID, pcbData: LPDWORD,
    ) -> LONG;
    pub fn RegGetValueW(
        hkey: HKEY, lpSubKey: LPCWSTR, lpValue: LPCWSTR, dwFlags: DWORD, pdwType: LPDWORD,
        pvData: PVOID, pcbData: LPDWORD,
    ) -> LONG;
    pub fn RegLoadMUIStringW(
        hKey: HKEY, pszValue: LPCWSTR, pszOutBuf: LPWSTR, cbOutBuf: DWORD, pcbData: LPDWORD,
        Flags: DWORD, pszDirectory: LPCWSTR,
    ) -> LONG;
    pub fn RegNotifyChangeKeyValue(
        hKey: HKEY, bWatchSubtree: BOOL, dwNotifyFilter: DWORD, hEvent: HANDLE,
        fAsynchronous: BOOL,
    ) -> LONG;
    pub fn RegOpenCurrentUser(samDesired: REGSAM, phkResult: PHKEY) -> LONG;
    pub fn RegOpenKeyExA(
        hKey: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY,
    ) -> LONG;
    pub fn RegOpenKeyExW(
        hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY,
    ) -> LONG;
    pub fn RegOpenUserClassesRoot(
        hToken: HANDLE, dwOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY,
    ) -> LONG;
    pub fn RegOverridePredefKey(hKey: HKEY, hNewHKey: HKEY) -> LONG;
    pub fn RegQueryInfoKeyA(
        hKey: HKEY, lpClass: LPSTR, lpcClass: LPDWORD, lpReserved: LPDWORD, lpcSubKeys: LPDWORD,
        lpcMaxSubKeyLen: LPDWORD, lpcMaxClassLen: LPDWORD, lpcValues: LPDWORD,
        lpcMaxValueNameLen: LPDWORD, lpcMaxValueLen: LPDWORD, lpcbSecurityDescriptor: LPDWORD,
        lpftLastWriteTime: PFILETIME,
    ) -> LONG;
    pub fn RegQueryInfoKeyW(
        hKey: HKEY, lpClass: LPWSTR, lpcClass: LPDWORD, lpReserved: LPDWORD, lpcSubKeys: LPDWORD,
        lpcMaxSubKeyLen: LPDWORD, lpcMaxClassLen: LPDWORD, lpcValues: LPDWORD,
        lpcMaxValueNameLen: LPDWORD, lpcMaxValueLen: LPDWORD, lpcbSecurityDescriptor: LPDWORD,
        lpftLastWriteTime: PFILETIME,
    ) -> LONG;
    pub fn RegQueryMultipleValuesA(
        hKey: HKEY, val_list: PVALENTA, num_vals: DWORD, lpValueBuf: LPSTR, ldwTotsize: LPDWORD,
    ) -> LONG;
    pub fn RegQueryMultipleValuesW(
        hKey: HKEY, val_list: PVALENTW, num_vals: DWORD, lpValueBuf: LPWSTR, ldwTotsize: LPDWORD,
    ) -> LONG;
    pub fn RegQueryReflectionKey(hBase: HKEY, bIsReflectionDisabled: PBOOL) -> LONG;
    pub fn RegQueryValueExA(
        hKey: HKEY, lpValueName: LPCSTR, lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE,
        lpcbData: LPDWORD,
    ) -> LONG;
    pub fn RegQueryValueExW(
        hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE,
        lpcbData: LPDWORD,
    ) -> LONG;
    pub fn RegSetKeyValueA(
        hKey: HKEY, lpSubKey: LPCSTR, lpValueName: LPCSTR, dwType: DWORD, lpData: LPCVOID,
        cbData: DWORD,
    ) -> LONG;
    pub fn RegSetKeyValueW(
        hKey: HKEY, lpSubKey: LPCWSTR, lpValueName: LPCWSTR, dwType: DWORD, lpData: LPCVOID,
        cbData: DWORD,
    ) -> LONG;
    pub fn RegSetValueExA(
        hKey: HKEY, lpValueName: LPCSTR, Reserved: DWORD, dwType: DWORD, lpData: *const BYTE,
        cbData: DWORD,
    ) -> LONG;
    pub fn RegSetValueExW(
        hKey: HKEY, lpValueName: LPCWSTR, Reserved: DWORD, dwType: DWORD, lpData: *const BYTE,
        cbData: DWORD,
    ) -> LONG;
}
<|endoftext|>


<commit_before>use ast::AST;

#[deriving(Show, PartialEq)]
pub enum Error {
    UnboundVariable(String),
    UnappliableValue(AST),
    WrongArgumentType(AST),
    BadArity(String),
}

pub fn eval(value: AST) -> Result<AST, Error> {
    match value {
        AST::Atom(atom) =>
            Err(Error::UnboundVariable(atom)),
        AST::Bool(_b) =>
            Ok(value),
        AST::Integer(_i) =>
            Ok(value),
        AST::List(ref list) =>
            eval_list(list.as_slice()),
    }
}

fn eval_list(list: &[AST]) -> Result<AST, Error> {
    if list.is_empty() {
        return Ok(AST::List(vec!()));
    }

    let fun = list.head().unwrap();
    let args = list.tail();

    match fun {
        &AST::Atom(ref atom) if atom.as_slice() == "quote" =>
            eval_quote(args),
        &AST::Atom(ref atom) if atom.as_slice() == "and" =>
            eval_and(args),
        &AST::Atom(ref atom) if atom.as_slice() == "or" =>
            eval_or(args),
        &AST::Atom(ref atom) if atom.as_slice() == "if" =>
            eval_if(args),
        &AST::Atom(ref atom) => {
            let args = try!(eval_args(args));
            apply(atom.as_slice(), args.as_slice())
        },
        _ =>
            Err(Error::UnappliableValue(fun.clone()))
    }
}

fn eval_args(args: &[AST]) -> Result<Vec<AST>, Error> {
    let mut out = Vec::with_capacity(args.len());

    for arg in args.iter() {
        let evald_arg = try!(eval(arg.clone()));
        out.push(evald_arg);
    }

    Ok(out)
}

fn apply(name: &str, args: &[AST]) -> Result<AST, Error> {
    match name {
        "+" => eval_fun_plus(args),
        "-" => eval_fun_minus(args),
        "*" => eval_fun_product(args),
        "/" => eval_fun_division(args),
        "=" => eval_fun_equals(args),
        "<" => eval_fun_less_than(args),
        "<=" => eval_fun_less_than_or_equal(args),
        ">" => eval_fun_greater_than(args),
        ">=" => eval_fun_greater_than_or_equal(args),
        "not" => eval_fun_not(args),
        _   => Err(Error::UnboundVariable(name.to_string()))
    }
}

fn eval_fun_plus(args: &[AST]) -> Result<AST, Error> {
    let args_ = try!(list_of_integers(args));
    let sum = args_.iter().fold(0, |sum, n| sum + *n);
    Ok(AST::Integer(sum))
}

fn eval_fun_minus(args_: &[AST]) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));

    if args.len() == 0 {
        return Err(Error::BadArity("-".to_string()))
    }

    let head = args.head().unwrap();
    let tail = args.tail();

    if tail.is_empty() {
        return Ok(AST::Integer(- *head))
    }

    let tail_sum = tail.iter().fold(0, |sum, n| sum + *n);
    Ok(AST::Integer(*head - tail_sum))
}

fn eval_fun_division(args_: &[AST]) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));

    if args.len() == 0 {
        return Err(Error::BadArity("/".to_string()))
    }

    let head = args.head().unwrap();
    let tail = args.tail();

    if tail.is_empty() {
        return Ok(AST::Integer(1 / *head))
    }

    let div = tail.iter().fold(*head, |div, n| div / *n);
    Ok(AST::Integer(div))
}

fn eval_fun_product(args_: &[AST]) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));
    let product = args.iter().fold(1, |product, n| product * *n);
    Ok(AST::Integer(product))
}

fn eval_fun_equals(args_: &[AST]) -> Result<AST, Error> {
    if args_.len() < 2 {
        return Ok(AST::Bool(true))
    }

    let args = try!(list_of_integers(args_));
    let head = args.head().unwrap();
    let outcome = args.iter().skip(1).all(|n| *n == *head);
    Ok(AST::Bool(outcome))
}

fn eval_fun_less_than(args: &[AST]) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a < b)
}

fn eval_fun_less_than_or_equal(args: &[AST]) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a <= b)
}

fn eval_fun_greater_than(args: &[AST]) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a > b)
}

fn eval_fun_greater_than_or_equal(args: &[AST]) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a >= b)
}

fn eval_fun_ord(args_: &[AST], cmp: |i64, i64| -> bool) -> Result<AST, Error> {
    if args_.len() < 2 {
        return Ok(AST::Bool(true))
    }

    let args = try!(list_of_integers(args_));
    let outcome = range(0, args.len() - 1).all(|i|
        cmp(args[i], args[i + 1u])
    );

    Ok(AST::Bool(outcome))
}

fn eval_fun_not(args: &[AST]) -> Result<AST, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity("not".to_string()))
    }

    let outcome = match args.head().unwrap() {
        &AST::Bool(false) => true,
        _                 => false,
    };

    Ok(AST::Bool(outcome))
}

fn eval_quote(list: &[AST]) -> Result<AST, Error> {
    Ok(list[0].clone())
}

fn list_of_integers(list: &[AST]) -> Result<Vec<i64>, Error> {
    let mut integers = Vec::with_capacity(list.len());

    for val in list.iter() {
        if let &AST::Integer(n) = val {
            integers.push(n);
        } else {
            return Err(Error::WrongArgumentType(val.clone()))
        };
    }

    Ok(integers)
}

fn eval_and(args: &[AST]) -> Result<AST, Error> {
    let mut last = AST::Bool(true);

    for val in args.iter() {
        let val = try!(eval(val.clone()));

        if val == AST::Bool(false) {
            return Ok(val)
        }

        last = val;
    }

    Ok(last)
}

fn eval_or(args: &[AST]) -> Result<AST, Error> {
    let mut last = AST::Bool(false);

    for val in args.iter() {
        let val = try!(eval(val.clone()));

        if val != AST::Bool(false) {
            return Ok(val)
        }

        last = val;
    }

    Ok(last)
}

fn eval_if(args: &[AST]) -> Result<AST, Error> {
    if args.len() != 3 {
        return Err(Error::BadArity("if".to_string()))
    }

    let condition = try!(eval(args[0].clone()));

    let result = if condition != AST::Bool(false) {
        try!(eval(args[1].clone()))
    } else {
        try!(eval(args[2].clone()))
    };

    Ok(result)
}
<commit_msg>Refactored ownerships and matches in eval.<commit_after>use ast::AST;

#[deriving(Show, PartialEq)]
pub enum Error {
    UnboundVariable(String),
    UnappliableValue(AST),
    WrongArgumentType(AST),
    BadArity(String),
}

pub fn eval(value: AST) -> Result<AST, Error> {
    match value {
        AST::Atom(atom) =>
            Err(Error::UnboundVariable(atom)),
        AST::Bool(_b) =>
            Ok(value),
        AST::Integer(_i) =>
            Ok(value),
        AST::List(ref list) =>
            eval_list(list.as_slice()),
    }
}

fn eval_list(list: &[AST]) -> Result<AST, Error> {
    if list.is_empty() {
        return Ok(AST::List(vec!()));
    }

    let fun = list.head().unwrap();
    let args = list.tail();

    match fun {
        &AST::Atom(ref atom) =>
            match atom.as_slice() {
                "and"   => eval_and(args),
                "if"    => eval_if(args),
                "or"    => eval_or(args),
                "quote" => eval_quote(args),
                fun     => apply(fun, args),
            },
        _ =>
            Err(Error::UnappliableValue(fun.clone()))
    }
}

fn eval_args(args: &[AST]) -> Result<Vec<AST>, Error> {
    let mut out = Vec::with_capacity(args.len());

    for arg in args.iter() {
        let evald_arg = try!(eval(arg.clone()));
        out.push(evald_arg);
    }

    Ok(out)
}

fn apply(fun: &str, args_: &[AST]) -> Result<AST, Error> {
    let args = try!(eval_args(args_));

    match fun {
        "+"   => eval_fun_plus(args),
        "-"   => eval_fun_minus(args),
        "*"   => eval_fun_product(args),
        "/"   => eval_fun_division(args),
        "="   => eval_fun_equals(args),
        "<"   => eval_fun_less_than(args),
        "<="  => eval_fun_less_than_or_equal(args),
        ">"   => eval_fun_greater_than(args),
        ">="  => eval_fun_greater_than_or_equal(args),
        "not" => eval_fun_not(args),
        _     => Err(Error::UnboundVariable(fun.to_string()))
    }
}

fn eval_fun_plus(args: Vec<AST>) -> Result<AST, Error> {
    let args_ = try!(list_of_integers(args));
    let sum = args_.iter().fold(0, |sum, n| sum + *n);
    Ok(AST::Integer(sum))
}

fn eval_fun_minus(args_: Vec<AST>) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));

    if args.len() == 0 {
        return Err(Error::BadArity("-".to_string()))
    }

    let head = args.head().unwrap();
    let tail = args.tail();

    if tail.is_empty() {
        return Ok(AST::Integer(- *head))
    }

    let tail_sum = tail.iter().fold(0, |sum, n| sum + *n);
    Ok(AST::Integer(*head - tail_sum))
}

fn eval_fun_division(args_: Vec<AST>) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));

    if args.len() == 0 {
        return Err(Error::BadArity("/".to_string()))
    }

    let head = args.head().unwrap();
    let tail = args.tail();

    if tail.is_empty() {
        return Ok(AST::Integer(1 / *head))
    }

    let div = tail.iter().fold(*head, |div, n| div / *n);
    Ok(AST::Integer(div))
}

fn eval_fun_product(args_: Vec<AST>) -> Result<AST, Error> {
    let args = try!(list_of_integers(args_));
    let product = args.iter().fold(1, |product, n| product * *n);
    Ok(AST::Integer(product))
}

fn eval_fun_equals(args_: Vec<AST>) -> Result<AST, Error> {
    if args_.len() < 2 {
        return Ok(AST::Bool(true))
    }

    let args = try!(list_of_integers(args_));
    let head = args.head().unwrap();
    let outcome = args.iter().skip(1).all(|n| *n == *head);
    Ok(AST::Bool(outcome))
}

fn eval_fun_less_than(args: Vec<AST>) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a < b)
}

fn eval_fun_less_than_or_equal(args: Vec<AST>) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a <= b)
}

fn eval_fun_greater_than(args: Vec<AST>) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a > b)
}

fn eval_fun_greater_than_or_equal(args: Vec<AST>) -> Result<AST, Error> {
    eval_fun_ord(args, |a, b| a >= b)
}

fn eval_fun_ord(args_: Vec<AST>, cmp: |i64, i64| -> bool) -> Result<AST, Error> {
    if args_.len() < 2 {
        return Ok(AST::Bool(true))
    }

    let args = try!(list_of_integers(args_));
    let outcome = range(0, args.len() - 1).all(|i|
        cmp(args[i], args[i + 1u])
    );

    Ok(AST::Bool(outcome))
}

fn eval_fun_not(args: Vec<AST>) -> Result<AST, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity("not".to_string()))
    }

    let outcome = match args.head().unwrap() {
        &AST::Bool(false) => true,
        _                 => false,
    };

    Ok(AST::Bool(outcome))
}

fn eval_quote(list: &[AST]) -> Result<AST, Error> {
    Ok(list[0].clone())
}

fn list_of_integers(list: Vec<AST>) -> Result<Vec<i64>, Error> {
    let mut integers = Vec::with_capacity(list.len());

    for val in list.iter() {
        if let &AST::Integer(n) = val {
            integers.push(n);
        } else {
            return Err(Error::WrongArgumentType(val.clone()))
        };
    }

    Ok(integers)
}

fn eval_and(args: &[AST]) -> Result<AST, Error> {
    let mut last = AST::Bool(true);

    for val in args.iter() {
        let val = try!(eval(val.clone()));

        if val == AST::Bool(false) {
            return Ok(val)
        }

        last = val;
    }

    Ok(last)
}

fn eval_or(args: &[AST]) -> Result<AST, Error> {
    let mut last = AST::Bool(false);

    for val in args.iter() {
        let val = try!(eval(val.clone()));

        if val != AST::Bool(false) {
            return Ok(val)
        }

        last = val;
    }

    Ok(last)
}

fn eval_if(args: &[AST]) -> Result<AST, Error> {
    if args.len() != 3 {
        return Err(Error::BadArity("if".to_string()))
    }

    let condition = try!(eval(args[0].clone()));

    let result = if condition != AST::Bool(false) {
        try!(eval(args[1].clone()))
    } else {
        try!(eval(args[2].clone()))
    };

    Ok(result)
}
<|endoftext|>


<commit_before>use super::dll::{DoublyLinkedList, Item, Node};
use parking_lot::Mutex;
use std::convert::TryFrom;
use std::ptr;

/// A simple LRU cache.
pub struct Lru {
    shards: Vec<Mutex<Shard>>,
}

#[allow(unsafe_code)]
unsafe impl Sync for Lru {}

impl Lru {
    /// Instantiates a new `Lru` cache.
    pub fn new(cache_capacity: u64) -> Self {
        assert!(
            cache_capacity >= 256,
            "Please configure the cache \
             capacity to be at least 256 bytes"
        );
        let n_shards = 256;
        let shard_capacity = cache_capacity / n_shards as u64;

        let mut shards = Vec::with_capacity(n_shards);
        shards.resize_with(n_shards, || Mutex::new(Shard::new(shard_capacity)));

        Self { shards }
    }

    /// Called when an item is accessed. Returns a Vec of items to be
    /// evicted.
    ///
    /// Items layout:
    ///   items:   1 2 3 4 5 6 7 8 9 10
    ///   shards:  1 0 1 0 1 0 1 0 1 0
    ///   shard 0:   2   4   6   8   10
    ///   shard 1: 1   3   5   7   9
    pub fn accessed(&self, id: Item, item_size: u64) -> Vec<Item> {
        let shards = self.shards.len() as u64;
        let (shard_idx, item_pos) = (id % shards, id / shards);
        let shard_mu: &Mutex<Shard> = &self.shards[safe_usize(shard_idx)];
        let mut shard = shard_mu.lock();
        let mut to_evict = shard.accessed(safe_usize(item_pos), item_size);
        // map shard internal offsets to global items ids
        to_evict.iter_mut().for_each(|pos| *pos = (*pos * shards) + shard_idx);
        to_evict
    }
}

#[derive(Clone)]
struct Entry {
    ptr: *mut Node,
    size: u64,
}

impl Default for Entry {
    fn default() -> Self {
        Self { ptr: ptr::null_mut(), size: 0 }
    }
}

struct Shard {
    list: DoublyLinkedList,
    entries: Vec<Entry>,
    capacity: u64,
    size: u64,
}

impl Shard {
    fn new(capacity: u64) -> Self {
        assert!(capacity > 0, "shard capacity must be non-zero");

        Self {
            list: DoublyLinkedList::default(),
            entries: vec![],
            capacity,
            size: 0,
        }
    }

    /// Items in the shard list are indexes of the entries.
    fn accessed(&mut self, pos: usize, size: u64) -> Vec<Item> {
        if pos >= self.entries.len() {
            self.entries.resize(pos + 1, Entry::default());
        }

        {
            let entry = &mut self.entries[pos];

            self.size -= entry.size;
            entry.size = size;
            self.size += size;

            if entry.ptr.is_null() {
                entry.ptr = self.list.push_head(Item::try_from(pos).unwrap());
            } else {
                entry.ptr = self.list.promote(entry.ptr);
            }
        }

        let mut to_evict = vec![];
        while self.size > self.capacity {
            if self.list.len() == 1 {
                // don't evict what we just added
                break;
            }

            let min_pid = self.list.pop_tail().unwrap();
            let min_pid_idx = safe_usize(min_pid);

            self.entries[min_pid_idx].ptr = ptr::null_mut();

            to_evict.push(min_pid);

            self.size -= self.entries[min_pid_idx].size;
            self.entries[min_pid_idx].size = 0;
        }

        to_evict
    }
}

#[inline]
fn safe_usize(value: Item) -> usize {
    usize::try_from(value).unwrap()
}
<commit_msg>Reduce cache shards to 8 to smooth out memory usage<commit_after>use super::dll::{DoublyLinkedList, Item, Node};
use parking_lot::Mutex;
use std::convert::TryFrom;
use std::ptr;

/// A simple LRU cache.
pub struct Lru {
    shards: Vec<Mutex<Shard>>,
}

#[allow(unsafe_code)]
unsafe impl Sync for Lru {}

impl Lru {
    /// Instantiates a new `Lru` cache.
    pub fn new(cache_capacity_raw: u64) -> Self {
        const N_SHARDS: usize = 8;

        let cache_capacity =
            std::cmp::max(cache_capacity_raw, u64::try_from(N_SHARDS).unwrap());

        let shard_capacity = cache_capacity / N_SHARDS as u64;

        let mut shards = Vec::with_capacity(N_SHARDS);
        shards.resize_with(N_SHARDS, || Mutex::new(Shard::new(shard_capacity)));

        Self { shards }
    }

    /// Called when an item is accessed. Returns a Vec of items to be
    /// evicted.
    ///
    /// Items layout:
    ///   items:   1 2 3 4 5 6 7 8 9 10
    ///   shards:  1 0 1 0 1 0 1 0 1 0
    ///   shard 0:   2   4   6   8   10
    ///   shard 1: 1   3   5   7   9
    pub fn accessed(&self, id: Item, item_size: u64) -> Vec<Item> {
        let shards = self.shards.len() as u64;
        let (shard_idx, item_pos) = (id % shards, id / shards);
        let shard_mu: &Mutex<Shard> = &self.shards[safe_usize(shard_idx)];
        let mut shard = shard_mu.lock();
        let mut to_evict = shard.accessed(safe_usize(item_pos), item_size);
        // map shard internal offsets to global items ids
        to_evict.iter_mut().for_each(|pos| *pos = (*pos * shards) + shard_idx);
        to_evict
    }
}

#[derive(Clone)]
struct Entry {
    ptr: *mut Node,
    size: u64,
}

impl Default for Entry {
    fn default() -> Self {
        Self { ptr: ptr::null_mut(), size: 0 }
    }
}

struct Shard {
    list: DoublyLinkedList,
    entries: Vec<Entry>,
    capacity: u64,
    size: u64,
}

impl Shard {
    fn new(capacity: u64) -> Self {
        assert!(capacity > 0, "shard capacity must be non-zero");

        Self {
            list: DoublyLinkedList::default(),
            entries: vec![],
            capacity,
            size: 0,
        }
    }

    /// Items in the shard list are indexes of the entries.
    fn accessed(&mut self, pos: usize, size: u64) -> Vec<Item> {
        if pos >= self.entries.len() {
            self.entries.resize(pos + 1, Entry::default());
        }

        {
            let entry = &mut self.entries[pos];

            self.size -= entry.size;
            entry.size = size;
            self.size += size;

            if entry.ptr.is_null() {
                entry.ptr = self.list.push_head(Item::try_from(pos).unwrap());
            } else {
                entry.ptr = self.list.promote(entry.ptr);
            }
        }

        let mut to_evict = vec![];
        while self.size > self.capacity {
            if self.list.len() == 1 {
                // don't evict what we just added
                break;
            }

            let min_pid = self.list.pop_tail().unwrap();
            let min_pid_idx = safe_usize(min_pid);

            self.entries[min_pid_idx].ptr = ptr::null_mut();

            to_evict.push(min_pid);

            self.size -= self.entries[min_pid_idx].size;
            self.entries[min_pid_idx].size = 0;
        }

        to_evict
    }
}

#[inline]
fn safe_usize(value: Item) -> usize {
    usize::try_from(value).unwrap()
}
<|endoftext|>


<commit_before>use crate::cell::UnsafeCell;
use crate::fmt;
use crate::future::Future;
use crate::ops::{Deref, DerefMut};
use crate::pin::Pin;
use crate::ptr::{NonNull, Unique};
use crate::stream::Stream;
use crate::sync::atomic;
use crate::task::{Context, Poll};

/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The
/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`]
/// boundary with no fear of unwind safety.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
///
/// ## What is unwind safety?
///
/// In Rust a function can "return" early if it either panics or calls a
/// function which transitively panics. This sort of control flow is not always
/// anticipated, and has the possibility of causing subtle bugs through a
/// combination of two critical components:
///
/// 1. A data structure is in a temporarily invalid state when the thread
///    panics.
/// 2. This broken invariant is then later observed.
///
/// Typically in Rust, it is difficult to perform step (2) because catching a
/// panic involves either spawning a thread (which in turns makes it difficult
/// to later witness broken invariants) or using the `catch_unwind` function in this
/// module. Additionally, even if an invariant is witnessed, it typically isn't a
/// problem in Rust because there are no uninitialized values (like in C or C++).
///
/// It is possible, however, for **logical** invariants to be broken in Rust,
/// which can end up causing behavioral bugs. Another key aspect of unwind safety
/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
/// memory unsafety.
///
/// That was a bit of a whirlwind tour of unwind safety, but for more information
/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc].
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// ## What is `UnwindSafe`?
///
/// Now that we've got an idea of what unwind safety is in Rust, it's also
/// important to understand what this trait represents. As mentioned above, one
/// way to witness broken invariants is through the `catch_unwind` function in this
/// module as it allows catching a panic and then re-using the environment of
/// the closure.
///
/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
/// witnessing a broken invariant through the use of `catch_unwind` (catching a
/// panic). This trait is an auto trait, so it is automatically implemented for
/// many types, and it is also structurally composed (e.g., a struct is unwind
/// safe if all of its components are unwind safe).
///
/// Note, however, that this is not an unsafe trait, so there is not a succinct
/// contract that this trait is providing. Instead it is intended as more of a
/// "speed bump" to alert users of `catch_unwind` that broken invariants may be
/// witnessed and may need to be accounted for.
///
/// ## Who implements `UnwindSafe`?
///
/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
/// unwind safe. The general idea is that any mutable state which can be shared
/// across `catch_unwind` is not unwind safe by default. This is because it is very
/// easy to witness a broken invariant outside of `catch_unwind` as the data is
/// simply accessed as usual.
///
/// Types like `&Mutex<T>`, however, are unwind safe because they implement
/// poisoning by default. They still allow witnessing a broken invariant, but
/// they already provide their own "speed bumps" to do so.
///
/// ## When should `UnwindSafe` be used?
///
/// It is not intended that most types or functions need to worry about this trait.
/// It is only used as a bound on the `catch_unwind` function and as mentioned
/// above, the lack of `unsafe` means it is mostly an advisory. The
/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
/// implemented for any closed over variables passed to `catch_unwind`.
#[stable(feature = "catch_unwind", since = "1.9.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")]
#[rustc_on_unimplemented(
    message = "the type `{Self}` may not be safely transferred across an unwind boundary",
    label = "`{Self}` may not be safely transferred across an unwind boundary"
)]
pub auto trait UnwindSafe {}

/// A marker trait representing types where a shared reference is considered
/// unwind safe.
///
/// This trait is namely not implemented by [`UnsafeCell`], the root of all
/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// [`UnwindSafe`] trait, for more information see that documentation.
#[stable(feature = "catch_unwind", since = "1.9.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")]
#[rustc_on_unimplemented(
    message = "the type `{Self}` may contain interior mutability and a reference may not be safely \
               transferrable across a catch_unwind boundary",
    label = "`{Self}` may contain interior mutability and a reference may not be safely \
             transferrable across a catch_unwind boundary"
)]
pub auto trait RefUnwindSafe {}

/// A simple wrapper around a type to assert that it is unwind safe.
///
/// When using [`catch_unwind`] it may be the case that some of the closed over
/// variables are not unwind safe. For example if `&mut T` is captured the
/// compiler will generate a warning indicating that it is not unwind safe. It
/// might not be the case, however, that this is actually a problem due to the
/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into
/// account. This wrapper struct is useful for a quick and lightweight
/// annotation that a variable is indeed unwind safe.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
///
/// # Examples
///
/// One way to use `AssertUnwindSafe` is to assert that the entire closure
/// itself is unwind safe, bypassing all checks for all variables:
///
/// ```
/// use std::panic::{self, AssertUnwindSafe};
///
/// let mut variable = 4;
///
/// // This code will not compile because the closure captures `&mut variable`
/// // which is not considered unwind safe by default.
///
/// // panic::catch_unwind(|| {
/// //     variable += 3;
/// // });
///
/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
///     variable += 3;
/// }));
/// // ...
/// ```
///
/// Wrapping the entire closure amounts to a blanket assertion that all captured
/// variables are unwind safe. This has the downside that if new captures are
/// added in the future, they will also be considered unwind safe. Therefore,
/// you may prefer to just wrap individual captures, as shown below. This is
/// more annotation, but it ensures that if a new capture is added which is not
/// unwind safe, you will get a compilation error at that time, which will
/// allow you to consider whether that new capture in fact represent a bug or
/// not.
///
/// ```
/// use std::panic::{self, AssertUnwindSafe};
///
/// let mut variable = 4;
/// let other_capture = 3;
///
/// let result = {
///     let mut wrapper = AssertUnwindSafe(&mut variable);
///     panic::catch_unwind(move || {
///         **wrapper += other_capture;
///     })
/// };
/// // ...
/// ```
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T);

// Implementations of the `UnwindSafe` trait:
//
// * By default everything is unwind safe
// * pointers T contains mutability of some form are not unwind safe
// * Unique, an owning pointer, lifts an implementation
// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
// * Our custom AssertUnwindSafe wrapper is indeed unwind safe

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !UnwindSafe for &mut T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> UnwindSafe for AssertUnwindSafe<T> {}

// Pretty simple implementations for the `RefUnwindSafe` marker trait,
// basically just saying that `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else).
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for atomic::AtomicIsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for atomic::AtomicI128 {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for atomic::AtomicUsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for atomic::AtomicU128 {}

#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for atomic::AtomicBool {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> Deref for AssertUnwindSafe<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> DerefMut for AssertUnwindSafe<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
    type Output = R;

    extern "rust-call" fn call_once(self, _args: ()) -> R {
        (self.0)()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("AssertUnwindSafe").field(&self.0).finish()
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: Future> Future for AssertUnwindSafe<F> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
        F::poll(pinned_field, cx)
    }
}

#[unstable(feature = "async_stream", issue = "79024")]
impl<S: Stream> Stream for AssertUnwindSafe<S> {
    type Item = S::Item;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
        unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}
<commit_msg>Fix unused sync::atomic import on targets without atomics<commit_after>use crate::cell::UnsafeCell;
use crate::fmt;
use crate::future::Future;
use crate::ops::{Deref, DerefMut};
use crate::pin::Pin;
use crate::ptr::{NonNull, Unique};
use crate::stream::Stream;
use crate::task::{Context, Poll};

/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The
/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`]
/// boundary with no fear of unwind safety.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
///
/// ## What is unwind safety?
///
/// In Rust a function can "return" early if it either panics or calls a
/// function which transitively panics. This sort of control flow is not always
/// anticipated, and has the possibility of causing subtle bugs through a
/// combination of two critical components:
///
/// 1. A data structure is in a temporarily invalid state when the thread
///    panics.
/// 2. This broken invariant is then later observed.
///
/// Typically in Rust, it is difficult to perform step (2) because catching a
/// panic involves either spawning a thread (which in turns makes it difficult
/// to later witness broken invariants) or using the `catch_unwind` function in this
/// module. Additionally, even if an invariant is witnessed, it typically isn't a
/// problem in Rust because there are no uninitialized values (like in C or C++).
///
/// It is possible, however, for **logical** invariants to be broken in Rust,
/// which can end up causing behavioral bugs. Another key aspect of unwind safety
/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
/// memory unsafety.
///
/// That was a bit of a whirlwind tour of unwind safety, but for more information
/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc].
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// ## What is `UnwindSafe`?
///
/// Now that we've got an idea of what unwind safety is in Rust, it's also
/// important to understand what this trait represents. As mentioned above, one
/// way to witness broken invariants is through the `catch_unwind` function in this
/// module as it allows catching a panic and then re-using the environment of
/// the closure.
///
/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
/// witnessing a broken invariant through the use of `catch_unwind` (catching a
/// panic). This trait is an auto trait, so it is automatically implemented for
/// many types, and it is also structurally composed (e.g., a struct is unwind
/// safe if all of its components are unwind safe).
///
/// Note, however, that this is not an unsafe trait, so there is not a succinct
/// contract that this trait is providing. Instead it is intended as more of a
/// "speed bump" to alert users of `catch_unwind` that broken invariants may be
/// witnessed and may need to be accounted for.
///
/// ## Who implements `UnwindSafe`?
///
/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
/// unwind safe. The general idea is that any mutable state which can be shared
/// across `catch_unwind` is not unwind safe by default. This is because it is very
/// easy to witness a broken invariant outside of `catch_unwind` as the data is
/// simply accessed as usual.
///
/// Types like `&Mutex<T>`, however, are unwind safe because they implement
/// poisoning by default. They still allow witnessing a broken invariant, but
/// they already provide their own "speed bumps" to do so.
///
/// ## When should `UnwindSafe` be used?
///
/// It is not intended that most types or functions need to worry about this trait.
/// It is only used as a bound on the `catch_unwind` function and as mentioned
/// above, the lack of `unsafe` means it is mostly an advisory. The
/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
/// implemented for any closed over variables passed to `catch_unwind`.
#[stable(feature = "catch_unwind", since = "1.9.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")]
#[rustc_on_unimplemented(
    message = "the type `{Self}` may not be safely transferred across an unwind boundary",
    label = "`{Self}` may not be safely transferred across an unwind boundary"
)]
pub auto trait UnwindSafe {}

/// A marker trait representing types where a shared reference is considered
/// unwind safe.
///
/// This trait is namely not implemented by [`UnsafeCell`], the root of all
/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// [`UnwindSafe`] trait, for more information see that documentation.
#[stable(feature = "catch_unwind", since = "1.9.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")]
#[rustc_on_unimplemented(
    message = "the type `{Self}` may contain interior mutability and a reference may not be safely \
               transferrable across a catch_unwind boundary",
    label = "`{Self}` may contain interior mutability and a reference may not be safely \
             transferrable across a catch_unwind boundary"
)]
pub auto trait RefUnwindSafe {}

/// A simple wrapper around a type to assert that it is unwind safe.
///
/// When using [`catch_unwind`] it may be the case that some of the closed over
/// variables are not unwind safe. For example if `&mut T` is captured the
/// compiler will generate a warning indicating that it is not unwind safe. It
/// might not be the case, however, that this is actually a problem due to the
/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into
/// account. This wrapper struct is useful for a quick and lightweight
/// annotation that a variable is indeed unwind safe.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
///
/// # Examples
///
/// One way to use `AssertUnwindSafe` is to assert that the entire closure
/// itself is unwind safe, bypassing all checks for all variables:
///
/// ```
/// use std::panic::{self, AssertUnwindSafe};
///
/// let mut variable = 4;
///
/// // This code will not compile because the closure captures `&mut variable`
/// // which is not considered unwind safe by default.
///
/// // panic::catch_unwind(|| {
/// //     variable += 3;
/// // });
///
/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
///     variable += 3;
/// }));
/// // ...
/// ```
///
/// Wrapping the entire closure amounts to a blanket assertion that all captured
/// variables are unwind safe. This has the downside that if new captures are
/// added in the future, they will also be considered unwind safe. Therefore,
/// you may prefer to just wrap individual captures, as shown below. This is
/// more annotation, but it ensures that if a new capture is added which is not
/// unwind safe, you will get a compilation error at that time, which will
/// allow you to consider whether that new capture in fact represent a bug or
/// not.
///
/// ```
/// use std::panic::{self, AssertUnwindSafe};
///
/// let mut variable = 4;
/// let other_capture = 3;
///
/// let result = {
///     let mut wrapper = AssertUnwindSafe(&mut variable);
///     panic::catch_unwind(move || {
///         **wrapper += other_capture;
///     })
/// };
/// // ...
/// ```
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T);

// Implementations of the `UnwindSafe` trait:
//
// * By default everything is unwind safe
// * pointers T contains mutability of some form are not unwind safe
// * Unique, an owning pointer, lifts an implementation
// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
// * Our custom AssertUnwindSafe wrapper is indeed unwind safe

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !UnwindSafe for &mut T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
#[unstable(feature = "ptr_internals", issue = "none")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> UnwindSafe for AssertUnwindSafe<T> {}

// Pretty simple implementations for the `RefUnwindSafe` marker trait,
// basically just saying that `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else).
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicIsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicI8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicI16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicUsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicU8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicU16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}

#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for crate::sync::atomic::AtomicBool {}

#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl<T> RefUnwindSafe for crate::sync::atomic::AtomicPtr<T> {}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> Deref for AssertUnwindSafe<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T> DerefMut for AssertUnwindSafe<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
    type Output = R;

    extern "rust-call" fn call_once(self, _args: ()) -> R {
        (self.0)()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("AssertUnwindSafe").field(&self.0).finish()
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: Future> Future for AssertUnwindSafe<F> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
        F::poll(pinned_field, cx)
    }
}

#[unstable(feature = "async_stream", issue = "79024")]
impl<S: Stream> Stream for AssertUnwindSafe<S> {
    type Item = S::Item;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
        unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::cmp::max;
use rand::{Rng, sample};
use calx_grid::Dir6;
use location::Location;
use terraform::{Terraform, TerrainQuery};
use terrain::Id;

pub fn caves<T, R>(world: &mut T, rng: &mut R, start_at: Location, mut cells_to_dig: u32)
    where T: TerrainQuery + Terraform,
          R: Rng
{
    if cells_to_dig == 0 {
        return;
    }

    let mut edge = BTreeSet::new();
    dig(world, &mut edge, start_at);

    // Arbitrary long iteration, should break after digging a sufficient number of cells before
    // this.
    for _ in 0..10000 {
        if edge.is_empty() {
            break;
        }

        let dig_loc = *sample(rng, edge.iter(), 1)[0];

        // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
        // selected location is in a very open space.
        let adjacent_floors = Dir6::iter()
                                  .filter(|d| world.terrain(dig_loc + **d).is_open())
                                  .count();
        if rng.gen_range(0, max(1, adjacent_floors * 2)) != 0 {
            continue;
        }

        dig(world, &mut edge, dig_loc);
        cells_to_dig -= 1;
        if cells_to_dig == 0 {
            break;
        }
    }

    fn dig<T>(world: &mut T, edge: &mut BTreeSet<Location>, loc: Location)
        where T: TerrainQuery + Terraform
    {
        assert!(world.is_valid_location(loc));
        world.set_terrain(loc, Id::Ground as u8);

        edge.remove(&loc);
        for &d in Dir6::iter() {
            let edge_loc = loc + d;

            if world.is_valid_location(edge_loc) && world.terrain(edge_loc).is_hull() {
                edge.insert(edge_loc);
            }
        }
    }
}
<commit_msg>Mapgen room placement<commit_after>use std::collections::BTreeSet;
use std::cmp::max;
use rand::{Rand, Rng, sample};
use euclid::Point2D;
use calx_grid::Dir6;
use location::Location;
use terraform::{Terraform, TerrainQuery};
use terrain::Id;

pub fn caves<T, R>(world: &mut T, rng: &mut R, start_at: Location, mut cells_to_dig: u32)
    where T: TerrainQuery + Terraform,
          R: Rng
{
    if cells_to_dig == 0 {
        return;
    }

    let mut edge = BTreeSet::new();
    dig(world, &mut edge, start_at);

    // Arbitrary long iteration, should break after digging a sufficient number of cells before
    // this.
    for _ in 0..10000 {
        if edge.is_empty() {
            break;
        }

        let dig_loc = *sample(rng, edge.iter(), 1)[0];

        // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
        // selected location is in a very open space.
        let adjacent_floors = Dir6::iter()
                                  .filter(|d| world.terrain(dig_loc + **d).is_open())
                                  .count();
        if rng.gen_range(0, max(1, adjacent_floors * 2)) != 0 {
            continue;
        }

        dig(world, &mut edge, dig_loc);
        cells_to_dig -= 1;
        if cells_to_dig == 0 {
            break;
        }
    }

    fn dig<T>(world: &mut T, edge: &mut BTreeSet<Location>, loc: Location)
        where T: TerrainQuery + Terraform
    {
        assert!(world.is_valid_location(loc));
        world.set_terrain(loc, Id::Ground as u8);

        edge.remove(&loc);
        for &d in Dir6::iter() {
            let edge_loc = loc + d;

            if world.is_valid_location(edge_loc) && world.terrain(edge_loc).is_hull() {
                edge.insert(edge_loc);
            }
        }
    }
}

pub trait Room {
    /// Return how well the room will fit in the given location.
    ///
    /// Lower values are better. None means that fit is impossible.
    fn fit_badness<T: TerrainQuery>(&self, w: &T, loc: Location) -> Option<f32>;

    /// Place the room in the given location.
    fn place<T: Terraform + TerrainQuery>(&self, w: &mut T, loc: Location);
}

struct EmptyRoom {
    // Room dimensions include walls.
    width: u32,
    height: u32,
}

impl Rand for EmptyRoom {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        EmptyRoom {
            width: rng.gen_range(3, 12),
            height: rng.gen_range(3, 12),
        }
    }
}

impl Room for EmptyRoom {
    fn fit_badness<T: TerrainQuery>(&self, w: &T, loc: Location) -> Option<f32> {
        let mut connected = false;
        let mut badness = 0.0;

        for y in 0..(self.height) {
            for x in 0..(self.width) {
                let is_wall = x == 0 || y == 0 || x == self.width - 1 || y == self.height - 1;

                // This is a corner tile that does not connect to the main floor, due to hex map
                // geometry. Breach of this corner will not make the space of the room connected to
                // the map.
                let is_blocked_corner = (x == self.width - 1 && y == 0) ||
                                        (y == self.width - 1 && x == 0);

                let is_corner = is_blocked_corner || (x == 0 && y == 0) ||
                                (x == self.width - 1 && y == self.width - 1);

                let loc = loc + Point2D::new(x as i32, y as i32);

                if !w.is_valid_location(loc) && !is_wall {
                    // Walls can be placed just outside the screen bounds, but definitely not
                    // floor.
                    return None;
                }

                if is_wall && !is_blocked_corner && w.terrain(loc).is_open() {
                    connected = true;
                }

                if w.belongs_to_a_room(loc) {
                    // Rooms overlapping is bad juju.
                    badness += 100.0;
                    continue;
                }

                if is_corner && w.terrain(loc).is_open() {
                    // Please keep corners intact.
                    badness += 40.0;
                    continue;
                }

                if !w.is_untouched(loc) {
                    if is_wall {
                        badness += 1.0;
                    } else {
                        badness += 3.0;
                    }
                }
            }
        }

        if !connected { None } else { Some(badness) }
    }

    fn place<T: Terraform + TerrainQuery>(&self, w: &mut T, loc: Location) {
        use terrain::Id::*;

        for y in 0..self.height {
            for x in 0..self.width {
                let is_wall = x == 0 || y == 0 || x == self.width - 1 || y == self.height - 1;
                let loc = loc + Point2D::new(x as i32, y as i32);

                if is_wall {
                    if w.terrain(loc).is_open() {
                        // TODO: Doors
                        w.set_terrain(loc, Ground as u8);
                    } else {
                        w.set_terrain(loc, Wall as u8);
                    }
                } else {
                    w.set_terrain(loc, Ground as u8);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use calx_alg::{Deciban, clamp};
use calx_ecs::Entity;
use calx_grid::{Dir6, Prefab};
use command::CommandResult;
use components::BrainState;
use effect::{Damage, Effect};
use event::Event;
use form::Form;
use item::{MagicEffect, ItemType, Slot};
use location::Location;
use query::Query;
use rand::Rng;
use terraform::Terraform;
use terrain::Terrain;
use volume::Volume;
use world::{Ecs, Loadout};

/// World-mutating methods that are not exposed outside the crate.
pub trait Mutate: Query + Terraform + Sized {
    /// Advance world state after player input has been received.
    ///
    /// Returns CommandResult Ok(()) so can used to end result-returning methods.
    fn next_tick(&mut self) -> CommandResult;

    fn set_entity_location(&mut self, e: Entity, loc: Location);

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot);

    fn set_player(&mut self, player: Option<Entity>);

    /// Mark an entity as dead, but don't remove it from the system yet.
    fn kill_entity(&mut self, e: Entity);

    /// Remove an entity from the system.
    ///
    /// You generally do not want to call this directly. Mark the entity as dead and it will be
    /// removed at the end of the turn.
    fn remove_entity(&mut self, e: Entity);

    /// Compute field-of-view into entity's map memory.
    ///
    /// Does nothing for entities without a map memory component.
    fn do_fov(&mut self, e: Entity);

    /// Push an event to the event queue for this tick.
    fn push_event(&mut self, event: Event);

    /// Access the persistent random number generator.
    fn rng(&mut self) -> &mut ::Rng;

    /// Mutable access to ecs
    fn ecs_mut(&mut self) -> &mut Ecs;

    /// Standard deciban roll, convert to i32 and clamp out extremes.
    fn roll(&mut self) -> f32 { clamp(-20.0, 20.0, self.rng().gen::<Deciban>().0.round()) }

    /// Run AI for all autonomous mobs.
    fn ai_main(&mut self) {
        for npc in self.active_mobs().into_iter() {
            if !self.is_npc(npc) {
                continue;
            }
            if self.acts_this_frame(npc) {
                self.run_ai_for(npc)
            }
        }
    }

    /// Run AI for one non-player-controlled creature.
    fn run_ai_for(&mut self, npc: Entity) {
        use components::BrainState::*;
        let brain_state = self.brain_state(npc).expect("Running AI for non-mob");
        match brain_state {
            Asleep => {
                // No-op designator
            }
            Hunting(target) => {
                if let (Some(my_loc), Some(target_loc)) =
                    (self.location(npc), self.location(target))
                {
                    // TODO: Pathfind around obstacles
                    if let Some(move_dir) = my_loc.dir6_towards(target_loc) {
                        let dest = my_loc.jump(self, move_dir);
                        if dest == target_loc {
                            let _ = self.entity_melee(npc, move_dir);
                        } else {
                            let _ = self.entity_step(npc, move_dir);
                        }
                    }
                }
            }
            PlayerControl => {}
        }
    }

    fn notify_attacked_by(&mut self, victim: Entity, attacker: Entity) {
        // TODO: Check if victim is already in close combat and don't disengage against new target
        // if it is.
        self.designate_enemy(victim, attacker);
    }

    fn designate_enemy(&mut self, e: Entity, target: Entity) {
        // TODO: Probably want this logic to be more complex eventually.
        if self.is_npc(e) {
            if self.brain_state(e) == Some(BrainState::Asleep) {
                self.shout(e);
            }
            if let Some(brain) = self.ecs_mut().brain.get_mut(e) {
                brain.state = BrainState::Hunting(target);
            }
        }
    }

    /// Make a mob shout according to its type.
    fn shout(&mut self, e: Entity) {
        // TODO: Create noise, wake up other nearby monsters.
        use components::ShoutType;
        if let Some(shout) = self.ecs().brain.get(e).map(|b| b.shout) {
            match shout {
                ShoutType::Shout => {
                    msg!(self, "The {} shouts angrily.", self.entity_name(e));
                }
                ShoutType::Hiss => {
                    msg!(self, "The {} hisses angrily.", self.entity_name(e));
                }
                ShoutType::Buzz => {
                    msg!(self, "The {} buzzes loudly.", self.entity_name(e));
                }
                ShoutType::Roar => {
                    msg!(self, "The {} roars angrily.", self.entity_name(e));
                }
                ShoutType::Gurgle => {
                    msg!(self, "The {} gurgles loudly.", self.entity_name(e));
                }
                ShoutType::Silent => {}
            }
        }
    }

    /// Remove destroyed entities from system
    fn clean_dead(&mut self) {
        let kill_list: Vec<Entity> = self.entities()
            .filter(|&&e| !self.is_alive(e))
            .cloned()
            .collect();

        for e in kill_list {
            self.remove_entity(e);
        }
    }

    fn place_entity(&mut self, e: Entity, mut loc: Location) {
        if self.is_item(e) {
            loc = self.empty_item_drop_location(loc);
        }
        self.set_entity_location(e, loc);
        self.after_entity_moved(e);
    }

    fn after_entity_moved(&mut self, e: Entity) { self.do_fov(e); }

    fn entity_step(&mut self, e: Entity, dir: Dir6) -> Result<(), ()> {
        let loc = try!(self.location(e).ok_or(())).jump(self, dir);
        if self.can_enter(e, loc) {
            self.place_entity(e, loc);
            return Ok(());
        }

        Err(())
    }

    fn entity_melee(&mut self, e: Entity, dir: Dir6) -> Result<(), ()> {
        if let Some(loc) = self.location(e) {
            if let Some(target) = self.mob_at(loc.jump(self, dir)) {

                // XXX: Using power stat for damage, should this be different?
                let damage = ::attack_damage(
                    self.roll(),
                    self.stats(e).attack,
                    self.stats(e).power,
                    self.stats(target).defense,
                    self.stats(target).armor,
                );

                if damage == 0 {
                    msg!(
                        self,
                        "{} misses {}.",
                        self.entity_name(e),
                        self.entity_name(target)
                    );
                } else {
                    msg!(
                        self,
                        "{} hits {} for {}.",
                        self.entity_name(e),
                        self.entity_name(target),
                        damage
                    );
                }
                self.damage(target, damage, Damage::Physical, Some(e));
                return Ok(());
            }
        }
        Err(())
    }

    fn damage(&mut self, e: Entity, amount: i32, damage_type: Damage, source: Option<Entity>) {
        if let Some(attacker) = source {
            self.notify_attacked_by(e, attacker);
        }

        let max_hp = self.max_hp(e);

        let mut kill = false;
        if let Some(health) = self.ecs_mut().health.get_mut(e) {
            if amount > 0 {
                health.wounds += amount;

                if health.wounds > max_hp {
                    kill = true;
                }
            }
        }

        if kill {
            if let Some(loc) = self.location(e) {
                if self.player_sees(loc) {
                    // TODO: message templating
                    msg!(
                        self,
                        "The {} {}.",
                        self.entity_name(e),
                        match damage_type {
                            Damage::Physical => "is killed",
                            Damage::Fire => "is burnt to ash",
                            Damage::Electricity => "is electrocuted",
                            Damage::Cold => "shatters to frozen pieces",
                        }
                    );
                }
            }
            self.kill_entity(e);
        }
    }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity;

    fn deploy_prefab(&mut self, origin: Location, prefab: &Prefab<(Terrain, Vec<String>)>) {
        for (p, &(ref terrain, _)) in prefab.iter() {
            let loc = origin + p;

            // Annihilate any existing entities in the drop zone.
            let es = self.entities_at(loc);
            for &e in &es {
                self.remove_entity(e);
            }

            self.set_terrain(loc, *terrain);
        }

        // Spawn entities after all terrain is in place so that initial FOV is good.
        for (p, &(_, ref entities)) in prefab.iter() {
            let loc = origin + p;

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.spawn_player(loc);
                } else {
                    let form = Form::named(spawn).expect(&format!("Form '{}' not found!", spawn));
                    self.spawn(&form.loadout, loc);
                }
            }
        }
    }

    /// Special method for setting the player start position.
    ///
    /// If player already exists and is placed in the world, do nothing.
    ///
    /// If player exists, but is not placed in spatial, teleport the player here.
    ///
    /// If player does not exist, create the initial player entity.
    fn spawn_player(&mut self, loc: Location) {
        if let Some(player) = self.player() {
            if self.location(player).is_none() {
                // Teleport player from limbo.
                self.place_entity(player, loc);
            }
        } else {
            // Initialize new player object.
            let form = Form::named("player").expect("Player form not found");
            let player = self.spawn(&form.loadout, loc);
            self.set_player(Some(player));
        }
    }

    fn entity_take(&mut self, e: Entity, item: Entity) -> Result<(), ()> {
        // Only mobs can take items.
        if !self.is_mob(e) {
            return Err(());
        }

        if !self.is_item(item) {
            return Err(());
        }

        // Somehow trying to pick up something we're inside of. Pls don't break the universe.
        if self.entity_contains(item, e) {
            panic!("Trying to pick up an entity you are inside of. This shouldn't happen");
        }

        if let Some(slot) = self.free_bag_slot(e) {
            self.equip_item(item, e, slot);
            if self.is_player(e) {
                msg!(self, "Picked up {}", self.entity_name(item));
            }

            Ok(())
        } else {
            // No more inventory space
            Err(())
        }
    }

    /// Cast an undirected spell
    fn cast_spell(
        &mut self,
        _origin: Location,
        effect: Entity,
        _caster: Option<Entity>,
    ) -> Result<(), ()> {
        if let ItemType::UntargetedUsable(effect) =
            self.ecs().item.get(effect).ok_or(())?.item_type
        {
            match effect {
                _ => {
                    msg!(self, "TODO cast untargeted spell {:?}", effect);
                }
            }
            Ok(())
        } else {
            Err(())
        }
    }

    /// Cast a directed spell
    fn cast_directed_spell(
        &mut self,
        origin: Location,
        dir: Dir6,
        effect: Entity,
        caster: Option<Entity>,
    ) -> Result<(), ()> {
        if let ItemType::TargetedUsable(effect) = self.ecs().item.get(effect).ok_or(())?.item_type {
            match effect {
                MagicEffect::Fireball => {
                    const FIREBALL_RANGE: u32 = 9;
                    const FIREBALL_RADIUS: u32 = 2;
                    const FIREBALL_EFFECT: Effect = Effect::Hit {
                        amount: 6,
                        damage: Damage::Fire,
                    };
                    let center = self.projected_explosion_center(origin, dir, FIREBALL_RANGE);
                    let volume = self.sphere_volume(center, FIREBALL_RADIUS);
                    self.apply_effect(&FIREBALL_EFFECT, &volume, caster);
                }
                _ => {
                    msg!(self, "TODO cast untargeted spell {:?}", effect);
                }
            }
            Ok(())
        } else {
            Err(())
        }
    }

    fn apply_effect_to_entity(&mut self, effect: &Effect, target: Entity, source: Option<Entity>) {
        use effect::Effect::*;
        match effect {
            &Heal(_amount) => {
                unimplemented!();
            }
            &Hit { amount, damage } => {
                self.damage(target, amount as i32, damage, source);
            }
            &Confuse => {
                unimplemented!();
            }
            &MagicMap => {
                unimplemented!();
            }
        }
    }

    fn apply_effect_to(&mut self, effect: &Effect, loc: Location, source: Option<Entity>) {
        if let Some(mob) = self.mob_at(loc) {
            self.apply_effect_to_entity(effect, mob, source);
        }
    }

    fn apply_effect(&mut self, effect: &Effect, volume: &Volume, source: Option<Entity>) {
        for loc in &volume.0 {
            self.apply_effect_to(effect, *loc, source);
        }
    }
}
<commit_msg>Normalize spelling<commit_after>use calx_alg::{Deciban, clamp};
use calx_ecs::Entity;
use calx_grid::{Dir6, Prefab};
use command::CommandResult;
use components::BrainState;
use effect::{Damage, Effect};
use event::Event;
use form::Form;
use item::{MagicEffect, ItemType, Slot};
use location::Location;
use query::Query;
use rand::Rng;
use terraform::Terraform;
use terrain::Terrain;
use volume::Volume;
use world::{Ecs, Loadout};

/// World-mutating methods that are not exposed outside the crate.
pub trait Mutate: Query + Terraform + Sized {
    /// Advance world state after player input has been received.
    ///
    /// Returns CommandResult Ok(()) so can used to end result-returning methods.
    fn next_tick(&mut self) -> CommandResult;

    fn set_entity_location(&mut self, e: Entity, loc: Location);

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot);

    fn set_player(&mut self, player: Option<Entity>);

    /// Mark an entity as dead, but don't remove it from the system yet.
    fn kill_entity(&mut self, e: Entity);

    /// Remove an entity from the system.
    ///
    /// You generally do not want to call this directly. Mark the entity as dead and it will be
    /// removed at the end of the turn.
    fn remove_entity(&mut self, e: Entity);

    /// Compute field-of-view into entity's map memory.
    ///
    /// Does nothing for entities without a map memory component.
    fn do_fov(&mut self, e: Entity);

    /// Push an event to the event queue for this tick.
    fn push_event(&mut self, event: Event);

    /// Access the persistent random number generator.
    fn rng(&mut self) -> &mut ::Rng;

    /// Mutable access to ecs
    fn ecs_mut(&mut self) -> &mut Ecs;

    /// Standard deciban roll, convert to i32 and clamp out extremes.
    fn roll(&mut self) -> f32 { clamp(-20.0, 20.0, self.rng().gen::<Deciban>().0.round()) }

    /// Run AI for all autonomous mobs.
    fn ai_main(&mut self) {
        for npc in self.active_mobs().into_iter() {
            if !self.is_npc(npc) {
                continue;
            }
            if self.acts_this_frame(npc) {
                self.run_ai_for(npc)
            }
        }
    }

    /// Run AI for one non-player-controlled creature.
    fn run_ai_for(&mut self, npc: Entity) {
        use components::BrainState::*;
        let brain_state = self.brain_state(npc).expect("Running AI for non-mob");
        match brain_state {
            Asleep => {
                // No-op designator
            }
            Hunting(target) => {
                if let (Some(my_loc), Some(target_loc)) =
                    (self.location(npc), self.location(target))
                {
                    // TODO: Pathfind around obstacles
                    if let Some(move_dir) = my_loc.dir6_towards(target_loc) {
                        let dest = my_loc.jump(self, move_dir);
                        if dest == target_loc {
                            let _ = self.entity_melee(npc, move_dir);
                        } else {
                            let _ = self.entity_step(npc, move_dir);
                        }
                    }
                }
            }
            PlayerControl => {}
        }
    }

    fn notify_attacked_by(&mut self, victim: Entity, attacker: Entity) {
        // TODO: Check if victim is already in close combat and don't disengage against new target
        // if it is.
        self.designate_enemy(victim, attacker);
    }

    fn designate_enemy(&mut self, e: Entity, target: Entity) {
        // TODO: Probably want this logic to be more complex eventually.
        if self.is_npc(e) {
            if self.brain_state(e) == Some(BrainState::Asleep) {
                self.shout(e);
            }
            if let Some(brain) = self.ecs_mut().brain.get_mut(e) {
                brain.state = BrainState::Hunting(target);
            }
        }
    }

    /// Make a mob shout according to its type.
    fn shout(&mut self, e: Entity) {
        // TODO: Create noise, wake up other nearby monsters.
        use components::ShoutType;
        if let Some(shout) = self.ecs().brain.get(e).map(|b| b.shout) {
            match shout {
                ShoutType::Shout => {
                    msg!(self, "The {} shouts angrily.", self.entity_name(e));
                }
                ShoutType::Hiss => {
                    msg!(self, "The {} hisses angrily.", self.entity_name(e));
                }
                ShoutType::Buzz => {
                    msg!(self, "The {} buzzes loudly.", self.entity_name(e));
                }
                ShoutType::Roar => {
                    msg!(self, "The {} roars angrily.", self.entity_name(e));
                }
                ShoutType::Gurgle => {
                    msg!(self, "The {} gurgles loudly.", self.entity_name(e));
                }
                ShoutType::Silent => {}
            }
        }
    }

    /// Remove destroyed entities from system
    fn clean_dead(&mut self) {
        let kill_list: Vec<Entity> = self.entities()
            .filter(|&&e| !self.is_alive(e))
            .cloned()
            .collect();

        for e in kill_list {
            self.remove_entity(e);
        }
    }

    fn place_entity(&mut self, e: Entity, mut loc: Location) {
        if self.is_item(e) {
            loc = self.empty_item_drop_location(loc);
        }
        self.set_entity_location(e, loc);
        self.after_entity_moved(e);
    }

    fn after_entity_moved(&mut self, e: Entity) { self.do_fov(e); }

    fn entity_step(&mut self, e: Entity, dir: Dir6) -> Result<(), ()> {
        let loc = try!(self.location(e).ok_or(())).jump(self, dir);
        if self.can_enter(e, loc) {
            self.place_entity(e, loc);
            return Ok(());
        }

        Err(())
    }

    fn entity_melee(&mut self, e: Entity, dir: Dir6) -> Result<(), ()> {
        if let Some(loc) = self.location(e) {
            if let Some(target) = self.mob_at(loc.jump(self, dir)) {

                // XXX: Using power stat for damage, should this be different?
                let damage = ::attack_damage(
                    self.roll(),
                    self.stats(e).attack,
                    self.stats(e).power,
                    self.stats(target).defense,
                    self.stats(target).armor,
                );

                if damage == 0 {
                    msg!(
                        self,
                        "{} misses {}.",
                        self.entity_name(e),
                        self.entity_name(target)
                    );
                } else {
                    msg!(
                        self,
                        "{} hits {} for {}.",
                        self.entity_name(e),
                        self.entity_name(target),
                        damage
                    );
                }
                self.damage(target, damage, Damage::Physical, Some(e));
                return Ok(());
            }
        }
        Err(())
    }

    fn damage(&mut self, e: Entity, amount: i32, damage_type: Damage, source: Option<Entity>) {
        if let Some(attacker) = source {
            self.notify_attacked_by(e, attacker);
        }

        let max_hp = self.max_hp(e);

        let mut kill = false;
        if let Some(health) = self.ecs_mut().health.get_mut(e) {
            if amount > 0 {
                health.wounds += amount;

                if health.wounds > max_hp {
                    kill = true;
                }
            }
        }

        if kill {
            if let Some(loc) = self.location(e) {
                if self.player_sees(loc) {
                    // TODO: message templating
                    msg!(
                        self,
                        "The {} {}.",
                        self.entity_name(e),
                        match damage_type {
                            Damage::Physical => "is killed",
                            Damage::Fire => "is burned to ash",
                            Damage::Electricity => "is electrocuted",
                            Damage::Cold => "shatters to frozen pieces",
                        }
                    );
                }
            }
            self.kill_entity(e);
        }
    }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity;

    fn deploy_prefab(&mut self, origin: Location, prefab: &Prefab<(Terrain, Vec<String>)>) {
        for (p, &(ref terrain, _)) in prefab.iter() {
            let loc = origin + p;

            // Annihilate any existing entities in the drop zone.
            let es = self.entities_at(loc);
            for &e in &es {
                self.remove_entity(e);
            }

            self.set_terrain(loc, *terrain);
        }

        // Spawn entities after all terrain is in place so that initial FOV is good.
        for (p, &(_, ref entities)) in prefab.iter() {
            let loc = origin + p;

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.spawn_player(loc);
                } else {
                    let form = Form::named(spawn).expect(&format!("Form '{}' not found!", spawn));
                    self.spawn(&form.loadout, loc);
                }
            }
        }
    }

    /// Special method for setting the player start position.
    ///
    /// If player already exists and is placed in the world, do nothing.
    ///
    /// If player exists, but is not placed in spatial, teleport the player here.
    ///
    /// If player does not exist, create the initial player entity.
    fn spawn_player(&mut self, loc: Location) {
        if let Some(player) = self.player() {
            if self.location(player).is_none() {
                // Teleport player from limbo.
                self.place_entity(player, loc);
            }
        } else {
            // Initialize new player object.
            let form = Form::named("player").expect("Player form not found");
            let player = self.spawn(&form.loadout, loc);
            self.set_player(Some(player));
        }
    }

    fn entity_take(&mut self, e: Entity, item: Entity) -> Result<(), ()> {
        // Only mobs can take items.
        if !self.is_mob(e) {
            return Err(());
        }

        if !self.is_item(item) {
            return Err(());
        }

        // Somehow trying to pick up something we're inside of. Pls don't break the universe.
        if self.entity_contains(item, e) {
            panic!("Trying to pick up an entity you are inside of. This shouldn't happen");
        }

        if let Some(slot) = self.free_bag_slot(e) {
            self.equip_item(item, e, slot);
            if self.is_player(e) {
                msg!(self, "Picked up {}", self.entity_name(item));
            }

            Ok(())
        } else {
            // No more inventory space
            Err(())
        }
    }

    /// Cast an undirected spell
    fn cast_spell(
        &mut self,
        _origin: Location,
        effect: Entity,
        _caster: Option<Entity>,
    ) -> Result<(), ()> {
        if let ItemType::UntargetedUsable(effect) =
            self.ecs().item.get(effect).ok_or(())?.item_type
        {
            match effect {
                _ => {
                    msg!(self, "TODO cast untargeted spell {:?}", effect);
                }
            }
            Ok(())
        } else {
            Err(())
        }
    }

    /// Cast a directed spell
    fn cast_directed_spell(
        &mut self,
        origin: Location,
        dir: Dir6,
        effect: Entity,
        caster: Option<Entity>,
    ) -> Result<(), ()> {
        if let ItemType::TargetedUsable(effect) = self.ecs().item.get(effect).ok_or(())?.item_type {
            match effect {
                MagicEffect::Fireball => {
                    const FIREBALL_RANGE: u32 = 9;
                    const FIREBALL_RADIUS: u32 = 2;
                    const FIREBALL_EFFECT: Effect = Effect::Hit {
                        amount: 6,
                        damage: Damage::Fire,
                    };
                    let center = self.projected_explosion_center(origin, dir, FIREBALL_RANGE);
                    let volume = self.sphere_volume(center, FIREBALL_RADIUS);
                    self.apply_effect(&FIREBALL_EFFECT, &volume, caster);
                }
                _ => {
                    msg!(self, "TODO cast untargeted spell {:?}", effect);
                }
            }
            Ok(())
        } else {
            Err(())
        }
    }

    fn apply_effect_to_entity(&mut self, effect: &Effect, target: Entity, source: Option<Entity>) {
        use effect::Effect::*;
        match effect {
            &Heal(_amount) => {
                unimplemented!();
            }
            &Hit { amount, damage } => {
                self.damage(target, amount as i32, damage, source);
            }
            &Confuse => {
                unimplemented!();
            }
            &MagicMap => {
                unimplemented!();
            }
        }
    }

    fn apply_effect_to(&mut self, effect: &Effect, loc: Location, source: Option<Entity>) {
        if let Some(mob) = self.mob_at(loc) {
            self.apply_effect_to_entity(effect, mob, source);
        }
    }

    fn apply_effect(&mut self, effect: &Effect, volume: &Volume, source: Option<Entity>) {
        for loc in &volume.0 {
            self.apply_effect_to(effect, *loc, source);
        }
    }
}
<|endoftext|>