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

use std::iter::range_step_inclusive;

/**
    Determines if a specified number is prime.

    # Arguments

    * 'num' - The number to check for primality

    # Examples

    ```rust
    use sothr_lib::prime_util::is_prime;
    assert_eq!(true, is_prime(1));
    assert_eq!(true, is_prime(5));
    assert_eq!(false, is_prime(6));
    assert_eq!(true, is_prime(6857));
    assert_eq!(false, is_prime(75031));
    ```
*/
pub fn is_prime(num: u64) -> bool {
    // 1-3 are prime numbers
    if num <= 3 {
        return true;
    }

    // numbers divisible by 2 and 3, but greater than 3 are not prime
    if num % 2 == 0 || num % 3 == 0 {
        return false;
    }

    // Check every number between i=5 and the square of i than is less than the
    // desired number
    let mut i = 5;
    while i*i < num {
    	// If the number is evenly divisible by i or i+2 it is not prime
        if num % i == 0 || num % (i+2) == 0 {
            return false;
        }
        // Increment by 6 because it is the product of 2 and 3. Therefore of
        // the numbers between 5 and 11 (i and i+6) only 5 and 7 could be prime
        // values. 6, 8, 9 and 10 are products or sums of 2 and 3.
        i += 6;
    }
    // If this far, then the number is definitively prime
    true
}

/**
  Generate a list of primes between 0 and the end value.

  # Arguments

  * 'look_until' - The end of the range to look for primes within

  # Examples

  ```rust
  use sothr_lib::prime_util::list_of_primes;
  let prime_list = vec![2,3,5,7,11];
  assert_eq!(prime_list, list_of_primes(12).expect("No Primes?!?!?"));
  ```
*/
pub fn list_of_primes(look_until: u64) -> Option<Vec<u64>> {
  if look_until < 2u64 {
    return None
  }

  let end = look_until as usize;

  //prepopulate the sieve
  let mut sieve: Vec<bool> = Vec::with_capacity(end/2);
  let mut i: usize = 0;
  while i < end {
    sieve.push(true);
    i += 1;
  }

  let f_look_until = look_until as f64;
  let estimate_of_primes = ((f_look_until / f_look_until.ln()) * (1f64 + (1.2762 / f_look_until.ln()))) as usize;
  let mut primes: Vec<u64> = Vec::with_capacity(estimate_of_primes);
  primes.push(2u64);

  let limit = (((look_until/2) as f64).sqrt() as usize) + 1;

  // in this lineup index 0 == 3
  // therefore index 1 == 5, 2 == 7, 3 == 9, etc...
  for i in 0..end/2 {
    if sieve[i] {
      primes.push((i+i+3) as u64);
      if i < limit {
        // selectively sieve out non primes. We're only concerned with odds as
        // we've already removed even values from the list.
        // i = 0, therefore i represents 3
        // i+i+3 = 3
        // simple proofs of odd counts
        // 0 1 2 3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
        //[3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49]
        //0,3,6,9,12 = <3>,9,15,21,27
        //1,6,11,16 = <5>,15,25,35
        //2,9,16,23 = <7>,21,35,49
        for j in range_step_inclusive(i+i+3, end-1, i+i+3) {
          sieve[j] = false;
        }
      }
    }
  }

  Some(primes)
}
<commit_msg>Added function to find n primes<commit_after>// Copyright 2015 Drew Short <drew@sothr.com>.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::iter::range_step_inclusive;

/**
    Determines if a specified number is prime.

    # Arguments

    * 'num' - The number to check for primality

    # Examples

    ```rust
    use sothr_lib::prime_util::is_prime;
    assert_eq!(true, is_prime(1));
    assert_eq!(true, is_prime(5));
    assert_eq!(false, is_prime(6));
    assert_eq!(true, is_prime(6857));
    assert_eq!(false, is_prime(75031));
    ```
*/
pub fn is_prime(num: u64) -> bool {
    // 1-3 are prime numbers
    if num <= 3 {
        return true;
    }

    // numbers divisible by 2 and 3, but greater than 3 are not prime
    if num % 2 == 0 || num % 3 == 0 {
        return false;
    }

    // Check every number between i=5 and the square of i than is less than the
    // desired number
    let mut i = 5;
    while i*i < num {
    	// If the number is evenly divisible by i or i+2 it is not prime
        if num % i == 0 || num % (i+2) == 0 {
            return false;
        }
        // Increment by 6 because it is the product of 2 and 3. Therefore of
        // the numbers between 5 and 11 (i and i+6) only 5 and 7 could be prime
        // values. 6, 8, 9 and 10 are products or sums of 2 and 3.
        i += 6;
    }
    // If this far, then the number is definitively prime
    true
}

/**
  Generate a list of primes between 0 and the end value.

  # Arguments

  * 'look_until' - The end of the range to look for primes within

  # Examples

  ```rust
  use sothr_lib::prime_util::list_of_primes;
  let prime_list = vec![2,3,5,7,11];
  assert_eq!(prime_list, list_of_primes(12).expect("No Primes?!?!?"));
  ```
*/
pub fn list_of_primes(look_until: u64) -> Option<Vec<u64>> {
  if look_until < 2u64 {
    return None
  }

  let end = look_until as usize;

  //prepopulate the sieve
  let mut sieve: Vec<bool> = Vec::with_capacity(end/2);
  let mut i: usize = 0;
  while i < end {
    sieve.push(true);
    i += 1;
  }

  let f_look_until = look_until as f64;
  let estimate_of_primes = ((f_look_until / f_look_until.ln()) * (1f64 + (1.2762 / f_look_until.ln()))) as usize;
  let mut primes: Vec<u64> = Vec::with_capacity(estimate_of_primes);
  primes.push(2u64);

  let limit = (((look_until/2) as f64).sqrt() as usize) + 1;

  // in this lineup index 0 == 3
  // therefore index 1 == 5, 2 == 7, 3 == 9, etc...
  for i in 0..end/2 {
    if sieve[i] {
      primes.push((i+i+3) as u64);
      if i < limit {
        // selectively sieve out non primes. We're only concerned with odds as
        // we've already removed even values from the list.
        // i = 0, therefore i represents 3
        // i+i+3 = 3
        // simple proofs of odd counts
        // 0 1 2 3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
        //[3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49]
        //0,3,6,9,12 = <3>,9,15,21,27
        //1,6,11,16 = <5>,15,25,35
        //2,9,16,23 = <7>,21,35,49
        for j in range_step_inclusive(i+i+3, end-1, i+i+3) {
          sieve[j] = false;
        }
      }
    }
  }
  Some(primes)
}

/**
    Find a specified number of primes.

    # Arguments

    * 'look_until' - The end of the range to look for primes within

    # Examples

    ```rust
    use sothr_lib::prime_util::find_number_of_primes;
    let prime_list = vec![2,3,5,7,11];
    assert_eq!(prime_list, find_number_of_primes(5).expect("No Primes?!?!?"));
    ```
*/
pub fn find_number_of_primes(num_of_primes: usize) -> Option<Vec<u64>> {
    // very slow way to find primes
    // TODO: Use a more efficient algorithm in the future

    if num_of_primes == 0 {
        return None;
    }

    let mut primes: Vec<u64> = Vec::with_capacity(num_of_primes);
    primes.push(2u64);

    let mut num = 3u64;
    loop {
        let mut is_prime = true;
        for prime in primes.iter() {
            if num % prime == 0 {
                is_prime = false;
                break;
            }
        }
        if is_prime { primes.push(num); }
        if primes.len() >= num_of_primes { break; }
        num += 1;
    }

    Some(primes)
}
<|endoftext|>


<commit_before>//! An outline of how linear types could be combined with JS-managed data
//!
//! The idea is to use the JS context as a linear token.
//! Each JS context gets its own type `Cx` which implements the `JSContext` trait.
//! Access to read-only JS-managed data requires a context of type `&Cx`.
//! Access to read-write JS-managed data requires a context of type `&mut Cx`.
//! Linear use of the context ensures that Rust's memory safety is preserved (er, I hope).
//!
//! This API doesn't address tracing, which would have to be handled similarly
//! to servo's current JS bindings.
//!
//! One thing that makes this easier is that we can arrange for any
//! calls into the JS engine which might trigger GC to take a `&mut Cx`
//! argument, which gives us control of when GC might occur.

use std::marker::PhantomData;

/// The trait for native JS-manageable data.
pub unsafe trait JSManageable<'a> {
    /// This type should have the same mnemory represention as `Self`.
    /// The only difference between `Self` and `Self::ChangeLifetime`
    /// is that any `JSManaged<'b, Cx, T>` should be replaced by
    /// `JSManaged<'a, Cx, T::ChangeLifetime>`.
    type ChangeLifetime: 'a;
}

/// The trait for accessing JS-managed data.
pub trait JSAccess<Cx>: Sized {
    /// Read-only access to native JS-managed data.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>;

    /// Read-write access to native JS-managed data.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Cx, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>;
}

/// The trait for JS contexts.
pub trait JSContext: JSAccess<Self> {
    /// Get a snapshot of the JS state.
    /// The snapshot only allows access to the methods that are guaranteed not to call GC,
    /// so we don't need to root JS-managed pointers during the lifetime of a snapshot.
    fn snapshot(&mut self) -> JSSnapshot<Self>;

