<commit_before>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

pub type ReaderResult<T, E> = Result<T, E>;

pub struct Reader {

    path: Path,

    read_buffer: BufferedReader<File>,

    write_buffer: BufferedWriter<File>,

}

struct Record {

    id: u64,

    payload: String,

    metadata: String,

}

pub trait ReaderFile {

    fn open(&self) -> Box<File>;

    fn insert_string(&mut self, String);

    fn encode_record(&self, String) -> String;

    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {

    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("fooo");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<commit_msg>Added long overdue basic documentation for Reader<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

// A result type that's specfici to the Reader module.
// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

// Reader struct of its basic properties.
pub struct Reader {
    // Path to file where the Reader is created.
    path: Path,
    // BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    // BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
}

// Each line in the database file is a 'Record' that contains the following data to be read
// and serialized.
struct Record {
    // Unique (?) id given to each record.
    id: u64,
    // The payload of each record that is Base64 encoded and JSON serialized.
    payload: String,
    // Any necessary metedata needed to identify the record. TODO Base64 encoded and JSON encoded?
    metadata: String,

}

// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> Box<File>;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
    // Encodes a record to Base64 (with standard encoding).
    fn encode_record(&self, String) -> String;
    // Decoes a record from Base64.
    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {
    // Creates a new Reader from the Path provided.
    // Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    // If the file doesn't exist, it is created.
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    // This is a helder function that realistically shouldn't exist in production.
    // Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    // Inserts a &str into the database.
    #[warn(experimental)]
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    // Inserts a byte array into the database.
    #[warn(experimental)]
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => box file,
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

// Test setup code. Current functions:
//  - Create a new file 'tests/base-test.txt'
//  - Write a 2x2 matrix of records into the base-test.txt file
//  - If 'tests/base-test-created.txt' is created, delete it
//  - Returns a Reader object to 'tests/base-test.txt'
#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("Unable to create test file");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<|endoftext|>


<commit_before>use std::marker;
use std::ffi::CString;
use std::mem;
use std::ptr;

use libc::{c_char, size_t, c_uint, c_int};

use {raw, Error, Repository, Oid, Signature, Index, MergeOptions};
use build::CheckoutBuilder;
use util::Binding;

/// A structure representing a [rebase][1]
///
/// [1]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase
///
/// It has a lifetime of the repository it is attached to.
pub struct Rebase<'repo> {
    raw: *mut raw::git_rebase,
    _marker: marker::PhantomData<&'repo Repository>,
}

/// A structure representing a single [operation][2] to be performed during the rebase.
///
/// [2]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase_operation
///
/// It has a lifetime of the rebase it belongs to.
pub struct RebaseOperation<'rebase, 'repo: 'rebase> {
    raw: *mut raw::git_rebase_operation,
    _marker: marker::PhantomData<&'rebase Rebase<'repo>>,
}

/// Type of rebase operation
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum RebaseOperationType {
    /// The given commit is to be cherry-picked.
    /// The client should commit the changes and continue if there are no conflicts.
    Pick,
    /// The given commit is to be cherry-picked, but the client should prompt
    /// the user to provide an updated commit message.
    Reword,
    /// The given commit is to be cherry-picked, but the client should stop
    /// to allow the user to edit the changes before committing them.
    Edit,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message will be merged with the previous message.
    Squash,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message from this commit will be discarded.
    FixUp,
    /// No commit will be cherry-picked.  The client should run the given
    /// command and (if successful) continue
    Exec,
}

/// A structure representing options for a `rebase`
pub struct RebaseOptions<'a> {
    /// Version of rebase options, defined by `GIT_REBASE_OPTIONS_VERSION`
    pub version: usize,

    /// this will instruct other clients working
    /// on this `rebase` that you want a quiet rebase experience.
    /// This is provided for interoperability between Git tools
    pub quiet: bool,

    /// Perform an in-memory rebase, will not updated the repository to be in a rebasing-state
    /// or modify the working directory.
    pub in_memory: bool,

    /// The name of the notes reference used to rewrite notes
    /// for rebased commits when finishing the rebase
    pub rewrite_notes_ref: Option<CString>,

    /// Options to control how trees are merged during a `rebase`.
    pub merge_options: Option<MergeOptions>,

    /// Options to control how files are written during a `rebase`.
    pub checkout_options: Option<CheckoutBuilder<'a>>,
}

impl<'repo> Rebase<'repo> {
    /// Returns the number of applied operations.
    pub fn operation_count(&self) -> usize {
        unsafe { raw::git_rebase_operation_entrycount(self.raw) }
    }

