<commit_before>use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::ops::Deref;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::cell::UnsafeCell;
use std::marker::Sync;
use {Future, Poll, Async};
use task::{self, Task};
use lock::Lock;

/// A wrapped item of the original future.
/// It is clonable and implements Deref for ease of use.
#[derive(Debug)]
pub struct SharedItem<T> {
    item: Arc<T>,
}

impl<T> Clone for SharedItem<T> {
    fn clone(&self) -> Self {
        SharedItem { item: self.item.clone() }
    }
}

impl<T> Deref for SharedItem<T> {
    type Target = T;

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

/// A wrapped error of the original future.
/// It is clonable and implements Deref for ease of use.
#[derive(Debug)]
pub struct SharedError<E> {
    error: Arc<E>,
}

impl<T> Clone for SharedError<T> {
    fn clone(&self) -> Self {
        SharedError { error: self.error.clone() }
    }
}

impl<E> Deref for SharedError<E> {
    type Target = E;

    fn deref(&self) -> &E {
        &self.error.as_ref()
    }
}

impl<T> SharedItem<T> {
    fn new(item: T) -> Self {
        SharedItem { item: Arc::new(item) }
    }
}

impl<E> SharedError<E> {
    fn new(error: E) -> Self {
        SharedError { error: Arc::new(error) }
    }
}

/// The data that has to be synced to implement `Shared`,
/// in order to satisfy the `Future` trait's constraints.
struct SyncedInner<F>
    where F: Future
{
    original_future: F, // The original future
}

struct Inner<F>
    where F: Future
{
    synced_inner: Lock<SyncedInner<F>>,
    tasks_unpark_started: AtomicBool,
    /// When original future is polled and ready, unparks all the tasks in that channel
    tasks_receiver: Lock<Receiver<Task>>,
    /// The original future result wrapped with `SharedItem`/`SharedError`
    result: UnsafeCell<Option<Result<Async<SharedItem<F::Item>>, SharedError<F::Error>>>>,
}

unsafe impl<F> Sync for Inner<F> where F: Future {}

/// TODO: doc
#[must_use = "futures do nothing unless polled"]
pub struct Shared<F>
    where F: Future
{
    inner: Arc<Inner<F>>,
    tasks_sender: Sender<Task>,
}

pub fn new<F>(future: F) -> Shared<F>
    where F: Future
{
    let (tasks_sender, tasks_receiver) = channel();
    Shared {
        inner: Arc::new(Inner {
            synced_inner: Lock::new(SyncedInner { original_future: future }),
            tasks_unpark_started: AtomicBool::new(false),
            tasks_receiver: Lock::new(tasks_receiver),
            result: UnsafeCell::new(None),
        }),
        tasks_sender: tasks_sender,
    }
}

impl<F> Future for Shared<F>
    where F: Future
{
    type Item = SharedItem<F::Item>;
    type Error = SharedError<F::Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // The logic is as follows:
        // 1. Check if the result is ready (with tasks_unpark_started)
        //  - If the result is ready, return it.
        //  - Otherwise:
        // 2. Try lock the self.inner.synced_inner:
        //    - If successfully locked, poll the original future.
        //      If the future is ready, unpark the tasks from
        //      self.inner.tasks_receiver and return the result.
        //    - If the future is not ready:
        // 3. Create a task and send it through self.tasks_sender.
        // 4. Check again if the result is ready (with tasks_unpark_started)
        // 5. Return the result if it's ready. It is necessary because otherwise there could be
        //    a race between the task sending and the thread receiving the tasks.

        let mut should_unpark_tasks: bool = false;

        // If the result is ready, just return it
        if self.inner.tasks_unpark_started.load(Ordering::Relaxed) {
            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return result.clone();
                }
            }
        }

        // The result was not ready.
        match self.inner.synced_inner.try_lock() {
            Some(mut inner_guard) => {
                let ref mut inner = *inner_guard;
                unsafe {
                    // Other thread could poll the result, so we check if result has a value
                    if (*self.inner.result.get()).is_some() {
                        should_unpark_tasks = true;
                    } else {
                        match inner.original_future.poll() {
                            Ok(Async::Ready(item)) => {
                                *self.inner.result.get() =
                                    Some(Ok(Async::Ready(SharedItem::new(item))));
                                should_unpark_tasks = true;
                            }
                            Err(error) => {
                                *self.inner.result.get() = Some(Err(SharedError::new(error)));
                                should_unpark_tasks = true;
                            }
                            Ok(Async::NotReady) => {} // Will be handled later
                        }
                    }
                }
            }
            None => {} // Will be handled later
        }

        if should_unpark_tasks {
            self.inner.tasks_unpark_started.store(true, Ordering::Relaxed);
            match self.inner.tasks_receiver.try_lock() {
                Some(tasks_receiver_guard) => {
                    let ref tasks_receiver = *tasks_receiver_guard;
                    loop {
                        match tasks_receiver.try_recv() {
                            Ok(task) => task.unpark(),
                            _ => break,
                        }
                    }
                }
                None => {} // Other thread is unparking the tasks
            }

            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return result.clone();
                } else {
                    // How should I use unwrap here?
                    // The compiler says cannot "move out of borrowed content"
                    unreachable!();
                }
            }
        }

        let t = task::park();
        let _ = self.tasks_sender.send(t);
        if self.inner.tasks_unpark_started.load(Ordering::Relaxed) {
            // If the tasks unpark has started, self.inner.result has a value (not None).
            // The result must be read here because it is possible that the task,
            // t (see variable above), had not been unparked.
            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return result.clone();
                } else {
                    // How should I use unwrap here?
                    // The compiler says cannot "move out of borrowed content"
                    unreachable!();
                }
            }
        }

        Ok(Async::NotReady)
    }
}

impl<F> Clone for Shared<F>
    where F: Future
{
    fn clone(&self) -> Self {
        Shared {
            inner: self.inner.clone(),
            tasks_sender: self.tasks_sender.clone(),
        }
    }
}
<commit_msg>Remove `Async` from Shared.inner.result<commit_after>use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::ops::Deref;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::cell::UnsafeCell;
use std::marker::Sync;
use {Future, Poll, Async};
use task::{self, Task};
use lock::Lock;

/// A wrapped item of the original future.
/// It is clonable and implements Deref for ease of use.
#[derive(Debug)]
pub struct SharedItem<T> {
    item: Arc<T>,
}

impl<T> Clone for SharedItem<T> {
    fn clone(&self) -> Self {
        SharedItem { item: self.item.clone() }
    }
}

impl<T> Deref for SharedItem<T> {
    type Target = T;

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

/// A wrapped error of the original future.
/// It is clonable and implements Deref for ease of use.
#[derive(Debug)]
pub struct SharedError<E> {
    error: Arc<E>,
}

impl<T> Clone for SharedError<T> {
    fn clone(&self) -> Self {
        SharedError { error: self.error.clone() }
    }
}

impl<E> Deref for SharedError<E> {
    type Target = E;