    /// Give ownership of data to JS.
    /// This allocates JS heap, which may trigger GC.
    fn manage<'a, T>(&'a self, value: T) -> JSManaged<'a, Self, T>
        where T: 'a + JSManageable<'a, ChangeLifetime=T>;

    // A real implementation would also have JS methods such as those in jsapi.
}

/// A placholder for the real `JSTraceable`.
pub unsafe trait JSTraceable<Cx> {}

/// A user of a JS context implements `JSContextConsumer`, which is called back
/// with a fresh JS context.
pub trait JSContextConsumer<T> {
    /// This callback is called with a fresh JS context.
    fn consume<Cx>(self, cx: &mut Cx) -> T where Cx: JSContext;
}

/// To create a fresh JS context, the user implements `JSContextConsumer`
/// for their type `K`, builds a `k:K`, then calls `with_js_context(k)`.
/// ```rust
///   struct MyConsumer;
///   impl JSContextConsumer<()> for MyConsumer {
///      fn consume<Cx: JSContext>(cx: Cx) {
///         // Do stuff with the JS context cx.
///      }
///   }
///   with_js_context(MyConsumer);
/// ```
pub fn with_js_context<C, T>(consumer: C) -> T where
    C: JSContextConsumer<T>
{
    // A real implementation would allocate a JS context
    let mut cx = JSContextImpl {};
    consumer.consume(&mut cx)
}

/// The type of JS-managed data in a JS context `Cx`.
///
/// If the user has access to a `&JSManaged`, then the JS-managed
/// data is live for the lifetime of the reference. In particular,
/// this means that there should never be any stack-allocated
/// `JSManaged` values, since they would allow the user to construct
/// `&JSManaged` references with arbitrary lifetimes.
pub struct JSManaged<'a, Cx, T> {
    // JS reflector goes here
    raw: *mut T,
    marker: PhantomData<(&'a(),Cx)>,
}

impl<'a, Cx, T> Clone for JSManaged<'a, Cx, T> {
    fn clone(&self) -> Self {
        JSManaged {
            raw: self.raw,
            marker: self.marker,
        }
    }
}

impl<'a, Cx, T> Copy for JSManaged<'a, Cx, T> {
}

unsafe impl<'a, 'b, Cx, T> JSManageable<'b> for JSManaged<'a, Cx, T> where
    Cx: 'b,
    T: JSManageable<'b>,
{
    type ChangeLifetime = JSManaged<'b, Cx, T::ChangeLifetime>;
}

impl<'a, Cx, T> JSManaged<'a, Cx, T> {
    /// Convenience method for `access.get(self)`.
    pub fn get<'b, Access: JSAccess<Cx>>(self, access: &'b Access) -> &'b T::ChangeLifetime where
        T: JSManageable<'b>,
        'a: 'b,
    {
        access.get::<'b, 'b, T>(self)
    }

    /// Convenience method for `access.get_mut(self)`.
    pub fn get_mut<'b, Access: JSAccess<Cx>>(self, access: &'b mut Access) -> &'b mut T::ChangeLifetime where
        T: JSManageable<'b>,
        'a: 'b,
    {
        access.get_mut(self)
    }

    /// Change the lifetime of JS-managed data.
    pub unsafe fn change_lifetime<'b>(self) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
    {
        JSManaged {
            raw: self.raw as *mut T::ChangeLifetime,
            marker: PhantomData,
        }
    }

    /// It's safe to contract the lifetime of JS-managed data.
    pub fn contract_lifetime<'b>(self) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
        'a: 'b,
    {
        unsafe { self.change_lifetime() }
    }

    /// It's safe to extend the lifetime of JS-managed data if it has been snapshotted.
    pub fn extend_lifetime<'b>(self, _: &JSSnapshot<'b, Cx>) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
        'b: 'a,
    {
        unsafe { self.change_lifetime() }
    }
}

/// A root set.
pub struct JSRoots<Cx> {
    // The real thing would contain a set of rooted JS objects.
    marker: PhantomData<Cx>,
}

impl<Cx> JSRoots<Cx> {
    pub fn new() -> JSRoots<Cx> {
        JSRoots {
            marker: PhantomData,
        }
    }
    pub fn root<'a, 'b, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> JSManaged<'a, Cx, T::ChangeLifetime> where
        'a: 'b,
        T: JSManageable<'a>,
    {
        // The real thing would add the JS reflector to the root set
        unsafe { managed.change_lifetime() }
    }
}

impl<Cx> Drop for JSRoots<Cx> {
    fn drop(&mut self) {
        // The real thing would unroot the root set.
    }
}

/// A snapshot of a JS context.
///
/// The idea here is that during the lifetime of a JSSnapshot<Cx>, the JS state
/// doesn't change, and in particular GC doesn't happen. This allows us to avoid
/// some rooting.
pub struct JSSnapshot<'c, Cx: 'c>(&'c mut Cx);

impl<'c, Cx: 'c> JSSnapshot<'c, Cx> where
    Cx: JSContext
{
    /// Build a new snapshot
    pub fn new(cx: &mut Cx) -> JSSnapshot<Cx> {
        JSSnapshot(cx)
    }
}

impl<'c, Cx: 'c> JSAccess<Cx> for JSSnapshot<'c, Cx> where
    Cx: JSContext
{
    /// Read-only access to native JS-managed data.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>
    {
        self.0.get(managed)
    }

    /// Read-write access to native JS-managed data.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Cx, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>
    {
        self.0.get_mut(managed)
    }
}

// It is important for safety that this implemention is not made public!
struct JSContextImpl {
    // JS context implementation goes here
}

impl JSAccess<JSContextImpl> for JSContextImpl {
    // The claim is that this is safe, since it takes a `&self`.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Self, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>
    {
        unsafe { &*(managed.raw as *mut T::ChangeLifetime) }
    }

    // The claim is that this is safe, since it takes a `&mut self`.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Self, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>
    {
        unsafe { &mut *(managed.raw as *mut T::ChangeLifetime) }
    }
}

impl JSContext for JSContextImpl {
    fn snapshot(&mut self) -> JSSnapshot<Self> {
        JSSnapshot(self)
    }

    // This outline implementation just space-leaks all data,
    // the real thing would create a reflector, and add a finalizer hook.
    fn manage<'a, T>(&'a self, value: T) -> JSManaged<'a, Self, T>
        where T: 'a + JSManageable<'a, ChangeLifetime=T>
    {
        JSManaged {
            raw: Box::into_raw(Box::new(value)),
            marker: PhantomData,
        }
    }
}

#[test]
// This test constructs a two-node cyclic graph, which is the smallest
// example of something that uses `RefCell`s in servo's JS bindings.
fn test() {
    // A graph type
    type Graph<'a, Cx> = JSManaged<'a, Cx, NativeGraph<'a, Cx>>;
    struct NativeGraph<'a, Cx> {
        nodes: Vec<Node<'a, Cx>>,
    }
    unsafe impl<'a, 'b, Cx: 'b> JSManageable<'b> for NativeGraph<'a, Cx> { type ChangeLifetime = NativeGraph<'b, Cx>; }
    unsafe impl<'a, Cx> JSTraceable<Cx> for NativeGraph<'a, Cx> {}
    // A node type
    type Node<'a, Cx> = JSManaged<'a, Cx, NativeNode<'a, Cx>>;
    struct NativeNode<'a, Cx> {
        data: usize,
        edges: Vec<Node<'a, Cx>>,
    }
    unsafe impl<'a, 'b, Cx: 'b> JSManageable<'b> for NativeNode<'a, Cx> { type ChangeLifetime = NativeNode<'b, Cx>; }
    unsafe impl<'a, Cx> JSTraceable<Cx> for NativeNode<'a, Cx> {}
    // Build a cyclic graph
    struct Test;
    impl JSContextConsumer<()> for Test {
        fn consume<Cx>(self, cx: &mut Cx) where Cx: JSContext {
            let roots = JSRoots::new();
            let graph = roots.root(cx.manage(NativeGraph { nodes: vec![] }));
            self.add_nodes(cx, graph);
            assert_eq!(graph.get(cx).nodes[0].get(cx).data, 1);
            assert_eq!(graph.get(cx).nodes[1].get(cx).data, 2);
            self.add_edges(&mut cx.snapshot(), graph);
            assert_eq!(graph.get(cx).nodes[0].get(cx).edges[0].get(cx).data, 2);
            assert_eq!(graph.get(cx).nodes[1].get(cx).edges[0].get(cx).data, 1);
        }
    }
    impl Test {
        fn add_nodes<'a, 'b, Cx: JSContext>(&'a self, cx: &'a mut Cx, graph: Graph<'b, Cx>) {
            // Creating nodes does memory allocation, which may trigger GC,
            // so the nodes need to be rooted while they are being added.
            let roots = JSRoots::new();
            let node1 = roots.root(cx.manage(NativeNode { data: 1, edges: vec![] }));
            let node2 = roots.root(cx.manage(NativeNode { data: 2, edges: vec![] }));
            graph.get_mut(cx).nodes.push(node1.contract_lifetime());
            graph.get_mut(cx).nodes.push(node2.contract_lifetime());
        }
        fn add_edges<Cx: JSContext>(&self, cx: &mut JSSnapshot<Cx>, graph: Graph<Cx>) {
            // Note that there's no rooting here.
            let node1 = graph.get(cx).nodes[0].extend_lifetime(cx);
            let node2 = graph.get(cx).nodes[1].extend_lifetime(cx);
            node1.get_mut(cx).edges.push(node2.contract_lifetime());
            node2.get_mut(cx).edges.push(node1.contract_lifetime());
        }
    }
    #[allow(dead_code)]
    // Test that we can contract the lifetimes of nodes and graphs.
    fn contract_graph<'a, 'b:'a, Cx: 'b>(graph: Graph<'b, Cx>) -> Graph<'a, Cx> {
        graph.contract_lifetime()
    }
    with_js_context(Test);
}