    /// Aborts a rebase that is currently in progress,
    /// resetting the repository and working directory to their state before rebase began.
    pub fn abort(&mut self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_abort(self.raw));
        }
        Ok(())
    }

    /// Commits the current patch.
    /// You must have resolved any conflicts
    /// that were introduced during the patch application from the `next` invocation.
    pub fn commit(&mut self,
                  author: &Signature,
                  committer: &Signature,
                  message: &str)
                  -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        let message = try!(CString::new(message));
        unsafe {
            try_call!(raw::git_rebase_commit(&mut raw,
                                             self.raw,
                                             author.raw(),
                                             committer.raw(),
                                             0 as *const c_char,
                                             message));
            Ok(Binding::from_raw(&raw as *const _))
        }
    }

    /// Finishes a rebase that is currently in progress once all patches have been applied.
    pub fn finish(&mut self, signature: Option<&Signature>) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_finish(self.raw,
                                             signature
                                                 .map(|s| {
                                                          s.raw() as *const raw::git_signature
                                                      })
                                                 .unwrap_or(0 as *const raw::git_signature)));
        }
        Ok(())
    }
    /// Gets the index produced by the last operation.
    /// This is useful for resolving conflicts in an in-memory rebase before committing them.
    pub fn inmemory_index(&self) -> Result<Index, Error> {
        let mut ret = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_rebase_inmemory_index(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Performs the next rebase operation and returns the `RebaseOperation` about it.
    pub fn next(&mut self) -> Result<RebaseOperation, Error> {
        let mut ret = 0 as *mut raw::git_rebase_operation;
        unsafe {
            try_call!(raw::git_rebase_next(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Gets the rebase operation specified by the given index.
    pub fn operation_at_index(&self, index: usize) -> Option<RebaseOperation> {
        unsafe {
            let ptr = raw::git_rebase_operation_byindex(self.raw, index as size_t);
            if ptr.is_null() {
                None
            } else {
                Some(Binding::from_raw(ptr))
            }
        }
    }

    /// Gets the index of the rebase operation that is currently being applied.
    /// If the first operation has not yet been applied it returns `None`.
    pub fn current_operation_index(&self) -> Option<usize> {
        unsafe {
            let index = raw::git_rebase_operation_current(self.raw);
            if index == raw::GIT_REBASE_NO_OPERATION {
                None
            } else {
                Some(index as usize)
            }
        }
    }

    /// Convenience function to get the operation at the current index.
    /// Returns none if the first operation has not yet been applied.
    pub fn current_operation(&self) -> Option<RebaseOperation> {
        if let Some(index) = self.current_operation_index() {
            self.operation_at_index(index)
        } else {
            None
        }
    }
}

impl<'repo> Binding for Rebase<'repo> {
    type Raw = *mut raw::git_rebase;
    unsafe fn from_raw(raw: *mut raw::git_rebase) -> Rebase<'repo> {
        Rebase {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase {
        self.raw
    }
}

impl<'repo> Drop for Rebase<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_rebase_free(self.raw) }
    }
}

impl<'rebase, 'repo: 'rebase> Binding for RebaseOperation<'rebase, 'repo> {
    type Raw = *mut raw::git_rebase_operation;
    unsafe fn from_raw(raw: *mut raw::git_rebase_operation) -> RebaseOperation<'rebase, 'repo> {
        RebaseOperation {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase_operation {
        self.raw
    }
}

impl<'a> RebaseOptions<'a> {
    /// Initiate default set of rebase options.
    pub fn new() -> RebaseOptions<'a> {
        RebaseOptions {
            version: raw::GIT_REBASE_OPTIONS_VERSION as usize,
            quiet: false,
            in_memory: false,
            rewrite_notes_ref: None,
            merge_options: None,
            checkout_options: None,
        }
    }

    /// raw value of options
    pub unsafe fn raw(&mut self) -> Result<raw::git_rebase_options, Error> {
        let mut checkout_options: raw::git_checkout_options = mem::zeroed();
        try_call!(raw::git_checkout_init_options(&mut checkout_options,
                                                 raw::GIT_CHECKOUT_OPTIONS_VERSION));
        if let Some(ref mut opts) = self.checkout_options {
            opts.configure(&mut checkout_options);
        }
        let mut merge_options: raw::git_merge_options = mem::zeroed();
        if let Some(ref opts) = self.merge_options {
            ptr::copy(opts.raw(), &mut merge_options, 1);
        }

        Ok(raw::git_rebase_options {
               version: self.version as c_uint,
               quiet: self.quiet as c_int,
               inmemory: self.in_memory as c_int,
               rewrite_notes_ref: ::call::convert(&self.rewrite_notes_ref),
               merge_options: merge_options,
               checkout_options: checkout_options,
           })
    }
}

impl<'rebase, 'repo: 'rebase> RebaseOperation<'rebase, 'repo> {
    /// The type of `rebase` operation
    pub fn kind(&self) -> RebaseOperationType {
        unsafe { Binding::from_raw((*self.raw).kind) }
    }

    /// The commit ID being cherry-picked.  This will be populated for
    /// all operations except those of type `Exec`
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(&(*self.raw).id as *const raw::git_oid) }
    }
    /// The executable the user has requested be run.  This will only
    /// be populated for operations of type `Exec`
    pub fn exec(&self) -> Option<CString> {
        unsafe {
            if !(*self.raw).exec.is_null() {
                Some(CString::from_raw((*self.raw).exec as *mut c_char))
            } else {
                None
            }
        }
    }
}

impl Binding for RebaseOperationType {
    type Raw = raw::git_rebase_operation_t;
    unsafe fn from_raw(raw: raw::git_rebase_operation_t) -> RebaseOperationType {
        match raw {
            raw::GIT_REBASE_OPERATION_PICK => RebaseOperationType::Pick,
            raw::GIT_REBASE_OPERATION_REWORD => RebaseOperationType::Reword,
            raw::GIT_REBASE_OPERATION_EDIT => RebaseOperationType::Edit,
            raw::GIT_REBASE_OPERATION_SQUASH => RebaseOperationType::Squash,
            raw::GIT_REBASE_OPERATION_FIXUP => RebaseOperationType::FixUp,
            raw::GIT_REBASE_OPERATION_EXEC => RebaseOperationType::Exec,
            _ => panic!("Unknown rebase operation type: {}", raw),
        }
    }

    fn raw(&self) -> raw::git_rebase_operation_t {
        match *self {
            RebaseOperationType::Pick => raw::GIT_REBASE_OPERATION_PICK,
            RebaseOperationType::Reword => raw::GIT_REBASE_OPERATION_REWORD,
            RebaseOperationType::Edit => raw::GIT_REBASE_OPERATION_EDIT,
            RebaseOperationType::Squash => raw::GIT_REBASE_OPERATION_SQUASH,
            RebaseOperationType::FixUp => raw::GIT_REBASE_OPERATION_FIXUP,
            RebaseOperationType::Exec => raw::GIT_REBASE_OPERATION_EXEC,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn smoke() {}
}
<commit_msg>Removed mut requirements for some methods<commit_after>use std::marker;
use std::ffi::CString;
use std::mem;
use std::ptr;

use libc::{c_char, size_t, c_uint, c_int};

use {raw, Error, Repository, Oid, Signature, Index, MergeOptions};
use build::CheckoutBuilder;
use util::Binding;

/// A structure representing a [rebase][1]
///
/// [1]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase
///
/// It has a lifetime of the repository it is attached to.
pub struct Rebase<'repo> {
    raw: *mut raw::git_rebase,
    _marker: marker::PhantomData<&'repo Repository>,
}

/// A structure representing a single [operation][2] to be performed during the rebase.
///
/// [2]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase_operation
///
/// It has a lifetime of the rebase it belongs to.
pub struct RebaseOperation<'rebase, 'repo: 'rebase> {
    raw: *mut raw::git_rebase_operation,
    _marker: marker::PhantomData<&'rebase Rebase<'repo>>,
}

/// Type of rebase operation
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum RebaseOperationType {
    /// The given commit is to be cherry-picked.
    /// The client should commit the changes and continue if there are no conflicts.
    Pick,
    /// The given commit is to be cherry-picked, but the client should prompt
    /// the user to provide an updated commit message.
    Reword,
    /// The given commit is to be cherry-picked, but the client should stop
    /// to allow the user to edit the changes before committing them.
    Edit,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message will be merged with the previous message.
    Squash,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message from this commit will be discarded.
    FixUp,
    /// No commit will be cherry-picked.  The client should run the given
    /// command and (if successful) continue
    Exec,
}

/// A structure representing options for a `rebase`
pub struct RebaseOptions<'a> {
    /// Version of rebase options, defined by `GIT_REBASE_OPTIONS_VERSION`
    pub version: usize,

    /// this will instruct other clients working
    /// on this `rebase` that you want a quiet rebase experience.
    /// This is provided for interoperability between Git tools
    pub quiet: bool,

    /// Perform an in-memory rebase, will not updated the repository to be in a rebasing-state
    /// or modify the working directory.
    pub in_memory: bool,

    /// The name of the notes reference used to rewrite notes
    /// for rebased commits when finishing the rebase
    pub rewrite_notes_ref: Option<CString>,

    /// Options to control how trees are merged during a `rebase`.
    pub merge_options: Option<MergeOptions>,

    /// Options to control how files are written during a `rebase`.
    pub checkout_options: Option<CheckoutBuilder<'a>>,
}

impl<'repo> Rebase<'repo> {
    /// Returns the number of applied operations.
    pub fn operation_count(&self) -> usize {
        unsafe { raw::git_rebase_operation_entrycount(self.raw) }
    }