    fn deref(&self) -> &E {
        &self.error.as_ref()
    }
}

impl<T> SharedItem<T> {
    fn new(item: T) -> Self {
        SharedItem { item: Arc::new(item) }
    }
}

impl<E> SharedError<E> {
    fn new(error: E) -> Self {
        SharedError { error: Arc::new(error) }
    }
}

/// The data that has to be synced to implement `Shared`,
/// in order to satisfy the `Future` trait's constraints.
struct SyncedInner<F>
    where F: Future
{
    original_future: F, // The original future
}

struct Inner<F>
    where F: Future
{
    synced_inner: Lock<SyncedInner<F>>,
    tasks_unpark_started: AtomicBool,
    /// When original future is polled and ready, unparks all the tasks in that channel
    tasks_receiver: Lock<Receiver<Task>>,
    /// The original future result wrapped with `SharedItem`/`SharedError`
    result: UnsafeCell<Option<Result<SharedItem<F::Item>, SharedError<F::Error>>>>,
}

unsafe impl<F> Sync for Inner<F> where F: Future {}

/// TODO: doc
#[must_use = "futures do nothing unless polled"]
pub struct Shared<F>
    where F: Future
{
    inner: Arc<Inner<F>>,
    tasks_sender: Sender<Task>,
}

impl<F> Shared<F>
    where F: Future
{
    fn result_to_polled_result(result: Result<SharedItem<F::Item>, SharedError<F::Error>>) -> Result<Async<SharedItem<F::Item>>, SharedError<F::Error>> {
        match result {
            Ok(item) => Ok(Async::Ready(item)),
            Err(error) => Err(error),
        }
    }
}

pub fn new<F>(future: F) -> Shared<F>
    where F: Future
{
    let (tasks_sender, tasks_receiver) = channel();
    Shared {
        inner: Arc::new(Inner {
            synced_inner: Lock::new(SyncedInner { original_future: future }),
            tasks_unpark_started: AtomicBool::new(false),
            tasks_receiver: Lock::new(tasks_receiver),
            result: UnsafeCell::new(None),
        }),
        tasks_sender: tasks_sender,
    }
}

impl<F> Future for Shared<F>
    where F: Future
{
    type Item = SharedItem<F::Item>;
    type Error = SharedError<F::Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // The logic is as follows:
        // 1. Check if the result is ready (with tasks_unpark_started)
        //  - If the result is ready, return it.
        //  - Otherwise:
        // 2. Try lock the self.inner.synced_inner:
        //    - If successfully locked, poll the original future.
        //      If the future is ready, unpark the tasks from
        //      self.inner.tasks_receiver and return the result.
        //    - If the future is not ready:
        // 3. Create a task and send it through self.tasks_sender.
        // 4. Check again if the result is ready (with tasks_unpark_started)
        // 5. Return the result if it's ready. It is necessary because otherwise there could be
        //    a race between the task sending and the thread receiving the tasks.

        let mut should_unpark_tasks: bool = false;

        // If the result is ready, just return it
        if self.inner.tasks_unpark_started.load(Ordering::Relaxed) {
            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return Self::result_to_polled_result(result.clone());
                }
            }
        }

        // The result was not ready.
        match self.inner.synced_inner.try_lock() {
            Some(mut inner_guard) => {
                let ref mut inner = *inner_guard;
                unsafe {
                    // Other thread could poll the result, so we check if result has a value
                    if (*self.inner.result.get()).is_some() {
                        should_unpark_tasks = true;
                    } else {
                        match inner.original_future.poll() {
                            Ok(Async::Ready(item)) => {
                                *self.inner.result.get() =
                                    Some(Ok(SharedItem::new(item)));
                                should_unpark_tasks = true;
                            }
                            Err(error) => {
                                *self.inner.result.get() = Some(Err(SharedError::new(error)));
                                should_unpark_tasks = true;
                            }
                            Ok(Async::NotReady) => {} // Will be handled later
                        }
                    }
                }
            }
            None => {} // Will be handled later
        }

        if should_unpark_tasks {
            self.inner.tasks_unpark_started.store(true, Ordering::Relaxed);
            match self.inner.tasks_receiver.try_lock() {
                Some(tasks_receiver_guard) => {
                    let ref tasks_receiver = *tasks_receiver_guard;
                    loop {
                        match tasks_receiver.try_recv() {
                            Ok(task) => task.unpark(),
                            _ => break,
                        }
                    }
                }
                None => {} // Other thread is unparking the tasks
            }

            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return Self::result_to_polled_result(result.clone());
                } else {
                    // How should I use unwrap here?
                    // The compiler says cannot "move out of borrowed content"
                    unreachable!();
                }
            }
        }

        let t = task::park();
        let _ = self.tasks_sender.send(t);
        if self.inner.tasks_unpark_started.load(Ordering::Relaxed) {
            // If the tasks unpark has started, self.inner.result has a value (not None).
            // The result must be read here because it is possible that the task,
            // t (see variable above), had not been unparked.
            unsafe {
                if let Some(ref result) = *self.inner.result.get() {
                    return Self::result_to_polled_result(result.clone());
                } else {
                    // How should I use unwrap here?
                    // The compiler says cannot "move out of borrowed content"
                    unreachable!();
                }
            }
        }

        Ok(Async::NotReady)
    }
}

