<commit_before>// Copyright (c) 2019, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::iter;

use crate::keytypes::User;
use crate::Keyring;

use super::utils;
use super::utils::kernel::*;
use super::utils::keys::*;

#[test]
fn empty_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<EmptyKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn unsupported_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<UnsupportedKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<InvalidKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EPERM));

    keyring.invalidate().unwrap()
}

#[test]
fn maxlen_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<MaxLenKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<OverlongKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn keyring_with_payload() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring
        .add_key::<KeyringShadow, _, _>("", "payload")
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn max_user_description() {
    let mut keyring = utils::new_test_keyring();
    // Subtract one because the NUL is added in the kernel API.
    let maxdesc: String = iter::repeat('a').take(*PAGE_SIZE - 1).collect();
    let res = keyring.add_key::<User, _, _>(maxdesc.as_ref(), "payload".as_bytes());
    // If the user's quota is smaller than this, it's an error.
    if KEY_INFO.maxbytes < *PAGE_SIZE {
        assert_eq!(res.unwrap_err(), errno::Errno(libc::EDQUOT));
    } else {
        let key = res.unwrap();
        assert_eq!(key.description().unwrap().description, maxdesc);
        key.invalidate().unwrap();
    }

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_user_description() {
    let mut keyring = utils::new_test_keyring();
    // On MIPS with < 3.19, there is a bug where this is allowed. 3.19 was released in Feb 2015,
    // so this is being ignored here.
    let toolarge: String = iter::repeat('a').take(*PAGE_SIZE).collect();
    let err = keyring
        .add_key::<User, _, _>(toolarge.as_ref(), "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_keyring() {
    let mut keyring = utils::invalid_keyring();
    let err = keyring
        .add_key::<User, _, _>("invalid_keyring", "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));
}

#[test]
fn add_key_to_non_keyring() {
    let mut keyring = utils::new_test_keyring();
    let expected = "stuff".as_bytes();
    let key = keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap();

    let mut not_a_keyring = unsafe { Keyring::new(key.serial()) };
    let err = not_a_keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENOTDIR));

    keyring.invalidate().unwrap()
}

#[test]
fn add_key() {
    let mut keyring = utils::new_test_keyring();

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>("add_key", payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}

#[test]
fn update_key_via_add() {
    let mut keyring = utils::new_test_keyring();

    let description = "update_key_via_add";

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    let payload = "updated_payload".as_bytes();
    let key_updated = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key, key_updated);
    assert_eq!(key.read().unwrap(), payload);
    assert_eq!(key_updated.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}
<commit_msg>tests/add: use a utility function to transform a keyring<commit_after>// Copyright (c) 2019, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::iter;

use crate::keytypes::User;

use super::utils;
use super::utils::kernel::*;
use super::utils::keys::*;

#[test]
fn empty_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<EmptyKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn unsupported_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<UnsupportedKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<InvalidKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EPERM));

    keyring.invalidate().unwrap()
}