    /// Aborts a rebase that is currently in progress,
    /// resetting the repository and working directory to their state before rebase began.
    pub fn abort(&self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_abort(self.raw));
        }
        Ok(())
    }

    /// Commits the current patch.
    /// You must have resolved any conflicts
    /// that were introduced during the patch application from the `next` invocation.
    pub fn commit(&self,
                  author: &Signature,
                  committer: &Signature,
                  message: &str)
                  -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        let message = try!(CString::new(message));
        unsafe {
            try_call!(raw::git_rebase_commit(&mut raw,
                                             self.raw,
                                             author.raw(),
                                             committer.raw(),
                                             0 as *const c_char,
                                             message));
            Ok(Binding::from_raw(&raw as *const _))
        }
    }

    /// Finishes a rebase that is currently in progress once all patches have been applied.
    pub fn finish(&self, signature: Option<&Signature>) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_finish(self.raw,
                                             signature
                                                 .map(|s| {
                                                          s.raw() as *const raw::git_signature
                                                      })
                                                 .unwrap_or(0 as *const raw::git_signature)));
        }
        Ok(())
    }
    /// Gets the index produced by the last operation.
    /// This is useful for resolving conflicts in an in-memory rebase before committing them.
    pub fn inmemory_index(&self) -> Result<Index, Error> {
        let mut ret = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_rebase_inmemory_index(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Performs the next rebase operation and returns the `RebaseOperation` about it.
    pub fn next(&mut self) -> Result<RebaseOperation, Error> {
        let mut ret = 0 as *mut raw::git_rebase_operation;
        unsafe {
            try_call!(raw::git_rebase_next(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Gets the rebase operation specified by the given index.
    pub fn operation_at_index(&self, index: usize) -> Option<RebaseOperation> {
        unsafe {
            let ptr = raw::git_rebase_operation_byindex(self.raw, index as size_t);
            if ptr.is_null() {
                None
            } else {
                Some(Binding::from_raw(ptr))
            }
        }
    }

    /// Gets the index of the rebase operation that is currently being applied.
    /// If the first operation has not yet been applied it returns `None`.
    pub fn current_operation_index(&self) -> Option<usize> {
        unsafe {
            let index = raw::git_rebase_operation_current(self.raw);
            if index == raw::GIT_REBASE_NO_OPERATION {
                None
            } else {
                Some(index as usize)
            }
        }
    }

    /// Convenience function to get the operation at the current index.
    /// Returns none if the first operation has not yet been applied.
    pub fn current_operation(&self) -> Option<RebaseOperation> {
        if let Some(index) = self.current_operation_index() {
            self.operation_at_index(index)
        } else {
            None
        }
    }
}

impl<'repo> Binding for Rebase<'repo> {
    type Raw = *mut raw::git_rebase;
    unsafe fn from_raw(raw: *mut raw::git_rebase) -> Rebase<'repo> {
        Rebase {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase {
        self.raw
    }
}

impl<'repo> Drop for Rebase<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_rebase_free(self.raw) }
    }
}

impl<'rebase, 'repo: 'rebase> Binding for RebaseOperation<'rebase, 'repo> {
    type Raw = *mut raw::git_rebase_operation;
    unsafe fn from_raw(raw: *mut raw::git_rebase_operation) -> RebaseOperation<'rebase, 'repo> {
        RebaseOperation {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase_operation {
        self.raw
    }
}

impl<'a> RebaseOptions<'a> {
    /// Initiate default set of rebase options.
    pub fn new() -> RebaseOptions<'a> {
        RebaseOptions {
            version: raw::GIT_REBASE_OPTIONS_VERSION as usize,
            quiet: false,
            in_memory: false,
            rewrite_notes_ref: None,
            merge_options: None,
            checkout_options: None,
        }
    }

    /// raw value of options
    pub unsafe fn raw(&mut self) -> Result<raw::git_rebase_options, Error> {
        let mut checkout_options: raw::git_checkout_options = mem::zeroed();
        try_call!(raw::git_checkout_init_options(&mut checkout_options,
                                                 raw::GIT_CHECKOUT_OPTIONS_VERSION));
        if let Some(ref mut opts) = self.checkout_options {
            opts.configure(&mut checkout_options);
        }
        let mut merge_options: raw::git_merge_options = mem::zeroed();
        if let Some(ref opts) = self.merge_options {
            ptr::copy(opts.raw(), &mut merge_options, 1);
        }

        Ok(raw::git_rebase_options {
               version: self.version as c_uint,
               quiet: self.quiet as c_int,
               inmemory: self.in_memory as c_int,
               rewrite_notes_ref: ::call::convert(&self.rewrite_notes_ref),
               merge_options: merge_options,
               checkout_options: checkout_options,
           })
    }
}

impl<'rebase, 'repo: 'rebase> RebaseOperation<'rebase, 'repo> {
    /// The type of `rebase` operation
    pub fn kind(&self) -> RebaseOperationType {
        unsafe { Binding::from_raw((*self.raw).kind) }
    }

    /// The commit ID being cherry-picked.  This will be populated for
    /// all operations except those of type `Exec`
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(&(*self.raw).id as *const raw::git_oid) }
    }
    /// The executable the user has requested be run.  This will only
    /// be populated for operations of type `Exec`
    pub fn exec(&self) -> Option<CString> {
        unsafe {
            if !(*self.raw).exec.is_null() {
                Some(CString::from_raw((*self.raw).exec as *mut c_char))
            } else {
                None
            }
        }
    }
}

impl Binding for RebaseOperationType {
    type Raw = raw::git_rebase_operation_t;
    unsafe fn from_raw(raw: raw::git_rebase_operation_t) -> RebaseOperationType {
        match raw {
            raw::GIT_REBASE_OPERATION_PICK => RebaseOperationType::Pick,
            raw::GIT_REBASE_OPERATION_REWORD => RebaseOperationType::Reword,
            raw::GIT_REBASE_OPERATION_EDIT => RebaseOperationType::Edit,
            raw::GIT_REBASE_OPERATION_SQUASH => RebaseOperationType::Squash,
            raw::GIT_REBASE_OPERATION_FIXUP => RebaseOperationType::FixUp,
            raw::GIT_REBASE_OPERATION_EXEC => RebaseOperationType::Exec,
            _ => panic!("Unknown rebase operation type: {}", raw),
        }
    }

    fn raw(&self) -> raw::git_rebase_operation_t {
        match *self {
            RebaseOperationType::Pick => raw::GIT_REBASE_OPERATION_PICK,
            RebaseOperationType::Reword => raw::GIT_REBASE_OPERATION_REWORD,
            RebaseOperationType::Edit => raw::GIT_REBASE_OPERATION_EDIT,
            RebaseOperationType::Squash => raw::GIT_REBASE_OPERATION_SQUASH,
            RebaseOperationType::FixUp => raw::GIT_REBASE_OPERATION_FIXUP,
            RebaseOperationType::Exec => raw::GIT_REBASE_OPERATION_EXEC,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn smoke() {}
}
<|endoftext|>


<commit_before>//! An efficient Fast Fourier transform.
//!
//! A `Transformer` must first be created to perform FFTs. The transformer
//! stores precomputed information to speed up the transform, and can only be
//! used to perform FFTs of the chosen size.
//!
//! # Example
//!
//! The following demonstrates how to use the `Transformer` to perform an
//! 8-point FFT.
//!
//! ```
//! # extern crate num;
//! # extern crate oxcable;
//! # fn main() {
//! use oxcable::utils::fft;
//!
//! // Initialize the FFT
//! let transformer = fft::Transformer::new(8);
//!
//! // Generate an input signal
//! let mut input = Vec::with_capacity(8);
//! for i in 0..8 {
//!     input.push(fft::Complex32::new(i as f32, 0.0));
//! }
//!
//! // Generate an empty output buffer
//! let mut output = vec![fft::Complex32::new(0.0, 0.0); 8];
//!
//! // Perform the FFT
//! transformer.fft(&input, &mut output);
//! # }
//! ```
//!
//! After this example, `output` will contain the FFT of `input`.

use num::traits::Zero;
use std::f32::consts::PI;

#[doc(no_inline)] pub use num::complex::Complex32;

/// A container for precomputed values to perform FFTs of a fixed size.
pub struct Transformer {
    size: usize,
    bit_reverses: Vec<usize>,
    twiddles: Vec<Complex32>,
}

impl Transformer {
    /// Initializes a transformer to perform FFTs of the provided size, rounded
    /// up to the nearest power of two.
    pub fn new(size: usize) -> Self {
        // Only operate in powers of two
        let bufsize = size.next_power_of_two();

        // Populate the bit reverses
        // We only use the lower log2(size) bits to express the index
        let mut bit_reverses = Vec::with_capacity(bufsize);
        for i in 0..size {
            let br = bit_reverse(i as u32, int_log(bufsize as u32));
            bit_reverses.push(br as usize);
        }

        // Populate the twiddle factors w_n^i
        // w_n = exp(-j*2*pi*n/N)
        let mut twiddles = Vec::with_capacity(bufsize);
        let exponent = Complex32::new(0.0, -2.0*PI/(bufsize as f32));
        for i in 0..bufsize {
            let c1 = exponent.scale(i as f32);
            let c = Complex32::new(c1.im.cos(), c1.im.sin()).scale(c1.re.exp());
            twiddles.push(c);
        }

        Transformer { size: bufsize, bit_reverses: bit_reverses,
            twiddles: twiddles }
    }

    /// Returns the size FFT this Transformer performs.
    pub fn get_size(&self) -> usize {
        self.size
    }

    /// Performs an FFT on `input`, and place the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn fft(&self, input: &[Complex32], output: &mut[Complex32]) {
        self.transform(input, output, false);
    }

    /// Performs an inverse FFT on `input`, and place the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn ifft(&self, input: &[Complex32], output: &mut[Complex32]) {
        self.transform(input, output, true);
    }

    /// Performs the actual transform on `input`, placing the result in `output`.
    ///
    /// This function performs both forward and backwards transforms, since
    /// there are only minor algorithmic differences in the beginning and end
    /// of transformation.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    fn transform(&self, input: &[Complex32], output: &mut[Complex32],
                 inverse: bool) {
        // Copy the input into bit reverse order, zero padding if necessary,
        // conjugating if we are inverse transforming
        for i in 0..input.len() {
            output[self.bit_reverses[i]] =
                if inverse {
                    input[i].conj()
                } else {
                    input[i]
                }
        }
        for i in self.bit_reverses[input.len() .. self.size].iter() {
            output[*i] = Complex32::zero();
        }

        // Iteratively perform FFT, starting at 2 points
        let mut n = 2;
        while n <= self.size {
            // For each of the small FFTs
            for set in 0..self.size/n {
                // For each pair of n
                for i in 0..n/2 {
                    let ilo = n*set + i;
                    let ihi = ilo + n/2;

                    // Grab out the lower and upper n
                    let lower = output[ilo];
                    let upper = output[ihi] * self.twiddles[self.size/n * i];

                    // Assign them back using a butterfly
                    output[ilo] = lower + upper;
                    output[ihi] = lower - upper;
                }
            }

            // Double the number of points per FFT
            n *= 2;
        }

        // If we are inverse transforming, conjugate and normalize the output
        if inverse {
            for i in 0..self.size {
                output[i] = output[i].conj().scale(1.0/(self.size as f32));
            }
        }
    }
}