#[test]
fn test_covariant() {
    #[allow(dead_code)]
    fn cast<'a, 'b:'a, Cx, T>(managed: JSManaged<'b, Cx, T>)
                              -> JSManaged<'a, Cx, T>
    {
        managed
    }
}
<commit_msg>Made JSTraceable a super-trait of JSManaged.<commit_after>//! An outline of how linear types could be combined with JS-managed data
//!
//! The idea is to use the JS context as a linear token.
//! Each JS context gets its own type `Cx` which implements the `JSContext` trait.
//! Access to read-only JS-managed data requires a context of type `&Cx`.
//! Access to read-write JS-managed data requires a context of type `&mut Cx`.
//! Linear use of the context ensures that Rust's memory safety is preserved (er, I hope).
//!
//! This API doesn't address tracing, which would have to be handled similarly
//! to servo's current JS bindings.
//!
//! One thing that makes this easier is that we can arrange for any
//! calls into the JS engine which might trigger GC to take a `&mut Cx`
//! argument, which gives us control of when GC might occur.

use std::marker::PhantomData;

/// The trait for accessing JS-managed data.
pub trait JSAccess<Cx>: Sized {
    /// Read-only access to native JS-managed data.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>;

    /// Read-write access to native JS-managed data.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Cx, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>;
}

/// The trait for JS contexts.
pub trait JSContext: JSAccess<Self> {
    /// Get a snapshot of the JS state.
    /// The snapshot only allows access to the methods that are guaranteed not to call GC,
    /// so we don't need to root JS-managed pointers during the lifetime of a snapshot.
    fn snapshot(&mut self) -> JSSnapshot<Self>;

    /// Give ownership of data to JS.
    /// This allocates JS heap, which may trigger GC.
    fn manage<'a, T>(&'a self, value: T) -> JSManaged<'a, Self, T>
        where T: 'a + JSManageable<'a, ChangeLifetime=T>;

    // A real implementation would also have JS methods such as those in jsapi.
}

/// A placholder for the real `JSTraceable`.
pub unsafe trait JSTraceable {}

/// The trait for native JS-manageable data.
pub unsafe trait JSManageable<'a>: JSTraceable {
    /// This type should have the same mnemory represention as `Self`.
    /// The only difference between `Self` and `Self::ChangeLifetime`
    /// is that any `JSManaged<'b, Cx, T>` should be replaced by
    /// `JSManaged<'a, Cx, T::ChangeLifetime>`.
    type ChangeLifetime: 'a;
}

/// A user of a JS context implements `JSContextConsumer`, which is called back
/// with a fresh JS context.
pub trait JSContextConsumer<T> {
    /// This callback is called with a fresh JS context.
    fn consume<Cx>(self, cx: &mut Cx) -> T where Cx: JSContext;
}

/// To create a fresh JS context, the user implements `JSContextConsumer`
/// for their type `K`, builds a `k:K`, then calls `with_js_context(k)`.
/// ```rust
///   struct MyConsumer;
///   impl JSContextConsumer<()> for MyConsumer {
///      fn consume<Cx: JSContext>(cx: Cx) {
///         // Do stuff with the JS context cx.
///      }
///   }
///   with_js_context(MyConsumer);
/// ```
pub fn with_js_context<C, T>(consumer: C) -> T where
    C: JSContextConsumer<T>
{
    // A real implementation would allocate a JS context
    let mut cx = JSContextImpl {};
    consumer.consume(&mut cx)
}

/// The type of JS-managed data in a JS context `Cx`.
///
/// If the user has access to a `&JSManaged`, then the JS-managed
/// data is live for the lifetime of the reference. In particular,
/// this means that there should never be any stack-allocated
/// `JSManaged` values, since they would allow the user to construct
/// `&JSManaged` references with arbitrary lifetimes.
pub struct JSManaged<'a, Cx, T> {
    // JS reflector goes here
    raw: *mut T,
    marker: PhantomData<(&'a(),Cx)>,
}

impl<'a, Cx, T> Clone for JSManaged<'a, Cx, T> {
    fn clone(&self) -> Self {
        JSManaged {
            raw: self.raw,
            marker: self.marker,
        }
    }
}

impl<'a, Cx, T> Copy for JSManaged<'a, Cx, T> {
}

unsafe impl<'a, Cx, T> JSTraceable for JSManaged<'a, Cx, T> where
    T: JSTraceable
{
}

unsafe impl<'a, 'b, Cx, T> JSManageable<'b> for JSManaged<'a, Cx, T> where
    Cx: 'b,
    T: JSManageable<'b>,
{
    type ChangeLifetime = JSManaged<'b, Cx, T::ChangeLifetime>;
}

impl<'a, Cx, T> JSManaged<'a, Cx, T> {
    /// Convenience method for `access.get(self)`.
    pub fn get<'b, Access: JSAccess<Cx>>(self, access: &'b Access) -> &'b T::ChangeLifetime where
        T: JSManageable<'b>,
        'a: 'b,
    {
        access.get::<'b, 'b, T>(self)
    }

    /// Convenience method for `access.get_mut(self)`.
    pub fn get_mut<'b, Access: JSAccess<Cx>>(self, access: &'b mut Access) -> &'b mut T::ChangeLifetime where
        T: JSManageable<'b>,
        'a: 'b,
    {
        access.get_mut(self)
    }

    /// Change the lifetime of JS-managed data.
    pub unsafe fn change_lifetime<'b>(self) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
    {
        JSManaged {
            raw: self.raw as *mut T::ChangeLifetime,
            marker: PhantomData,
        }
    }

    /// It's safe to contract the lifetime of JS-managed data.
    pub fn contract_lifetime<'b>(self) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
        'a: 'b,
    {
        unsafe { self.change_lifetime() }
    }

    /// It's safe to extend the lifetime of JS-managed data if it has been snapshotted.
    pub fn extend_lifetime<'b>(self, _: &JSSnapshot<'b, Cx>) -> JSManaged<'b, Cx, T::ChangeLifetime> where
        T: JSManageable<'b>,
        'b: 'a,
    {
        unsafe { self.change_lifetime() }
    }
}

/// A root set.
pub struct JSRoots<Cx> {
    // The real thing would contain a set of rooted JS objects.
    marker: PhantomData<Cx>,
}

impl<Cx> JSRoots<Cx> {
    pub fn new() -> JSRoots<Cx> {
        JSRoots {
            marker: PhantomData,
        }
    }
    pub fn root<'a, 'b, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> JSManaged<'a, Cx, T::ChangeLifetime> where
        'a: 'b,
        T: JSManageable<'a>,
    {
        // The real thing would add the JS reflector to the root set
        unsafe { managed.change_lifetime() }
    }
}

impl<Cx> Drop for JSRoots<Cx> {
    fn drop(&mut self) {
        // The real thing would unroot the root set.
    }
}

/// A snapshot of a JS context.
///
/// The idea here is that during the lifetime of a JSSnapshot<Cx>, the JS state
/// doesn't change, and in particular GC doesn't happen. This allows us to avoid
/// some rooting.
pub struct JSSnapshot<'c, Cx: 'c>(&'c mut Cx);

impl<'c, Cx: 'c> JSSnapshot<'c, Cx> where
    Cx: JSContext
{
    /// Build a new snapshot
    pub fn new(cx: &mut Cx) -> JSSnapshot<Cx> {
        JSSnapshot(cx)
    }
}

impl<'c, Cx: 'c> JSAccess<Cx> for JSSnapshot<'c, Cx> where
    Cx: JSContext
{
    /// Read-only access to native JS-managed data.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Cx, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>
    {
        self.0.get(managed)
    }

    /// Read-write access to native JS-managed data.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Cx, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>
    {
        self.0.get_mut(managed)
    }
}

// It is important for safety that this implemention is not made public!
struct JSContextImpl {
    // JS context implementation goes here
}

impl JSAccess<JSContextImpl> for JSContextImpl {
    // The claim is that this is safe, since it takes a `&self`.
    fn get<'a, 'b:'a, T>(&'a self, managed: JSManaged<'b, Self, T>) -> &'a T::ChangeLifetime where
        T: JSManageable<'a>
    {
        unsafe { &*(managed.raw as *mut T::ChangeLifetime) }
    }

    // The claim is that this is safe, since it takes a `&mut self`.
    fn get_mut<'a, 'b:'a, T>(&'a mut self, managed: JSManaged<'b, Self, T>) -> &'a mut T::ChangeLifetime where
        T: JSManageable<'a>
    {
        unsafe { &mut *(managed.raw as *mut T::ChangeLifetime) }
    }
}

impl JSContext for JSContextImpl {
    fn snapshot(&mut self) -> JSSnapshot<Self> {
        JSSnapshot(self)
    }

    // This outline implementation just space-leaks all data,
    // the real thing would create a reflector, and add a finalizer hook.
    fn manage<'a, T>(&'a self, value: T) -> JSManaged<'a, Self, T>
        where T: 'a + JSManageable<'a, ChangeLifetime=T>
    {
        JSManaged {
            raw: Box::into_raw(Box::new(value)),
            marker: PhantomData,
        }
    }
}