impl<F> Clone for Shared<F>
    where F: Future
{
    fn clone(&self) -> Self {
        Shared {
            inner: self.inner.clone(),
            tasks_sender: self.tasks_sender.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::ioivec;
import std::ioivec::stdout;
import std::vec;
import std::ivec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::walk;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

/*
// Imports for "the rest of driver::compile_input"
import driver = rustc::driver::rustc; // see https://github.com/graydon/rust/issues/624
import rustc::back::link;
import rustc::driver::rustc::time;
import rustc::driver::session;

import rustc::metadata::creader;
import rustc::metadata::cstore;
import rustc::syntax::parse::parser;
import rustc::syntax::parse::token;
import rustc::front;
import rustc::front::attr;
import rustc::middle;
import rustc::middle::trans;
import rustc::middle::resolve;
import rustc::middle::ty;
import rustc::middle::typeck;
import rustc::middle::tstate::ck;
import rustc::syntax::print::pp;
import rustc::util::ppaux;
import rustc::lib::llvm;
*/

fn read_whole_file(&str filename) -> str {
    str::unsafe_from_bytes_ivec(ioivec::file_reader(filename).read_whole_stream())
}

fn write_file(&str filename, &str content) {
    ioivec::file_writer(filename, ~[ioivec::create,
                                    ioivec::truncate]).write_str(content);
}

fn file_contains(&str filename, &str needle) -> bool {
    auto contents = read_whole_file(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(&str haystack, &str needle) -> bool { str::find(haystack, needle) != -1 }

fn find_rust_files(&mutable str[] files, str path) {
    if (str::ends_with(path, ".rs")) {
        if (file_contains(path, "xfail-stage1")) {
            //log_err "Skipping " + path + " because it is marked as xfail-stage1";
        } else {
            files += ~[path];
        }
    } else if (fs::file_is_dir(path) && str::find(path, "compile-fail") == -1) {
        for (str p in fs::list_dir(path)) {
            find_rust_files(files, p);
        }
    }
}

fn safe_to_steal(ast::expr_ e) -> bool {
    alt (e) {
        // pretty-printer precedence issues -- https://github.com/graydon/rust/issues/670
        case (ast::expr_unary(_, _)) { false }
        case (ast::expr_lit(?lit)) {
            alt(lit.node) {
                case(ast::lit_str(_, _)) { true }
                case(ast::lit_char(_)) { true }
                case(ast::lit_int(_)) { false }
                case(ast::lit_uint(_)) { false }
                case(ast::lit_mach_int(_, _)) { false }
                case(ast::lit_float(_)) { false }
                case(ast::lit_mach_float(_, _)) { false }
                case(ast::lit_nil) { true }
                case(ast::lit_bool(_)) { true }
            }
        }
        case (ast::expr_cast(_, _)) { false }
        case (ast::expr_send(_, _)) { false }
        case (ast::expr_recv(_, _)) { false }
        case (ast::expr_assert(_)) { false }
        case (ast::expr_binary(_, _, _)) { false }
        case (ast::expr_assign(_, _)) { false }
        case (ast::expr_assign_op(_, _, _)) { false }

        // https://github.com/graydon/rust/issues/676
        case (ast::expr_ret(option::none)) { false }
        case (ast::expr_put(option::none)) { false }

        case (_) { true }
    }
}

fn steal_exprs(&ast::crate crate) -> ast::expr[] {
    let @mutable ast::expr[] exprs = @mutable ~[];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(@mutable ast::expr[] es, &@ast::expr e) { if (safe_to_steal(e.node)) { *es += ~[*e]; } else { /* now my indices are wrong :( */ } }
    auto v = rec(visit_expr_pre = bind stash_expr(exprs, _) with walk::default_visitor());
    walk::walk_crate(v, crate);
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(ast::expr_ e) -> bool {
    alt (e) {
        case (ast::expr_if(_, _, _)) { false }
        case (ast::expr_block(_)) { false }
        case (_) { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(&ast::crate crate, uint i, ast::expr_ newexpr) -> ast::crate {
    let @mutable uint j = @mutable 0u;
    fn fold_expr_rep(@mutable uint j_, uint i_, &ast::expr_ newexpr_, &ast::expr_ original, fold::ast_fold fld) -> ast::expr_ {
      *j_ += 1u;
      if (i_ + 1u == *j_ && safe_to_replace(original)) {
        newexpr_
      } else {
        fold::noop_fold_expr(original, fld)
      }
    }
    auto afp = rec(fold_expr = bind fold_expr_rep(j, i, newexpr, _, _) with *fold::default_ast_fold());
    auto af = fold::make_fold(afp);
    let @ast::crate crate2 = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    *crate2
}

iter under(uint n) -> uint { let uint i = 0u; while (i < n) { put i; i += 1u; } }

fn devnull() -> ioivec::writer { std::ioivec::string_writer().get_writer() }

fn as_str(fn (ioivec::writer) f) -> str {
    auto w = std::ioivec::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

/*
fn pp_variants(&ast::crate crate, &codemap::codemap cmap, &str filename) {
    auto exprs = steal_exprs(crate);
    auto exprsL = ivec::len(exprs);
    if (exprsL < 100u) {
        for each (uint i in under(uint::min(exprsL, 20u))) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs.(i));
            for each (uint j in under(uint::min(exprsL, 5u))) {
                log_err "With... " + pprust::expr_to_str(@exprs.(j));
                auto crate2 = @replace_expr_in_crate(crate, i, exprs.(j).node);
                check_roundtrip(crate2, cmap, filename + ".4.rs");
            }
        }
    }
}
*/

fn parse_and_print(&str code) -> str {
    auto filename = "";
    auto codemap = codemap::new_codemap();
    auto crate = parser::parse_crate_from_source_str(filename, code, ~[], codemap);
    ret as_str(bind pprust::print_crate(codemap, crate, filename,
                                        ioivec::string_reader(code),
                                        _, pprust::no_ann()));
}

fn content_is_confusing(&str code) -> bool {
    auto confusing_patterns = [
        "#macro",      // https://github.com/graydon/rust/issues/671
        "][]",         // https://github.com/graydon/rust/issues/669
        "][mutable]",  // https://github.com/graydon/rust/issues/669
        "][mutable ]", // https://github.com/graydon/rust/issues/669
        "self",        // crazy rules enforced by parser rather than typechecker?
        "spawn",       // more precedence issues
        "bind"         // more precedence issues?
    ];

    for (str p in confusing_patterns) {
        if contains(code, p) {
            ret true;
        }
    }
    ret false;
}

fn file_is_confusing(&str filename) -> bool {
    auto confusing_files = [

        "block-expr-precedence.rs",  // https://github.com/graydon/rust/issues/674

        "syntax-extension-fmt.rs"    // an issue where -2147483648 gains an
                                     // extra negative sign each time through,
                                     // which i can't reproduce using "rustc
                                     // --pretty normal"???
    ];

    for (str f in confusing_files) {
        if contains(filename, f) {
            ret true;
        }
    }

    ret false;
}

fn check_roundtrip_convergence(&str code) {

    auto i = 0;
    auto new = code;
    auto old = code;

    while (i < 10) {
        old = new;
        new = parse_and_print(old);
        i += 1;
        log_err #fmt("cycle %d", i);
    }

    if old != new {
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("kdiff3", ["round-trip-a.rs", "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn main(vec[str] args) {
    if (vec::len(args) != 2u) {
        log_err #fmt("usage: %s <testdir>", args.(0));
        ret;
    }
    auto files = ~[];
    auto root = args.(1);
    find_rust_files(files, root); // not using time here because that currently screws with passing-a-mutable-array
    log_err #fmt("%u files", ivec::len(files));

    for (str file in files) {
        log_err "=== " + file + " ===";
        if ! file_is_confusing(file) {
            auto s = read_whole_file(file);
            if ! content_is_confusing(s) {
                check_roundtrip_convergence(s);
            }
        }

        //pprust::print_crate(cm, crate, file, devnull(), pprust::no_ann());
        // Currently hits https://github.com/graydon/rust/issues/675
        //pp_variants(*crate, cm, file);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Tidy up fuzzer logic a bit.<commit_after>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::ioivec;
import std::ioivec::stdout;
import std::vec;
import std::ivec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::walk;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

/*
// Imports for "the rest of driver::compile_input"
import driver = rustc::driver::rustc; // see https://github.com/graydon/rust/issues/624
import rustc::back::link;
import rustc::driver::rustc::time;
import rustc::driver::session;

import rustc::metadata::creader;
import rustc::metadata::cstore;
import rustc::syntax::parse::parser;
import rustc::syntax::parse::token;
import rustc::front;
import rustc::front::attr;
import rustc::middle;
import rustc::middle::trans;
import rustc::middle::resolve;
import rustc::middle::ty;
import rustc::middle::typeck;
import rustc::middle::tstate::ck;
import rustc::syntax::print::pp;
import rustc::util::ppaux;
import rustc::lib::llvm;
*/

fn read_whole_file(&str filename) -> str {
    str::unsafe_from_bytes_ivec(ioivec::file_reader(filename).read_whole_stream())
}

fn write_file(&str filename, &str content) {
    ioivec::file_writer(filename, ~[ioivec::create,
                                    ioivec::truncate]).write_str(content);
}

fn file_contains(&str filename, &str needle) -> bool {
    auto contents = read_whole_file(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(&str haystack, &str needle) -> bool { str::find(haystack, needle) != -1 }

fn find_rust_files(&mutable str[] files, str path) {
    if (str::ends_with(path, ".rs")) {
        if (file_contains(path, "xfail-stage1")) {
            //log_err "Skipping " + path + " because it is marked as xfail-stage1";
        } else {
            files += ~[path];
        }
    } else if (fs::file_is_dir(path) && str::find(path, "compile-fail") == -1) {
        for (str p in fs::list_dir(path)) {
            find_rust_files(files, p);
        }
    }
}

fn safe_to_steal(ast::expr_ e) -> bool {
    alt (e) {
        // pretty-printer precedence issues -- https://github.com/graydon/rust/issues/670
        case (ast::expr_unary(_, _)) { false }
        case (ast::expr_lit(?lit)) {
            alt(lit.node) {
                case(ast::lit_str(_, _)) { true }
                case(ast::lit_char(_)) { true }
                case(ast::lit_int(_)) { false }
                case(ast::lit_uint(_)) { false }
                case(ast::lit_mach_int(_, _)) { false }
                case(ast::lit_float(_)) { false }
                case(ast::lit_mach_float(_, _)) { false }
                case(ast::lit_nil) { true }
                case(ast::lit_bool(_)) { true }
            }
        }
        case (ast::expr_cast(_, _)) { false }
        case (ast::expr_send(_, _)) { false }
        case (ast::expr_recv(_, _)) { false }
        case (ast::expr_assert(_)) { false }
        case (ast::expr_binary(_, _, _)) { false }
        case (ast::expr_assign(_, _)) { false }
        case (ast::expr_assign_op(_, _, _)) { false }

        // https://github.com/graydon/rust/issues/676
        case (ast::expr_ret(option::none)) { false }
        case (ast::expr_put(option::none)) { false }

        case (_) { true }
    }
}

fn steal_exprs(&ast::crate crate) -> ast::expr[] {
    let @mutable ast::expr[] exprs = @mutable ~[];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(@mutable ast::expr[] es, &@ast::expr e) { if (safe_to_steal(e.node)) { *es += ~[*e]; } else { /* now my indices are wrong :( */ } }
    auto v = rec(visit_expr_pre = bind stash_expr(exprs, _) with walk::default_visitor());
    walk::walk_crate(v, crate);
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(ast::expr_ e) -> bool {
    alt (e) {
        case (ast::expr_if(_, _, _)) { false }
        case (ast::expr_block(_)) { false }
        case (_) { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(&ast::crate crate, uint i, ast::expr_ newexpr) -> ast::crate {
    let @mutable uint j = @mutable 0u;
    fn fold_expr_rep(@mutable uint j_, uint i_, &ast::expr_ newexpr_, &ast::expr_ original, fold::ast_fold fld) -> ast::expr_ {
      *j_ += 1u;
      if (i_ + 1u == *j_ && safe_to_replace(original)) {
        newexpr_
      } else {
        fold::noop_fold_expr(original, fld)
      }
    }
    auto afp = rec(fold_expr = bind fold_expr_rep(j, i, newexpr, _, _) with *fold::default_ast_fold());
    auto af = fold::make_fold(afp);
    let @ast::crate crate2 = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    *crate2
}

iter under(uint n) -> uint { let uint i = 0u; while (i < n) { put i; i += 1u; } }

fn devnull() -> ioivec::writer { std::ioivec::string_writer().get_writer() }

fn as_str(fn (ioivec::writer) f) -> str {
    auto w = std::ioivec::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

/*
fn pp_variants(&ast::crate crate, &codemap::codemap cmap, &str filename) {
    auto exprs = steal_exprs(crate);
    auto exprsL = ivec::len(exprs);
    if (exprsL < 100u) {
        for each (uint i in under(uint::min(exprsL, 20u))) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs.(i));
            for each (uint j in under(uint::min(exprsL, 5u))) {
                log_err "With... " + pprust::expr_to_str(@exprs.(j));
                auto crate2 = @replace_expr_in_crate(crate, i, exprs.(j).node);
                check_roundtrip(crate2, cmap, filename + ".4.rs");
            }
        }
    }
}
*/

fn parse_and_print(&str code) -> str {
    auto filename = "";
    auto codemap = codemap::new_codemap();
    auto crate = parser::parse_crate_from_source_str(filename, code, ~[], codemap);
    ret as_str(bind pprust::print_crate(codemap, crate, filename,
                                        ioivec::string_reader(code),
                                        _, pprust::no_ann()));
}

fn content_is_confusing(&str code) -> bool {
    auto confusing_patterns = [
        "#macro",      // https://github.com/graydon/rust/issues/671
        "][]",         // https://github.com/graydon/rust/issues/669
        "][mutable]",  // https://github.com/graydon/rust/issues/669
        "][mutable ]", // https://github.com/graydon/rust/issues/669
        "self",        // crazy rules enforced by parser rather than typechecker?
        "spawn",       // more precedence issues
        "bind"         // more precedence issues?
    ];

    for (str p in confusing_patterns) {
        if contains(code, p) {
            ret true;
        }
    }
    ret false;
}

fn file_is_confusing(&str filename) -> bool {
    auto confusing_files = [

        "block-expr-precedence.rs",  // https://github.com/graydon/rust/issues/674

        "nil-pattern.rs",            // something to do with () as a lone pattern

        "syntax-extension-fmt.rs"    // an issue where -2147483648 gains an
                                     // extra negative sign each time through,
                                     // which i can't reproduce using "rustc
                                     // --pretty normal"???
    ];

    for (str f in confusing_files) {
        if contains(filename, f) {
            ret true;
        }
    }

    ret false;
}

fn check_roundtrip_convergence(&str code) {

    auto i = 0;
    auto new = code;
    auto old = code;

    while (i < 10) {
        old = new;
        new = parse_and_print(old);
        if content_is_confusing(new) {
            ret;
        }
        i += 1;
        log #fmt("cycle %d", i);
    }

    if old != new {
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("kdiff3", ["round-trip-a.rs", "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn check_convergence(&str[] files) {

    log_err #fmt("pp convergence tests: %u files", ivec::len(files));
    for (str file in files)  {

        log_err #fmt("pp converge: %s", file);
        if ! file_is_confusing(file) {
            auto s = read_whole_file(file);
            if ! content_is_confusing(s) {
                check_roundtrip_convergence(s);
            }
        }

        //pprust::print_crate(cm, crate, file, devnull(), pprust::no_ann());
        // Currently hits https://github.com/graydon/rust/issues/675
        //pp_variants(*crate, cm, file);
    }
    }

fn main(vec[str] args) {
    if (vec::len(args) != 2u) {
        log_err #fmt("usage: %s <testdir>", args.(0));
        ret;
    }
    auto files = ~[];
    auto root = args.(1);

    find_rust_files(files, root);
    check_convergence(files);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>#[macro_use]
use game::gfx_macros::{TilemapSettings, Projection, VertexData, pipe, TileMapData};
use std::io::Cursor;
use gfx;
use image;
use cgmath;
use gfx_app::{Application, WindowTargets}; //
use gfx::{Resources, Factory, texture};
use gfx::handle::{ShaderResourceView};
use gfx::format::{Rgba8};
use gfx::traits::{FactoryExt};
use cgmath::{SquareMatrix, Matrix4, AffineMatrix3};
use cgmath::{Point3, Vector3};
use cgmath::{Transform};
use views::Point;
use game::constants::{MAP_FILE_PATH, TILES_PCS_W, TILES_PCS_H};
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon, SharedVertexIterator};
use views::{TileMap};
use data::{load_map_file};

const TILEMAP_BUF_LENGTH: usize = 4096;

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}

fn cartesian_to_isometric(point_x: f32, point_y: f32) -> (f32, f32) {
  ((point_x - point_y), (point_x + point_y) / 2.0)
}

impl TileMapData {
  pub fn new_empty() -> TileMapData {
    TileMapData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> TileMapData {
    TileMapData { data: data }
  }
}

pub struct TileMapPlane<R> where R: Resources {
  pub params: pipe::Data<R>,
  pub slice: gfx::Slice<R>,
  projection: Projection,
  is_projection_dirty: bool,
  tilemap_settings: TilemapSettings,
  is_tilemap_dirty: bool,
  pub data: Vec<TileMapData>,
}

impl<R> TileMapPlane<R> where R: Resources {
  pub fn new<F>(factory: &mut F, width: usize, height: usize, tile_size: usize,
                targets: WindowTargets<R>)
                -> TileMapPlane<R> where F: gfx::Factory<R> {
    let half_width = (tile_size * width) / 2;
    let half_height = (tile_size * height) / 2;
    let total_size = width * height;

    let tilesheet_bytes = &include_bytes!("../../assets/maps/terrain.png")[..];
    let tilesheet_width = 32;
    let tilesheet_height = 32;
    let tilesheet_tilesize = 32;

    let tilesheet_total_width = tilesheet_width * tilesheet_tilesize;
    let tilesheet_total_height = tilesheet_height * tilesheet_tilesize;
    let plane = Plane::subdivide(width, width);

    let vertex_data: Vec<VertexData> = plane.shared_vertex_iter()
      .map(|(x, y)| {
        let (raw_x, raw_y) = cartesian_to_isometric(x, y);
        let vertex_x = half_width as f32 * raw_x;
        let vertex_y = half_height as f32 * raw_y;

        let (u_pos, v_pos) = ((raw_x / 4.0 - raw_y / 2.0) + 0.5, (raw_x / 4.0 + raw_y / 2.0) + 0.5);
        let tilemap_x = u_pos * width as f32;
        let tilemap_y = v_pos * height as f32;

        VertexData {
          pos: [vertex_x, vertex_y, 0.0],
          buf_pos: [tilemap_x as f32, tilemap_y as f32]
        }
      })
      .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
      .triangulate()
      .vertices()
      .map(|i| i as u32)
      .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let params = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      tilemap: factory.create_constant_buffer(TILEMAP_BUF_LENGTH),
      tilemap_cb: factory.create_constant_buffer(1),
      tilesheet: (tile_texture, factory.create_sampler_linear()),
      out_color: targets.color,
      out_depth: targets.depth,
    };

    let mut charmap_data = Vec::with_capacity(total_size);

    for _ in 0..total_size {
      charmap_data.push(TileMapData::new_empty());
    }

    let view: AffineMatrix3<f32> = Transform::look_at(
      Point3::new(0.0, 0.0, 1000.0),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    TileMapPlane {
      slice: slice,
      params: params,
      projection: Projection {
        model: Matrix4::identity().into(),
        view: view.mat.into(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), targets.aspect_ratio, 0.1, 4000.0).into(),
      },
      is_projection_dirty: true,
      tilemap_settings: TilemapSettings {
        world_size: [width as f32, height as f32, tile_size as f32, 0.0],
        tilesheet_size: [tilesheet_width as f32, tilesheet_height as f32, tilesheet_total_width as f32, tilesheet_total_height as f32],
        offsets: [0.0, 0.0],
      },
      is_tilemap_dirty: true,
      data: charmap_data,
    }
  }

  pub fn resize(&mut self, targets: WindowTargets<R>) {
    self.params.out_color = targets.color;
    self.params.out_depth = targets.depth;
    self.projection.proj = cgmath::perspective(cgmath::deg(60.0f32), targets.aspect_ratio, 0.1, 4000.0).into();
    self.is_projection_dirty = true;
  }

  pub fn prepare_buffers<C>(&mut self, encoder: &mut gfx::Encoder<R, C>, update_data: bool) where C: gfx::CommandBuffer<R> {
    if update_data {
      encoder.update_buffer(&self.params.tilemap, self.data.as_slice(), 0).unwrap();
    }
    if self.is_projection_dirty {
      encoder.update_constant_buffer(&self.params.projection_cb, &self.projection);
      self.is_projection_dirty = false;
    }
    if self.is_tilemap_dirty {
      encoder.update_constant_buffer(&self.params.tilemap_cb, &self.tilemap_settings);
      self.is_tilemap_dirty = false;
    }
  }

  pub fn clear<C>(&self, encoder: &mut gfx::Encoder<R, C>) where C: gfx::CommandBuffer<R> {
    encoder.clear(&self.params.out_color,
                  [16.0 / 256.0, 14.0 / 256.0, 22.0 / 256.0, 1.0]);
    encoder.clear_depth(&self.params.out_depth, 1.0);
  }

  pub fn update_view(&mut self, view: &AffineMatrix3<f32>) {
    self.projection.view = view.mat.into();
    self.is_projection_dirty = true;
  }

  pub fn update_x_offset(&mut self, amount: f32) {
    self.tilemap_settings.offsets[0] = amount;
    self.is_tilemap_dirty = true;
  }

  pub fn update_y_offset(&mut self, amount: f32) {
    self.tilemap_settings.offsets[1] = amount;
    self.is_tilemap_dirty = true;
  }
}

pub struct Tilemap<R> where R: Resources {
  pub limit_coords: [usize; 2],
  pub focus_coords: [usize; 2],
  tilemap_size: [usize; 2],
  tilemap_plane: TileMapPlane<R>,
  focus_dirty: bool,
  tiles: Vec<usize>,
}

impl<R: gfx::Resources> TileMap<R> {
  pub fn set_focus(&mut self, focus: [usize; 2]) {
    if focus[0] <= self.limit_coords[0] && focus[1] <= self.limit_coords[1] {
      self.focus_coords = focus;
      let mut charmap_ypos = 0;
      for ypos in self.focus_coords[1]..self.focus_coords[1] + self.charmap_size[1] {
        let mut charmap_xpos = 0;
        for xpos in self.focus_coords[0]..self.focus_coords[0] + self.charmap_size[0] {
          let tile_idx = (ypos * self.tilemap_size[0]) + xpos;
          let charmap_idx = (charmap_ypos * self.charmap_size[0]) + charmap_xpos;
          self.tilemap_plane.data[charmap_idx] = self.tiles[tile_idx];
          charmap_xpos += 1;
        }
        charmap_ypos += 1;
      }
      self.focus_dirty = true;
    } else {
      panic!("tried to set focus to {:?} with tilemap_size of {:?}", focus, self.tilemap_size);
    }
  }

  fn calc_index(&self, xpos: usize, ypos: usize) -> usize {
    (ypos * self.tilemap_size[0]) + xpos
  }

  pub fn set_tile(&mut self, xpos: usize, ypos: usize, data: [f32; 4]) {
    let idx = self.calc_index(xpos, ypos);
    self.tiles[idx] = TileMapData::new(data);
  }

  pub fn populate_tilemap(&mut self, tilemap_size: [usize; 2]) {
    let map = load_map_file(MAP_FILE_PATH);
    for ypos in 0..self.tilemap_size[1] {
      for xpos in 0..self.tilemap_size[0] {
        self.set_tile(xpos, ypos, [7.0, 7.0, 0.0, 0.0]);
      }
    }
    self.set_tile(1, 1, [4.0, 4.0, 0.0, 0.0]);
    self.set_tile(3, 3, [4.0, 4.0, 0.0, 0.0]);
  }
}
<commit_msg>Setup tiled-map rendering<commit_after>#[macro_use]
use game::gfx_macros::{TilemapSettings, Projection, VertexData, pipe, TileMapData};
use std::io::Cursor;
use gfx;
use image;
use cgmath;
use gfx_app::{Application, WindowTargets}; //
use gfx::{Resources, Factory, texture};
use gfx::handle::{ShaderResourceView};
use gfx::format::{Rgba8};
use gfx::traits::{FactoryExt};
use cgmath::{SquareMatrix, Matrix4, AffineMatrix3};
use cgmath::{Point3, Vector3};
use cgmath::{Transform};
use views::Point;
use game::constants::{MAP_FILE_PATH, TILES_PCS_W, TILES_PCS_H};
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon, SharedVertexIterator};
use views::{TileMap};
use data::{load_map_file, get_map_tile};

const TILEMAP_BUF_LENGTH: usize = 4096;

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}

fn cartesian_to_isometric(point_x: f32, point_y: f32) -> (f32, f32) {
  ((point_x - point_y), (point_x + point_y) / 2.0)
}

impl TileMapData {
  pub fn new_empty() -> TileMapData {
    TileMapData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> TileMapData {
    TileMapData { data: data }
  }
}

pub struct TileMapPlane<R> where R: Resources {
  pub params: pipe::Data<R>,
  pub slice: gfx::Slice<R>,
  projection: Projection,
  is_projection_dirty: bool,
  tilemap_settings: TilemapSettings,
  is_tilemap_dirty: bool,
  pub data: Vec<TileMapData>,
}

impl<R> TileMapPlane<R> where R: Resources {
  pub fn new<F>(factory: &mut F, width: usize, height: usize, tile_size: usize,
                targets: WindowTargets<R>)
                -> TileMapPlane<R> where F: gfx::Factory<R> {
    let half_width = (tile_size * width) / 2;
    let half_height = (tile_size * height) / 2;
    let total_size = width * height;

    let tilesheet_bytes = &include_bytes!("../../assets/maps/terrain.png")[..];
    let tilesheet_width = 32;
    let tilesheet_height = 32;
    let tilesheet_tilesize = 32;

    let tilesheet_total_width = tilesheet_width * tilesheet_tilesize;
    let tilesheet_total_height = tilesheet_height * tilesheet_tilesize;
    let plane = Plane::subdivide(width, width);

    let vertex_data: Vec<VertexData> = plane.shared_vertex_iter()
      .map(|(x, y)| {
        let (raw_x, raw_y) = cartesian_to_isometric(x, y);
        let vertex_x = half_width as f32 * raw_x;
        let vertex_y = half_height as f32 * raw_y;

        let (u_pos, v_pos) = ((raw_x / 4.0 - raw_y / 2.0) + 0.5, (raw_x / 4.0 + raw_y / 2.0) + 0.5);
        let tilemap_x = u_pos * width as f32;
        let tilemap_y = v_pos * height as f32;

        VertexData {
          pos: [vertex_x, vertex_y, 0.0],
          buf_pos: [tilemap_x as f32, tilemap_y as f32]
        }
      })
      .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
      .triangulate()
      .vertices()
      .map(|i| i as u32)
      .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let params = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      tilemap: factory.create_constant_buffer(TILEMAP_BUF_LENGTH),
      tilemap_cb: factory.create_constant_buffer(1),
      tilesheet: (tile_texture, factory.create_sampler_linear()),
      out_color: targets.color,
      out_depth: targets.depth,
    };

    let mut charmap_data = Vec::with_capacity(total_size);

    for _ in 0..total_size {
      charmap_data.push(TileMapData::new_empty());
    }

    let view: AffineMatrix3<f32> = Transform::look_at(
      Point3::new(0.0, 0.0, 1000.0),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    TileMapPlane {
      slice: slice,
      params: params,
      projection: Projection {
        model: Matrix4::identity().into(),
        view: view.mat.into(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), targets.aspect_ratio, 0.1, 4000.0).into(),
      },
      is_projection_dirty: true,
      tilemap_settings: TilemapSettings {
        world_size: [width as f32, height as f32, tile_size as f32, 0.0],
        tilesheet_size: [tilesheet_width as f32, tilesheet_height as f32, tilesheet_total_width as f32, tilesheet_total_height as f32],
        offsets: [0.0, 0.0],
      },
      is_tilemap_dirty: true,
      data: charmap_data,
    }
  }

  pub fn resize(&mut self, targets: WindowTargets<R>) {
    self.params.out_color = targets.color;
    self.params.out_depth = targets.depth;
    self.projection.proj = cgmath::perspective(cgmath::deg(60.0f32), targets.aspect_ratio, 0.1, 4000.0).into();
    self.is_projection_dirty = true;
  }

  pub fn prepare_buffers<C>(&mut self, encoder: &mut gfx::Encoder<R, C>, update_data: bool) where C: gfx::CommandBuffer<R> {
    if update_data {
      encoder.update_buffer(&self.params.tilemap, self.data.as_slice(), 0).unwrap();
    }
    if self.is_projection_dirty {
      encoder.update_constant_buffer(&self.params.projection_cb, &self.projection);
      self.is_projection_dirty = false;
    }
    if self.is_tilemap_dirty {
      encoder.update_constant_buffer(&self.params.tilemap_cb, &self.tilemap_settings);
      self.is_tilemap_dirty = false;
    }
  }

  pub fn clear<C>(&self, encoder: &mut gfx::Encoder<R, C>) where C: gfx::CommandBuffer<R> {
    encoder.clear(&self.params.out_color,
                  [16.0 / 256.0, 14.0 / 256.0, 22.0 / 256.0, 1.0]);
    encoder.clear_depth(&self.params.out_depth, 1.0);
  }

  pub fn update_view(&mut self, view: &AffineMatrix3<f32>) {
    self.projection.view = view.mat.into();
    self.is_projection_dirty = true;
  }

  pub fn update_x_offset(&mut self, amount: f32) {
    self.tilemap_settings.offsets[0] = amount;
    self.is_tilemap_dirty = true;
  }

  pub fn update_y_offset(&mut self, amount: f32) {
    self.tilemap_settings.offsets[1] = amount;
    self.is_tilemap_dirty = true;
  }
}

pub struct Tilemap<R> where R: Resources {
  pub limit_coords: [usize; 2],
  pub focus_coords: [usize; 2],
  tilemap_size: [usize; 2],
  tilemap_plane: TileMapPlane<R>,
  focus_dirty: bool,
  tiles: Vec<usize>,
}

impl<R: gfx::Resources> TileMap<R> {
  pub fn set_focus(&mut self, focus: [usize; 2]) {
    if focus[0] <= self.limit_coords[0] && focus[1] <= self.limit_coords[1] {
      self.focus_coords = focus;
      let mut charmap_ypos = 0;
      for ypos in self.focus_coords[1]..self.focus_coords[1] + self.charmap_size[1] {
        let mut charmap_xpos = 0;
        for xpos in self.focus_coords[0]..self.focus_coords[0] + self.charmap_size[0] {
          let tile_idx = (ypos * self.tilemap_size[0]) + xpos;
          let charmap_idx = (charmap_ypos * self.charmap_size[0]) + charmap_xpos;
          self.tilemap_plane.data[charmap_idx] = self.tiles[tile_idx];
          charmap_xpos += 1;
        }
        charmap_ypos += 1;
      }
      self.focus_dirty = true;
    } else {
      panic!("tried to set focus to {:?} with tilemap_size of {:?}", focus, self.tilemap_size);
    }
  }

  fn calc_index(&self, xpos: usize, ypos: usize) -> usize {
    (ypos * self.tilemap_size[0]) + xpos
  }

  pub fn set_tile(&mut self, xpos: usize, ypos: usize, data: [f32; 4]) {
    let idx = self.calc_index(xpos, ypos);
    self.tiles[idx] = TileMapData::new(data);
  }

  pub fn populate_tilemap(&mut self, tilemap_size: [usize; 2]) {
    let map = load_map_file(MAP_FILE_PATH);
    for ypos in 0..self.tilemap_size[1] {
      for xpos in 0..self.tilemap_size[0] {
        let map_val = get_map_tile(&map, 0, xpos as usize, ypos as usize);
        let tex_x = map_val % 32;
        let tex_y = (map_val - tex_x) / 32;
        self.set_tile(xpos, ypos, [(tex_x-1) as f32, tex_y as f32, 0.0, 0.0]);
      }
    }
  }
}
<|endoftext|>


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

//! Generic char output trait.

use core::option::{Some, None};
use core::str::{Str, StrSlice};
use core::slice::{Vector, ImmutableVector};
use core::collections::Collection;
use core::iter::Iterator;

use core::mem::zeroed;

use lib::strconv;

/// CharIO provides interface for outputting characters.
///
/// This trait implements the common functions to output strings and numbers,
/// requiring only one method: `putc`.
pub trait CharIO {
  /// Outputs a character.
  fn putc(&self, value: char);

  /// Outputs a string.
  fn puts(&self, s: &str) {
    let chars : &[u8] = s.as_slice().as_bytes();
    let mut i = 0;
    while i < s.len() {
      let c : char = chars[i] as char;
      self.putc(c);
      i += 1;
    }
  }

  /// Outputs an integer with given base.
  fn putint(&self, i: u32, base: u32) {
    let mut buf : [u8, ..32] = unsafe { zeroed() };
    let bsl : &mut [u8] = buf;
    strconv::itoa(i, bsl, base);

    for &i in bsl.iter() {
      if i == 0 {
        break;
      }
      self.putc(i as char);
    }
  }

  /// Outputs an integer.
  fn puti(&self, i: u32) {
    self.putint(i, 10);
  }

  /// Outputs an integer as a hex string.
  fn puth(&self, i: u32) {
    self.putint(i, 16);
  }
}
<commit_msg>Add tests to CharIO<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Generic char output trait.

use core::option::{Some, None};
use core::str::{Str, StrSlice};
use core::slice::{Vector, ImmutableVector};
use core::collections::Collection;
use core::iter::{Iterator, range};

use core::mem::zeroed;

use lib::strconv;

/// CharIO provides interface for outputting characters.
///
/// This trait implements the common functions to output strings and numbers,
/// requiring only one method: `putc`.
pub trait CharIO {
  /// Outputs a character.
  fn putc(&self, value: char);

  /// Outputs a string.
  fn puts(&self, s: &str) {
    let chars : &[u8] = s.as_slice().as_bytes();
    for i in range(0, s.len()) {
      let c : char = chars[i] as char;
      self.putc(c);
    }
  }

  /// Outputs an integer with given base.
  fn putint(&self, i: u32, base: u32) {
    let mut buf : [u8, ..32] = unsafe { zeroed() };
    let bsl : &mut [u8] = buf;
    strconv::itoa(i, bsl, base);

    for &i in bsl.iter() {
      if i == 0 {
        break;
      }
      self.putc(i as char);
    }
  }

  /// Outputs an integer.
  fn puti(&self, i: u32) {
    self.putint(i, 10);
  }

  /// Outputs an integer as a hex string.
  fn puth(&self, i: u32) {
    self.putint(i, 16);
  }
}

#[cfg(test)]
pub mod test {
  use core::cell::RefCell;

  use drivers::chario::CharIO;

  pub struct TestCharIOData {
    last_char: char,
    putc_calls: uint,
  }

  pub struct TestCharIO {
    data: RefCell<TestCharIOData>
  }

  impl CharIO for TestCharIO {
    fn putc(&self, value: char) {
      let mut data = self.data.borrow_mut();
      data.putc_calls += 1;
      data.last_char = value;
    }
  }

  impl TestCharIO {
    pub fn new() -> TestCharIO {
      TestCharIO {
        data: RefCell::new(TestCharIOData {
          last_char: '\0',
          putc_calls: 0,
        }),
      }
    }

    fn get_last_char(&self) -> char {
      self.data.borrow().last_char
    }

    fn get_and_reset_putc_calls(&self) -> uint {
      let current = self.data.borrow().putc_calls;
      self.data.borrow_mut().putc_calls = 0;
      current
    }
  }

  #[test]
  fn putc_should_store_a_char() {
    let io = TestCharIO::new();
    io.putc('a');
    assert!(io.get_last_char() == 'a');
    io.putc('z');
    assert!(io.get_last_char() == 'z');
  }

  #[test]
  fn puti_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puti(3);
    assert!(io.get_last_char() == '3');
    io.puti(9);
    assert!(io.get_last_char() == '9');
    io.puti(10);
    assert!(io.get_last_char() == '0');
    io.puti(11);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn puth_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puth(3);
    assert!(io.get_last_char() == '3');
    io.puth(9);
    assert!(io.get_last_char() == '9');
    io.puth(10);
    assert!(io.get_last_char() == 'a');
    io.puth(11);
    assert!(io.get_last_char() == 'b');
    io.puth(16);
    assert!(io.get_last_char() == '0');
    io.puth(17);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn putint_should_work_with_different_bases() {
    let io = TestCharIO::new();
    io.putint(0, 2);
    assert!(io.get_last_char() == '0');
    io.putint(1, 2);
    assert!(io.get_last_char() == '1');
    io.putint(2, 2);
    assert!(io.get_last_char() == '0');
    io.putint(3, 2);
    assert!(io.get_last_char() == '1');
    io.putint(7, 7);
    assert!(io.get_last_char() == '0');
    io.putint(8, 7);
    assert!(io.get_last_char() == '1');
    io.putint(12, 7);
    assert!(io.get_last_char() == '5');
    io.putint(14, 7);
    assert!(io.get_last_char() == '0');
  }

  #[test]
  fn puts_should_leave_us_with_just_the_last_char() {
    let io = TestCharIO::new();
    io.puts("fu!");
    assert!(io.get_last_char() == '!');
    assert!(io.get_and_reset_putc_calls() == 3);
    io.puts("\n\t");
    assert!(io.get_last_char() == '\t');
    assert!(io.get_and_reset_putc_calls() == 2);
  }
}
<|endoftext|>


<commit_before>mod terminal;
mod ansi;

use std::io::{self, Write, BufWriter};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, color, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Options {
    pub choices: Vec<String>,
    pub initial: String,
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    width: usize,
    terminal: Terminal,
}

impl Interface {
    /// Creates a new Interface from the provided options.
    pub fn from_opts(opts: Options) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: opts.choices,
            matching: Vec::new(),
            selected: 0,
            search: opts.initial,
            width: term.max_width,
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing_matches();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn filter_existing_matches(&mut self) {
        let mut matches = self.matching.
            par_iter().
            map(|c| c.text().to_string()).
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.matching.iter().take(10).len() as u16;

        self.render_matches()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_matches(&mut self) -> io::Result<()> {
        let mut term = BufWriter::new(&mut self.terminal);
        let matches = self.matching.iter().take(10);

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;
            let chars = choice.text().chars().take(self.width);

            write!(term, "\r\n")?;

            if selected {
                write!(term, "{}", style::Invert)?;
            }

            if let Some(positions) = choice.positions() {
                for (i, ch) in chars.enumerate() {
                    let match_position = positions.iter().any(|p| *p == i);

                    if match_position {
                        let color = color::Fg(color::Colors::Magenta);
                        let reset = color::Fg(color::Reset);
                        write!(term, "{}{}{}", color, ch, reset)?;
                    } else {
                        write!(term, "{}", ch)?;
                    }
                }

            } else {
                write!(term, "{}", chars.collect::<String>())?;
            }

            if selected {
                write!(term, "{}", style::NoInvert)?;
            }
        }

        Ok(())
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<commit_msg>Move cursor position reset into render_matches()<commit_after>mod terminal;
mod ansi;

use std::io::{self, Write, BufWriter};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, color, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Options {
    pub choices: Vec<String>,
    pub initial: String,
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    width: usize,
    terminal: Terminal,
}

impl Interface {
    /// Creates a new Interface from the provided options.
    pub fn from_opts(opts: Options) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: opts.choices,
            matching: Vec::new(),
            selected: 0,
            search: opts.initial,
            width: term.max_width,
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing_matches();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn filter_existing_matches(&mut self) {
        let mut matches = self.matching.
            par_iter().
            map(|c| c.text().to_string()).
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;
        self.render_matches()?;
        Ok(())
    }

    fn render_matches(&mut self) -> io::Result<()> {
        let mut term = BufWriter::new(&mut self.terminal);
        let matches = self.matching.iter().take(10);
        let n = matches.len() as u16;

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;
            let chars = choice.text().chars().take(self.width);

            write!(term, "\r\n")?;

            if selected {
                write!(term, "{}", style::Invert)?;
            }

            if let Some(positions) = choice.positions() {
                for (i, ch) in chars.enumerate() {
                    let match_position = positions.iter().any(|p| *p == i);

                    if match_position {
                        let color = color::Fg(color::Colors::Magenta);
                        let reset = color::Fg(color::Reset);
                        write!(term, "{}{}{}", color, ch, reset)?;
                    } else {
                        write!(term, "{}", ch)?;
                    }
                }

            } else {
                write!(term, "{}", chars.collect::<String>())?;
            }

            if selected {
                write!(term, "{}", style::NoInvert)?;
            }
        }

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(term, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<|endoftext|>


<commit_before>use context::timeout;
use device::pic;
use device::serial::{COM1, COM2};
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use time;
use context;

//resets to 0 in context::switch()
pub static PIT_TICKS: AtomicUsize = ATOMIC_USIZE_INIT;

unsafe fn trigger(irq: u8) {
    extern {
        fn irq_trigger(irq: u8);
    }

    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_set(irq - 8);
            pic::MASTER.ack();
            pic::SLAVE.ack();
        } else {
            pic::MASTER.mask_set(irq);
            pic::MASTER.ack();
        }
    }

    irq_trigger(irq);
}

pub unsafe fn acknowledge(irq: usize) {
    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_clear(irq as u8 - 8);
        } else {
            pic::MASTER.mask_clear(irq as u8);
        }
    }
}

interrupt!(pit, {
    // Saves CPU time by not sending IRQ event irq_trigger(0);

    const PIT_RATE: u64 = 2250286;

    {
        let mut offset = time::OFFSET.lock();
        let sum = offset.1 + PIT_RATE;
        offset.1 = sum % 1000000000;
        offset.0 += sum / 1000000000;
    }

    pic::MASTER.ack();

    /*
    if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
        context::switch();
    }
    */

    // Any better way of doing this?
    timeout::trigger();
});

interrupt!(keyboard, {
    trigger(1);
});

interrupt!(cascade, {
    // No need to do any operations on cascade
    pic::MASTER.ack();
});

interrupt!(com2, {
    COM2.lock().receive();
    pic::MASTER.ack();
});

interrupt!(com1, {
    COM1.lock().receive();
    pic::MASTER.ack();
});

interrupt!(lpt2, {
    trigger(5);
});

interrupt!(floppy, {
    trigger(6);
});

interrupt!(lpt1, {
    trigger(7);
});

interrupt!(rtc, {
    trigger(8);
});

interrupt!(pci1, {
    trigger(9);
});

interrupt!(pci2, {
    trigger(10);
});

interrupt!(pci3, {
    trigger(11);
});

interrupt!(mouse, {
    trigger(12);
});

interrupt!(fpu, {
    trigger(13);
});

interrupt!(ata1, {
    trigger(14);
});

interrupt!(ata2, {
    trigger(15);
});
<commit_msg>Reenable preemption<commit_after>use context::timeout;
use device::pic;
use device::serial::{COM1, COM2};
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use time;
use context;

//resets to 0 in context::switch()
pub static PIT_TICKS: AtomicUsize = ATOMIC_USIZE_INIT;

unsafe fn trigger(irq: u8) {
    extern {
        fn irq_trigger(irq: u8);
    }

    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_set(irq - 8);
            pic::MASTER.ack();
            pic::SLAVE.ack();
        } else {
            pic::MASTER.mask_set(irq);
            pic::MASTER.ack();
        }
    }

    irq_trigger(irq);
}

pub unsafe fn acknowledge(irq: usize) {
    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_clear(irq as u8 - 8);
        } else {
            pic::MASTER.mask_clear(irq as u8);
        }
    }
}

interrupt!(pit, {
    // Saves CPU time by not sending IRQ event irq_trigger(0);

    const PIT_RATE: u64 = 2250286;

    {
        let mut offset = time::OFFSET.lock();
        let sum = offset.1 + PIT_RATE;
        offset.1 = sum % 1000000000;
        offset.0 += sum / 1000000000;
    }

    pic::MASTER.ack();

    if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
        context::switch();
    }

    // Any better way of doing this?
    timeout::trigger();
});

interrupt!(keyboard, {
    trigger(1);
});

interrupt!(cascade, {
    // No need to do any operations on cascade
    pic::MASTER.ack();
});

interrupt!(com2, {
    COM2.lock().receive();
    pic::MASTER.ack();
});

interrupt!(com1, {
    COM1.lock().receive();
    pic::MASTER.ack();
});

interrupt!(lpt2, {
    trigger(5);
});

interrupt!(floppy, {
    trigger(6);
});

interrupt!(lpt1, {
    trigger(7);
});

interrupt!(rtc, {
    trigger(8);
});

interrupt!(pci1, {
    trigger(9);
});

interrupt!(pci2, {
    trigger(10);
});

interrupt!(pci3, {
    trigger(11);
});

interrupt!(mouse, {
    trigger(12);
});

interrupt!(fpu, {
    trigger(13);
});

interrupt!(ata1, {
    trigger(14);
});

interrupt!(ata2, {
    trigger(15);
});
<|endoftext|>


<commit_before>use cf = core_foundation;
use cf::array::CFArrayRef;
use cf::base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeRef,
    kCFAllocatorDefault,
};
use cf::dictionary::{CFDictionary, CFDictionaryRef};
use cf::number::CFNumber;
use cf::string::{CFString, CFStringRef};

use libc::c_void;

struct __CTFontCollection { private: () }
pub type CTFontCollectionRef = *__CTFontCollection;

impl CTFontCollectionRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CTFontCollection {
    obj: CTFontCollectionRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl CTFontCollection : AbstractCFType<CTFontCollectionRef> {
    pure fn get_ref() -> CTFontCollectionRef { self.obj }

    static fn wrap(obj: CTFontCollectionRef) -> CTFontCollection {
        CTFontCollection { obj: obj }
    }

    static fn unwrap(wrapper: CTFontCollection) -> CTFontCollectionRef {
        wrapper.obj
    }
}

pub impl CTFontCollection {
    static fn new() -> CTFontCollection {
        let options = CFDictionary::new([
            (CFString::wrap_extern(kCTFontCollectionRemoveDuplicatesOption), CFNumber::new(1_i8))
        ]);
        let collection = CTFontCollectionCreateFromAvailableFonts(options.get_ref());
        CTFontCollection { obj: move collection }
    }
}

extern {
    /*
     * CTFontCollection.h
     */

    const kCTFontCollectionRemoveDuplicatesOption: CFStringRef;

    fn CTFontCollectionCreateCopyWithFontDescriptors(descriptors: CFArrayRef, options: CFDictionaryRef) ->CTFontCollectionRef;
    fn CTFontCollectionCreateFromAvailableFonts(options: CFDictionaryRef) -> CTFontCollectionRef;
    fn CTFontCollectionCreateMatchingFontDescriptors(collection: CTFontCollectionRef) -> CFArrayRef;
    fn CTFontCollectionCreateWithFontDescriptors(original: CTFontCollectionRef,
                                                 descriptors: CFArrayRef,
                                                 options: CFDictionaryRef) -> CTFontCollectionRef;
    //fn CTFontCollectionCreateMatchingFontDescriptorsSortedWithCallback;
    //fn CTFontCollectionGetTypeID;
}<commit_msg>Add CTFontCollection::get_descriptocrs, and bind CTFontCollectionGetTypeID.<commit_after>use cf = core_foundation;
use cf::array::{CFArray, CFArrayRef};
use cf::base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeID,
    CFTypeRef,
    kCFAllocatorDefault,
};
use cf::dictionary::{CFDictionary, CFDictionaryRef};
use cf::number::CFNumber;
use cf::string::{CFString, CFStringRef};

use font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};

use libc::c_void;

struct __CTFontCollection { private: () }
pub type CTFontCollectionRef = *__CTFontCollection;

impl CTFontCollectionRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CTFontCollection {
    obj: CTFontCollectionRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl CTFontCollection : AbstractCFType<CTFontCollectionRef> {
    pure fn get_ref() -> CTFontCollectionRef { self.obj }

    static fn wrap(obj: CTFontCollectionRef) -> CTFontCollection {
        CTFontCollection { obj: obj }
    }

    static fn unwrap(wrapper: CTFontCollection) -> CTFontCollectionRef {
        wrapper.obj
    }
}

pub impl CTFontCollection {
    static fn new() -> CTFontCollection {
        let options = CFDictionary::new([
            (CFString::wrap_extern(kCTFontCollectionRemoveDuplicatesOption), CFNumber::new(1_i8))
        ]);
        let collection = CTFontCollectionCreateFromAvailableFonts(options.get_ref());
        CTFontCollection { obj: move collection }
    }

    fn get_descriptors() -> CFArray<CTFontDescriptorRef, CTFontDescriptor> {
        cf::base::wrap(CTFontCollectionCreateMatchingFontDescriptors(self.obj))
    }
}

extern {
    /*
     * CTFontCollection.h
     */

    const kCTFontCollectionRemoveDuplicatesOption: CFStringRef;

    fn CTFontCollectionCreateCopyWithFontDescriptors(descriptors: CFArrayRef, options: CFDictionaryRef) -> CTFontCollectionRef;
    fn CTFontCollectionCreateFromAvailableFonts(options: CFDictionaryRef) -> CTFontCollectionRef;
    fn CTFontCollectionCreateMatchingFontDescriptors(collection: CTFontCollectionRef) -> CFArrayRef;
    fn CTFontCollectionCreateWithFontDescriptors(original: CTFontCollectionRef,
                                                 descriptors: CFArrayRef,
                                                 options: CFDictionaryRef) -> CTFontCollectionRef;
    //fn CTFontCollectionCreateMatchingFontDescriptorsSortedWithCallback;
    fn CTFontCollectionGetTypeID() -> CFTypeID;
}<|endoftext|>


<commit_before>use toc::Toc;
use super::test_eq;

#[test]
fn toc_simple() {
    let mut toc = Toc::new();
    toc.add(3, String::from("#1"), "0.0.1".to_owned());
    toc.add(1, String::from("#2"), "1".to_owned());
    toc.add(3, String::from("#3"), "1.0.1".to_owned());
    toc.add(2, String::from("#4"), "1.1".to_owned());
    toc.add(1, String::from("#5"), "2".to_owned());
    let actual = toc.render();
    let expected = "

0.0.1

1

1.0.1

1.1

2

";
    test_eq(&actual, expected);
}
<commit_msg>Add tests for toc.render_epub<commit_after>use toc::Toc;
use super::test_eq;

#[test]
fn toc_simple() {
    let mut toc = Toc::new();
    toc.add(3, String::from("#1"), "0.0.1".to_owned());
    toc.add(1, String::from("#2"), "1".to_owned());
    toc.add(3, String::from("#3"), "1.0.1".to_owned());
    toc.add(2, String::from("#4"), "1.1".to_owned());
    toc.add(1, String::from("#5"), "2".to_owned());
    let actual = toc.render();
    let expected = "

0.0.1

1

1.0.1

1.1

2

";
    test_eq(&actual, expected);
}

#[test]
fn toc_epub_simple() {
    let mut toc = Toc::new();
    toc.add(1, String::from("#1"), "1".to_owned());
    toc.add(1, String::from("#2"), "2".to_owned());
    let actual = toc.render_epub(1);
    let expected = "
   <navPoint id = \"navPoint-1\">
     <navLabel>
       <text>1</text>
     </navLabel>
     <content src = \"#1\" />
    </navPoint>

   <navPoint id = \"navPoint-2\">
     <navLabel>
       <text>2</text>
     </navLabel>
     <content src = \"#2\" />
    </navPoint>
";
    test_eq(&actual, expected);
}

#[test]
fn toc_epub_simple_sublevels() {
    let mut toc = Toc::new();
    toc.add(1, String::from("#1"), "1".to_owned());
    toc.add(2, String::from("#1.1"), "1.1".to_owned());
    toc.add(1, String::from("#2"), "2".to_owned());
    toc.add(2, String::from("#2.1"), "2.1".to_owned());
    let actual = toc.render_epub(1);
    let expected = "
   <navPoint id = \"navPoint-1\">
     <navLabel>
       <text>1</text>
     </navLabel>
     <content src = \"#1\" />

   <navPoint id = \"navPoint-2\">
     <navLabel>
       <text>1.1</text>
     </navLabel>
     <content src = \"#1.1\" />
    </navPoint>
    </navPoint>

   <navPoint id = \"navPoint-3\">
     <navLabel>
       <text>2</text>
     </navLabel>
     <content src = \"#2\" />

   <navPoint id = \"navPoint-4\">
     <navLabel>
       <text>2.1</text>
     </navLabel>
     <content src = \"#2.1\" />
    </navPoint>
    </navPoint>
";
    test_eq(&actual, expected);
}

#[test]
fn toc_epub_broken_sublevels() {
    let mut toc = Toc::new();
    toc.add(2, String::from("#1.1"), "1.1".to_owned());
    toc.add(1, String::from("#2"), "2".to_owned());
    toc.add(2, String::from("#2.1"), "2.1".to_owned());
    let actual = toc.render_epub(1);
    let expected = "
   <navPoint id = \"navPoint-1\">
     <navLabel>
       <text>1.1</text>
     </navLabel>
     <content src = \"#1.1\" />
    </navPoint>

   <navPoint id = \"navPoint-2\">
     <navLabel>
       <text>2</text>
     </navLabel>
     <content src = \"#2\" />

   <navPoint id = \"navPoint-3\">
     <navLabel>
       <text>2.1</text>
     </navLabel>
     <content src = \"#2.1\" />
    </navPoint>
    </navPoint>
";
    test_eq(&actual, expected);
}
<|endoftext|>


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

//! Traits for working with Errors.
//!
//! # The `Error` trait
//!
//! `Error` is a trait representing the basic expectations for error values,
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
//! a description, but they may optionally provide additional detail (via
//! `Display`) and cause chain information:
//!
//! ```
//! use std::fmt::Display;
//!
//! trait Error: Display {
//!     fn description(&self) -> &str;
//!
//!     fn cause(&self) -> Option<&Error> { None }
//! }
//! ```
//!
//! The `cause` method is generally used when errors cross "abstraction
//! boundaries", i.e.  when a one module must report an error that is "caused"
//! by an error from a lower-level module. This setup makes it possible for the
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.
//!
//! # The `FromError` trait
//!
//! `FromError` is a simple trait that expresses conversions between different
//! error types. To provide maximum flexibility, it does not require either of
//! the types to actually implement the `Error` trait, although this will be the
//! common case.
//!
//! The main use of this trait is in the `try!` macro, which uses it to
//! automatically convert a given error to the error specified in a function's
//! return type.
//!
//! For example,
//!
//! ```
//! #![feature(core)]
//! use std::error::FromError;
//! use std::{io, str};
//! use std::fs::File;
//!
//! enum MyError { Io(io::Error), Utf8(str::Utf8Error), }
//!
//! impl FromError<io::Error> for MyError {
//!     fn from_error(err: io::Error) -> MyError { MyError::Io(err) }
//! }
//!
//! impl FromError<str::Utf8Error> for MyError {
//!     fn from_error(err: str::Utf8Error) -> MyError { MyError::Utf8(err) }
//! }
//!
//! #[allow(unused_variables)]
//! fn open_and_map() -> Result<(), MyError> {
//!     let b = b"foo.txt";
//!     let s = try!(str::from_utf8(b));
//!     let f = try!(File::open(s));
//!
//!     // do something interesting here...
//!     Ok(())
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::*;
use fmt::{Debug, Display};

/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display {
    /// A short description of the error.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn description(&self) -> &str;

    /// The lower-level cause of this error, if any.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn cause(&self) -> Option<&Error> { None }
}

/// A trait for types that can be converted from a given error type `E`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromError<E> {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_error(err: E) -> Self;
}

// Any type is convertable from itself
#[stable(feature = "rust1", since = "1.0.0")]
impl<E> FromError<E> for E {
    fn from_error(err: E) -> E {
        err
    }
}
<commit_msg>Fix line spacing.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits for working with Errors.
//!
//! # The `Error` trait
//!
//! `Error` is a trait representing the basic expectations for error values,
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
//! a description, but they may optionally provide additional detail (via
//! `Display`) and cause chain information:
//!
//! ```
//! use std::fmt::Display;
//!
//! trait Error: Display {
//!     fn description(&self) -> &str;
//!
//!     fn cause(&self) -> Option<&Error> { None }
//! }
//! ```
//!
//! The `cause` method is generally used when errors cross "abstraction
//! boundaries", i.e.  when a one module must report an error that is "caused"
//! by an error from a lower-level module. This setup makes it possible for the
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.
//!
//! # The `FromError` trait
//!
//! `FromError` is a simple trait that expresses conversions between different
//! error types. To provide maximum flexibility, it does not require either of
//! the types to actually implement the `Error` trait, although this will be the
//! common case.
//!
//! The main use of this trait is in the `try!` macro, which uses it to
//! automatically convert a given error to the error specified in a function's
//! return type.
//!
//! For example,
//!
//! ```
//! #![feature(core)]
//! use std::error::FromError;
//! use std::{io, str};
//! use std::fs::File;
//!
//! enum MyError {
//!     Io(io::Error),
//!     Utf8(str::Utf8Error),
//! }
//!
//! impl FromError<io::Error> for MyError {
//!     fn from_error(err: io::Error) -> MyError { MyError::Io(err) }
//! }
//!
//! impl FromError<str::Utf8Error> for MyError {
//!     fn from_error(err: str::Utf8Error) -> MyError { MyError::Utf8(err) }
//! }
//!
//! #[allow(unused_variables)]
//! fn open_and_map() -> Result<(), MyError> {
//!     let b = b"foo.txt";
//!     let s = try!(str::from_utf8(b));
//!     let f = try!(File::open(s));
//!
//!     // do something interesting here...
//!     Ok(())
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::*;
use fmt::{Debug, Display};

/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display {
    /// A short description of the error.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn description(&self) -> &str;

    /// The lower-level cause of this error, if any.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn cause(&self) -> Option<&Error> { None }
}

/// A trait for types that can be converted from a given error type `E`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromError<E> {
    /// Perform the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_error(err: E) -> Self;
}

// Any type is convertable from itself
#[stable(feature = "rust1", since = "1.0.0")]
impl<E> FromError<E> for E {
    fn from_error(err: E) -> E {
        err
    }
}
<|endoftext|>