/// Returns the bit reverse of `n`, for the lower `bits` bits.
///
/// For small examples, the bit reverse of 0b00011010 is 0b01011000, but the bit
/// reverse of just the lower 5 bits is 0b00001011.
fn bit_reverse(n: u32, bits: u32) -> u32 {
    let mut i = n;
    i = (i >> 16) | (i << 16);
    i = ((i & 0xFF00FF00) >> 8) | ((i & 0x00FF00FF) << 8);
    i = ((i & 0xF0F0F0F0) >> 4) | ((i & 0x0F0F0F0F) << 4);
    i = ((i & 0xCCCCCCCC) >> 2) | ((i & 0x33333333) << 2);
    i = ((i & 0xAAAAAAAA) >> 1) | ((i & 0x55555555) << 1);
    i >> ((32 - bits) as u32)
}

/// Returns the log base 2 of n, rounded up.
fn int_log(n: u32) -> u32 {
    let mut i = n-1; // correct for exact powers of 2
    let mut res = 0;
    while i > 0 {
        i = i >> 1;
        res += 1;
    }
    res
}

// Unit tests...
#[cfg(test)]
mod test {
    use num::complex::Complex32;
    use num::traits::{One, Zero};

    use testing::flt_eq;
    use super::{Transformer, int_log, bit_reverse};

    /// Tests int_log with many values
    #[test]
    fn test_int_log() {
        assert_eq!(int_log(1), 0);
        assert_eq!(int_log(2), 1);
        assert_eq!(int_log(3), 2);
        assert_eq!(int_log(4), 2);
        assert_eq!(int_log(7), 3);
        assert_eq!(int_log(8), 3);
        assert_eq!(int_log(31), 5);
        assert_eq!(int_log(32), 5);
    }

    /// Tests bit_reverse.
    #[test]
    fn test_bit_reverse() {
        assert_eq!(bit_reverse(0x00000000, 32), 0x00000000);
        assert_eq!(bit_reverse(0xFFFFFFFF, 32), 0xFFFFFFFF);
        assert_eq!(bit_reverse(0x00000001, 32), 0x80000000);
        assert_eq!(bit_reverse(0x11111111, 32), 0x88888888);
        assert_eq!(bit_reverse(0x234f9e01, 32), 0x8079f2c4); //random
        assert_eq!(bit_reverse(0x00000001, 4), 0x00000008);
        assert_eq!(bit_reverse(0x0000000F, 4), 0x0000000F);
    }

    /// Tests the FFT of an impulse function.
    ///
    /// Analytically, an impulse function has a constant fourier transform.
    #[test]
    fn test_fft_impulse() {
        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            impulse.push(if i == 0 { Complex32::one() } else { Complex32::zero() });
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&impulse, &mut out);

        for c in out.iter() {
            assert!(c.eq(&Complex32::one()))
        }
    }

    /// Tests the IFFT of an impulse function.
    ///
    /// Analytically, a constant frequency domain results in an impulse
    /// function.
    #[test]
    fn test_ifft_impulse() {
        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for _i in 0..8 {
            impulse.push(Complex32::one());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.ifft(&impulse, &mut out);

        assert!(out[0].eq(&Complex32::one()));
        for c in out[1 .. 8].iter() {
            assert!(c.eq(&Complex32::zero()));
        }
    }

    /// Tests that the identify property, i.e. IFFT(FTT(f)) == f
    #[test]
    fn test_fft_identity() {
        let mut input = Vec::with_capacity(8);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            input.push(Complex32::new((i+1) as f32, 0.0));
            fft.push(Complex32::zero());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in 0..7 {
            println!("{}",out[i].re - ((i+1) as f32));
            assert!(flt_eq(out[i].re - ((i+1) as f32), 0.0));
            assert!(flt_eq(out[i].im, 0.0));
        }
    }

    /// Tests that the Transformer properly handles input buffers that are too
    /// short by zero padding them.
    #[test]
    fn test_fft_zero_pad() {
        let mut input = Vec::with_capacity(7);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            if i < 7 {
                input.push(Complex32::new((i+1) as f32, 0.0));
            }
            fft.push(Complex32::zero());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in 0..7 {
            println!("{}",out[i].re - ((i+1) as f32));
            assert!(flt_eq(out[i].re - ((i+1) as f32), 0.0));
            assert!(flt_eq(out[i].im, 0.0));
        }
    }
}
<commit_msg>Fix indentation in fft<commit_after>//! An efficient Fast Fourier transform.
//!
//! A `Transformer` must first be created to perform FFTs. The transformer
//! stores precomputed information to speed up the transform, and can only be
//! used to perform FFTs of the chosen size.
//!
//! # Example
//!
//! The following demonstrates how to use the `Transformer` to perform an
//! 8-point FFT.
//!
//! ```
//! # extern crate num;
//! # extern crate oxcable;
//! # fn main() {
//! use oxcable::utils::fft;
//!
//! // Initialize the FFT
//! let transformer = fft::Transformer::new(8);
//!
//! // Generate an input signal
//! let mut input = Vec::with_capacity(8);
//! for i in 0..8 {
//!     input.push(fft::Complex32::new(i as f32, 0.0));
//! }
//!
//! // Generate an empty output buffer
//! let mut output = vec![fft::Complex32::new(0.0, 0.0); 8];
//!
//! // Perform the FFT
//! transformer.fft(&input, &mut output);
//! # }
//! ```
//!
//! After this example, `output` will contain the FFT of `input`.

use num::traits::Zero;
use std::f32::consts::PI;

#[doc(no_inline)] pub use num::complex::Complex32;