#[test]
// This test constructs a two-node cyclic graph, which is the smallest
// example of something that uses `RefCell`s in servo's JS bindings.
fn test() {
    // A graph type
    type Graph<'a, Cx> = JSManaged<'a, Cx, NativeGraph<'a, Cx>>;
    struct NativeGraph<'a, Cx> {
        nodes: Vec<Node<'a, Cx>>,
    }
    unsafe impl<'a, Cx> JSTraceable for NativeGraph<'a, Cx> {}
    unsafe impl<'a, 'b, Cx: 'b> JSManageable<'b> for NativeGraph<'a, Cx> { type ChangeLifetime = NativeGraph<'b, Cx>; }
    // A node type
    type Node<'a, Cx> = JSManaged<'a, Cx, NativeNode<'a, Cx>>;
    struct NativeNode<'a, Cx> {
        data: usize,
        edges: Vec<Node<'a, Cx>>,
    }
    unsafe impl<'a, Cx> JSTraceable for NativeNode<'a, Cx> {}
    unsafe impl<'a, 'b, Cx: 'b> JSManageable<'b> for NativeNode<'a, Cx> { type ChangeLifetime = NativeNode<'b, Cx>; }
    // Build a cyclic graph
    struct Test;
    impl JSContextConsumer<()> for Test {
        fn consume<Cx>(self, cx: &mut Cx) where Cx: JSContext {
            let roots = JSRoots::new();
            let graph = roots.root(cx.manage(NativeGraph { nodes: vec![] }));
            self.add_nodes(cx, graph);
            assert_eq!(graph.get(cx).nodes[0].get(cx).data, 1);
            assert_eq!(graph.get(cx).nodes[1].get(cx).data, 2);
            self.add_edges(&mut cx.snapshot(), graph);
            assert_eq!(graph.get(cx).nodes[0].get(cx).edges[0].get(cx).data, 2);
            assert_eq!(graph.get(cx).nodes[1].get(cx).edges[0].get(cx).data, 1);
        }
    }
    impl Test {
        fn add_nodes<'a, 'b, Cx: JSContext>(&'a self, cx: &'a mut Cx, graph: Graph<'b, Cx>) {
            // Creating nodes does memory allocation, which may trigger GC,
            // so the nodes need to be rooted while they are being added.
            let roots = JSRoots::new();
            let node1 = roots.root(cx.manage(NativeNode { data: 1, edges: vec![] }));
            let node2 = roots.root(cx.manage(NativeNode { data: 2, edges: vec![] }));
            graph.get_mut(cx).nodes.push(node1.contract_lifetime());
            graph.get_mut(cx).nodes.push(node2.contract_lifetime());
        }
        fn add_edges<Cx: JSContext>(&self, cx: &mut JSSnapshot<Cx>, graph: Graph<Cx>) {
            // Note that there's no rooting here.
            let node1 = graph.get(cx).nodes[0].extend_lifetime(cx);
            let node2 = graph.get(cx).nodes[1].extend_lifetime(cx);
            node1.get_mut(cx).edges.push(node2.contract_lifetime());
            node2.get_mut(cx).edges.push(node1.contract_lifetime());
        }
    }
    #[allow(dead_code)]
    // Test that we can contract the lifetimes of nodes and graphs.
    fn contract_graph<'a, 'b:'a, Cx: 'b>(graph: Graph<'b, Cx>) -> Graph<'a, Cx> {
        graph.contract_lifetime()
    }
    with_js_context(Test);
}

#[test]
fn test_covariant() {
    #[allow(dead_code)]
    fn cast<'a, 'b:'a, Cx, T>(managed: JSManaged<'b, Cx, T>)
                              -> JSManaged<'a, Cx, T>
    {
        managed
    }
}
<|endoftext|>


<commit_before>/// Creates a [`Vec`] containing the arguments.
///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro:
///
/// - Create a [`Vec`] containing a given list of elements:
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
///
/// - Create a [`Vec`] from a given element and size:
///
/// ```
/// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]);
/// ```
///
/// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant.
///
/// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently
/// boxed integers.
///
/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector.
/// This will still evaluate `expr`, however, and immediately drop the resulting value, so
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
#[cfg(not(test))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(box_syntax, liballoc_internals)]
macro_rules! vec {
    () => (
        $crate::force_expr!($crate::vec::Vec::new())
    );
    ($elem:expr; $n:expr) => (
        $crate::force_expr!($crate::vec::from_elem($elem, $n))
    );
    ($($x:expr),+ $(,)?) => (
        $crate::force_expr!(<[_]>::into_vec(box [$($x),+]))
    );
}

// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
// required for this macro definition, is not available. Instead use the
// `slice::into_vec`  function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),*) => (
        $crate::slice::into_vec(box [$($x),*])
    );
    ($($x:expr,)*) => (vec![$($x),*])
}

/// Creates a `String` using interpolation of runtime expressions.
///
/// The first argument `format!` receives is a format string. This must be a string
/// literal. The power of the formatting string is in the `{}`s contained.
///
/// Additional parameters passed to `format!` replace the `{}`s within the
/// formatting string in the order given unless named or positional parameters
/// are used; see [`std::fmt`] for more information.
///
/// A common use for `format!` is concatenation and interpolation of strings.
/// The same convention is used with [`print!`] and [`write!`] macros,
/// depending on the intended destination of the string.
///
/// To convert a single value to a string, use the [`to_string`] method. This
/// will use the [`Display`] formatting trait.
///
/// [`std::fmt`]: ../std/fmt/index.html
/// [`print!`]: ../std/macro.print.html
/// [`write!`]: core::write
/// [`to_string`]: crate::string::ToString
/// [`Display`]: core::fmt::Display
///
/// # Panics
///
/// `format!` panics if a formatting trait implementation returns an error.
/// This indicates an incorrect implementation
/// since `fmt::Write for String` never returns an error itself.
///
/// # Examples
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! format {
    ($($arg:tt)*) => {{
        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
        res
    }}
}

/// Force AST node to an expression to improve diagnostics in pattern position.
#[doc(hidden)]
#[macro_export]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
macro_rules! force_expr {
    ($e:expr) => {
        $e
    };
}
<commit_msg>Rename alloc::force_expr to __rust_force_expr.<commit_after>/// Creates a [`Vec`] containing the arguments.
///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro:
///
/// - Create a [`Vec`] containing a given list of elements:
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3);
/// ```
///
/// - Create a [`Vec`] from a given element and size:
///
/// ```
/// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]);
/// ```
///
/// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant.
///
/// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently
/// boxed integers.
///
/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector.
/// This will still evaluate `expr`, however, and immediately drop the resulting value, so
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
#[cfg(not(test))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(box_syntax, liballoc_internals)]
macro_rules! vec {
    () => (
        $crate::__rust_force_expr!($crate::vec::Vec::new())
    );
    ($elem:expr; $n:expr) => (
        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
    );
    ($($x:expr),+ $(,)?) => (
        $crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
    );
}

// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
// required for this macro definition, is not available. Instead use the
// `slice::into_vec`  function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
macro_rules! vec {
    () => (
        $crate::vec::Vec::new()
    );
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );
    ($($x:expr),*) => (
        $crate::slice::into_vec(box [$($x),*])
    );
    ($($x:expr,)*) => (vec![$($x),*])
}

/// Creates a `String` using interpolation of runtime expressions.
///
/// The first argument `format!` receives is a format string. This must be a string
/// literal. The power of the formatting string is in the `{}`s contained.
///
/// Additional parameters passed to `format!` replace the `{}`s within the
/// formatting string in the order given unless named or positional parameters
/// are used; see [`std::fmt`] for more information.
///
/// A common use for `format!` is concatenation and interpolation of strings.
/// The same convention is used with [`print!`] and [`write!`] macros,
/// depending on the intended destination of the string.
///
/// To convert a single value to a string, use the [`to_string`] method. This
/// will use the [`Display`] formatting trait.
///
/// [`std::fmt`]: ../std/fmt/index.html
/// [`print!`]: ../std/macro.print.html
/// [`write!`]: core::write
/// [`to_string`]: crate::string::ToString
/// [`Display`]: core::fmt::Display
///
/// # Panics
///
/// `format!` panics if a formatting trait implementation returns an error.
/// This indicates an incorrect implementation
/// since `fmt::Write for String` never returns an error itself.
///
/// # Examples
///
/// ```
/// format!("test");
/// format!("hello {}", "world!");
/// format!("x = {}, y = {y}", 10, y = 30);
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! format {
    ($($arg:tt)*) => {{
        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
        res
    }}
}