#[test]
fn maxlen_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<MaxLenKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<OverlongKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn keyring_with_payload() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring
        .add_key::<KeyringShadow, _, _>("", "payload")
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn max_user_description() {
    let mut keyring = utils::new_test_keyring();
    // Subtract one because the NUL is added in the kernel API.
    let maxdesc: String = iter::repeat('a').take(*PAGE_SIZE - 1).collect();
    let res = keyring.add_key::<User, _, _>(maxdesc.as_ref(), "payload".as_bytes());
    // If the user's quota is smaller than this, it's an error.
    if KEY_INFO.maxbytes < *PAGE_SIZE {
        assert_eq!(res.unwrap_err(), errno::Errno(libc::EDQUOT));
    } else {
        let key = res.unwrap();
        assert_eq!(key.description().unwrap().description, maxdesc);
        key.invalidate().unwrap();
    }

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_user_description() {
    let mut keyring = utils::new_test_keyring();
    // On MIPS with < 3.19, there is a bug where this is allowed. 3.19 was released in Feb 2015,
    // so this is being ignored here.
    let toolarge: String = iter::repeat('a').take(*PAGE_SIZE).collect();
    let err = keyring
        .add_key::<User, _, _>(toolarge.as_ref(), "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_keyring() {
    let mut keyring = utils::invalid_keyring();
    let err = keyring
        .add_key::<User, _, _>("invalid_keyring", "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));
}

#[test]
fn add_key_to_non_keyring() {
    let mut keyring = utils::new_test_keyring();
    let expected = "stuff".as_bytes();
    let key = keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap();

    let mut not_a_keyring = utils::key_as_keyring(&key);
    let err = not_a_keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENOTDIR));

    keyring.invalidate().unwrap()
}

#[test]
fn add_key() {
    let mut keyring = utils::new_test_keyring();

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>("add_key", payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}

#[test]
fn update_key_via_add() {
    let mut keyring = utils::new_test_keyring();

    let description = "update_key_via_add";

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    let payload = "updated_payload".as_bytes();
    let key_updated = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key, key_updated);
    assert_eq!(key.read().unwrap(), payload);
    assert_eq!(key_updated.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::thread;
use std::path::PathBuf;

use git2;
use url::Url;

fn root() -> PathBuf {
    env::current_dir().unwrap().join("tmp").join(thread::current().name().unwrap())
}

pub fn checkout() -> PathBuf { root().join("checkout") }
pub fn bare() -> PathBuf { root().join("bare") }

pub fn init() {
    let _ = fs::remove_dir_all(&checkout());
    let _ = fs::remove_dir_all(&bare());
    // Prepare a bare remote repo
    {
        let bare = git2::Repository::init_bare(&bare()).unwrap();
        let mut config = bare.config().unwrap();
        config.set_str("user.name", "name").unwrap();
        config.set_str("user.email", "email").unwrap();
    }

    // Initialize a fresh checkout
    let checkout = git2::Repository::init(&checkout()).unwrap();
    let url = Url::from_file_path(&*bare()).ok().unwrap().to_string();

    // Setup the `origin` remote
    let mut origin = checkout.remote("origin", url.as_slice()).unwrap();
    origin.set_pushurl(Some(url.as_slice())).unwrap();
    origin.add_push("refs/heads/master").unwrap();
    origin.save().unwrap();

    // Create an empty initial commit
    let mut config = checkout.config().unwrap();
    config.set_str("user.name", "name").unwrap();
    config.set_str("user.email", "email").unwrap();
    let mut index = checkout.index().unwrap();
    let id = index.write_tree().unwrap();
    let tree = checkout.find_tree(id).unwrap();
    let sig = checkout.signature().unwrap();
    checkout.commit(Some("HEAD"), &sig, &sig,
                    "Initial Commit",
                    &tree, &[]).unwrap();

    // Push the commit to the remote repo
    let mut origin = checkout.find_remote("origin").unwrap();
    let mut push = origin.push().unwrap();
    push.add_refspec("refs/heads/master").unwrap();
    push.finish().unwrap();
    assert!(!push.statuses().unwrap().iter().any(|s| s.message.is_some()));
    push.update_tips(None, None).unwrap();

    // Set up master to track origin/master
    let branch = checkout.find_reference("refs/heads/master");
    let mut branch = git2::Branch::wrap(branch.unwrap());
    branch.set_upstream(Some("origin/master")).unwrap();

}
<commit_msg>Fix a race in tests on a clean build dir<commit_after>use std::fs;
use std::env;
use std::thread;
use std::path::PathBuf;
use std::sync::{Once, ONCE_INIT};

use git2;
use url::Url;

fn root() -> PathBuf {
    env::current_dir().unwrap().join("tmp").join(thread::current().name().unwrap())
}

pub fn checkout() -> PathBuf { root().join("checkout") }
pub fn bare() -> PathBuf { root().join("bare") }

pub fn init() {
    static INIT: Once = ONCE_INIT;
    let _ = fs::remove_dir_all(&checkout());
    let _ = fs::remove_dir_all(&bare());

    INIT.call_once(|| {
        fs::create_dir_all(root().parent().unwrap()).unwrap();
    });

    // Prepare a bare remote repo
    {
        let bare = git2::Repository::init_bare(&bare()).unwrap();
        let mut config = bare.config().unwrap();
        config.set_str("user.name", "name").unwrap();
        config.set_str("user.email", "email").unwrap();
    }

    // Initialize a fresh checkout
    let checkout = git2::Repository::init(&checkout()).unwrap();
    let url = Url::from_file_path(&*bare()).ok().unwrap().to_string();

    // Setup the `origin` remote
    let mut origin = checkout.remote("origin", url.as_slice()).unwrap();
    origin.set_pushurl(Some(url.as_slice())).unwrap();
    origin.add_push("refs/heads/master").unwrap();
    origin.save().unwrap();

    // Create an empty initial commit
    let mut config = checkout.config().unwrap();
    config.set_str("user.name", "name").unwrap();
    config.set_str("user.email", "email").unwrap();
    let mut index = checkout.index().unwrap();
    let id = index.write_tree().unwrap();
    let tree = checkout.find_tree(id).unwrap();
    let sig = checkout.signature().unwrap();
    checkout.commit(Some("HEAD"), &sig, &sig,
                    "Initial Commit",
                    &tree, &[]).unwrap();

    // Push the commit to the remote repo
    let mut origin = checkout.find_remote("origin").unwrap();
    let mut push = origin.push().unwrap();
    push.add_refspec("refs/heads/master").unwrap();
    push.finish().unwrap();
    assert!(!push.statuses().unwrap().iter().any(|s| s.message.is_some()));
    push.update_tips(None, None).unwrap();

    // Set up master to track origin/master
    let branch = checkout.find_reference("refs/heads/master");
    let mut branch = git2::Branch::wrap(branch.unwrap());
    branch.set_upstream(Some("origin/master")).unwrap();

}
<|endoftext|>


<commit_before>extern crate core;

use std::mem;
use self::core::str::next_code_point;
use super::token::Token;
use super::token::Category;

pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store
/// tokens for the various language and format lexers.
pub struct Tokenizer {
    data: Vec<u8>,
    head: usize,
    tail: usize,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.to_string().into_bytes(),
      head: 0,
      tail: 0,
      tokens: vec![],
      states: vec![]
    }
}

impl Tokenizer {
    /// Returns a copy of the tokens processed to date.
    ///
    /// # Examples
    ///
    /// ```
    /// let tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.tokens();
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        self.tokens.clone()
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    /// tokenizer.advance();
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        if self.has_more_data() {
            // Get the current character so that we can calculate
            // its byte length and advance the head appropriately.
            match self.current_char() {
                Some(c) => {
                    self.head += c.len_utf8();
                },
                None => (),
            }
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("l");
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    /// tokenizer.advance();
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        if self.has_more_data() {
            // Create an iterator for the remaining data.
            let mut remaining_data = self.data[self.head..].iter();

            // Pull the first UTF-8 byte sequence and convert it to a char.
            next_code_point(&mut remaining_data).map(|code_point| {
                unsafe {
                    mem::transmute(code_point)
                }
            })
        } else {
            None
        }
    }

    /// Whether or not the remaining data starts
    /// with the specified string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// assert!(tokenizer.starts_with("luth"));
    /// tokenizer.advance();
    /// assert!(tokenizer.starts_with("utho"));
    /// assert!(!tokenizer.starts_with("luth"));
    /// ```
    pub fn starts_with(&self, data: &str) -> bool {
        // Get a byte representation of the passed data
        // that we'll compare to the binary buffer.
        let data_bytes = data.as_bytes();

        // Don't even bother if the remaining data is smaller
        // than the string we're going to compare it to.
        let remaining_data_size = self.data.len() - self.head;
        if remaining_data_size >= data_bytes.len() {
            // There's enough data left. Take a leading slice of the same size for comparison.
            let leading_data = &self.data[self.head..(self.head+data_bytes.len())];

            // Compare!
            leading_data == data_bytes
        } else {
            // Not enough remaining data.
            false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if self.head > self.tail {
            // Build the lexeme by slicing the currently
            // selected range out of the buffer.
            let lexeme = unsafe {
                String::from_utf8_unchecked(
                    self.data[self.tail..self.head].to_vec()
                )
            };
            let token = Token{
                lexeme: lexeme,
                category: category,
            };
            self.tokens.push(token);
            self.tail = self.head;
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// Category::Text category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    /// assert_eq!(tokenizer.tokens()[0], Token{ lexeme: "l".to_string(), category: Category::Text});
    /// assert_eq!(tokenizer.tokens()[1], Token{ lexeme: "uthor".to_string(), category: Category::Keyword});
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Determines whether or not there is more unprocessed data.
    fn has_more_data(&self) -> bool {
        self.head < self.data.len()
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    #[test]
    fn advance_does_nothing_when_there_is_no_more_data() {
        let data = "élégant";
        let mut tokenizer = new(data);

        // Try to go beyond the last character.
        for _ in 0..10 {
            tokenizer.advance();
        }

        assert!(!tokenizer.has_more_data())
    }

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }
}
<commit_msg>Add benchmark tests for current_char and starts_with.<commit_after>extern crate core;

use std::mem;
use self::core::str::next_code_point;
use super::token::Token;
use super::token::Category;

pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store
/// tokens for the various language and format lexers.
pub struct Tokenizer {
    data: Vec<u8>,
    head: usize,
    tail: usize,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.to_string().into_bytes(),
      head: 0,
      tail: 0,
      tokens: vec![],
      states: vec![]
    }
}

impl Tokenizer {
    /// Returns a copy of the tokens processed to date.
    ///
    /// # Examples
    ///
    /// ```
    /// let tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.tokens();
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        self.tokens.clone()
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    /// tokenizer.advance();
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        if self.has_more_data() {
            // Get the current character so that we can calculate
            // its byte length and advance the head appropriately.
            match self.current_char() {
                Some(c) => {
                    self.head += c.len_utf8();
                },
                None => (),
            }
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("l");
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    /// tokenizer.advance();
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        if self.has_more_data() {
            // Create an iterator for the remaining data.
            let mut remaining_data = self.data[self.head..].iter();

            // Pull the first UTF-8 byte sequence and convert it to a char.
            next_code_point(&mut remaining_data).map(|code_point| {
                unsafe {
                    mem::transmute(code_point)
                }
            })
        } else {
            None
        }
    }

    /// Whether or not the remaining data starts
    /// with the specified string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// assert!(tokenizer.starts_with("luth"));
    /// tokenizer.advance();
    /// assert!(tokenizer.starts_with("utho"));
    /// assert!(!tokenizer.starts_with("luth"));
    /// ```
    pub fn starts_with(&self, data: &str) -> bool {
        // Get a byte representation of the passed data
        // that we'll compare to the binary buffer.
        let data_bytes = data.as_bytes();

        // Don't even bother if the remaining data is smaller
        // than the string we're going to compare it to.
        let remaining_data_size = self.data.len() - self.head;
        if remaining_data_size >= data_bytes.len() {
            // There's enough data left. Take a leading slice of the same size for comparison.
            let leading_data = &self.data[self.head..(self.head+data_bytes.len())];

            // Compare!
            leading_data == data_bytes
        } else {
            // Not enough remaining data.
            false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if self.head > self.tail {
            // Build the lexeme by slicing the currently
            // selected range out of the buffer.
            let lexeme = unsafe {
                String::from_utf8_unchecked(
                    self.data[self.tail..self.head].to_vec()
                )
            };
            let token = Token{
                lexeme: lexeme,
                category: category,
            };
            self.tokens.push(token);
            self.tail = self.head;
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// Category::Text category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    /// assert_eq!(tokenizer.tokens()[0], Token{ lexeme: "l".to_string(), category: Category::Text});
    /// assert_eq!(tokenizer.tokens()[1], Token{ lexeme: "uthor".to_string(), category: Category::Keyword});
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Determines whether or not there is more unprocessed data.
    fn has_more_data(&self) -> bool {
        self.head < self.data.len()
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    // Benchmarking
    extern crate test;
    use self::test::Bencher;

    #[test]
    fn advance_does_nothing_when_there_is_no_more_data() {
        let data = "élégant";
        let mut tokenizer = new(data);

        // Try to go beyond the last character.
        for _ in 0..10 {
            tokenizer.advance();
        }

        assert!(!tokenizer.has_more_data())
    }

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[bench]
    fn bench_current_char(b: &mut Bencher) {
        let data = include_str!("../test_data/data.json");
        let mut tokenizer = new(data);
        b.iter(|| tokenizer.current_char());
    }

    #[bench]
    fn bench_starts_with(b: &mut Bencher) {
        let data = include_str!("../test_data/data.json");
        let mut tokenizer = new(data);
        b.iter(|| tokenizer.starts_with("something"));
    }
}
<|endoftext|>


<commit_before>use luminance::linear::M44;
use luminance::shader::uniform::UniformUpdate;
use luminance_gl::gl33::Uniform;
use nalgebra::{ToHomogeneous, UnitQuaternion, Quaternion};
use std::default::Default;

pub use nalgebra::{Matrix4, Vector3};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
  pub translation: Translation,
  pub orientation: Orientation,
  pub scale: Scale
}

impl Transform {
  pub fn new(translation: Translation, orientation: Orientation, scale: Scale) -> Self {
    Transform {
      translation: translation,
      orientation: orientation,
      scale: scale
    }
  }

  pub fn repos(self, pos: Position) -> Self {
    Transform { translation: pos, .. self }
  }

  pub fn translate(self, t: Translation) -> Self {
    Transform { translation: self.translation + t, .. self }
  }

  pub fn reorient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::new(&Quaternion::from_parts(phi, axis)), .. self }
  }

  pub fn orient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::new(&Quaternion::from_parts(phi, axis)) * self.orientation, .. self }
  }

  pub fn set_uniform_scale(self, scale: f32) -> Self {
    Transform { scale: Scale { x: scale, y: scale, z: scale }, .. self }
  }

  pub fn rescale(self, scale: Scale) -> Self {
    Transform { scale: scale, .. self }
  }

  pub fn scale(self, scale: Scale) -> Self {
    let new_scale = Scale {
      x: self.scale.x * scale.x,
      y: self.scale.y * scale.y,
      z: self.scale.z * scale.z,
    };

    Transform { scale: new_scale, .. self }
  }

  pub fn to_inst_mat(&self) -> Matrix4<f32> {
    translation_matrix(self.translation) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }

  pub fn to_view_mat(&self) -> Matrix4<f32> {
    self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(self.translation) * self.scale.to_mat()
  }

  pub fn as_inst_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_inst_mat().as_ref() })
  }

  pub fn as_view_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_view_mat().as_ref() })
  }
}