/// A container for precomputed values to perform FFTs of a fixed size.
pub struct Transformer {
    size: usize,
    bit_reverses: Vec<usize>,
    twiddles: Vec<Complex32>,
}

impl Transformer {
    /// Initializes a transformer to perform FFTs of the provided size, rounded
    /// up to the nearest power of two.
    pub fn new(size: usize) -> Self {
        // Only operate in powers of two
        let bufsize = size.next_power_of_two();

        // Populate the bit reverses
        // We only use the lower log2(size) bits to express the index
        let mut bit_reverses = Vec::with_capacity(bufsize);
        for i in 0..size {
            let br = bit_reverse(i as u32, int_log(bufsize as u32));
            bit_reverses.push(br as usize);
        }

        // Populate the twiddle factors w_n^i
        // w_n = exp(-j*2*pi*n/N)
        let mut twiddles = Vec::with_capacity(bufsize);
        let exponent = Complex32::new(0.0, -2.0*PI/(bufsize as f32));
        for i in 0..bufsize {
            let c1 = exponent.scale(i as f32);
            let c = Complex32::new(c1.im.cos(), c1.im.sin()).scale(c1.re.exp());
            twiddles.push(c);
        }

        Transformer {
            size: bufsize,
            bit_reverses: bit_reverses,
            twiddles: twiddles
        }
    }

    /// Returns the size FFT this Transformer performs.
    pub fn get_size(&self) -> usize {
        self.size
    }

    /// Performs an FFT on `input`, and place the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn fft(&self, input: &[Complex32], output: &mut[Complex32]) {
        self.transform(input, output, false);
    }

    /// Performs an inverse FFT on `input`, and place the result in `output`.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    pub fn ifft(&self, input: &[Complex32], output: &mut[Complex32]) {
        self.transform(input, output, true);
    }

    /// Performs the actual transform on `input`, placing the result in `output`.
    ///
    /// This function performs both forward and backwards transforms, since
    /// there are only minor algorithmic differences in the beginning and end
    /// of transformation.
    ///
    /// The input is zero padded if less than `size` samples are provided, and
    /// truncated if more than `size` samples are provided.
    fn transform(&self, input: &[Complex32], output: &mut[Complex32],
                 inverse: bool) {
        // Copy the input into bit reverse order, zero padding if necessary,
        // conjugating if we are inverse transforming
        for i in 0..input.len() {
            output[self.bit_reverses[i]] =
                if inverse {
                    input[i].conj()
                } else {
                    input[i]
                }
        }
        for i in self.bit_reverses[input.len() .. self.size].iter() {
            output[*i] = Complex32::zero();
        }

        // Iteratively perform FFT, starting at 2 points
        let mut n = 2;
        while n <= self.size {
            // For each of the small FFTs
            for set in 0..self.size/n {
                // For each pair of n
                for i in 0..n/2 {
                    let ilo = n*set + i;
                    let ihi = ilo + n/2;

                    // Grab out the lower and upper n
                    let lower = output[ilo];
                    let upper = output[ihi] * self.twiddles[self.size/n * i];

                    // Assign them back using a butterfly
                    output[ilo] = lower + upper;
                    output[ihi] = lower - upper;
                }
            }

            // Double the number of points per FFT
            n *= 2;
        }

        // If we are inverse transforming, conjugate and normalize the output
        if inverse {
            for i in 0..self.size {
                output[i] = output[i].conj().scale(1.0/(self.size as f32));
            }
        }
    }
}

/// Returns the bit reverse of `n`, for the lower `bits` bits.
///
/// For small examples, the bit reverse of 0b00011010 is 0b01011000, but the bit
/// reverse of just the lower 5 bits is 0b00001011.
fn bit_reverse(n: u32, bits: u32) -> u32 {
    let mut i = n;
    i = (i >> 16) | (i << 16);
    i = ((i & 0xFF00FF00) >> 8) | ((i & 0x00FF00FF) << 8);
    i = ((i & 0xF0F0F0F0) >> 4) | ((i & 0x0F0F0F0F) << 4);
    i = ((i & 0xCCCCCCCC) >> 2) | ((i & 0x33333333) << 2);
    i = ((i & 0xAAAAAAAA) >> 1) | ((i & 0x55555555) << 1);
    i >> ((32 - bits) as u32)
}

/// Returns the log base 2 of n, rounded up.
fn int_log(n: u32) -> u32 {
    let mut i = n-1; // correct for exact powers of 2
    let mut res = 0;
    while i > 0 {
        i = i >> 1;
        res += 1;
    }
    res
}

// Unit tests...
#[cfg(test)]
mod test {
    use num::complex::Complex32;
    use num::traits::{One, Zero};

    use testing::flt_eq;
    use super::{Transformer, int_log, bit_reverse};

    /// Tests int_log with many values
    #[test]
    fn test_int_log() {
        assert_eq!(int_log(1), 0);
        assert_eq!(int_log(2), 1);
        assert_eq!(int_log(3), 2);
        assert_eq!(int_log(4), 2);
        assert_eq!(int_log(7), 3);
        assert_eq!(int_log(8), 3);
        assert_eq!(int_log(31), 5);
        assert_eq!(int_log(32), 5);
    }

    /// Tests bit_reverse.
    #[test]
    fn test_bit_reverse() {
        assert_eq!(bit_reverse(0x00000000, 32), 0x00000000);
        assert_eq!(bit_reverse(0xFFFFFFFF, 32), 0xFFFFFFFF);
        assert_eq!(bit_reverse(0x00000001, 32), 0x80000000);
        assert_eq!(bit_reverse(0x11111111, 32), 0x88888888);
        assert_eq!(bit_reverse(0x234f9e01, 32), 0x8079f2c4); //random
        assert_eq!(bit_reverse(0x00000001, 4), 0x00000008);
        assert_eq!(bit_reverse(0x0000000F, 4), 0x0000000F);
    }

    /// Tests the FFT of an impulse function.
    ///
    /// Analytically, an impulse function has a constant fourier transform.
    #[test]
    fn test_fft_impulse() {
        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            impulse.push(if i == 0 { Complex32::one() } else { Complex32::zero() });
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&impulse, &mut out);

        for c in out.iter() {
            assert!(c.eq(&Complex32::one()))
        }
    }

    /// Tests the IFFT of an impulse function.
    ///
    /// Analytically, a constant frequency domain results in an impulse
    /// function.
    #[test]
    fn test_ifft_impulse() {
        let mut impulse = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for _i in 0..8 {
            impulse.push(Complex32::one());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.ifft(&impulse, &mut out);

        assert!(out[0].eq(&Complex32::one()));
        for c in out[1 .. 8].iter() {
            assert!(c.eq(&Complex32::zero()));
        }
    }

    /// Tests that the identify property, i.e. IFFT(FTT(f)) == f
    #[test]
    fn test_fft_identity() {
        let mut input = Vec::with_capacity(8);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            input.push(Complex32::new((i+1) as f32, 0.0));
            fft.push(Complex32::zero());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in 0..7 {
            println!("{}",out[i].re - ((i+1) as f32));
            assert!(flt_eq(out[i].re - ((i+1) as f32), 0.0));
            assert!(flt_eq(out[i].im, 0.0));
        }
    }

    /// Tests that the Transformer properly handles input buffers that are too
    /// short by zero padding them.
    #[test]
    fn test_fft_zero_pad() {
        let mut input = Vec::with_capacity(7);
        let mut fft = Vec::with_capacity(8);
        let mut out = Vec::with_capacity(8);
        for i in 0..8 {
            if i < 7 {
                input.push(Complex32::new((i+1) as f32, 0.0));
            }
            fft.push(Complex32::zero());
            out.push(Complex32::zero());
        }

        let t = Transformer::new(8);
        t.fft(&input, &mut fft);
        t.ifft(&fft, &mut out);

        for i in 0..7 {
            println!("{}",out[i].re - ((i+1) as f32));
            assert!(flt_eq(out[i].re - ((i+1) as f32), 0.0));
            assert!(flt_eq(out[i].im, 0.0));
        }
    }
}
<|endoftext|>