/// Force AST node to an expression to improve diagnostics in pattern position.
#[doc(hidden)]
#[macro_export]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
macro_rules! __rust_force_expr {
    ($e:expr) => {
        $e
    };
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate getopts;
extern crate markovpass;
extern crate test;

use markovpass::*;
use std::error::Error;
use std::io::Write;

fn build_opts() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optopt("n", "", "Number of passphrases to generate (default 1)", "NUM");
    opts.optopt("e", "", "Minimum entropy (default 60)", "MINENTROPY");
    opts.optopt("l", "", "NGram length (default 3, must be > 1)", "LENGTH");
    opts.optopt("w", "", "Minimum word length for corpus (default 5)", "LENGTH");
    opts.optflag("h", "help", "Display this help and exit");

    opts
}

fn parse_flag<T: std::str::FromStr>(matches: &getopts::Matches, flag: &str, default: T)
        -> Result<T, &'static str> {
    matches.opt_str(flag)
        .map(|c| c.parse::<T>())
        .unwrap_or(Ok(default))
        .map_err(|_| "Failed to parse flag.")
}

fn parse_args(opts: &getopts::Options, args: &Vec<String>)
        -> Result<(Option<String>, usize, f64, usize, usize), &'static str> {
    let matches = try!(opts.parse(&args[1..]).map_err(|_| "Failed to parse arguments."));

    if matches.opt_present("h") || matches.free.len() > 1 {
        return Err("Failed to parse arguments.");
    };

    let number = try!(parse_flag(&matches, "n", 1));
    let min_entropy = try!(parse_flag(&matches, "e", 60.0));
    let ngram_length = try!(parse_flag(&matches, "l", 3));
    let min_word_length = try!(parse_flag(&matches, "w", 5));

    if ngram_length < 2 {
        return Err("Ngram length must be greater than one.");
    };

    let filename = if matches.free.is_empty() || matches.free[0] == "-" {
        None
    } else {
        Some(matches.free[0].clone())
    };

    Ok((filename, number, min_entropy, ngram_length, min_word_length))
}

fn get_corpus(filename: Option<&str>) -> Result<String, std::io::Error> {
    let mut input: Box<std::io::Read> = match filename {
        Some(filename) => Box::new(try!(std::fs::File::open(&filename))),
        None => Box::new(std::io::stdin()),
    };
    let mut corpus = String::new();
    try!(input.read_to_string(&mut corpus));

    Ok(corpus)
}

fn is_word_char(c: char) -> bool {
    c.is_alphabetic() || c == '\''
}

fn clean_word(word: &str, min_length: usize) -> Option<&str> {
    let word = word.trim_matches(|c| ! is_word_char(c));

    if word.chars().all(is_word_char) && word.len() >= min_length {
        Some(word)
    } else {
        None
    }
}

fn get_ngrams(corpus: String, ngram_length: usize, min_word_length: usize) -> Vec<String> {
    let corpus = corpus.to_lowercase();
    let words = corpus.split_whitespace()
      .filter_map(|word| clean_word(word, min_word_length));
    let cleaned_corpus = Some("").into_iter().chain(words).collect::<Vec<&str>>().join(" ");
    let count = cleaned_corpus.chars().count();
    if count < ngram_length { return vec![]; };

    let mut chars = cleaned_corpus.chars().cycle();
    let mut ngrams = Vec::with_capacity(count);
    for _ in 0..count {
        let ngram: String = chars.clone().take(ngram_length).collect();
        ngrams.push(ngram);
        chars.next();
    };

    ngrams
}

fn gen_passphrases(ngrams: Vec<String>, number: usize, min_entropy: f64)
        -> Result<Vec<(String, f64)>, PassphraseMarkovChainError> {
    let chain = try!(PassphraseMarkovChain::new(ngrams.iter().cloned()));
    let mut passphrases = Vec::with_capacity(number);
    for _ in 0..number {
        passphrases.push(chain.passphrase(min_entropy));
    };

    Ok(passphrases)
}

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [FILE] [options]", program);
    print!("{}", opts.usage(&brief));
}

fn write_error(message: &str) {
    writeln!(&mut std::io::stderr(), "{}", &message).expect("Failed to write to stderr.");
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();
    let opts = build_opts();

    let (filename, number, min_entropy, ngram_length, min_word_length) =
            match parse_args(&opts, &args) {
        Ok(parsed_args) => { parsed_args },
        Err(_) => {
            print_usage(&program, &opts);
            return;
        }
    };
    let corpus = match get_corpus(filename.as_ref().map(String::as_ref)) {
        Ok(corpus) => { corpus },
        Err(_) => {
            let filename_str = filename.unwrap_or("-".to_string());
            write_error(&format!("{}: {}: {}", &program, &filename_str, "Failed to read input."));
            return;
        },
    };
    let ngrams = get_ngrams(corpus, ngram_length, min_word_length);
    let passphrases = match gen_passphrases(ngrams, number, min_entropy) {
        Ok(passphrases) => { passphrases },
        Err(e) => {
            write_error(&format!("{}: {}", &program, e.description()));
            return;
        },
    };

    for (passphrase, entropy) in passphrases {
        println!("{} <{}>", passphrase, entropy);
    };
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use super::{clean_word,get_corpus,get_ngrams,gen_passphrases};
    use test::Bencher;

    #[test]
    fn test_clean_word() {
        assert_eq!(clean_word("Test", 3), Some("Test"));
        assert_eq!(clean_word("123test@314", 3), Some("test"));
        assert_eq!(clean_word("2#@test'in23", 3), Some("test'in"));
        assert_eq!(clean_word("31ld;Test", 3), None);
        assert_eq!(clean_word("a", 2), None);
        assert_eq!(clean_word("Test", 5), None);
    }

    #[test]
    fn test_get_ngrams() {
        assert_eq!(
            get_ngrams("this is a test".to_string(), 3, 3),
            vec! [" th", "thi", "his", "is ", "s t", " te", "tes", "est", "st ", "t t"]
        );
        assert_eq!(
            get_ngrams("this is a test".to_string(), 5, 3),
            vec! [" this", "this ", "his t", "is te", "s tes", " test",
                  "test ", "est t", "st th", "t thi"]
        );
        assert_eq!(
            get_ngrams("this is a test".to_string(), 3, 2),
            vec! [" th", "thi", "his", "is ", "s i", " is", "is ", "s t",
                  " te", "tes", "est", "st ", "t t"]
        );
        assert!(get_ngrams("this is a test".to_string(), 3, 5).is_empty(), "Ngrams not empty");
        assert_eq!(
            get_ngrams("Some awes0me test".to_string(), 6, 3),
            vec! [" some ", "some t", "ome te", "me tes", "e test", " test ",
                  "test s", "est so", "st som", "t some"]
        );
        assert_eq!(
            get_ngrams("test'in".to_string(), 3, 3),
            vec! [" te", "tes", "est", "st'", "t'i", "'in", "in ", "n t"]
        );
    }

    #[test]
    fn test_gen_passphrases() {
        let ngrams = get_ngrams("tic toc".to_string(), 3, 3);
        let min_entropy = 60.0;
        let result = gen_passphrases(ngrams, 5, min_entropy);
        assert!(result.is_ok(), "Passphrase generation failed.");
        let passphrases = result.unwrap();
        assert_eq!(passphrases.len(), 5);
    }

    #[test]
    fn test_gen_passphrases_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no ngrams.");
    }

    #[test]
    fn test_gen_passphrases_no_entropy() {
        let ngrams = get_ngrams("abc def ghijkl mnopqr stuvw xyz".to_string(), 2, 1);
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no entropy.");
    }

    #[test]
    fn test_gen_passphrases_no_starting_entropy() {
        let ngrams = get_ngrams("tictoctictactoe".to_string(), 2, 1);
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no starting entropy.");
    }

    #[bench]
    fn bench_get_ngrams(b: &mut Bencher) {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("testdata/Jane Austen - Pride and Prejudice.txt");
        let corpus = get_corpus(p.to_str()).unwrap();
        b.iter(|| get_ngrams(corpus.clone(), 3, 5));
    }
}
<commit_msg>Add gen_passphrases benchmark<commit_after>#![feature(test)]

extern crate getopts;
extern crate markovpass;
extern crate test;

use markovpass::*;
use std::error::Error;
use std::io::Write;

fn build_opts() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optopt("n", "", "Number of passphrases to generate (default 1)", "NUM");
    opts.optopt("e", "", "Minimum entropy (default 60)", "MINENTROPY");
    opts.optopt("l", "", "NGram length (default 3, must be > 1)", "LENGTH");
    opts.optopt("w", "", "Minimum word length for corpus (default 5)", "LENGTH");
    opts.optflag("h", "help", "Display this help and exit");

    opts
}

fn parse_flag<T: std::str::FromStr>(matches: &getopts::Matches, flag: &str, default: T)
        -> Result<T, &'static str> {
    matches.opt_str(flag)
        .map(|c| c.parse::<T>())
        .unwrap_or(Ok(default))
        .map_err(|_| "Failed to parse flag.")
}

fn parse_args(opts: &getopts::Options, args: &Vec<String>)
        -> Result<(Option<String>, usize, f64, usize, usize), &'static str> {
    let matches = try!(opts.parse(&args[1..]).map_err(|_| "Failed to parse arguments."));

    if matches.opt_present("h") || matches.free.len() > 1 {
        return Err("Failed to parse arguments.");
    };

    let number = try!(parse_flag(&matches, "n", 1));
    let min_entropy = try!(parse_flag(&matches, "e", 60.0));
    let ngram_length = try!(parse_flag(&matches, "l", 3));
    let min_word_length = try!(parse_flag(&matches, "w", 5));

    if ngram_length < 2 {
        return Err("Ngram length must be greater than one.");
    };

    let filename = if matches.free.is_empty() || matches.free[0] == "-" {
        None
    } else {
        Some(matches.free[0].clone())
    };

    Ok((filename, number, min_entropy, ngram_length, min_word_length))
}