impl Default for Transform {
  fn default() -> Self {
    Transform {
      translation: Vector3::new(0., 0., 0.),
      orientation: UnitQuaternion::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
      scale: Scale::default()
    }
  }
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}
<commit_msg>Fixed Transform::{re,}orient.<commit_after>use luminance::linear::M44;
use luminance::shader::uniform::UniformUpdate;
use luminance_gl::gl33::Uniform;
use nalgebra::{ToHomogeneous, Unit, UnitQuaternion, Quaternion};
use std::default::Default;

pub use nalgebra::{Matrix4, Vector3};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
  pub translation: Translation,
  pub orientation: Orientation,
  pub scale: Scale
}

impl Transform {
  pub fn new(translation: Translation, orientation: Orientation, scale: Scale) -> Self {
    Transform {
      translation: translation,
      orientation: orientation,
      scale: scale
    }
  }

  pub fn repos(self, pos: Position) -> Self {
    Transform { translation: pos, .. self }
  }

  pub fn translate(self, t: Translation) -> Self {
    Transform { translation: self.translation + t, .. self }
  }

  pub fn reorient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi), .. self }
  }

  pub fn orient(self, axis: Axis, phi: f32) -> Self {
    Transform { orientation: UnitQuaternion::from_axisangle(Unit::new(&axis), phi) * self.orientation, .. self }
  }

  pub fn set_uniform_scale(self, scale: f32) -> Self {
    Transform { scale: Scale { x: scale, y: scale, z: scale }, .. self }
  }

  pub fn rescale(self, scale: Scale) -> Self {
    Transform { scale: scale, .. self }
  }

  pub fn scale(self, scale: Scale) -> Self {
    let new_scale = Scale {
      x: self.scale.x * scale.x,
      y: self.scale.y * scale.y,
      z: self.scale.z * scale.z,
    };

    Transform { scale: new_scale, .. self }
  }

  pub fn to_inst_mat(&self) -> Matrix4<f32> {
    translation_matrix(self.translation) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }

  pub fn to_view_mat(&self) -> Matrix4<f32> {
    self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(self.translation) * self.scale.to_mat()
  }

  pub fn as_inst_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_inst_mat().as_ref() })
  }

  pub fn as_view_uniform<'a>(u: Uniform<M44>) -> UniformUpdate<'a, Self> {
    let u: UniformUpdate<M44> = u.into();
    u.contramap(|transform: Transform| { *transform.to_view_mat().as_ref() })
  }
}