<commit_before>//! Running of programs.

use parser::Instruction;
use std;

///
/// A runner of programs.
///
#[derive(Default)]
pub struct Runner {
    /// Program to be run.
    prog: Vec<Instruction>,
    /// A potentially infinite number of data cells.
    data: Vec<u8>,
    /// Instruction pointer (index).
    ip: usize,
    /// Data-cell pointer (index).
    dp: usize,
}

impl Runner {
    ///
    /// Constructs a new runner.
    ///
    pub fn new() -> Self {
        Runner::default()
    }

    ///
    /// Runs the given program.
    ///
    /// # Arguments
    ///
    /// * `prog` - Program to be run.
    /// * `input` - Input for the program.
    /// * `output` - Output for the program.
    ///
    pub fn run(&mut self,
               prog: Vec<Instruction>,
               mut input: &mut std::io::Read,
               mut output: &mut std::io::Write)
               -> Result<(), String> {
        self.prog = prog;
        self.data.clear();
        self.ip = 0;
        self.dp = 0;

        while !self.is_prog_end() {
            try!(self.run_instruction(&mut input, &mut output));
        }

        Ok(())
    }

    fn is_prog_end(&self) -> bool {
        self.ip >= self.prog.len()
    }

    fn run_instruction(&mut self,
                       mut input: &mut std::io::Read,
                       mut output: &mut std::io::Write)
                       -> Result<(), String> {
        match self.prog[self.ip] {
            Instruction::Next => {
                self.dp += 1;
            }
            Instruction::Prev => {
                self.dp -= 1;
            }
            Instruction::Inc => {
                let value = self.load_value();
                self.store_value(value.wrapping_add(1));
            }
            Instruction::Dec => {
                let value = self.load_value();
                self.store_value(value.wrapping_sub(1));
            }
            Instruction::Read => {
                let value = try!(self.read_value(&mut input));
                self.store_value(value);
            }
            Instruction::Write => {
                let value = self.load_value();
                try!(self.write_value(&mut output, value));
            }
            Instruction::LoopStart(loop_end_ip) => {
                if self.is_current_cell_zero() {
                    self.ip = loop_end_ip;
                }
            }
            Instruction::LoopEnd(loop_start_ip) => {
                if !self.is_current_cell_zero() {
                    self.ip = loop_start_ip;
                }
            }
        }
        self.ip += 1;
        Ok(())
    }

    fn load_value(&mut self) -> u8 {
        self.ensure_current_cell_is_accessible();
        self.data[self.dp]
    }

    fn store_value(&mut self, value: u8) {
        self.ensure_current_cell_is_accessible();
        self.data[self.dp] = value;
    }

    fn read_value(&self, mut input: &mut std::io::Read) -> Result<u8, String> {
        let mut buf = [0u8];
        match input.read_exact(&mut buf) {
            Err(err) => Err(
                format!("reading of a value failed (reason: {})", err)
            ),
            Ok(_) => Ok(buf[0]),
        }
    }

    fn write_value(&self, mut output: &mut std::io::Write, value: u8) -> Result<(), String> {
        match output.write(&[value]) {
            Err(err) => Err(
                format!("writing of a value failed (reason: {})", err)
            ),
            Ok(_) => Ok(()),
        }
    }

    fn is_current_cell_zero(&mut self) -> bool {
        self.load_value() == 0
    }

    fn ensure_current_cell_is_accessible(&mut self) {
        let cell_count = self.data.len();
        if self.dp >= cell_count {
            for _ in 0..(self.dp - cell_count + 1) {
                self.data.push(0);
            }
        }
    }
}

///
/// Runs the given program.
///
/// # Arguments
///
/// * `prog` - Program to be run.
/// * `input` - Input for the program.
/// * `output` - Output for the program.
///
pub fn run(prog: Vec<Instruction>,
           mut input: &mut std::io::Read,
           mut output: &mut std::io::Write)
           -> Result<(), String> {
    let mut runner = Runner::new();
    runner.run(prog, &mut input, &mut output)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std;
    use parser::Instruction;

    fn assert_run_writes_correct_output(prog: Vec<Instruction>,
                                        input: &[u8],
                                        expected_output: &[u8]) {
        let mut output = Vec::new();
        {
            let mut input_reader = std::io::BufReader::new(input.as_ref());
            let mut output_writer = std::io::BufWriter::new(&mut output);
            run(prog, &mut input_reader, &mut output_writer).unwrap();
        }

        assert_eq!(output, expected_output);
    }

    #[test]
    fn test_run_does_nothing_when_program_has_no_instructions() {
        assert_run_writes_correct_output(
            vec![],
            &[],
            &[]
        );
    }

    #[test]
    fn test_run_can_read_from_input_and_write_to_output() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Write
            ],
            &[1],
            &[1]
        );
    }

    #[test]
    fn test_run_can_increment_cell() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Inc,
                Instruction::Write,
            ],
            &[1],
            &[2]
        );
    }

    #[test]
    fn test_run_can_decrement_cell() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Dec,
                Instruction::Write,
            ],
            &[1],
            &[0]
        );
    }

    #[test]
    fn test_run_can_move_between_cells() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Next,
                Instruction::Read,
                Instruction::Next,
                Instruction::Prev,
                Instruction::Write,
                Instruction::Prev,
                Instruction::Write,
            ],
            &[1, 2],
            &[2, 1]
        );
    }

    #[test]
    fn test_run_can_loop() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::LoopStart(6),
                Instruction::Dec,
                Instruction::Next,
                Instruction::Inc,
                Instruction::Prev,
                Instruction::LoopEnd(1),
                Instruction::Write,
                Instruction::Next,
                Instruction::Write
            ],
            &[2],
            &[0, 2]
        );
    }
}
<commit_msg>Properly handle end of input.<commit_after>//! Running of programs.

use parser::Instruction;
use std;

///
/// A runner of programs.
///
#[derive(Default)]
pub struct Runner {
    /// Program to be run.
    prog: Vec<Instruction>,
    /// A potentially infinite number of data cells.
    data: Vec<u8>,
    /// Instruction pointer (index).
    ip: usize,
    /// Data-cell pointer (index).
    dp: usize,
}

impl Runner {
    ///
    /// Constructs a new runner.
    ///
    pub fn new() -> Self {
        Runner::default()
    }

    ///
    /// Runs the given program.
    ///
    /// # Arguments
    ///
    /// * `prog` - Program to be run.
    /// * `input` - Input for the program.
    /// * `output` - Output for the program.
    ///
    pub fn run(&mut self,
               prog: Vec<Instruction>,
               mut input: &mut std::io::Read,
               mut output: &mut std::io::Write)
               -> Result<(), String> {
        self.prog = prog;
        self.data.clear();
        self.ip = 0;
        self.dp = 0;

        while !self.is_prog_end() {
            try!(self.run_instruction(&mut input, &mut output));
        }

        Ok(())
    }

    fn is_prog_end(&self) -> bool {
        self.ip >= self.prog.len()
    }

    fn run_instruction(&mut self,
                       mut input: &mut std::io::Read,
                       mut output: &mut std::io::Write)
                       -> Result<(), String> {
        match self.prog[self.ip] {
            Instruction::Next => {
                self.dp += 1;
            }
            Instruction::Prev => {
                self.dp -= 1;
            }
            Instruction::Inc => {
                let value = self.load_value();
                self.store_value(value.wrapping_add(1));
            }
            Instruction::Dec => {
                let value = self.load_value();
                self.store_value(value.wrapping_sub(1));
            }
            Instruction::Read => {
                let value = try!(self.read_value(&mut input));
                self.store_value(value);
            }
            Instruction::Write => {
                let value = self.load_value();
                try!(self.write_value(&mut output, value));
            }
            Instruction::LoopStart(loop_end_ip) => {
                if self.is_current_cell_zero() {
                    self.ip = loop_end_ip;
                }
            }
            Instruction::LoopEnd(loop_start_ip) => {
                if !self.is_current_cell_zero() {
                    self.ip = loop_start_ip;
                }
            }
        }
        self.ip += 1;
        Ok(())
    }