fn get_corpus(filename: Option<&str>) -> Result<String, std::io::Error> {
    let mut input: Box<std::io::Read> = match filename {
        Some(filename) => Box::new(try!(std::fs::File::open(&filename))),
        None => Box::new(std::io::stdin()),
    };
    let mut corpus = String::new();
    try!(input.read_to_string(&mut corpus));

    Ok(corpus)
}

fn is_word_char(c: char) -> bool {
    c.is_alphabetic() || c == '\''
}

fn clean_word(word: &str, min_length: usize) -> Option<&str> {
    let word = word.trim_matches(|c| ! is_word_char(c));

    if word.chars().all(is_word_char) && word.len() >= min_length {
        Some(word)
    } else {
        None
    }
}

fn get_ngrams(corpus: String, ngram_length: usize, min_word_length: usize) -> Vec<String> {
    let corpus = corpus.to_lowercase();
    let words = corpus.split_whitespace()
      .filter_map(|word| clean_word(word, min_word_length));
    let cleaned_corpus = Some("").into_iter().chain(words).collect::<Vec<&str>>().join(" ");
    let count = cleaned_corpus.chars().count();
    if count < ngram_length { return vec![]; };

    let mut chars = cleaned_corpus.chars().cycle();
    let mut ngrams = Vec::with_capacity(count);
    for _ in 0..count {
        let ngram: String = chars.clone().take(ngram_length).collect();
        ngrams.push(ngram);
        chars.next();
    };

    ngrams
}

fn gen_passphrases(ngrams: Vec<String>, number: usize, min_entropy: f64)
        -> Result<Vec<(String, f64)>, PassphraseMarkovChainError> {
    let chain = try!(PassphraseMarkovChain::new(ngrams.iter().cloned()));
    let mut passphrases = Vec::with_capacity(number);
    for _ in 0..number {
        passphrases.push(chain.passphrase(min_entropy));
    };

    Ok(passphrases)
}

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [FILE] [options]", program);
    print!("{}", opts.usage(&brief));
}

fn write_error(message: &str) {
    writeln!(&mut std::io::stderr(), "{}", &message).expect("Failed to write to stderr.");
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();
    let opts = build_opts();

    let (filename, number, min_entropy, ngram_length, min_word_length) =
            match parse_args(&opts, &args) {
        Ok(parsed_args) => { parsed_args },
        Err(_) => {
            print_usage(&program, &opts);
            return;
        }
    };
    let corpus = match get_corpus(filename.as_ref().map(String::as_ref)) {
        Ok(corpus) => { corpus },
        Err(_) => {
            let filename_str = filename.unwrap_or("-".to_string());
            write_error(&format!("{}: {}: {}", &program, &filename_str, "Failed to read input."));
            return;
        },
    };
    let ngrams = get_ngrams(corpus, ngram_length, min_word_length);
    let passphrases = match gen_passphrases(ngrams, number, min_entropy) {
        Ok(passphrases) => { passphrases },
        Err(e) => {
            write_error(&format!("{}: {}", &program, e.description()));
            return;
        },
    };

    for (passphrase, entropy) in passphrases {
        println!("{} <{}>", passphrase, entropy);
    };
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use super::{clean_word,get_corpus,get_ngrams,gen_passphrases};
    use test::Bencher;

    #[test]
    fn test_clean_word() {
        assert_eq!(clean_word("Test", 3), Some("Test"));
        assert_eq!(clean_word("123test@314", 3), Some("test"));
        assert_eq!(clean_word("2#@test'in23", 3), Some("test'in"));
        assert_eq!(clean_word("31ld;Test", 3), None);
        assert_eq!(clean_word("a", 2), None);
        assert_eq!(clean_word("Test", 5), None);
    }

    #[test]
    fn test_get_ngrams() {
        assert_eq!(
            get_ngrams("this is a test".to_string(), 3, 3),
            vec! [" th", "thi", "his", "is ", "s t", " te", "tes", "est", "st ", "t t"]
        );
        assert_eq!(
            get_ngrams("this is a test".to_string(), 5, 3),
            vec! [" this", "this ", "his t", "is te", "s tes", " test",
                  "test ", "est t", "st th", "t thi"]
        );
        assert_eq!(
            get_ngrams("this is a test".to_string(), 3, 2),
            vec! [" th", "thi", "his", "is ", "s i", " is", "is ", "s t",
                  " te", "tes", "est", "st ", "t t"]
        );
        assert!(get_ngrams("this is a test".to_string(), 3, 5).is_empty(), "Ngrams not empty");
        assert_eq!(
            get_ngrams("Some awes0me test".to_string(), 6, 3),
            vec! [" some ", "some t", "ome te", "me tes", "e test", " test ",
                  "test s", "est so", "st som", "t some"]
        );
        assert_eq!(
            get_ngrams("test'in".to_string(), 3, 3),
            vec! [" te", "tes", "est", "st'", "t'i", "'in", "in ", "n t"]
        );
    }

    #[test]
    fn test_gen_passphrases() {
        let ngrams = get_ngrams("tic toc".to_string(), 3, 3);
        let min_entropy = 60.0;
        let result = gen_passphrases(ngrams, 5, min_entropy);
        assert!(result.is_ok(), "Passphrase generation failed.");
        let passphrases = result.unwrap();
        assert_eq!(passphrases.len(), 5);
    }

    #[test]
    fn test_gen_passphrases_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no ngrams.");
    }

    #[test]
    fn test_gen_passphrases_no_entropy() {
        let ngrams = get_ngrams("abc def ghijkl mnopqr stuvw xyz".to_string(), 2, 1);
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no entropy.");
    }

    #[test]
    fn test_gen_passphrases_no_starting_entropy() {
        let ngrams = get_ngrams("tictoctictactoe".to_string(), 2, 1);
        let result = gen_passphrases(ngrams, 1, 60.0);
        assert!(result.is_err(), "No error despite no starting entropy.");
    }

    #[bench]
    fn bench_get_ngrams(b: &mut Bencher) {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("testdata/Jane Austen - Pride and Prejudice.txt");
        let corpus = get_corpus(p.to_str()).unwrap();
        b.iter(|| get_ngrams(corpus.clone(), 3, 5));
    }

    #[bench]
    fn bench_gen_passphrases(b: &mut Bencher) {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("testdata/Jane Austen - Pride and Prejudice.txt");
        let corpus = get_corpus(p.to_str()).unwrap();
        let ngrams = get_ngrams(corpus, 3, 5);
        b.iter(|| gen_passphrases(ngrams.clone(), 1, 80.0));
    }
}
<|endoftext|>


<commit_before>use cast::transmute;
use cmp::Eq;
use num::from_int;
use ptr::to_unsafe_ptr;
use vec::raw::buf_as_slice;
use std::cmp::FuzzyEq;

use funs::exp::Exp;
use math::*;
use matrix::{Mat3, Mat4};
use ncast::*;
use vector::Vec3;

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;         /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;         /// a double-precision floating-point quaternion

//
//  Quaternion
//
pub trait Quaternion<T> {
    pure fn dim() -> uint;

    pure fn mul_t(value: T) -> self;
    pure fn div_t(value: T) -> self;

    // pure fn mul_v(other: &Vec3) -> Vec3;

    pure fn add_q(other: &self) -> self;
    pure fn sub_q(other: &self) -> self;
    pure fn mul_q(other: &self) -> self;

    pure fn dot(other: &self) -> T;

    pure fn conjugate() -> self;
    pure fn inverse() -> self;
    pure fn length2() -> T;
    pure fn length() -> T;

    pure fn to_Mat3() -> Mat3<T>;
    pure fn to_Mat4() -> Mat4<T>;
}

pub trait ToQuat<T> {
    pure fn to_Quat() -> Quat<T>;
}

pub struct Quat<T> { w: T, x: T, y: T, z: T }

pub mod Quat {

    #[inline(always)]
    pub pure fn new<T>(w: T, x: T, y: T, z: T) -> Quat<T> {
        Quat { w: move w, x: move x, y: move y, z: move z }
    }

    #[inline(always)]
    pub pure fn from_sv<T:Copy>(s: T, v: Vec3<T>) -> Quat<T> {
        Quat::new(s, v.x, v.y, v.z)
    }

    #[inline(always)]
    pub pure fn zero<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(_0, _0, _0, _0)
    }

    #[inline(always)]
    pub pure fn identity<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(cast(1), _0, _0, _0)
    }
}