impl Default for Transform {
  fn default() -> Self {
    Transform {
      translation: Vector3::new(0., 0., 0.),
      orientation: UnitQuaternion::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
      scale: Scale::default()
    }
  }
}

pub type Translation = Vector3<f32>;
pub type Axis = Vector3<f32>;
pub type Position = Vector3<f32>;
pub type Orientation = UnitQuaternion<f32>;

pub const X_AXIS: Axis = Axis { x: 1., y: 0., z: 0. };
pub const Y_AXIS: Axis = Axis { x: 0., y: 1., z: 0. };
pub const Z_AXIS: Axis = Axis { x: 0., y: 0., z: 1. };

/// Arbritrary scale.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Scale {
  pub x: f32,
  pub y: f32,
  pub z: f32
}

impl Scale {
  pub fn new(x: f32, y: f32, z: f32) -> Self {
    Scale {
      x: x,
      y: y,
      z: z
    }
  }

  pub fn uni(x: f32) -> Self {
    Scale {
      x: x,
      y: x,
      z: x
    }
  }

  pub fn to_mat(&self) -> Matrix4<f32> {
    Matrix4::new(
      self.x,     0.,     0., 0.,
          0., self.y,     0., 0.,
          0.,     0., self.z, 0.,
          0.,     0.,     0., 1.
    )
  }
}

fn translation_matrix(v: Translation) -> Matrix4<f32> {
  Matrix4::new(
    1., 0., 0., v.x,
    0., 1., 0., v.y,
    0., 0., 1., v.z,
    0., 0., 0.,  1.,
  )
}

impl Default for Scale {
  fn default() -> Self { Scale::new(1., 1., 1.) }
}
<|endoftext|>


<commit_before>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy)  {
    }
}

pub struct GraphQuery {
	// many paths
    paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let paths = Vec::new();
        let path: Path;
        for p in vertices {

            //paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    fn map(closure: &Fn() -> Path) -> GraphQuery  {
        GraphQuery{paths:Vec::new()}

    }
    pub fn outV(&self) -> GraphQuery {
        let g = GraphQuery::empty();
        g
    }
}

<commit_msg>improvements to path tracking<commit_after>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy) -> Path {
		Path{path:vec![GraphIterable::Vertex(vertex)]}
    }
}

pub struct GraphQuery {
	// many paths
    paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    fn map(closure: &Fn() -> Path) -> GraphQuery  {
        GraphQuery{paths:Vec::new()}

    }
    pub fn outV(&self) -> GraphQuery {
        let g = GraphQuery::empty();
        g
    }
}

<|endoftext|>


<commit_before>use binary_encoding::{from_binary};
use lambda_encoding::{encode, decode};
use lambda_calculus::reduction::beta_full;
use self::Error::*;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidProgram
}

pub fn execute(blc_program: &[u8], blc_argument: &[u8]) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }

    let calculation = beta_full(program.unwrap().app(encode(blc_argument))); // safe

    Ok(decode(calculation))
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn tmp() {
        let inflate = b"010001000100010001101000000101100000000101111001000110100000000000010110011111111111101111001011110011111101111101100101111110111110110100001111001111001110011100111100111100111100001011011000001000000101100000101100000010110000011011000000";
        let argument = [0x1u8, 0x7a, 0x74];

        assert_eq!(execute(&*inflate, &argument[..]), Ok("000000010111101001110100".into()));
    }
}
<commit_msg>add execution test and some docs<commit_after>use binary_encoding::{from_binary};
use lambda_encoding::{encode, decode};
use lambda_calculus::reduction::beta_full;
use self::Error::*;

/// An error that can occur during blc execution.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidProgram
}

/// Executes a binary lambda calculus program, feeding it the given argument.
pub fn execute(blc_program: &[u8], blc_argument: &[u8]) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }
    let calculation = beta_full(program.unwrap().app(encode(blc_argument))); // safe

    Ok(decode(calculation))
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn inflating() {
        // program code from http://www.ioccc.org/2012/tromp/inflate.Blc
        let inflate = b"01000100010001000110100000010110000000010111100100011010000000000001011001\
            11111111111011110010111100111111011111011001011111101111101101000011110011110011100111\
            00111100111100111100001011011000001000000101100000101100000010110000011011000000";
        let s_compressed = [0x1u8, 0x7a, 0x74];

        assert_eq!(execute(&*inflate, &s_compressed[..]).unwrap(), "000000010111101001110100".to_owned());
    }

    #[test]
    fn deflating() {
        // program code from http://www.ioccc.org/2012/tromp/deflate.Blc
        let deflate = b"01000100011010000001011000000101011111100000000100010111000000001011111001\
            01010111111111111100000000110111000001100010111011001011000001101100001111100001111100\
            00101101110110000000010110011110000010010111111110111111101100010100100000111001110011\
            10100000011100111010000000";

        let s_blc = b"00000001011110100111010";

        assert_eq!(execute(&*deflate, &s_blc[..]).unwrap().as_bytes(), [0x1u8, 0x7a, 0x74]);
    }
}
<|endoftext|>


<commit_before>//! Functions related to formatting and printing lines from a `Tokenizer`.