    fn load_value(&mut self) -> u8 {
        self.ensure_current_cell_is_accessible();
        self.data[self.dp]
    }

    fn store_value(&mut self, value: u8) {
        self.ensure_current_cell_is_accessible();
        self.data[self.dp] = value;
    }

    fn read_value(&self, mut input: &mut std::io::Read) -> Result<u8, String> {
        let mut buf = [0u8];
        match input.read_exact(&mut buf) {
            Err(err) => match err.kind() {
                // There are multiple ways of dealing with EOF. We have chosen
                // to return 0.
                std::io::ErrorKind::UnexpectedEof => Ok(0),
                _ => Err(format!("reading of a value failed (reason: {:?})", err.kind())),
            },
            Ok(_) => Ok(buf[0]),
        }
    }

    fn write_value(&self, mut output: &mut std::io::Write, value: u8) -> Result<(), String> {
        match output.write(&[value]) {
            Err(err) => Err(
                format!("writing of a value failed (reason: {})", err)
            ),
            Ok(_) => Ok(()),
        }
    }

    fn is_current_cell_zero(&mut self) -> bool {
        self.load_value() == 0
    }

    fn ensure_current_cell_is_accessible(&mut self) {
        let cell_count = self.data.len();
        if self.dp >= cell_count {
            for _ in 0..(self.dp - cell_count + 1) {
                self.data.push(0);
            }
        }
    }
}

///
/// Runs the given program.
///
/// # Arguments
///
/// * `prog` - Program to be run.
/// * `input` - Input for the program.
/// * `output` - Output for the program.
///
pub fn run(prog: Vec<Instruction>,
           mut input: &mut std::io::Read,
           mut output: &mut std::io::Write)
           -> Result<(), String> {
    let mut runner = Runner::new();
    runner.run(prog, &mut input, &mut output)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std;
    use parser::Instruction;

    fn assert_run_writes_correct_output(prog: Vec<Instruction>,
                                        input: &[u8],
                                        expected_output: &[u8]) {
        let mut output = Vec::new();
        {
            let mut input_reader = std::io::BufReader::new(input.as_ref());
            let mut output_writer = std::io::BufWriter::new(&mut output);
            run(prog, &mut input_reader, &mut output_writer).unwrap();
        }

        assert_eq!(output, expected_output);
    }

    #[test]
    fn test_run_does_nothing_when_program_has_no_instructions() {
        assert_run_writes_correct_output(
            vec![],
            &[],
            &[]
        );
    }

    #[test]
    fn test_run_can_read_from_input_and_write_to_output() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Write
            ],
            &[1],
            &[1]
        );
    }

    #[test]
    fn test_read_stores_zero_when_at_end_of_file() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Write
            ],
            &[],
            &[0]
        );
    }

    #[test]
    fn test_run_can_increment_cell() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Inc,
                Instruction::Write,
            ],
            &[1],
            &[2]
        );
    }

    #[test]
    fn test_run_can_decrement_cell() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Dec,
                Instruction::Write,
            ],
            &[1],
            &[0]
        );
    }

    #[test]
    fn test_run_can_move_between_cells() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::Next,
                Instruction::Read,
                Instruction::Next,
                Instruction::Prev,
                Instruction::Write,
                Instruction::Prev,
                Instruction::Write,
            ],
            &[1, 2],
            &[2, 1]
        );
    }

    #[test]
    fn test_run_can_loop() {
        assert_run_writes_correct_output(
            vec![
                Instruction::Read,
                Instruction::LoopStart(6),
                Instruction::Dec,
                Instruction::Next,
                Instruction::Inc,
                Instruction::Prev,
                Instruction::LoopEnd(1),
                Instruction::Write,
                Instruction::Next,
                Instruction::Write
            ],
            &[2],
            &[0, 2]
        );
    }

    #[test]
    fn test_copies_input_to_output() {
        assert_run_writes_correct_output(
            vec![
                // Read the whole input:
                Instruction::Next,
                Instruction::Inc,
                Instruction::LoopStart(5),
                Instruction::Next,
                Instruction::Read,
                Instruction::LoopEnd(2),
                // Rewind to the beginning:
                Instruction::Prev,
                Instruction::LoopStart(9),
                Instruction::Prev,
                Instruction::LoopEnd(7),
                // Write the whole input:
                Instruction::Next,
                Instruction::Next,
                Instruction::LoopStart(15),
                Instruction::Write,
                Instruction::Next,
                Instruction::LoopEnd(12)
            ],
            &[4, 3, 1, 5],
            &[4, 3, 1, 5]
        );
    }
}
<|endoftext|>


<commit_before>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use sdl2::pixels::Color;
use sdl2::render::Renderer;

const PLAYER_SPEED: f64 = 150.0;
const CHARACTER_W: f64 = 56.0;
const CHARACTER_H: f64 = 43.0;

const TERRAIN_W: f64 = 102.0;
const TERRAIN_H: f64 = 67.0;

#[derive(Clone)]
struct Background {
  pos: f64,
  sprite: Sprite,
}

impl Background {
  fn render(&mut self, renderer: &mut Renderer) {
    let size = self.sprite.size();

    let (window_w, window_h) = renderer.output_size().unwrap();
    let scale = window_h as f64 / size.1;
    renderer.copy_sprite(&self.sprite, Rectangle {
      x: 0.0,
      y: 0.0,
      w: size.0,
      h: window_h as f64,
    })
  }
}

#[derive(Clone, Copy)]
enum CharacterFrame {
  Down = 0,
  DownLeft = 1,
  Left = 2,
  UpLeft = 3,
  Up = 4,
  UpRight = 5,
  Right = 6,
  DownRight = 7
}

#[derive(Clone, Copy)]
enum TerrainFrame {
  Sand = 0,
  Grass = 1,
  Water = 2,
  Wood = 3,
}

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
}

struct TerrainTile {
  rect: Rectangle,
  terrain_sprites: Vec<Sprite>,
  current: TerrainFrame,
}