pub impl<T:Copy Num NumCast Exp FuzzyEq> Quat<T>: Quaternion<T> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn mul_t(value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn add_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
                  self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
                  self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z,
                  self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x)
    }

    #[inline(always)]
    pure fn dot(other: &Quat<T>) -> T {
        self.w * other.w +
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    #[inline(always)]
    pure fn conjugate() -> Quat<T> {
        Quat::new(self.w, -self.x, -self.y, -self.z)
    }

    #[inline(always)]
    pure fn inverse() -> Quat<T> {
        let mut n: T = from_int(1);
        n /= self.length2();
        self.conjugate().mul_t(n)
    }

    #[inline(always)]
    pure fn length2() -> T {
        self.w * self.w +
        self.x * self.x +
        self.y * self.y +
        self.z * self.z
    }

    #[inline(always)]
    pure fn length() -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn to_Mat3() -> Mat3<T> {
        let x2 = self.x + self.x;
        let y2 = self.y + self.y;
        let z2 = self.z + self.z;

        let xx2 = x2 * self.x;
        let xy2 = x2 * self.y;
        let xz2 = x2 * self.z;

        let yy2 = y2 * self.y;
        let yz2 = y2 * self.z;
        let zz2 = z2 * self.z;

        let wy2 = y2 * self.w;
        let wz2 = z2 * self.w;
        let wx2 = x2 * self.w;

        let _1: T = from_int(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 - wz2,      xz2 + wy2,
                       xy2 + wz2, _1 - xx2 - zz2,      yz2 - wx2,
                       xz2 - wy2,      yz2 + wx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_Mat4() -> Mat4<T> {
        self.to_Mat3().to_Mat4()
    }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&self)), 4) |slice| { slice[i] }
        }
    }
}

pub impl<T:Copy Neg<T>> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg() -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

// TODO: make work for T:Integer
pub impl<T:Copy FuzzyEq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(other: &Quat<T>) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn ne(other: &Quat<T>) -> bool {
        !(self == *other)
    }
}

pub impl<T:Copy Eq> Quat<T>: ExactEq {
    #[inline(always)]
    pure fn exact_eq(other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr() -> *T {
        to_unsafe_ptr(&self[0])
    }
}<commit_msg>Add normalize method<commit_after>use cast::transmute;
use cmp::Eq;
use num::from_int;
use ptr::to_unsafe_ptr;
use vec::raw::buf_as_slice;
use std::cmp::FuzzyEq;

use funs::exp::Exp;
use math::*;
use matrix::{Mat3, Mat4};
use ncast::*;
use vector::Vec3;

// These quaternion type aliases are not actually specified in the GLSL spec
// but they follow the same nomenclature

pub type quat4  = Quat<f32>;         /// a single-precision floating-point quaternion
pub type dquat4 = Quat<f64>;         /// a double-precision floating-point quaternion

//
//  Quaternion
//
pub trait Quaternion<T> {
    pure fn dim() -> uint;

    pure fn mul_t(value: T) -> self;
    pure fn div_t(value: T) -> self;

    // pure fn mul_v(other: &Vec3) -> Vec3;

    pure fn add_q(other: &self) -> self;
    pure fn sub_q(other: &self) -> self;
    pure fn mul_q(other: &self) -> self;

    pure fn dot(other: &self) -> T;

    pure fn conjugate() -> self;
    pure fn inverse() -> self;
    pure fn length2() -> T;
    pure fn length() -> T;
    pure fn normalize() -> self;

    pure fn to_Mat3() -> Mat3<T>;
    pure fn to_Mat4() -> Mat4<T>;
}

pub trait ToQuat<T> {
    pure fn to_Quat() -> Quat<T>;
}

pub struct Quat<T> { w: T, x: T, y: T, z: T }

pub mod Quat {

    #[inline(always)]
    pub pure fn new<T>(w: T, x: T, y: T, z: T) -> Quat<T> {
        Quat { w: move w, x: move x, y: move y, z: move z }
    }

    #[inline(always)]
    pub pure fn from_sv<T:Copy>(s: T, v: Vec3<T>) -> Quat<T> {
        Quat::new(s, v.x, v.y, v.z)
    }

    #[inline(always)]
    pub pure fn zero<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(_0, _0, _0, _0)
    }

    #[inline(always)]
    pub pure fn identity<T:Copy NumCast>() -> Quat<T> {
        let _0 = cast(0);
        Quat::new(cast(1), _0, _0, _0)
    }
}

pub impl<T:Copy Num NumCast Exp FuzzyEq> Quat<T>: Quaternion<T> {
    #[inline(always)]
    pure fn dim() -> uint { 4 }

    #[inline(always)]
    pure fn mul_t(value: T) -> Quat<T> {
        Quat::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(value: T) -> Quat<T> {
        Quat::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn add_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_q(other: &Quat<T>) -> Quat<T> {
        Quat::new(self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
                  self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
                  self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z,
                  self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x)
    }

    #[inline(always)]
    pure fn dot(other: &Quat<T>) -> T {
        self.w * other.w +
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    #[inline(always)]
    pure fn conjugate() -> Quat<T> {
        Quat::new(self.w, -self.x, -self.y, -self.z)
    }

    #[inline(always)]
    pure fn inverse() -> Quat<T> {
        let mut n: T = from_int(1);
        n /= self.length2();
        self.conjugate().mul_t(n)
    }

    #[inline(always)]
    pure fn length2() -> T {
        self.w * self.w +
        self.x * self.x +
        self.y * self.y +
        self.z * self.z
    }

    #[inline(always)]
    pure fn length() -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn normalize() -> Quat<T> {
        let mut n: T = cast(1);
        n /= self.length();
        return self.mul_t(n);
    }

    #[inline(always)]
    pure fn to_Mat3() -> Mat3<T> {
        let x2 = self.x + self.x;
        let y2 = self.y + self.y;
        let z2 = self.z + self.z;

        let xx2 = x2 * self.x;
        let xy2 = x2 * self.y;
        let xz2 = x2 * self.z;

        let yy2 = y2 * self.y;
        let yz2 = y2 * self.z;
        let zz2 = z2 * self.z;

        let wy2 = y2 * self.w;
        let wz2 = z2 * self.w;
        let wx2 = x2 * self.w;

        let _1: T = from_int(1);

        Mat3::new(_1 - yy2 - zz2,      xy2 - wz2,      xz2 + wy2,
                       xy2 + wz2, _1 - xx2 - zz2,      yz2 - wx2,
                       xz2 - wy2,      yz2 + wx2, _1 - xx2 - yy2)
    }

    #[inline(always)]
    pure fn to_Mat4() -> Mat4<T> {
        self.to_Mat3().to_Mat4()
    }
}

pub impl<T:Copy> Quat<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(i: uint) -> T {
        unsafe { do buf_as_slice(
            transmute::<*Quat<T>, *T>(
                to_unsafe_ptr(&self)), 4) |slice| { slice[i] }
        }
    }
}

pub impl<T:Copy Neg<T>> Quat<T>: Neg<Quat<T>> {
    #[inline(always)]
    pure fn neg() -> Quat<T> {
        Quat::new(-self[0], -self[1], -self[2], -self[3])
    }
}

// TODO: make work for T:Integer
pub impl<T:Copy FuzzyEq> Quat<T>: Eq {
    #[inline(always)]
    pure fn eq(other: &Quat<T>) -> bool {
        self.fuzzy_eq(other)
    }

    #[inline(always)]
    pure fn ne(other: &Quat<T>) -> bool {
        !(self == *other)
    }
}

pub impl<T:Copy Eq> Quat<T>: ExactEq {
    #[inline(always)]
    pure fn exact_eq(other: &Quat<T>) -> bool {
        self[0] == other[0] &&
        self[1] == other[1] &&
        self[2] == other[2] &&
        self[3] == other[3]
    }
}

pub impl<T:Copy FuzzyEq> Quat<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Quat<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy> Quat<T>: ToPtr<T> {
    #[inline(always)]
    pure fn to_ptr() -> *T {
        to_unsafe_ptr(&self[0])
    }
}<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::ops::Index;
use std::ops::IndexMut;

#[derive(Copy, Clone)]
pub enum MemSection {
    Vram,
    RomBank0,
}

pub struct AddressSpace {
    bios:  [u8; 0x100],
    data: [u8; 0x10000],
    bios_readable: bool,
}

pub const IOREG_P1:     u16 = 0xFF00;
pub const IOREG_SB:     u16 = 0xFF01;
pub const IOREG_DIV:    u16 = 0xFF04;
pub const IOREG_TIMA:   u16 = 0xFF05;
pub const IOREG_TMA:    u16 = 0xFF06;
pub const IOREG_TAC:    u16 = 0xFF07;
pub const IOREG_IF:     u16 = 0xFF0F;
pub const IOREG_LCDC:   u16 = 0xFF40;
pub const IOREG_STAT:   u16 = 0xFF41;
pub const IOREG_SCY:    u16 = 0xFF42;
pub const IOREG_SCX:    u16 = 0xFF43;
pub const IOREG_LY:     u16 = 0xFF44;
pub const IOREG_LYC:    u16 = 0xFF45;
pub const IOREG_DMA:    u16 = 0xFF46;
pub const IOREG_BGP:    u16 = 0xFF47;
pub const IOREG_OBP0:   u16 = 0xFF48;
pub const IOREG_OBP1:   u16 = 0xFF49;
pub const IOREG_WY:     u16 = 0xFF4A;
pub const IOREG_WX:     u16 = 0xFF4B;
pub const IOREG_BIOSRW: u16 = 0xFF50;
pub const IOREG_IE:     u16 = 0xFFFF;

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace {
            bios: [0; 0x100],
            data: [0; 0x10000],
            bios_readable: true,
        }
    }