use crate::extensions::FindFrom;
use crate::types::LineType;

use log::debug;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightingSnippet<'a> {
    CommandName(&'a str),
    Variable(&'a str),
    NormalCode(&'a str),
    Description(&'a str),
    Text(&'a str),
    Linebreak,
}

impl<'a> HighlightingSnippet<'a> {
    pub fn is_empty(&self) -> bool {
        use HighlightingSnippet::*;

        match self {
            CommandName(s) | Variable(s) | NormalCode(s) | Description(s) | Text(s) => s.is_empty(),
            Linebreak => false,
        }
    }
}

/// Checks whether the characters right before and after the substring (given by half-open index interval) are whitespace (if they exist).
fn is_freestanding_substring(surrouding: &str, substring: (usize, usize)) -> bool {
    let (start, end) = substring;
    // "okay" meaning <exists and is whitespace> or <doesn't exist>
    let char_before_is_okay = surrouding[..start]
        .chars()
        .last()
        .filter(|prev_char| !prev_char.is_whitespace())
        .is_none();
    let char_after_is_okay = surrouding[end..]
        .chars()
        .next()
        .filter(|next_char| !next_char.is_whitespace())
        .is_none();
    char_before_is_okay && char_after_is_okay
}

/// Yields `NormalCode` and `CommandName` in alternating order according to the occurences of
/// `command_name` in `segment`. Variables are not detected here, see `highlight_code`
/// instead.
fn highlight_code_segment<'a, E>(
    command_name: &'a str,
    mut segment: &'a str,
    yield_snippet: &mut impl FnMut(HighlightingSnippet<'a>) -> Result<(), E>,
) -> Result<(), E> {
    if !command_name.is_empty() {
        let mut search_start = 0;
        while let Some(match_start) = segment.find_from(command_name, search_start) {
            let match_end = match_start + command_name.len();
            if is_freestanding_substring(segment, (match_start, match_end)) {
                yield_snippet(HighlightingSnippet::NormalCode(&segment[..match_start]))?;
                yield_snippet(HighlightingSnippet::CommandName(command_name))?;
                segment = &segment[match_end..];
                search_start = 0;
            } else {
                search_start = segment[match_start..]
                    .char_indices()
                    .nth(1)
                    .map_or(segment.len(), |(i, _)| match_start + i);
            }
        }
    }
    yield_snippet(HighlightingSnippet::NormalCode(segment))?;
    Ok(())
}

/// Highlight code examples including user variables in {{ curly braces }}.
fn highlight_code<'a, E>(
    command: &'a str,
    text: &'a str,
    yield_snippet: &mut impl FnMut(HighlightingSnippet<'a>) -> Result<(), E>,
) -> Result<(), E> {
    let variable_splits = text
        .split("}}")
        .map(|s| s.split_once("{{").unwrap_or((s, "")));
    for (code_segment, variable) in variable_splits {
        highlight_code_segment(&command, code_segment, yield_snippet)?;
        yield_snippet(HighlightingSnippet::Variable(variable))?;
    }
    Ok(())
}

/// Print a token stream to an ANSI terminal.
pub fn highlight_lines<L, F, E>(
    lines: L,
    yield_snippet: &mut F,
    keep_empty_lines: bool,
) -> Result<(), E>
where
    L: Iterator<Item = LineType>,
    F: for<'snip> FnMut(HighlightingSnippet<'snip>) -> Result<(), E>,
{
    let mut command = String::new();
    for line in lines {
        match line {
            LineType::Empty => {
                if keep_empty_lines {
                    yield_snippet(HighlightingSnippet::Linebreak)?;
                }
            }
            LineType::Title(title) => {
                debug!("Ignoring title");

                // This is safe as long as the parsed title is only the command,
                // and the iterator yields values in order of appearance.
                command = title;
                debug!("Detected command name: {}", &command);
            }
            LineType::Description(text) => yield_snippet(HighlightingSnippet::Description(&text))?,
            LineType::ExampleText(text) => yield_snippet(HighlightingSnippet::Text(&text))?,
            LineType::ExampleCode(text) => {
                yield_snippet(HighlightingSnippet::NormalCode("      "))?;
                highlight_code(&command, &text, yield_snippet)?;
                yield_snippet(HighlightingSnippet::Linebreak)?;
            }

            LineType::Other(text) => debug!("Unknown line type: {:?}", text),
        }
    }
    yield_snippet(HighlightingSnippet::Linebreak)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use HighlightingSnippet::*;

    #[test]
    fn test_is_freestanding_substring() {
        assert!(is_freestanding_substring("I love tldr", (0, 1)));
        assert!(is_freestanding_substring("I love tldr", (2, 6)));
        assert!(is_freestanding_substring("I love tldr", (7, 11)));

        assert!(is_freestanding_substring("tldr", (0, 4)));
        assert!(is_freestanding_substring("tldr ", (0, 4)));
        assert!(is_freestanding_substring(" tldr", (1, 5)));
        assert!(is_freestanding_substring(" tldr ", (1, 5)));

        assert!(!is_freestanding_substring("tldr", (1, 3)));
        assert!(!is_freestanding_substring("tldr ", (1, 4)));
        assert!(!is_freestanding_substring(" tldr", (1, 4)));

        assert!(is_freestanding_substring(
            " épicé ",
            (1, " épicé".len()) // note the missing trailing space
        ));
        assert!(!is_freestanding_substring(
            " épicé ",
            (1, " épic".len()) // note the missing trailing space and character
        ));
    }

    fn run<'a>(cmd: &'a str, segment: &'a str) -> Vec<HighlightingSnippet<'a>> {
        let mut yielded = Vec::new();
        let mut yield_snippet = |snip: HighlightingSnippet<'a>| {
            if !snip.is_empty() {
                yielded.push(snip);
            }
            Ok::<(), ()>(())
        };

        highlight_code_segment(cmd, segment, &mut yield_snippet)
            .expect("highlight code segment failed");
        yielded
    }

    #[test]
    fn test_highlight_code_segment() {
        assert!(run("make", "").is_empty());
        assert_eq!(
            &run("make", "make all CC=clang -q"),
            &[CommandName("make"), NormalCode(" all CC=clang -q")]
        );
        assert_eq!(
            &run("make", "  make money --always-make"),
            &[
                NormalCode("  "),
                CommandName("make"),
                NormalCode(" money --always-make")
            ]
        );
        assert_eq!(
            &run("git commit", "git commit -m 'git commit'"),
            &[CommandName("git commit"), NormalCode(" -m 'git commit'"),]
        );
    }

    #[test]
    fn test_i18n() {
        assert_eq!(
            &run("mäke", "mäke höhlenrätselbücher"),
            &[CommandName("mäke"), NormalCode(" höhlenrätselbücher")]
        );
        assert_eq!(
            &run(
                "Müll",
                "1000 Gründe warum Müll heute größer ist als Müll früher, ärgerlich"
            ),
            &[
                NormalCode("1000 Gründe warum "),
                CommandName("Müll"),
                NormalCode(" heute größer ist als "),
                CommandName("Müll"),
                NormalCode(" früher, ärgerlich")
            ]
        );
        assert_eq!(
            &run(
                "übergang",
                "die Zustandsübergangsfunktion übergang Änderungen",
            ),
            &[
                NormalCode("die Zustandsübergangsfunktion "),
                CommandName("übergang"),
                NormalCode(" Änderungen")
            ],
        );
    }
}
<commit_msg>Reorder functions in `formatter.rs`<commit_after>//! Functions related to formatting and printing lines from a `Tokenizer`.

use crate::extensions::FindFrom;
use crate::types::LineType;

use log::debug;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Represents a snippet from a page from a specific highlighting class.
pub enum HighlightingSnippet<'a> {
    CommandName(&'a str),
    Variable(&'a str),
    NormalCode(&'a str),
    Description(&'a str),
    Text(&'a str),
    Linebreak,
}

impl<'a> HighlightingSnippet<'a> {
    pub fn is_empty(&self) -> bool {
        use HighlightingSnippet::*;

        match self {
            CommandName(s) | Variable(s) | NormalCode(s) | Description(s) | Text(s) => s.is_empty(),
            Linebreak => false,
        }
    }
}

/// Parse the content of each line yielded by `lines` and yield `HighLightingSnippet`s accordingly.
pub fn highlight_lines<L, F, E>(
    lines: L,
    yield_snippet: &mut F,
    keep_empty_lines: bool,
) -> Result<(), E>
where
    L: Iterator<Item = LineType>,
    F: for<'snip> FnMut(HighlightingSnippet<'snip>) -> Result<(), E>,
{
    let mut command = String::new();
    for line in lines {
        match line {
            LineType::Empty => {
                if keep_empty_lines {
                    yield_snippet(HighlightingSnippet::Linebreak)?;
                }
            }
            LineType::Title(title) => {
                debug!("Ignoring title");

                // This is safe as long as the parsed title is only the command,
                // and the iterator yields values in order of appearance.
                command = title;
                debug!("Detected command name: {}", &command);
            }
            LineType::Description(text) => yield_snippet(HighlightingSnippet::Description(&text))?,
            LineType::ExampleText(text) => yield_snippet(HighlightingSnippet::Text(&text))?,
            LineType::ExampleCode(text) => {
                yield_snippet(HighlightingSnippet::NormalCode("      "))?;
                highlight_code(&command, &text, yield_snippet)?;
                yield_snippet(HighlightingSnippet::Linebreak)?;
            }

            LineType::Other(text) => debug!("Unknown line type: {:?}", text),
        }
    }
    yield_snippet(HighlightingSnippet::Linebreak)?;
    Ok(())
}

/// Highlight code examples including user variables in {{ curly braces }}.
fn highlight_code<'a, E>(
    command: &'a str,
    text: &'a str,
    yield_snippet: &mut impl FnMut(HighlightingSnippet<'a>) -> Result<(), E>,
) -> Result<(), E> {
    let variable_splits = text
        .split("}}")
        .map(|s| s.split_once("{{").unwrap_or((s, "")));
    for (code_segment, variable) in variable_splits {
        highlight_code_segment(command, code_segment, yield_snippet)?;
        yield_snippet(HighlightingSnippet::Variable(variable))?;
    }
    Ok(())
}

/// Yields `NormalCode` and `CommandName` in alternating order according to the occurences of
/// `command_name` in `segment`. Variables are not detected here, see `highlight_code`
/// instead.
fn highlight_code_segment<'a, E>(
    command_name: &'a str,
    mut segment: &'a str,
    yield_snippet: &mut impl FnMut(HighlightingSnippet<'a>) -> Result<(), E>,
) -> Result<(), E> {
    if !command_name.is_empty() {
        let mut search_start = 0;
        while let Some(match_start) = segment.find_from(command_name, search_start) {
            let match_end = match_start + command_name.len();
            if is_freestanding_substring(segment, (match_start, match_end)) {
                yield_snippet(HighlightingSnippet::NormalCode(&segment[..match_start]))?;
                yield_snippet(HighlightingSnippet::CommandName(command_name))?;
                segment = &segment[match_end..];
                search_start = 0;
            } else {
                search_start = segment[match_start..]
                    .char_indices()
                    .nth(1)
                    .map_or(segment.len(), |(i, _)| match_start + i);
            }
        }
    }
    yield_snippet(HighlightingSnippet::NormalCode(segment))?;
    Ok(())
}

/// Checks whether the characters right before and after the substring (given by half-open index interval) are whitespace (if they exist).
fn is_freestanding_substring(surrouding: &str, substring: (usize, usize)) -> bool {
    let (start, end) = substring;
    // "okay" meaning <exists and is whitespace> or <doesn't exist>
    let char_before_is_okay = surrouding[..start]
        .chars()
        .last()
        .filter(|prev_char| !prev_char.is_whitespace())
        .is_none();
    let char_after_is_okay = surrouding[end..]
        .chars()
        .next()
        .filter(|next_char| !next_char.is_whitespace())
        .is_none();
    char_before_is_okay && char_after_is_okay
}

#[cfg(test)]
mod tests {
    use super::*;
    use HighlightingSnippet::*;

    #[test]
    fn test_is_freestanding_substring() {
        assert!(is_freestanding_substring("I love tldr", (0, 1)));
        assert!(is_freestanding_substring("I love tldr", (2, 6)));
        assert!(is_freestanding_substring("I love tldr", (7, 11)));

        assert!(is_freestanding_substring("tldr", (0, 4)));
        assert!(is_freestanding_substring("tldr ", (0, 4)));
        assert!(is_freestanding_substring(" tldr", (1, 5)));
        assert!(is_freestanding_substring(" tldr ", (1, 5)));

        assert!(!is_freestanding_substring("tldr", (1, 3)));
        assert!(!is_freestanding_substring("tldr ", (1, 4)));
        assert!(!is_freestanding_substring(" tldr", (1, 4)));

        assert!(is_freestanding_substring(
            " épicé ",
            (1, " épicé".len()) // note the missing trailing space
        ));
        assert!(!is_freestanding_substring(
            " épicé ",
            (1, " épic".len()) // note the missing trailing space and character
        ));
    }

    fn run<'a>(cmd: &'a str, segment: &'a str) -> Vec<HighlightingSnippet<'a>> {
        let mut yielded = Vec::new();
        let mut yield_snippet = |snip: HighlightingSnippet<'a>| {
            if !snip.is_empty() {
                yielded.push(snip);
            }
            Ok::<(), ()>(())
        };

        highlight_code_segment(cmd, segment, &mut yield_snippet)
            .expect("highlight code segment failed");
        yielded
    }

    #[test]
    fn test_highlight_code_segment() {
        assert!(run("make", "").is_empty());
        assert_eq!(
            &run("make", "make all CC=clang -q"),
            &[CommandName("make"), NormalCode(" all CC=clang -q")]
        );
        assert_eq!(
            &run("make", "  make money --always-make"),
            &[
                NormalCode("  "),
                CommandName("make"),
                NormalCode(" money --always-make")
            ]
        );
        assert_eq!(
            &run("git commit", "git commit -m 'git commit'"),
            &[CommandName("git commit"), NormalCode(" -m 'git commit'"),]
        );
    }

    #[test]
    fn test_i18n() {
        assert_eq!(
            &run("mäke", "mäke höhlenrätselbücher"),
            &[CommandName("mäke"), NormalCode(" höhlenrätselbücher")]
        );
        assert_eq!(
            &run(
                "Müll",
                "1000 Gründe warum Müll heute größer ist als Müll früher, ärgerlich"
            ),
            &[
                NormalCode("1000 Gründe warum "),
                CommandName("Müll"),
                NormalCode(" heute größer ist als "),
                CommandName("Müll"),
                NormalCode(" früher, ärgerlich")
            ]
        );
        assert_eq!(
            &run(
                "übergang",
                "die Zustandsübergangsfunktion übergang Änderungen",
            ),
            &[
                NormalCode("die Zustandsübergangsfunktion "),
                CommandName("übergang"),
                NormalCode(" Änderungen")
            ],
        );
    }
}
<|endoftext|>


<commit_before>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let values = matches.map(|s| {
        let numbers = s.split(',').map(|v| v.parse::<u32>().unwrap());
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    fn merge(filename: &str) -> (Vec<u32>, Vec<u32>) {
        let result = Merge::new(filename).collect::<Vec<u32>>();
        let output = get_output(filename).unwrap().collect::<Vec<u32>>();
        (result, output)
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (result, output) = merge(filename);
        assert_eq!(result, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (result, output) = merge(filename);
        assert_ne!(result, output);
    }
}
<commit_msg>Zero does not crash<commit_after>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> u32 {
        if let Ok(i) = v.parse::<u32>() {
            i
        } else {
            0
        }
    };
    let values = matches.map(move |s| {
        let numbers = s.split(',').map(|v| to_int(&v));
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    fn merge(filename: &str) -> (Vec<u32>, Vec<u32>) {
        let result = Merge::new(filename).collect::<Vec<u32>>();
        let output = get_output(filename).unwrap().collect::<Vec<u32>>();
        (result, output)
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (result, output) = merge(filename);
        assert_eq!(result, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (result, output) = merge(filename);
        assert_eq!(output.len(), 0);
        assert_eq!(result.len(), 0);
        assert_eq!(result, output);
    }
}
<|endoftext|>


<commit_before>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use game::constants::{CHARACTER_POS_W, CHARACTER_POS_H, TILES_PCS_W, TILES_PCS_H, PLAYER_SPEED, ZOOM_SPEED, CHARACTER_W, CHARACTER_H, FIRE_SPRITE_START_INDEX};
use views::tilemap::{TerrainTile, TerrainSpriteSheet, get_tiles, viewport_move};
use views::background::{Background};
use data::{load_character};
use sdl2::mixer::{Chunk};
use std::path::Path;

mod tilemap;
mod background;

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

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
  heading: CharacterFrame,
  move_anim_index: u32,
  fire_anim_index: u32
}

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

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/character.png").unwrap();
    let pistol_audio = Chunk::from_file(Path::new("assets/audio/pistol.ogg")).unwrap();
    let character_datapoints = load_character();
    let mut sprites = Vec::with_capacity(512);

    for x in 0..(FIRE_SPRITE_START_INDEX - 1) {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in FIRE_SPRITE_START_INDEX..255 {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    GameView {
      player: Character {
        rect: Rectangle {
          x: CHARACTER_POS_W,
          y: CHARACTER_POS_H,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites.clone(),
        current: CharacterFrame::Down,
        heading: CharacterFrame::Down,
        move_anim_index: 0,
        fire_anim_index: 0
      },

      tiles: get_tiles(),

      sprite_sheet: TerrainSpriteSheet::new(&game),

      pistol: pistol_audio,

      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 * 1.5,
      (false, true) => moved * 1.5,
    };

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

    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 * 2.0,
      h: game.output_size().1 * 2.0,
    };

    let curr_rect = game.renderer.viewport();
    let rect = viewport_move(&game, curr_rect, dx, dy);
    game.renderer.set_viewport(rect.to_sdl());

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

    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 { self.player.heading }
    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!() };

    self.player.heading = self.player.current;
    for x in 0..TILES_PCS_W {
      for y in 0..TILES_PCS_H {
        let index = x * TILES_PCS_H + y;
        game.renderer.copy_sprite(&self.sprite_sheet[(self.tiles[index].current-1) as usize], self.tiles[index].rect);
      }
    }

    match game.events.mouse_click {
      Some(_) => {
        let index = 211 + self.player.current as usize * 5 + self.player.fire_anim_index as usize;
        game.renderer.copy_sprite(&self.player.sprites[index], self.player.rect);
        self.player.fire_anim_index =
          if self.player.fire_anim_index < 4u32 { self.player.fire_anim_index + 1u32 } else { 0u32 };
        if self.player.fire_anim_index == 0 {
          game.play_sound(&self.pistol);
        }
      },
      None => {
        let index = self.player.current as usize * 28 + self.player.move_anim_index as usize;
        game.renderer.copy_sprite(&self.player.sprites[index], self.player.rect);
        self.player.move_anim_index =
          if dx == 0.0 && dy == 0.0 { 0u32 } else if self.player.move_anim_index < 13u32 { self.player.move_anim_index + 1u32 } else { 0u32 };
      },
    };

    let scale = game.renderer.scale();
    if game.events.zoom_in == true && scale.0 <= 2.0 && scale.1 <= 2.0 {
      let _ = game.renderer.set_scale(scale.0 + ZOOM_SPEED, scale.1 + ZOOM_SPEED);
    } else if game.events.zoom_out == true && scale.0 > 0.85 && scale.1 > 0.85 {
      let _ = game.renderer.set_scale(scale.0 - ZOOM_SPEED, scale.1 - ZOOM_SPEED);
    }

    ViewAction::None
  }
}
<commit_msg>Reformat GameView<commit_after>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use game::constants::{CHARACTER_POS_W, CHARACTER_POS_H, TILES_PCS_W, TILES_PCS_H, PLAYER_SPEED, ZOOM_SPEED, CHARACTER_W, CHARACTER_H, FIRE_SPRITE_START_INDEX};
use views::tilemap::{TerrainTile, TerrainSpriteSheet, get_tiles, viewport_move};
use views::background::{Background};
use data::{load_character};
use sdl2::mixer::{Chunk};
use std::path::Path;

mod tilemap;
mod background;

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

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
  heading: CharacterFrame,
  move_anim_index: u32,
  fire_anim_index: u32
}

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

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/character.png").unwrap();
    let pistol_audio = Chunk::from_file(Path::new("assets/audio/pistol.ogg")).unwrap();
    let character_datapoints = load_character();
    let mut sprites = Vec::with_capacity(512);

    for x in 0..(FIRE_SPRITE_START_INDEX - 1) {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in FIRE_SPRITE_START_INDEX..255 {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    GameView {
      player: Character {
        rect: Rectangle {
          x: CHARACTER_POS_W,
          y: CHARACTER_POS_H,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites.clone(),
        current: CharacterFrame::Down,
        heading: CharacterFrame::Down,
        move_anim_index: 0,
        fire_anim_index: 0
      },
      tiles: get_tiles(),
      sprite_sheet: TerrainSpriteSheet::new(&game),
      pistol: pistol_audio,
      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 * 1.5,
      (false, true) => moved * 1.5,
    };

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

    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 * 2.0,
      h: game.output_size().1 * 2.0,
    };

    let curr_rect = game.renderer.viewport();
    let rect = viewport_move(&game, curr_rect, dx, dy);
    game.renderer.set_viewport(rect.to_sdl());

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

    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 { self.player.heading }
    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!() };

    self.player.heading = self.player.current;
    for x in 0..TILES_PCS_W {
      for y in 0..TILES_PCS_H {
        let index = x * TILES_PCS_H + y;
        game.renderer.copy_sprite(&self.sprite_sheet[(self.tiles[index].current-1) as usize], self.tiles[index].rect);
      }
    }

    match game.events.mouse_click {
      Some(_) => {
        let index = 211 + self.player.current as usize * 5 + self.player.fire_anim_index as usize;
        game.renderer.copy_sprite(&self.player.sprites[index], self.player.rect);
        self.player.fire_anim_index =
          if self.player.fire_anim_index < 4u32 { self.player.fire_anim_index + 1u32 } else { 0u32 };
        if self.player.fire_anim_index == 0 {
          game.play_sound(&self.pistol);
        }
      },
      None => {
        let index = self.player.current as usize * 28 + self.player.move_anim_index as usize;
        game.renderer.copy_sprite(&self.player.sprites[index], self.player.rect);
        self.player.move_anim_index =
          if dx == 0.0 && dy == 0.0 { 0u32 } else if self.player.move_anim_index < 13u32 { self.player.move_anim_index + 1u32 } else { 0u32 };
      },
    };

    let scale = game.renderer.scale();
    if game.events.zoom_in == true && scale.0 <= 2.0 && scale.1 <= 2.0 {
      let _ = game.renderer.set_scale(scale.0 + ZOOM_SPEED, scale.1 + ZOOM_SPEED);
    } else if game.events.zoom_out == true && scale.0 > 0.85 && scale.1 > 0.85 {
      let _ = game.renderer.set_scale(scale.0 - ZOOM_SPEED, scale.1 - ZOOM_SPEED);
    }

    ViewAction::None
  }
}
<|endoftext|>


<commit_before>extern crate liquid;

use grammar::{LexicalUnit, ProductionRule, RuleComponent, Grammar};
use self::liquid::{Renderable, Context, Value, FilterError};

static template : &'static str = include_str!("parser.liquid");

pub fn generate(grammar: Grammar) {
    let tmplt = liquid::parse(template, Default::default()).unwrap();

    let mut ctx = Context::new();

    ctx.add_filter("capitalize", Box::new(|input, _args| {
        if let &Value::Str(ref s) = input {
            let res = s.chars().enumerate().map(|(i, c)| if i == 0 {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            }).collect();

            Ok(Value::Str(res))
        } else {
            Err(FilterError::InvalidType("Expected a string".to_owned()))
        }
    }));

    ctx.set_val("production_rules", Value::Array(grammar.get_all_production_rules_name()
                                                        .iter()
                                                        .map(|x| Value::Str(x.clone()))
                                                        .collect()));

    match tmplt.render(&mut ctx) {
        Err(msg) => println!("Error : {}", msg),
        Ok(generated_code) => save_generated_code(generated_code.unwrap()),
    }
}

pub fn save_generated_code(code : String) {
    println!("{}", code);
}
<commit_msg>Write the generated code into a file<commit_after>extern crate liquid;

use grammar::{LexicalUnit, ProductionRule, RuleComponent, Grammar};
use self::liquid::{Renderable, Context, Value, FilterError};
use std::fs::File;
use std::io;
use std::io::Write;

static template : &'static str = include_str!("parser.liquid");

pub fn generate(grammar: Grammar) {
    let tmplt = liquid::parse(template, Default::default()).unwrap();

    let mut ctx = Context::new();

    ctx.add_filter("capitalize", Box::new(|input, _args| {
        if let &Value::Str(ref s) = input {
            let res = s.chars().enumerate().map(|(i, c)| if i == 0 {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            }).collect();

            Ok(Value::Str(res))
        } else {
            Err(FilterError::InvalidType("Expected a string".to_owned()))
        }
    }));

    ctx.set_val("production_rules", Value::Array(grammar.get_all_production_rules_name()
                                                        .iter()
                                                        .map(|x| Value::Str(x.clone()))
                                                        .collect()));

    match tmplt.render(&mut ctx) {
        Err(msg) => println!("Error : {}", msg),
        Ok(generated_code) => {
            match save_generated_code(generated_code.unwrap()) {
                Ok(()) => {},
                Err(err) => println!("Error : {}", err),
            }
        },
    }
}

pub fn save_generated_code(code : String) -> io::Result<()> {
    let mut f = try!(File::create("out.rs"));
    try!(f.write_all(code.as_bytes()));

    Ok(())
}
<|endoftext|>