pub struct GameView {
  player: Character,
  tiles: TerrainTile,
  background: Background,
}

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/warrior.png").unwrap();
    let terrain_spritesheet = Sprite::load(&mut game.renderer, "assets/terrain.png").unwrap();
    let mut sprites = Vec::with_capacity(9);
    let mut terrain_sprites = Vec::with_capacity(4);

    for x in 0..3 {
      terrain_sprites.push(terrain_spritesheet.region(Rectangle {
        w: TERRAIN_W,
        h: TERRAIN_H,
        x: TERRAIN_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }

    for x in 0..8 {
      sprites.push(spritesheet.region(Rectangle {
        w: CHARACTER_W,
        h: CHARACTER_H,
        x: CHARACTER_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }
    GameView {
      player: Character {
        rect: Rectangle {
          x: 64.0,
          y: 64.0,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites,
        current: CharacterFrame::Down,
      },

      tiles: TerrainTile {
        rect: Rectangle {
          x: 102.0,
          y: 64.0,
          w: TERRAIN_W,
          h: TERRAIN_H,
        },
        terrain_sprites: terrain_sprites,
        current: TerrainFrame::Grass,
      },

      background: Background {
        pos: 0.0,
        sprite: Sprite::load(&mut game.renderer, "assets/background.png").unwrap(),
      },
    }
  }
}

impl View for GameView {
  fn render(&mut self, game: &mut Game, elapsed: f64) -> ViewAction {
    if game.events.now.quit || game.events.now.key_escape == Some(true) {
      return ViewAction::Quit;
    }

    let diagonal = (game.events.key_up ^ game.events.key_down) && (game.events.key_left ^ game.events.key_right);
    let moved = if diagonal { 1.0 / 2.0f64.sqrt() } else { 1.0 } * PLAYER_SPEED * elapsed;
    let dx = match (game.events.key_left, game.events.key_right) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    let dy = match (game.events.key_up, game.events.key_down) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    self.player.rect.x += dx;
    self.player.rect.y += dy;

    let movable_region = Rectangle {
      x: 0.0,
      y: 0.0,
      w: game.output_size().0 * 0.70,
      h: game.output_size().1,
    };

    self.player.rect = self.player.rect.move_inside(movable_region).unwrap();
    self.player.current =
    if dx == 0.0 && dy < 0.0       { CharacterFrame::Up }
    else if dx > 0.0 && dy < 0.0   { CharacterFrame::UpRight }
    else if dx < 0.0 && dy < 0.0   { CharacterFrame::UpLeft }
    else if dx == 0.0 && dy == 0.0 { CharacterFrame::Down }
    else if dx > 0.0 && dy == 0.0  { CharacterFrame::Right }
    else if dx < 0.0 && dy == 0.0  { CharacterFrame::Left }
    else if dx == 0.0 && dy > 0.0  { CharacterFrame::Down }
    else if dx > 0.0 && dy > 0.0   { CharacterFrame::DownRight }
    else if dx < 0.0 && dy > 0.0   { CharacterFrame::DownLeft }
    else { unreachable!() };

    game.renderer.set_draw_color(Color::RGB(0, 0, 0));
    game.renderer.clear();

    // background
    self.background.render(&mut game.renderer);

    // player
    game.renderer.set_draw_color(Color::RGB(119,119,119));
    game.renderer.fill_rect(self.player.rect.to_sdl().unwrap());
    game.renderer.copy_sprite(&self.player.sprites[self.player.current as usize], self.player.rect);

    // tile
    game.renderer.set_draw_color(Color::RGBA(120, 120, 120, 1));
    game.renderer.fill_rect(self.tiles.rect.to_sdl().unwrap());
    game.renderer.copy_sprite(&self.tiles.terrain_sprites[self.tiles.current as usize], self.tiles.rect);

    ViewAction::None
  }
}
<commit_msg>Render multiple tiles<commit_after>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use sdl2::pixels::Color;
use sdl2::render::Renderer;

const PLAYER_SPEED: f64 = 150.0;
const CHARACTER_W: f64 = 56.0;
const CHARACTER_H: f64 = 43.0;

const TERRAIN_W: f64 = 102.0;
const TERRAIN_H: f64 = 67.0;

#[derive(Clone)]
struct Background {
  pos: f64,
  sprite: Sprite,
}

impl Background {
  fn render(&mut self, renderer: &mut Renderer) {
    let size = self.sprite.size();

    let (window_w, window_h) = renderer.output_size().unwrap();
    let scale = window_h as f64 / size.1;
    renderer.copy_sprite(&self.sprite, Rectangle {
      x: 0.0,
      y: 0.0,
      w: size.0,
      h: window_h as f64,
    })
  }
}

#[derive(Clone, Copy)]
enum CharacterFrame {
  Down = 0,
  DownLeft = 1,
  Left = 2,
  UpLeft = 3,
  Up = 4,
  UpRight = 5,
  Right = 6,
  DownRight = 7
}

#[derive(Clone, Copy)]
enum TerrainFrame {
  Sand = 0,
  Grass = 1,
  Water = 2,
  Wood = 3,
}

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
}

struct TerrainTile {
  rect: Rectangle,
  terrain_sprites: Vec<Sprite>,
  current: TerrainFrame,
}

pub struct GameView {
  player: Character,
  tiles: Vec<TerrainTile>,
  background: Background,
}

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/warrior.png").unwrap();
    let terrain_spritesheet = Sprite::load(&mut game.renderer, "assets/terrain.png").unwrap();
    let mut sprites = Vec::with_capacity(9);
    let mut terrain_sprites = Vec::with_capacity(4);
    let mut tiles = Vec::with_capacity(4);

    for x in 0..3 {
      terrain_sprites.push(terrain_spritesheet.region(Rectangle {
        w: TERRAIN_W,
        h: TERRAIN_H,
        x: TERRAIN_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }

    for x in 0..8 {
      sprites.push(spritesheet.region(Rectangle {
        w: CHARACTER_W,
        h: CHARACTER_H,
        x: CHARACTER_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }

    for x in 0..4 {
      tiles.push(TerrainTile {
        rect: Rectangle {
          x: 102.0 * x as f64,
          y: 64.0,
          w: TERRAIN_W,
          h: TERRAIN_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Grass,
      });
    }

    GameView {
      player: Character {
        rect: Rectangle {
          x: 64.0,
          y: 64.0,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites,
        current: CharacterFrame::Down,
      },

      tiles: tiles,

      background: Background {
        pos: 0.0,
        sprite: Sprite::load(&mut game.renderer, "assets/background.png").unwrap(),
      },
    }
  }
}

impl View for GameView {
  fn render(&mut self, game: &mut Game, elapsed: f64) -> ViewAction {
    if game.events.now.quit || game.events.now.key_escape == Some(true) {
      return ViewAction::Quit;
    }

    let diagonal = (game.events.key_up ^ game.events.key_down) && (game.events.key_left ^ game.events.key_right);
    let moved = if diagonal { 1.0 / 2.0f64.sqrt() } else { 1.0 } * PLAYER_SPEED * elapsed;
    let dx = match (game.events.key_left, game.events.key_right) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    let dy = match (game.events.key_up, game.events.key_down) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    self.player.rect.x += dx;
    self.player.rect.y += dy;

    let movable_region = Rectangle {
      x: 0.0,
      y: 0.0,
      w: game.output_size().0 * 0.70,
      h: game.output_size().1,
    };

    self.player.rect = self.player.rect.move_inside(movable_region).unwrap();
    self.player.current =
    if dx == 0.0 && dy < 0.0       { CharacterFrame::Up }
    else if dx > 0.0 && dy < 0.0   { CharacterFrame::UpRight }
    else if dx < 0.0 && dy < 0.0   { CharacterFrame::UpLeft }
    else if dx == 0.0 && dy == 0.0 { CharacterFrame::Down }
    else if dx > 0.0 && dy == 0.0  { CharacterFrame::Right }
    else if dx < 0.0 && dy == 0.0  { CharacterFrame::Left }
    else if dx == 0.0 && dy > 0.0  { CharacterFrame::Down }
    else if dx > 0.0 && dy > 0.0   { CharacterFrame::DownRight }
    else if dx < 0.0 && dy > 0.0   { CharacterFrame::DownLeft }
    else { unreachable!() };

    game.renderer.set_draw_color(Color::RGB(0, 0, 0));
    game.renderer.clear();

    // background
    self.background.render(&mut game.renderer);

    // player
    game.renderer.set_draw_color(Color::RGB(119,119,119));
    game.renderer.fill_rect(self.player.rect.to_sdl().unwrap());
    game.renderer.copy_sprite(&self.player.sprites[self.player.current as usize], self.player.rect);

    // tile
    game.renderer.set_draw_color(Color::RGBA(120, 120, 120, 1));
    for x in 0..4 {
      game.renderer.fill_rect(self.tiles[x].rect.to_sdl().unwrap());
      game.renderer.copy_sprite(&self.tiles[x].terrain_sprites[self.tiles[x].current as usize], self.tiles[x].rect);
    }
    ViewAction::None
  }
}
<|endoftext|>