    pub fn read(&self, addr: u16) -> u8 {
        if addr < 0x100 && self.bios_readable {
            self.bios[addr as usize]
        } else {
            self.data[addr as usize]
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let lo = self.read(addr) as u16;
        let hi = (self.read(addr + 1) as u16) << 8;
        lo | hi
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        let mut addr = addr;
        let mut data = data;
        let rw = match addr {
            // ROM Banks, read only
            0x0000...0x7FFF => false,
            // Switchable RAM bank
            // TODO: Make RAM switchable
            0xA000...0xBFFF => true,
            // Internal RAM echo
            0xE000...0xFDFF => {
                addr -= 0x2000;
                true
            },
            // I/O registers
            IOREG_DIV => {
                data = 0;
                true
            },
            IOREG_LY => {
                data = 0;
                true
            },
            // Don't write, but begin a DMA instead
            IOREG_DMA => {
                let to_addr = 0xFE00;
                let from_addr = (data as u16) << 8;
                for i in 0x000..0x100 {
                    self.data[to_addr as usize + i] = self.data[from_addr as usize + i];
                }
                true
            },
            // Disable access to BIOS memory
            IOREG_BIOSRW => {
                if self.bios_readable && data == 1 {
                    self.bios_readable = false;
                }
                false
            },
            // No special write rules
            _ => true,
        };
        if rw {
            self.data[addr as usize] = data;
        }
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.write(addr, lo);
        self.write(addr + 1, hi);
    }

    pub fn load_bios(&mut self, bios: &mut File) -> ::std::io::Result<()> {
        try!(bios.read(&mut self.bios[0x000..0x100]));
        Ok(())
    }

    pub fn load_rom(&mut self, rom: &mut File) -> ::std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

    pub fn set_bios_readable(&mut self) {
        self.bios_readable = true;
    }

}

impl Index<u16> for AddressSpace {
    type Output = u8;

    fn index(&self, idx: u16) -> &u8 {
        &self.data[idx as usize]
    }
}

impl IndexMut<u16> for AddressSpace {
    fn index_mut(&mut self, idx: u16) -> &mut u8 {
        &mut self.data[idx as usize]
    }
}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x000,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = (((data & 0xFF00) >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.e = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

    pub fn get_pc(&self) -> u16 {
        self.pc
    }

}
<commit_msg>Implement WriteObserver to aid caching<commit_after>use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::ops::Index;
use std::ops::IndexMut;

#[derive(Copy, Clone)]
pub enum MemSection {
    Vram,
    RomBank0,
}

pub const REGION_TILEDATA_UNSIGNED_BEG: u16 = 0x8000;
pub const REGION_TILEDATA_UNSIGNED_END: u16 = 0x8FFF;
pub const REGION_TILEDATA_SIGNED_BEG:   u16 = 0x8800;
pub const REGION_TILEDATA_SIGNED_END:   u16 = 0x97FF;
pub const REGION_TILEMAP0_BEG:          u16 = 0x9800;
pub const REGION_TILEMAP0_END:          u16 = 0x9BFF;
pub const REGION_TILEMAP1_BEG:          u16 = 0x9C00;
pub const REGION_TILEMAP1_END:          u16 = 0x9FFF;

pub enum Region {
    TileDataUnsigned,
    TileDataSigned,
    TileMap0,
    TileMap1,
}

pub struct WriteObserver {
    td_signed_dirty:    bool,
    td_unsigned_dirty:  bool,
    tmap0_dirty:        bool,
    tmap1_dirty:        bool,
}

impl WriteObserver {

    pub fn new() -> WriteObserver {
        WriteObserver {
            td_signed_dirty:    true,
            td_unsigned_dirty:  true,
            tmap0_dirty:        true,
            tmap1_dirty:        true,
        }
    }

    pub fn record_write(&mut self, addr: u16) {
        match addr {
            REGION_TILEDATA_UNSIGNED_BEG...REGION_TILEDATA_UNSIGNED_END => {
                self.td_unsigned_dirty = true;
            },
            REGION_TILEDATA_SIGNED_BEG...REGION_TILEDATA_SIGNED_END => {
                self.td_signed_dirty = true;
            },
            REGION_TILEMAP0_BEG...REGION_TILEMAP0_END => {
                self.tmap0_dirty = true;
            },
            REGION_TILEMAP1_BEG...REGION_TILEMAP1_END => {
                self.tmap1_dirty = true;
            },
            _ => (),
        }
    }

    pub fn check_dirty(&self, region: Region) -> bool {
        match region {
            Region::TileDataUnsigned => {
                self.td_unsigned_dirty
            },
            Region::TileDataSigned => {
                self.td_signed_dirty
            },
            Region::TileMap0 => {
                self.tmap0_dirty
            },
            Region::TileMap1 => {
                self.tmap1_dirty
            },
        }
    }

    pub fn clean_region(&mut self, region: Region) {
        match region {
            Region::TileDataUnsigned => {
                self.td_unsigned_dirty = false;
            },
            Region::TileDataSigned => {
                self.td_signed_dirty = false;
            },
            Region::TileMap0 => {
                self.tmap0_dirty = false;
            },
            Region::TileMap1 => {
                self.tmap1_dirty = false;
            },
        }
    }

}

pub struct AddressSpace {
    bios:  [u8; 0x100],
    data: [u8; 0x10000],
    bios_readable: bool,
    observer: WriteObserver,
}

pub const IOREG_P1:     u16 = 0xFF00;
pub const IOREG_SB:     u16 = 0xFF01;
pub const IOREG_DIV:    u16 = 0xFF04;
pub const IOREG_TIMA:   u16 = 0xFF05;
pub const IOREG_TMA:    u16 = 0xFF06;
pub const IOREG_TAC:    u16 = 0xFF07;
pub const IOREG_IF:     u16 = 0xFF0F;
pub const IOREG_LCDC:   u16 = 0xFF40;
pub const IOREG_STAT:   u16 = 0xFF41;
pub const IOREG_SCY:    u16 = 0xFF42;
pub const IOREG_SCX:    u16 = 0xFF43;
pub const IOREG_LY:     u16 = 0xFF44;
pub const IOREG_LYC:    u16 = 0xFF45;
pub const IOREG_DMA:    u16 = 0xFF46;
pub const IOREG_BGP:    u16 = 0xFF47;
pub const IOREG_OBP0:   u16 = 0xFF48;
pub const IOREG_OBP1:   u16 = 0xFF49;
pub const IOREG_WY:     u16 = 0xFF4A;
pub const IOREG_WX:     u16 = 0xFF4B;
pub const IOREG_BIOSRW: u16 = 0xFF50;
pub const IOREG_IE:     u16 = 0xFFFF;

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace {
            bios: [0; 0x100],
            data: [0; 0x10000],
            bios_readable: true,
            observer: WriteObserver::new(),
        }
    }

    pub fn read(&self, addr: u16) -> u8 {
        if addr < 0x100 && self.bios_readable {
            self.bios[addr as usize]
        } else {
            self.data[addr as usize]
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let lo = self.read(addr) as u16;
        let hi = (self.read(addr + 1) as u16) << 8;
        lo | hi
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        let mut addr = addr;
        let mut data = data;
        let rw = match addr {
            // ROM Banks, read only
            0x0000...0x7FFF => false,
            // Switchable RAM bank
            // TODO: Make RAM switchable
            0xA000...0xBFFF => true,
            // Internal RAM echo
            0xE000...0xFDFF => {
                addr -= 0x2000;
                true
            },
            // I/O registers
            IOREG_DIV => {
                data = 0;
                true
            },
            IOREG_LY => {
                data = 0;
                true
            },
            // Don't write, but begin a DMA instead
            IOREG_DMA => {
                let to_addr = 0xFE00;
                let from_addr = (data as u16) << 8;
                for i in 0x000..0x100 {
                    self.data[to_addr as usize + i] = self.data[from_addr as usize + i];
                }
                true
            },
            // Disable access to BIOS memory
            IOREG_BIOSRW => {
                if self.bios_readable && data == 1 {
                    self.bios_readable = false;
                }
                false
            },
            // No special write rules
            _ => true,
        };
        if rw {
            self.observer.record_write(addr);
            self.data[addr as usize] = data;
        }
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.write(addr, lo);
        self.write(addr + 1, hi);
    }

    pub fn load_bios(&mut self, bios: &mut File) -> ::std::io::Result<()> {
        try!(bios.read(&mut self.bios[0x000..0x100]));
        Ok(())
    }

    pub fn load_rom(&mut self, rom: &mut File) -> ::std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

    pub fn set_bios_readable(&mut self) {
        self.bios_readable = true;
    }

    pub fn get_observer(&mut self) -> &mut WriteObserver {
        &mut self.observer
    }

}

impl Index<u16> for AddressSpace {
    type Output = u8;

    fn index(&self, idx: u16) -> &u8 {
        &self.data[idx as usize]
    }
}

impl IndexMut<u16> for AddressSpace {
    fn index_mut(&mut self, idx: u16) -> &mut u8 {
        &mut self.data[idx as usize]
    }
}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x000,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = (((data & 0xFF00) >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.e = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

    pub fn get_pc(&self) -> u16 {
        self.pc
    }

}
<|endoftext|>


<commit_before>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<commit_msg>Get the Blender version number.<commit_after>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<|endoftext|>