<commit_before>//! A short tutorial on how to use vikos
//!
//! # Tutorial
//! Look, a bunch of data! Let us do something with it.
//!
//! ```
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! ```
//! The first elements of each tuple represent our feature vector,
//! the second elements represents the truth. We want to
//! use a [Training] to find the coefficients of a [Model]
//! which minimizes a `Cost` function. Let us start with
//! finding the mean value of the truth.
//!
//! ## Estimating mean
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! //mean is 9, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The mean is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the square error
//! let cost = cost::LeastSquares{};
//! // Use stochastic gradient descent with an annealed learning rate
//! let teacher = teacher::GradientDescentAl{ l0 : 0.3, t : 4.0 };
//! // Train 100 (admittedly repetitive) events
//! learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(100).cloned());
//! // We need an input vector for predictions, the 42 will not influence the mean
//! println!("{}", model.predict(&42.0));
//! // Since we know the model's type is `Constant`, we could just access the members
//! println!("{}", model.c);
//! ```
//! As far as the mean is concerned, the first element of each tuple, i.e., the feature, is just
//! ignored. The code would also compile if the first
//! element would be an empty tuple or any other type for
//! that matter.
//!
//! ## Estimating median
//!
//! If we want to estimate the median instead, we only need to change
//! our cost function:
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! //median is 7, but we don't know that yet of course
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The median is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation{};
//! let teacher = teacher::GradientDescentAl{ l0 : 1.0, t : 9.0 };
//! learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(100).cloned());
//! ```
//! Most notably we changed the cost function to train for the median. We also had to
//! increase our learning rate to be able to converge to `7` more quickly. Maybe we
//! should try a slightly more sophisticated `Training` algorithm.
//!
//! ## Estimating median again
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! //median is 7, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The median is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation{};
//! // Use stochasic gradient descent with an annealed learning rate and momentum
//! let teacher = teacher::Momentum{ l0 : 1.0, t : 3.0, inertia : 0.9};
//! learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(100).cloned());
//! println!("{}", model.predict(&42.0));
//! ```
//! The momentum term allowed us to drop our learning rate way quicker and to retrieve a
//! more precise result in the same number of iterations. The algorithms and their
//! parameters are not the point however---the important thing is we could switch them
//! quite easily and independently of both cost function and model. Speaking of which:
//! it is time to fit a straight line through our data points.
//!
//! ## Line of best fit
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! //Best described by 2 * m - 3
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! let mut model = model::Linear{ m : 0.0, c : 0.0 };
//! let cost = cost::LeastSquares{};
//! let teacher = teacher::Momentum{ l0 : 0.0001, t : 1000.0, inertia : 0.99};
//! learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(500).cloned());
//! for &(input, truth) in history.iter(){
//!     println!("Input: {}, Truth: {}, Prediction: {}", input, truth, model.predict(&input));
//! }
//! println!("slope: {}, intercept: {}", model.m, model.c);
//! ```
<commit_msg>Rust style guide<commit_after>//! A short tutorial on how to use vikos
//!
//! # Tutorial
//! Look, a bunch of data! Let us do something with it.
//!
//! ```
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! ```
//! The first elements of each tuple represent our feature vector,
//! the second elements represents the truth. We want to
//! use a [Training] to find the coefficients of a [Model]
//! which minimizes a `Cost` function. Let us start with
//! finding the mean value of the truth.
//!
//! ## Estimating mean
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! //mean is 9, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The mean is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the square error
//! let cost = cost::LeastSquares {};
//! // Use stochastic gradient descent with an annealed learning rate
//! let teacher = teacher::GradientDescentAl { l0: 0.3, t: 4.0 };
//! // Train 100 (admittedly repetitive) events
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(100).cloned());
//! // We need an input vector for predictions, the 42 will not influence the mean
//! println!("{}", model.predict(&42.0));
//! // Since we know the model's type is `Constant`, we could just access the members
//! println!("{}", model.c);
//! ```
//! As far as the mean is concerned, the first element of each tuple, i.e., the feature, is just
//! ignored. The code would also compile if the first
//! element would be an empty tuple or any other type for
//! that matter.
//!
//! ## Estimating median
//!
//! If we want to estimate the median instead, we only need to change
//! our cost function:
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! // median is 7, but we don't know that yet of course
//!
//! // The median is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! let teacher = teacher::GradientDescentAl { l0: 1.0, t: 9.0 };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(100).cloned());
//! ```
//! Most notably we changed the cost function to train for the median. We also had to
//! increase our learning rate to be able to converge to `7` more quickly. Maybe we
//! should try a slightly more sophisticated `Training` algorithm.
//!
//! ## Estimating median again
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! // median is 7, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The median is just a simple number ...
//! let mut model = model::Constant::new(0.0);
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! // Use stochasic gradient descent with an annealed learning rate and momentum
//! let teacher = teacher::Momentum {
//!     l0: 1.0,
//!     t: 3.0,
//!     inertia: 0.9,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(100).cloned());
//! println!("{}", model.predict(&42.0));
//! ```
//! The momentum term allowed us to drop our learning rate way quicker and to retrieve a
//! more precise result in the same number of iterations. The algorithms and their
//! parameters are not the point however---the important thing is we could switch them
//! quite easily and independently of both cost function and model. Speaking of which:
//! it is time to fit a straight line through our data points.
//!
//! ## Line of best fit
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! // Best described by 2 * m - 3
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! let mut model = model::Linear { m: 0.0, c: 0.0 };
//! let cost = cost::LeastSquares {};
//! let teacher = teacher::Momentum {
//!     l0: 0.0001,
//!     t: 1000.0,
//!     inertia: 0.99,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(500).cloned());
//! for &(input, truth) in history.iter() {
//!     println!("Input: {}, Truth: {}, Prediction: {}",
//!              input,
//!              truth,
//!              model.predict(&input));
//! }
//! println!("slope: {}, intercept: {}", model.m, model.c);
//! ```
<|endoftext|>


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

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_name="zinc"]
#![crate_type="rlib"]
#![allow(improper_ctypes)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

#[phase(plugin,link)] extern crate core;
#[cfg(not(test))] extern crate rlibc;

#[cfg(test)] #[phase(plugin,link)] extern crate std;
#[cfg(test)] extern crate native;
#[phase(plugin)] extern crate ioreg;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
pub mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
}
<commit_msg>`native` has been removed<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_name="zinc"]
#![crate_type="rlib"]
#![allow(improper_ctypes)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

#[phase(plugin,link)] extern crate core;
#[cfg(not(test))] extern crate rlibc;

#[cfg(test)] #[phase(plugin,link)] extern crate std;
#[phase(plugin)] extern crate ioreg;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
pub mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate const_cstr;

use dlopen::raw::Library;
use failure::Error;
use std::u16::MAX;
use std::{env, str};
use test_server::HttpResponse;

#[cfg(target_os = "windows")]
const LIB_PATH: &str = "./target/debug/ctehxk2.dll";
#[cfg(target_os = "linux")]
const LIB_PATH: &str = "./target/debug/libctehxk2.so";
#[cfg(target_os = "macos")]
const LIB_PATH: &str = "./target/debug/libctehxk2.dylib";

#[test]
fn use_ct_api_functions() -> Result<(), Error> {
    let lib = Library::open(LIB_PATH)?;

    let init: unsafe extern "system" fn(u16, u16) -> i8 =
        unsafe { lib.symbol_cstr(const_cstr!("CT_init").as_cstr()) }?;

    let data: unsafe extern "system" fn(
        u16,
        *mut u8,
        *mut u8,
        u16,
        *const u8,
        *mut u16,
        *mut u8,
    ) -> i8 = unsafe { lib.symbol_cstr(const_cstr!("CT_data").as_cstr()) }?;

    let close: unsafe extern "system" fn(u16) -> i8 =
        unsafe { lib.symbol_cstr(const_cstr!("CT_close").as_cstr()) }?;

    let ctn = rand::random::<u16>();
    let pn = rand::random::<u16>();
    let mut dad = rand::random::<u8>();
    let mut sad = rand::random::<u8>();

    let commands: [u8; 1] = [rand::random::<u8>(); 1];
    let commands_ptr: *const u8 = &commands[0];
    let lenc: u16 = commands.len() as u16;

    let mut response: [u8; MAX as usize] = [rand::random::<u8>(); MAX as usize];
    let response_ptr: *mut u8 = &mut response[0];
    let mut lenr: u16 = response.len() as u16;

    let server = test_server::new(65432, |req| {
        let path = req.path();
        if path.starts_with("/ct_data") {
            return HttpResponse::Ok().body(
                "{\"dad\":1,\"sad\":1,\"lenr\":5,\"response\":\"AQIDBAU=\",\"responseCode\":0}",
            );
        }
        if path.starts_with("/ct_") {
            return HttpResponse::Ok().body("0");
        }
        HttpResponse::BadRequest().into()
    })?;
    env::set_var("K2_BASE_URL", server.url());

    assert_eq!(0, unsafe { init(ctn, pn) });
    assert_eq!(0, unsafe {
        data(
            ctn,
            &mut dad,
            &mut sad,
            lenc,
            commands_ptr,
            &mut lenr,
            response_ptr,
        )
    });
    assert_eq!(0, unsafe { close(ctn) });

    Ok(())
}
<commit_msg>Adjust integration test<commit_after>#[macro_use]
extern crate const_cstr;

use dlopen::raw::Library;
use failure::Error;
use std::u16::MAX;
use std::{env, str};
use test_server::{HttpRequest, HttpResponse};

#[cfg(target_os = "windows")]
const LIB_PATH: &str = "./target/debug/ctehxk2.dll";
#[cfg(target_os = "linux")]
const LIB_PATH: &str = "./target/debug/libctehxk2.so";
#[cfg(target_os = "macos")]
const LIB_PATH: &str = "./target/debug/libctehxk2.dylib";

#[test]
fn use_ct_api_functions() -> Result<(), Error> {
    let lib = Library::open(LIB_PATH)?;

    let init: unsafe extern "system" fn(u16, u16) -> i8 =
        unsafe { lib.symbol_cstr(const_cstr!("CT_init").as_cstr()) }?;

    let data: unsafe extern "system" fn(
        u16,
        *mut u8,
        *mut u8,
        u16,
        *const u8,
        *mut u16,
        *mut u8,
    ) -> i8 = unsafe { lib.symbol_cstr(const_cstr!("CT_data").as_cstr()) }?;

    let close: unsafe extern "system" fn(u16) -> i8 =
        unsafe { lib.symbol_cstr(const_cstr!("CT_close").as_cstr()) }?;

    let ctn = rand::random::<u16>();
    let pn = rand::random::<u16>();
    let mut dad = rand::random::<u8>();
    let mut sad = rand::random::<u8>();

    let commands: [u8; 1] = [rand::random::<u8>(); 1];
    let commands_ptr: *const u8 = &commands[0];
    let lenc: u16 = commands.len() as u16;

    let mut response: [u8; MAX as usize] = [rand::random::<u8>(); MAX as usize];
    let response_ptr: *mut u8 = &mut response[0];
    let mut lenr: u16 = response.len() as u16;

    let server = test_server::new(65432, |req: HttpRequest| {
        let path = req.path();
        if path.starts_with("/ct_data") {
            return HttpResponse::Ok().body(
                "{\"dad\":1,\"sad\":1,\"lenr\":5,\"response\":\"AQIDBAU=\",\"responseCode\":0}",
            );
        }
        if path.starts_with("/ct_") {
            return HttpResponse::Ok().body("0");
        }
        HttpResponse::BadRequest().into()
    })?;
    env::set_var("K2_BASE_URL", server.url());

    assert_eq!(0, unsafe { init(ctn, pn) });
    assert_eq!(0, unsafe {
        data(
            ctn,
            &mut dad,
            &mut sad,
            lenc,
            commands_ptr,
            &mut lenr,
            response_ptr,
        )
    });
    assert_eq!(0, unsafe { close(ctn) });

    Ok(())
}
<|endoftext|>


<commit_before>
use num::{Zero, One, FromPrimitive, Integer, PrimInt};
use std::mem::swap;

pub fn primitive_root(prime: u64) -> Option<u64> {
	let test_exponents: Vec<u64> = distinct_prime_factors(prime - 1)
		.iter()
		.map(|factor| (prime - 1) / factor)
		.collect();

	'next: for potential_root in 2..prime {
		//for each distinct factor, if potential_root^(p-1)/factor mod p is 1, reject it
		for exp in &test_exponents {
			if modular_exponent(potential_root, *exp, prime) == 1 {
				continue 'next;
			}
		}

		//if we reach this point, it means this root was not rejected, so return it
		return Some(potential_root);
	}
	None
}

/// computes base^exponent % modulo using the standard exponentiation by squaring algorithm
pub fn modular_exponent<T: PrimInt + Integer>(mut base: T, mut exponent: T, modulo: T) -> T {
	let mut result = One::one();

	while exponent > Zero::zero() {
		if exponent.is_odd() {
			result = result * base % modulo;
		}
		exponent = exponent >> One::one();
		base = (base * base) % modulo;
	}

	result
}

pub fn multiplicative_inverse<T: PrimInt + Integer + FromPrimitive>(a: T, n: T) -> T {
	// we're going to use a modified version extended euclidean algorithm
	// we only need half the output

	let mut t = Zero::zero();
	let mut t_new = One::one();

	let mut r = n;
	let mut r_new = a;

	while r_new > Zero::zero() {
		let quotient = r / r_new;

		r = r - quotient * r_new;
		swap(&mut r, &mut r_new);

		//t might go negative here, so we have to do a checked subtract
		//if it underflows, wrap it around to the other end of the modulo
		//IE, 3 - 4 mod 5  =  -1 mod 5  =  4
		let t_subtract = quotient * t_new;
		t = if t_subtract < t {
			t - t_subtract
		} else {
			n - (t_subtract - t) % n
		};
		swap(&mut t, &mut t_new);
	}

	t
}

/// return all of the prime factors of n, but omit duplicate prime factors
pub fn distinct_prime_factors(mut n: u64) -> Vec<u64> {
	let mut result = Vec::new();

	//handle 2 separately so we dont have to worry about adding 2 vs 1
	if n % 2 == 0 {
		while n % 2 == 0 {
			n /= 2;
		}
		result.push(2);
	}

	let mut divisor = 3;
	let mut limit = (n as f32).sqrt() as u64 + 1;
	while divisor < limit {
		if n % divisor == 0 {

			//remove as many factors as possible from n
			while n % divisor == 0 {
				n /= divisor;
			}
			result.push(divisor);

			//recalculate the limit to reduce the amount of work we need to do
			limit = (n as f32).sqrt() as u64 + 1;
		}

		divisor += 2;
	}

	result.push(n);

	result
}

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

	#[test]
	fn test_modular_exponent() {
		// make sure to test something that would overflow under ordinary circumstances
		// ie 3 ^ 416788 mod 47
		let test_list = vec![
			((2,8,300), 256),
			((2,9,300), 212),
			((1,9,300), 1),
			((3,416788,47), 8),
		];

		for (input, expected) in test_list {
			let (base, exponent, modulo) = input;

			let result = modular_exponent(base, exponent, modulo);

			assert_eq!(result, expected);
		}
	}

	#[test]
	fn test_multiplicative_inverse() {
		let prime_list = vec![3,5,7,11,13,17,19,23,29];

		for modulo in prime_list {
			for i in 2..modulo {
				let inverse = multiplicative_inverse(i, modulo);

				assert_eq!(i * inverse % modulo, 1);
			}
		}
	}

	#[test]
	fn test_primitive_root() {
		let test_list = vec![
			(3, 2),
			(7, 3),
			(11, 2),
			(13, 2),
			(47, 5),
			(7919, 7)
			];

		for (input, expected) in test_list {
			let root = primitive_root(input).unwrap();

			assert_eq!(root, expected);
		}
	}

	#[test]
	fn test_prime_factors() {
		println!("beginning of test");
		let test_list = vec![
			(46, vec![2,23]),
			];

		for (input, expected) in test_list {
			let factors = distinct_prime_factors(input);

			assert_eq!(factors, expected);
		}
	}
}
<commit_msg>fixed prime factor implementation<commit_after>
use num::{Zero, One, FromPrimitive, Integer, PrimInt};
use std::mem::swap;

pub fn primitive_root(prime: u64) -> Option<u64> {
	let test_exponents: Vec<u64> = distinct_prime_factors(prime - 1)
		.iter()
		.map(|factor| (prime - 1) / factor)
		.collect();
	'next: for potential_root in 2..prime {
		//for each distinct factor, if potential_root^(p-1)/factor mod p is 1, reject it
		for exp in &test_exponents {
			if modular_exponent(potential_root, *exp, prime) == 1 {
				continue 'next;
			}
		}

		//if we reach this point, it means this root was not rejected, so return it
		return Some(potential_root);
	}
	None
}

/// computes base^exponent % modulo using the standard exponentiation by squaring algorithm
pub fn modular_exponent<T: PrimInt + Integer>(mut base: T, mut exponent: T, modulo: T) -> T {
	let mut result = One::one();

	while exponent > Zero::zero() {
		if exponent.is_odd() {
			result = result * base % modulo;
		}
		exponent = exponent >> One::one();
		base = (base * base) % modulo;
	}

	result
}

pub fn multiplicative_inverse<T: PrimInt + Integer + FromPrimitive>(a: T, n: T) -> T {
	// we're going to use a modified version extended euclidean algorithm
	// we only need half the output

	let mut t = Zero::zero();
	let mut t_new = One::one();

	let mut r = n;
	let mut r_new = a;

	while r_new > Zero::zero() {
		let quotient = r / r_new;

		r = r - quotient * r_new;
		swap(&mut r, &mut r_new);

		//t might go negative here, so we have to do a checked subtract
		//if it underflows, wrap it around to the other end of the modulo
		//IE, 3 - 4 mod 5  =  -1 mod 5  =  4
		let t_subtract = quotient * t_new;
		t = if t_subtract < t {
			t - t_subtract
		} else {
			n - (t_subtract - t) % n
		};
		swap(&mut t, &mut t_new);
	}

	t
}

/// return all of the prime factors of n, but omit duplicate prime factors
pub fn distinct_prime_factors(mut n: u64) -> Vec<u64> {
	let mut result = Vec::new();

	//handle 2 separately so we dont have to worry about adding 2 vs 1
	if n % 2 == 0 {
		while n % 2 == 0 {
			n /= 2;
		}
		result.push(2);
	}
	if n > 1 {
		let mut divisor = 3;
		let mut limit = (n as f32).sqrt() as u64 + 1;
		while divisor < limit {
			if n % divisor == 0 {

				//remove as many factors as possible from n
				while n % divisor == 0 {
					n /= divisor;
				}
				result.push(divisor);

				//recalculate the limit to reduce the amount of work we need to do
				limit = (n as f32).sqrt() as u64 + 1;
			}

			divisor += 2;
		}

		if n > 1 {
			result.push(n);
		}
	}

	result
}

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

	#[test]
	fn test_modular_exponent() {
		// make sure to test something that would overflow under ordinary circumstances
		// ie 3 ^ 416788 mod 47
		let test_list = vec![
			((2,8,300), 256),
			((2,9,300), 212),
			((1,9,300), 1),
			((3,416788,47), 8),
		];

		for (input, expected) in test_list {
			let (base, exponent, modulo) = input;

			let result = modular_exponent(base, exponent, modulo);

			assert_eq!(result, expected);
		}
	}

	#[test]
	fn test_multiplicative_inverse() {
		let prime_list = vec![3,5,7,11,13,17,19,23,29];

		for modulo in prime_list {
			for i in 2..modulo {
				let inverse = multiplicative_inverse(i, modulo);

				assert_eq!(i * inverse % modulo, 1);
			}
		}
	}

	#[test]
	fn test_primitive_root() {
		let test_list = vec![
			(3, 2),
			(7, 3),
			(11, 2),
			(13, 2),
			(47, 5),
			(7919, 7)
			];

		for (input, expected) in test_list {
			println!("testing {}", input);
			let root = primitive_root(input).unwrap();

			assert_eq!(root, expected);
		}
	}

	#[test]
	fn test_prime_factors() {
		println!("beginning of test");
		let test_list = vec![
			(46, vec![2,23]),
			(2, vec![2]),
			(3, vec![3]),
			(162, vec![2, 3]),
			];

		for (input, expected) in test_list {
			let factors = distinct_prime_factors(input);

			assert_eq!(factors, expected);
		}
	}
}
<|endoftext|>


<commit_before>use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::quote::rt::{ExtParseUtils};
use syntax::ast::{MetaItem,MetaList};
use syntax::codemap::{Span};

trace_macros!(true);

use super::options::ModelOptions;

#[allow(unused_variables)]
pub fn expand_model(excx: &mut ExtCtxt,
					sp: Span,
					mi: &MetaItem,
					item: &Annotatable,
					push: &mut FnMut(Annotatable)) {

	// get model options
	let result = ModelOptions::from_annotatable(item);

	match result {
		Err(e) => excx.span_err(sp, format!(r#"Error {:?}"#, e).as_str()),
		Ok(r) => {
			let mo_impl = r.get_impl();
			let _a = Annotatable::Item(excx.parse_item(mo_impl));
			push(_a)

			// @TODO: additional generated implementations.
		},
	}

	excx.span_note(sp, "Please don't forged Treasure is for now proof of concept, which will hopefully end as succesfull ORM!
There are still unanswered questions, and I hope I will found right answers.
However any help with design and/or programming is really appreciated, since write ORM is not easy task.

Right now it's very rough still nice concept, which we can make together to green badge on arewewebyet.com

Thank you,
	(phonkee)
	");
}

#[test]
fn it_works() {
}
<commit_msg>Commented out trace_macros<commit_after>use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::quote::rt::{ExtParseUtils};
use syntax::ast::{MetaItem,MetaList};
use syntax::codemap::{Span};

//trace_macros!(true);

use super::options::ModelOptions;

#[allow(unused_variables)]
pub fn expand_model(excx: &mut ExtCtxt,
					sp: Span,
					mi: &MetaItem,
					item: &Annotatable,
					push: &mut FnMut(Annotatable)) {

	// get model options
	let result = ModelOptions::from_annotatable(item);

	match result {
		Err(e) => excx.span_err(sp, format!(r#"Error {:?}"#, e).as_str()),
		Ok(r) => {
			let mo_impl = r.get_impl();
			let _a = Annotatable::Item(excx.parse_item(mo_impl));
			push(_a)

			// @TODO: additional generated implementations.
		},
	}

	excx.span_note(sp, "Please don't forged Treasure is for now proof of concept, which will hopefully end as succesfull ORM!
There are still unanswered questions, and I hope I will found right answers.
However any help with design and/or programming is really appreciated, since write ORM is not easy task.

Right now it's very rough still nice concept, which we can make together to green badge on arewewebyet.com

Thank you,
	(phonkee)
	");
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
use std::convert::AsRef;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Get the `PascalStr` as an immutable `&str` reference.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.string.as_str()
    }

    /// Get this string as a `CStr`.
    ///
    /// Returns `Err(InteriorNullError)` if the string contains any interior nulls. If this string is full,
    /// then a new `CString` will be allocated to hold the trailing null byte.
    #[inline]
    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        if let Some(pos) = self.chars().position(|&c| c == AsciiChar::Null) {
            Err(InteriorNullError(pos))
        } else if self.is_full() {
            let str_clone = self.to_owned();
            Ok(Cow::Owned(CString::new(str_clone).unwrap()))
        } else {
            Ok(Cow::Borrowed(CStr::from_bytes_with_nul(self.as_ref()).unwrap()))
        }
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

impl AsRef<str> for PascalStr {
    fn as_ref(&self) -> &str {
        self.string.as_ref()
    }
}

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        assert!(range.start < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        assert!(range.start < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

#[derive(Clone, Debug, Hash)]
pub struct InteriorNullError(usize);

impl InteriorNullError {
    #[inline]
    pub fn interior_null_index(&self) -> usize {
        self.0
    }
}

impl fmt::Display for InteriorNullError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "interior null at {}", self.0)
    }
}

impl Error for InteriorNullError {
    fn description(&self) -> &str {
        "an interior null was found when creating a CStr from a pascal string"
    }
}
<commit_msg>Fix PascalStr::as_cstr<commit_after>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
use std::convert::AsRef;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Get the `PascalStr` as an immutable `&str` reference.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.string.as_str()
    }

    /// Get this string as a `CStr`.
    ///
    /// Returns `Err(InteriorNullError)` if the string contains any interior nulls. If this string is full,
    /// then a new `CString` will be allocated to hold the trailing null byte.
    #[inline]
    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        match self.chars().position(|&c| c == AsciiChar::Null) {
            Some(pos) if pos != (self.len() - 1) => Err(InteriorNullError(pos)),
            _ if self.is_full() && self.string[PASCAL_STRING_BUF_SIZE - 1] != AsciiChar::Null => {
                let str_clone = self.to_owned();
                Ok(Cow::Owned(CString::new(str_clone).unwrap()))
            }
            _ => Ok(Cow::Borrowed(CStr::from_bytes_with_nul(self.as_ref()).unwrap()))
        }
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

impl AsRef<str> for PascalStr {
    fn as_ref(&self) -> &str {
        self.string.as_ref()
    }
}

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        assert!(range.start < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        assert!(range.start < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

#[derive(Clone, Debug, Hash)]
pub struct InteriorNullError(usize);

impl InteriorNullError {
    #[inline]
    pub fn interior_null_index(&self) -> usize {
        self.0
    }
}

impl fmt::Display for InteriorNullError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "interior null at {}", self.0)
    }
}

impl Error for InteriorNullError {
    fn description(&self) -> &str {
        "an interior null was found when creating a CStr from a pascal string"
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variable)]

#[deriving(Show)]
#[deriving(Clone)]
pub enum Doc {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Nest(uint, Box<Doc>),
    Text(String),
    Break(uint, uint),
    Newline,
    Group(Box<Doc>)
}

impl Doc {
    pub fn append(&self, e:Doc) -> Doc {
        match self {
            &Nil => e,
            x => match e {
                Nil => x.clone(),
                y => Append(box x.clone(), box y)
            }
        }
    }
}

fn concat(ds:&[Doc]) -> Doc {
    ds.iter().fold(Nil, |a, b| Append(box a, box b.clone()))
}

fn int(i:int) -> Doc {
    Text(format!("{}", i))
}

fn char(c:char) -> Doc {
    Text(format!("{}", c))
}

fn bool(b:bool) -> Doc {
    if b {
        Text(String::from_str("true"))
    } else {
        Text(String::from_str("false"))
    }
}

mod mode {
    #[deriving(Clone)]
    pub enum Mode {
        Flat,
        Break
    }
}

fn replicate<A:Clone>(x:A, l:uint) -> Vec<A> {
    let i = 0u;
    let mut res = Vec::new();
    for _ in range(i,l) {
        res.push(x.clone());
    }
    res
}
fn pad_right(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
        let padding = replicate(String::from_chars([c]), l - str_len).concat();
        let mut res = str.clone();
        res.push_str(padding.as_slice());
        res
    } else {
        str
    }
}
fn pad_left(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
      let mut res = replicate(String::from_chars([c]), l - str_len).concat();
      res.push_str(str.as_slice());
      res
    } else {
        str
    }
}

fn nlspace(s:Vec<String>, i:uint) -> Vec<String> {
    prepend(s, pad_right(' ', i + String::from_str("\n").len(), String::from_str("\n")))
}

fn spaces(s:Vec<String>, i:uint) -> Vec<String> {
    prepend(s, pad_left(' ', i, String::from_str("")))
}

fn fitting(xs:&Vec<(uint,mode::Mode,Doc)>, left:uint) -> bool {
    if left as int >= 0 {
        match xs.as_slice() {
            [] => true,
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => fitting(&rest.to_vec(), left),
                Append(ref x, ref y) => {
                    let mut ys = [(*i,*mode,*x.clone()), (*i,*mode,*y.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys,left)
                },
                Nest(j, ref x) => {
                    let mut ys = [(*i+j,*mode,*x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                },
                Text(ref str) => fitting(&rest.to_vec(), left - str.len()),
                Break(sp, _) => match *mode {
                    mode::Flat => fitting(&rest.to_vec(), left - sp),
                    mode::Break => true
                },
                Newline => true,
                Group(ref x) => {
                    let mut ys = [(*i,*mode, *x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                }
            }
        }
    }
    else {
        false
    }
}

fn prepend<A:Clone>(v: Vec<A>, x:A) -> Vec<A> {
    let mut res = [x].to_vec();
    res.push_all(v.as_slice());
    res
}

fn best(w:uint, s:Vec<String>, x:Doc) -> Vec<String> {
    fn go(w:uint, s:Vec<String>, k:uint, xs:Vec<(uint,mode::Mode,Doc)>) -> Vec<String> {
        match xs.as_slice() {
            [] => s.clone(),
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => go(w, s, k, rest.to_vec()),
                Append(ref x, ref y) => {
                    let mut zs = [(*i, *mode, *x.clone()), (*i, *mode, *y.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Nest(j, ref x) => {
                    let mut zs = [(*i + j, *mode, *x.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Text(ref str) => {
                    let ss = prepend(s, str.clone());
                    go(w, ss, k + str.len(), rest.to_vec())
                },
                Newline => {
                    let ss = nlspace(s, *i);
                    go(w, ss, *i, rest.to_vec())
                },
                Break(sp, off) => {
                    match *mode {
                        mode::Flat => {
                            let ss = spaces(s.clone(), sp);
                            go(w, ss, k + sp, rest.to_vec())
                        },
                        mode::Break => {
                            let ss = nlspace(s.clone(), i + off);
                            go(w, ss, i + off, rest.to_vec())
                        }
                    }
                },
                Group(ref x) => {
                    match *mode {
                        mode::Flat => {
                            let mut zs = [(*i,mode::Flat,*x.clone())].to_vec();
                            zs.push_all(*rest);
                            go(w, s, k, zs)
                        },
                        mode::Break => {
                            let mut ys = [(*i,mode::Flat,*x.clone())].to_vec();
                            ys.push_all(*rest);
                            if fitting(&ys, w - k) {
                                go(w, s, k, ys)
                            } else {
                                let mut zs = [(*i,mode::Break,*x.clone())].to_vec();
                                zs.push_all(*rest);
                                go(w, s, k, zs)
                            }
                        }
                    }
                }
            }
        }
    }
    go(w, s, 0, [(0,mode::Break,x)].to_vec())
}

impl Doc {
    pub fn to_string(&self, w:uint) -> String {
        let mut strs = best(w, [].to_vec(), self.clone());
        strs.reverse();
        strs.push(String::from_str("\n"));
        strs.concat()
    }
}
<commit_msg>Give prepend in terms of insert<commit_after>#![allow(dead_code)]
#![allow(unused_variable)]

#[deriving(Show)]
#[deriving(Clone)]
pub enum Doc {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Nest(uint, Box<Doc>),
    Text(String),
    Break(uint, uint),
    Newline,
    Group(Box<Doc>)
}

impl Doc {
    pub fn append(&self, e:Doc) -> Doc {
        match self {
            &Nil => e,
            x => match e {
                Nil => x.clone(),
                y => Append(box x.clone(), box y)
            }
        }
    }
}

fn concat(ds:&[Doc]) -> Doc {
    ds.iter().fold(Nil, |a, b| Append(box a, box b.clone()))
}

fn int(i:int) -> Doc {
    Text(format!("{}", i))
}

fn char(c:char) -> Doc {
    Text(format!("{}", c))
}

fn bool(b:bool) -> Doc {
    if b {
        Text(String::from_str("true"))
    } else {
        Text(String::from_str("false"))
    }
}

mod mode {
    #[deriving(Clone)]
    pub enum Mode {
        Flat,
        Break
    }
}

fn replicate<A:Clone>(x:A, l:uint) -> Vec<A> {
    let i = 0u;
    let mut res = Vec::new();
    for _ in range(i,l) {
        res.push(x.clone());
    }
    res
}
fn pad_right(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
        let padding = replicate(String::from_chars([c]), l - str_len).concat();
        let mut res = str.clone();
        res.push_str(padding.as_slice());
        res
    } else {
        str
    }
}
fn pad_left(c:char, l:uint, str:String) -> String {
    let str_len = str.len();
    if l > str_len {
      let mut res = replicate(String::from_chars([c]), l - str_len).concat();
      res.push_str(str.as_slice());
      res
    } else {
        str
    }
}

fn nlspace(s:Vec<String>, i:uint) -> Vec<String> {
    prepend(s, pad_right(' ', i + String::from_str("\n").len(), String::from_str("\n")))
}

fn spaces(s:Vec<String>, i:uint) -> Vec<String> {
    prepend(s, pad_left(' ', i, String::from_str("")))
}

fn fitting(xs:&Vec<(uint,mode::Mode,Doc)>, left:uint) -> bool {
    if left as int >= 0 {
        match xs.as_slice() {
            [] => true,
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => fitting(&rest.to_vec(), left),
                Append(ref x, ref y) => {
                    let mut ys = [(*i,*mode,*x.clone()), (*i,*mode,*y.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys,left)
                },
                Nest(j, ref x) => {
                    let mut ys = [(*i+j,*mode,*x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                },
                Text(ref str) => fitting(&rest.to_vec(), left - str.len()),
                Break(sp, _) => match *mode {
                    mode::Flat => fitting(&rest.to_vec(), left - sp),
                    mode::Break => true
                },
                Newline => true,
                Group(ref x) => {
                    let mut ys = [(*i,*mode, *x.clone())].to_vec();
                    ys.push_all(*rest);
                    fitting(&ys, left)
                }
            }
        }
    }
    else {
        false
    }
}

fn prepend<A:Clone>(v: Vec<A>, x:A) -> Vec<A> {
    let mut res = v;
    res.insert(0,x);
    res
}

fn best(w:uint, s:Vec<String>, x:Doc) -> Vec<String> {
    fn go(w:uint, s:Vec<String>, k:uint, xs:Vec<(uint,mode::Mode,Doc)>) -> Vec<String> {
        match xs.as_slice() {
            [] => s.clone(),
            [(ref i, ref mode, ref doc), ref rest..] => match *doc {
                Nil => go(w, s, k, rest.to_vec()),
                Append(ref x, ref y) => {
                    let mut zs = [(*i, *mode, *x.clone()), (*i, *mode, *y.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Nest(j, ref x) => {
                    let mut zs = [(*i + j, *mode, *x.clone())].to_vec();
                    zs.push_all(*rest);
                    go(w, s, k, zs)
                },
                Text(ref str) => {
                    let ss = prepend(s, str.clone());
                    go(w, ss, k + str.len(), rest.to_vec())
                },
                Newline => {
                    let ss = nlspace(s, *i);
                    go(w, ss, *i, rest.to_vec())
                },
                Break(sp, off) => {
                    match *mode {
                        mode::Flat => {
                            let ss = spaces(s.clone(), sp);
                            go(w, ss, k + sp, rest.to_vec())
                        },
                        mode::Break => {
                            let ss = nlspace(s.clone(), i + off);
                            go(w, ss, i + off, rest.to_vec())
                        }
                    }
                },
                Group(ref x) => {
                    match *mode {
                        mode::Flat => {
                            let mut zs = [(*i,mode::Flat,*x.clone())].to_vec();
                            zs.push_all(*rest);
                            go(w, s, k, zs)
                        },
                        mode::Break => {
                            let mut ys = [(*i,mode::Flat,*x.clone())].to_vec();
                            ys.push_all(*rest);
                            if fitting(&ys, w - k) {
                                go(w, s, k, ys)
                            } else {
                                let mut zs = [(*i,mode::Break,*x.clone())].to_vec();
                                zs.push_all(*rest);
                                go(w, s, k, zs)
                            }
                        }
                    }
                }
            }
        }
    }
    go(w, s, 0, [(0,mode::Break,x)].to_vec())
}

impl Doc {
    pub fn to_string(&self, w:uint) -> String {
        let mut strs = best(w, [].to_vec(), self.clone());
        strs.reverse();
        strs.push(String::from_str("\n"));
        strs.concat()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! A collection for storing data associated with a range of values.

use std::cmp::Ordering;
use std::iter::FromIterator;
use std::slice::Iter;

/// The value type for the endpoints of ranges.
pub type Addr = u64;
/// Entries are indexed by a `Range` of `Addr`s.
///
/// The start of the range is inclusive, the end is exclusive.
pub type Range = (Addr, Addr);
/// Entry type, a tuple of `Range` and `T`.
pub type Entry<T> = (Range, T);

/// A `RangeMap` stores values of `T` that map to `Range`s.
#[derive(Debug, PartialEq)]
pub struct RangeMap<T> {
    /// Entries are stored in a sorted list internally.
    entries: Vec<Entry<T>>,
}

fn compare_address_to_entry<T>(addr : Addr, entry : &Entry<T>) -> Ordering {
    let &((start, end), _) = entry;
    return if start <= addr && end > addr {
        Ordering::Equal
    } else if start > addr {
        Ordering::Greater
    } else {
        Ordering::Less
    }
}

impl<T> RangeMap<T> {
    /// Create a new, empty `RangeMap`.
    pub fn new() -> RangeMap<T> {
        RangeMap::<T> { entries: Vec::new() }
    }

    /// Create a `RangeMap` with `entries`.
    pub fn from(mut entries : Vec<Entry<T>>) -> RangeMap<T> {
        entries.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
        RangeMap::<T> { entries: entries }
    }

    /// Returns the number of entries in the `RangeMap`.
    pub fn len(&self) -> usize { self.entries.len() }

    /// Insert `value` in `range`.
    pub fn insert(&mut self, range : Range, value : T) -> Result<(),()> {
        match self.entries.binary_search_by(|&(ref r, ref _v)| r.cmp(&range)) {
            Ok(_) => Err(()),
            Err(index) => {
                self.entries.insert(index, (range, value));
                Ok(())
            }
        }
    }

    /// Find an entry whose `Range` encompasses `addr`.
    pub fn lookup(&self, addr : Addr) -> Option<&T> {
        if let Ok(index) = self.entries.binary_search_by(|ref entry| compare_address_to_entry(addr, entry)) {
            let ((_, _), ref value) = self.entries[index];
            Some(value)
        } else {
            None
        }
    }

    /// Return an iterator over the entries of the `RangeMap`.
    pub fn iter(&self) -> Iter<Entry<T>> {
        self.entries.iter()
    }
}

impl<T> IntoIterator for RangeMap<T> {
    type Item = Entry<T>;
    type IntoIter = <Vec<Entry<T>> as IntoIterator>::IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.entries.into_iter()
    }
}

impl<T> FromIterator<Entry<T>> for RangeMap<T> {
    fn from_iter<U>(iterator: U) -> RangeMap<T> where U: IntoIterator<Item=Entry<T>> {
        RangeMap::from(iterator.into_iter().collect())
    }
}

impl<T : Clone> Clone for RangeMap<T> {
    fn clone(&self) -> RangeMap<T> {
        RangeMap::<T> {
            entries: self.entries.clone(),
        }
    }
}

#[test]
fn test_range_map() {
    let mut map = RangeMap::<u32>::new();
    map.insert((7,10), 2).unwrap();
    map.insert((0,4), 1).unwrap();
    map.insert((15,16), 3).unwrap();

    assert_eq!(map.len(), 3);

    assert_eq!(map.lookup(7).unwrap(), &2);
    assert_eq!(map.lookup(9).unwrap(), &2);
    assert_eq!(map.lookup(0).unwrap(), &1);
    assert_eq!(map.lookup(3).unwrap(), &1);
    assert_eq!(map.lookup(15).unwrap(), &3);
    assert_eq!(map.lookup(4), None);
    assert_eq!(map.lookup(6), None);
    assert_eq!(map.lookup(10), None);
    assert_eq!(map.lookup(16), None);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((0,4), 1),
        ((7,10), 2),
        ((15,16), 3),
        ));
}

#[test]
fn test_from_iter() {
    let v = vec!(
        ((10, 20), 1),
        ((5, 6), 2),
        ((20, 22), 3),
        ((8, 10), 4),
        );
    let map = v.into_iter().collect::<RangeMap<u32>>();
    assert_eq!(map.len(), 4);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((5, 6), 2),
        ((8, 10), 4),
        ((10, 20), 1),
        ((20, 22), 3),
        ));
}
<commit_msg>add a test for RangeMap::clone<commit_after>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! A collection for storing data associated with a range of values.

use std::cmp::Ordering;
use std::iter::FromIterator;
use std::slice::Iter;

/// The value type for the endpoints of ranges.
pub type Addr = u64;
/// Entries are indexed by a `Range` of `Addr`s.
///
/// The start of the range is inclusive, the end is exclusive.
pub type Range = (Addr, Addr);
/// Entry type, a tuple of `Range` and `T`.
pub type Entry<T> = (Range, T);

/// A `RangeMap` stores values of `T` that map to `Range`s.
#[derive(Debug, PartialEq)]
pub struct RangeMap<T> {
    /// Entries are stored in a sorted list internally.
    entries: Vec<Entry<T>>,
}

fn compare_address_to_entry<T>(addr : Addr, entry : &Entry<T>) -> Ordering {
    let &((start, end), _) = entry;
    return if start <= addr && end > addr {
        Ordering::Equal
    } else if start > addr {
        Ordering::Greater
    } else {
        Ordering::Less
    }
}

impl<T> RangeMap<T> {
    /// Create a new, empty `RangeMap`.
    pub fn new() -> RangeMap<T> {
        RangeMap::<T> { entries: Vec::new() }
    }

    /// Create a `RangeMap` with `entries`.
    pub fn from(mut entries : Vec<Entry<T>>) -> RangeMap<T> {
        entries.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
        RangeMap::<T> { entries: entries }
    }

    /// Returns the number of entries in the `RangeMap`.
    pub fn len(&self) -> usize { self.entries.len() }

    /// Insert `value` in `range`.
    pub fn insert(&mut self, range : Range, value : T) -> Result<(),()> {
        match self.entries.binary_search_by(|&(ref r, ref _v)| r.cmp(&range)) {
            Ok(_) => Err(()),
            Err(index) => {
                self.entries.insert(index, (range, value));
                Ok(())
            }
        }
    }

    /// Find an entry whose `Range` encompasses `addr`.
    pub fn lookup(&self, addr : Addr) -> Option<&T> {
        if let Ok(index) = self.entries.binary_search_by(|ref entry| compare_address_to_entry(addr, entry)) {
            let ((_, _), ref value) = self.entries[index];
            Some(value)
        } else {
            None
        }
    }

    /// Return an iterator over the entries of the `RangeMap`.
    pub fn iter(&self) -> Iter<Entry<T>> {
        self.entries.iter()
    }
}

impl<T> IntoIterator for RangeMap<T> {
    type Item = Entry<T>;
    type IntoIter = <Vec<Entry<T>> as IntoIterator>::IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.entries.into_iter()
    }
}

impl<T> FromIterator<Entry<T>> for RangeMap<T> {
    fn from_iter<U>(iterator: U) -> RangeMap<T> where U: IntoIterator<Item=Entry<T>> {
        RangeMap::from(iterator.into_iter().collect())
    }
}

impl<T : Clone> Clone for RangeMap<T> {
    fn clone(&self) -> RangeMap<T> {
        RangeMap::<T> {
            entries: self.entries.clone(),
        }
    }
}

#[test]
fn test_range_map() {
    let mut map = RangeMap::<u32>::new();
    map.insert((7,10), 2).unwrap();
    map.insert((0,4), 1).unwrap();
    map.insert((15,16), 3).unwrap();

    assert_eq!(map.len(), 3);

    assert_eq!(map.lookup(7).unwrap(), &2);
    assert_eq!(map.lookup(9).unwrap(), &2);
    assert_eq!(map.lookup(0).unwrap(), &1);
    assert_eq!(map.lookup(3).unwrap(), &1);
    assert_eq!(map.lookup(15).unwrap(), &3);
    assert_eq!(map.lookup(4), None);
    assert_eq!(map.lookup(6), None);
    assert_eq!(map.lookup(10), None);
    assert_eq!(map.lookup(16), None);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((0,4), 1),
        ((7,10), 2),
        ((15,16), 3),
        ));
}

#[test]
fn test_clone() {
    let mut map = RangeMap::<u32>::new();
    map.insert((7,10), 2).unwrap();
    map.insert((0,4), 1).unwrap();
    map.insert((15,16), 3).unwrap();

    assert_eq!(map.len(), 3);

    let map2 = map.clone();
    let items : Vec<_> = map2.into_iter().collect();
    assert_eq!(items, vec!(
        ((0,4), 1),
        ((7,10), 2),
        ((15,16), 3),
        ));
}

#[test]
fn test_from_iter() {
    let v = vec!(
        ((10, 20), 1),
        ((5, 6), 2),
        ((20, 22), 3),
        ((8, 10), 4),
        );
    let map = v.into_iter().collect::<RangeMap<u32>>();
    assert_eq!(map.len(), 4);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((5, 6), 2),
        ((8, 10), 4),
        ((10, 20), 1),
        ((20, 22), 3),
        ));
}
<|endoftext|>


<commit_before>extern crate lopdf;
use lopdf::{Document};

#[macro_use]
extern crate clap;
use clap::{App, Arg};

fn main() {
	let arguments = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input")
			.short("i")
			.long("input")
			.value_name("input file")
			.takes_value(true)
			.required(true))
		.arg(Arg::with_name("output")
			.short("o")
			.long("output")
			.value_name("output file")
			.takes_value(true))
		.get_matches();

	if let Some(input) = arguments.value_of("input") {
		let mut doc = Document::load(input).unwrap();

		if let Some(output) = arguments.value_of("output") {
			doc.save(output).unwrap();
		}
	}
}
<commit_msg>Add compress/decompress subcommands to pdfutil<commit_after>extern crate lopdf;
use lopdf::Document;

#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};

fn main() {
	let app = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input")
			.short("i")
			.long("input")
			.value_name("input file")
			.takes_value(true)
			.global(true))
		.arg(Arg::with_name("output")
			.short("o")
			.long("output")
			.value_name("output file")
			.takes_value(true)
			.global(true))
		.subcommand(SubCommand::with_name("compress")
			.about("Compress PDF document"))
		.subcommand(SubCommand::with_name("decompress")
			.about("Decompress PDF document"))
		.get_matches();

	if let (cmd, Some(args)) = app.subcommand() {
		if let Some(input) = args.value_of("input") {

			println!("Open {}", input);
			let mut doc = Document::load(input).unwrap();

			println!("Do {}", cmd);
			match cmd {
				"compress" => doc.compress(),
				"decompress" => doc.decompress(),
				_ => (),
			}

			if let Some(output) = args.value_of("output") {
				println!("Save to {}", output);
				doc.save(output).unwrap();
			}
		}
	}
}
<|endoftext|>


<commit_before>//! Rate Limit interface
use serde::Deserialize;

use crate::{Future, Github};

pub struct RateLimit {
    github: Github,
}

impl RateLimit {
    #[doc(hidden)]
    pub fn new(github: Github) -> Self {
        Self { github }
    }

    /// https://developer.github.com/v3/rate_limit/#get-your-current-rate-limit-status
    pub fn get(&self) -> Future<RateLimitStatus> {
        self.github.get("/rate_limit")
    }
}

// representations

#[derive(Debug, Deserialize)]
pub struct RateLimitStatus {
    pub resources: RateLimitResourcesStatus,
}

#[derive(Debug, Deserialize)]
pub struct RateLimitResourcesStatus {
    pub core: RateLimitResourceStatus,
    pub search: RateLimitResourceStatus,
    pub graphql: RateLimitResourceStatus,
}

#[derive(Debug, Deserialize)]
pub struct RateLimitResourceStatus {
    pub limit: u32,
    pub remaining: u32,
    pub reset: u32, // ideally something like std::time::Duration
}
<commit_msg>remove empty line<commit_after>//! Rate Limit interface
use serde::Deserialize;
use crate::{Future, Github};

pub struct RateLimit {
    github: Github,
}

impl RateLimit {
    #[doc(hidden)]
    pub fn new(github: Github) -> Self {
        Self { github }
    }

    /// https://developer.github.com/v3/rate_limit/#get-your-current-rate-limit-status
    pub fn get(&self) -> Future<RateLimitStatus> {
        self.github.get("/rate_limit")
    }
}

// representations

#[derive(Debug, Deserialize)]
pub struct RateLimitStatus {
    pub resources: RateLimitResourcesStatus,
}

#[derive(Debug, Deserialize)]
pub struct RateLimitResourcesStatus {
    pub core: RateLimitResourceStatus,
    pub search: RateLimitResourceStatus,
    pub graphql: RateLimitResourceStatus,
}

#[derive(Debug, Deserialize)]
pub struct RateLimitResourceStatus {
    pub limit: u32,
    pub remaining: u32,
    pub reset: u32, // ideally something like std::time::Duration
}
<|endoftext|>


<commit_before>//! TCP message service.

use std::io;
use std::net::SocketAddr;
use futures::{Future, Poll};
use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::net::{TcpStream, TcpStreamNew};
use tokio_core::reactor;
use super::conf::ServerConf;
use super::request::ServiceHandle;
use super::service::{Service, ServiceMode};
use super::transport::{Transport, StreamWriter, StreamReader};

//------------ tcp_service ---------------------------------------------------

/// Creates a new DNS service using TCP as the transport.
pub fn tcp_service(reactor: reactor::Handle, conf: &ServerConf)
                   -> io::Result<Option<ServiceHandle>> {
    let mode = match ServiceMode::resolve(conf.tcp, ServiceMode::Sequential) {
        Some(mode) => mode,
        None => return Ok(None)
    };
    let transport = TcpTransport::new(conf.addr);
    Service::spawn(reactor, transport, mode, conf).map(Some)
}

//------------ TcpTransport --------------------------------------------------

/// A transport for TCP.
pub struct TcpTransport {
    addr: SocketAddr,
}

impl TcpTransport {
    /// Creates a new TCP transport.
    pub fn new(addr: SocketAddr) -> Self {
        TcpTransport{addr: addr}
    }
}

//--- Transport

impl Transport for TcpTransport {
    type Read = StreamReader<ReadHalf<TcpStream>>;
    type Write = StreamWriter<WriteHalf<TcpStream>>;
    type Future = TcpTransportNew;

    fn create(&self, reactor: &reactor::Handle) -> io::Result<Self::Future> {
        Ok(TcpTransportNew(TcpStream::connect(&self.addr, reactor)))
    }
}

//------------ TcpTransportNew -----------------------------------------------

/// A future resolving into a connected TCP transport connection.
pub struct TcpTransportNew(TcpStreamNew);

impl Future for TcpTransportNew {
    type Item = (StreamReader<ReadHalf<TcpStream>>,
                 StreamWriter<WriteHalf<TcpStream>>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.0.poll().map(|ready| ready.map(|stream| {
            let (rd, wr) = stream.split();
            (rd.into(), wr.into())
        }))
    }
}

<commit_msg>Use ServiceMode::SingleRequest as default for TCP.<commit_after>//! TCP message service.

use std::io;
use std::net::SocketAddr;
use futures::{Future, Poll};
use tokio_core::io::{Io, ReadHalf, WriteHalf};
use tokio_core::net::{TcpStream, TcpStreamNew};
use tokio_core::reactor;
use super::conf::ServerConf;
use super::request::ServiceHandle;
use super::service::{Service, ServiceMode};
use super::transport::{Transport, StreamWriter, StreamReader};

//------------ tcp_service ---------------------------------------------------

/// Creates a new DNS service using TCP as the transport.
pub fn tcp_service(reactor: reactor::Handle, conf: &ServerConf)
                   -> io::Result<Option<ServiceHandle>> {
    let mode = match ServiceMode::resolve(conf.tcp,
                                          ServiceMode::SingleRequest) {
        Some(mode) => mode,
        None => return Ok(None)
    };
    let transport = TcpTransport::new(conf.addr);
    Service::spawn(reactor, transport, mode, conf).map(Some)
}

//------------ TcpTransport --------------------------------------------------

/// A transport for TCP.
pub struct TcpTransport {
    addr: SocketAddr,
}

impl TcpTransport {
    /// Creates a new TCP transport.
    pub fn new(addr: SocketAddr) -> Self {
        TcpTransport{addr: addr}
    }
}

//--- Transport

impl Transport for TcpTransport {
    type Read = StreamReader<ReadHalf<TcpStream>>;
    type Write = StreamWriter<WriteHalf<TcpStream>>;
    type Future = TcpTransportNew;

    fn create(&self, reactor: &reactor::Handle) -> io::Result<Self::Future> {
        Ok(TcpTransportNew(TcpStream::connect(&self.addr, reactor)))
    }
}

//------------ TcpTransportNew -----------------------------------------------

/// A future resolving into a connected TCP transport connection.
pub struct TcpTransportNew(TcpStreamNew);

impl Future for TcpTransportNew {
    type Item = (StreamReader<ReadHalf<TcpStream>>,
                 StreamWriter<WriteHalf<TcpStream>>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.0.poll().map(|ready| ready.map(|stream| {
            let (rd, wr) = stream.split();
            (rd.into(), wr.into())
        }))
    }
}

<|endoftext|>


<commit_before>use codegen;
use cpu::global_pointers;
use cpu_context::CpuContext;
use jit::JitContext;
use prefix::{PREFIX_MASK_SEGMENT, SEG_PREFIX_ZERO};
use profiler;
use regs::{BP, BX, DI, SI};
use regs::{CS, DS, SS};
use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};

pub struct ModrmByte {
    segment: u32,
    first_reg: Option<u32>,
    second_reg: Option<u32>,
    shift: u8,
    immediate: i32,
    is_16: bool,
}
impl ModrmByte {
    pub fn is_nop(&self, reg: u32) -> bool {
        self.first_reg == Some(reg)
            && self.second_reg.is_none()
            && self.shift == 0
            && self.immediate == 0
            && !self.is_16
    }
}

pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    if ctx.asize_32() { decode32(ctx, modrm_byte) } else { decode16(ctx, modrm_byte) }
}

fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk16(
        segment: u32,
        first_reg: Option<u32>,
        second_reg: Option<u32>,
        immediate: i32,
    ) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg,
            shift: 0,
            immediate,
            is_16: true,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk16(DS, Some(BX), Some(SI), 0),
        0o001 => mk16(DS, Some(BX), Some(DI), 0),
        0o002 => mk16(SS, Some(BP), Some(SI), 0),
        0o003 => mk16(SS, Some(BP), Some(DI), 0),
        0o004 => mk16(DS, Some(SI), None, 0),
        0o005 => mk16(DS, Some(DI), None, 0),
        0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
        0o007 => mk16(DS, Some(BX), None, 0),

        0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
        0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
        0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
        0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
        0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
        0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
        0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
        0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),

        0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
        0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
        0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
        0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
        0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
        0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
        0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
        0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg: None,
            shift: 0,
            immediate,
            is_16: false,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk32(DS, Some(EAX), 0),
        0o001 => mk32(DS, Some(ECX), 0),
        0o002 => mk32(DS, Some(EDX), 0),
        0o003 => mk32(DS, Some(EBX), 0),
        0o004 => decode_sib(ctx, Imm32::None),
        0o005 => mk32(DS, None, ctx.read_imm32() as i32),
        0o006 => mk32(DS, Some(ESI), 0),
        0o007 => mk32(DS, Some(EDI), 0),

        0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
        0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
        0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
        0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
        0o104 => decode_sib(ctx, Imm32::Imm8),
        0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
        0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
        0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),

        0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
        0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
        0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
        0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
        0o204 => decode_sib(ctx, Imm32::Imm32),
        0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
        0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
        0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
    let sib_byte = ctx.read_imm8();
    let r = sib_byte & 7;
    let m = sib_byte >> 3 & 7;
    let shift = sib_byte >> 6 & 3;

    let second_reg = if m == 4 { None } else { Some(m as u32) };

    let segment;
    let reg;

    if r == 4 {
        segment = SS;
        reg = ESP;
    }
    else if r == 5 {
        if immediate == Imm32::None {
            return ModrmByte {
                segment: DS,
                first_reg: None,
                second_reg,
                shift,
                immediate: ctx.read_imm32() as i32,
                is_16: false,
            };
        }
        else {
            segment = SS;
            reg = EBP;
        }
    }
    else {
        segment = DS;
        reg = r as u32;
    }

    let immediate = match immediate {
        Imm32::None => 0,
        Imm32::Imm8 => ctx.read_imm8s() as i32,
        Imm32::Imm32 => ctx.read_imm32() as i32,
    };

    ModrmByte {
        segment,
        first_reg: Some(reg),
        second_reg,
        shift,
        immediate,
        is_16: false,
    }
}

pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte) {
    codegen::gen_profiler_stat_increment(
        ctx.builder,
        match modrm_byte {
            ModrmByte {
                first_reg: None,
                second_reg: None,
                ..
            } => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
            ModrmByte {
                first_reg: Some(_),
                second_reg: None,
                ..
            }
            | ModrmByte {
                first_reg: None,
                second_reg: Some(_),
                shift: 0,
                ..
            } => {
                if modrm_byte.immediate == 0 {
                    profiler::stat::MODRM_SIMPLE_REG
                }
                else {
                    profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
                }
            },
            _ => profiler::stat::MODRM_COMPLEX,
        },
    );

    let mut have_something_on_stack = false;

    if let Some(reg) = modrm_byte.first_reg {
        codegen::gen_get_reg32(ctx, reg);
        have_something_on_stack = true;
    }

    if let Some(reg) = modrm_byte.second_reg {
        codegen::gen_get_reg32(ctx, reg);
        if modrm_byte.shift != 0 {
            ctx.builder.const_i32(modrm_byte.shift.into());
            ctx.builder.shl_i32();
        }
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
        have_something_on_stack = true;
    }

    if modrm_byte.immediate != 0 || !have_something_on_stack {
        ctx.builder.const_i32(modrm_byte.immediate);
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
    }

    if modrm_byte.is_16 {
        ctx.builder.const_i32(0xFFFF);
        ctx.builder.and_i32();
    }
    jit_add_seg_offset(ctx, modrm_byte.segment);
}

pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }

#[derive(PartialEq)]
enum Imm32 {
    None,
    Imm8,
    Imm32,
}

fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
    (segment == DS || segment == SS) && ctx.cpu.has_flat_segmentation()
}

pub fn jit_add_seg_offset(ctx: &mut JitContext, default_segment: u32) {
    let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
    let seg = if prefix != 0 { prefix - 1 } else { default_segment };

    if can_optimize_get_seg(ctx, seg) || prefix == SEG_PREFIX_ZERO {
        codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_OPTIMISED);
        return;
    }
    codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_NOT_OPTIMISED);

    if cfg!(feature = "profiler") && seg != CS && seg != SS {
        ctx.builder.const_i32(seg as i32);
        ctx.builder.call_fn1("log_segment_null");
    }

    ctx.builder
        .load_fixed_u8(global_pointers::get_segment_is_null_offset(seg));
    ctx.builder.if_void();
    codegen::gen_trigger_gp(ctx, 0);
    ctx.builder.block_end();

    ctx.builder
        .load_fixed_i32(global_pointers::get_seg_offset(seg));
    ctx.builder.add_i32();
}
<commit_msg>Avoid seg null check for ss/cs<commit_after>use codegen;
use cpu::global_pointers;
use cpu_context::CpuContext;
use jit::JitContext;
use prefix::{PREFIX_MASK_SEGMENT, SEG_PREFIX_ZERO};
use profiler;
use regs::{BP, BX, DI, SI};
use regs::{CS, DS, SS};
use regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};

pub struct ModrmByte {
    segment: u32,
    first_reg: Option<u32>,
    second_reg: Option<u32>,
    shift: u8,
    immediate: i32,
    is_16: bool,
}
impl ModrmByte {
    pub fn is_nop(&self, reg: u32) -> bool {
        self.first_reg == Some(reg)
            && self.second_reg.is_none()
            && self.shift == 0
            && self.immediate == 0
            && !self.is_16
    }
}

pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    if ctx.asize_32() { decode32(ctx, modrm_byte) } else { decode16(ctx, modrm_byte) }
}

fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk16(
        segment: u32,
        first_reg: Option<u32>,
        second_reg: Option<u32>,
        immediate: i32,
    ) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg,
            shift: 0,
            immediate,
            is_16: true,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk16(DS, Some(BX), Some(SI), 0),
        0o001 => mk16(DS, Some(BX), Some(DI), 0),
        0o002 => mk16(SS, Some(BP), Some(SI), 0),
        0o003 => mk16(SS, Some(BP), Some(DI), 0),
        0o004 => mk16(DS, Some(SI), None, 0),
        0o005 => mk16(DS, Some(DI), None, 0),
        0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
        0o007 => mk16(DS, Some(BX), None, 0),

        0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
        0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
        0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
        0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
        0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
        0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
        0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
        0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),

        0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
        0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
        0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
        0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
        0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
        0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
        0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
        0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
    fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
        ModrmByte {
            segment,
            first_reg,
            second_reg: None,
            shift: 0,
            immediate,
            is_16: false,
        }
    }

    match modrm_byte & !0o070 {
        0o000 => mk32(DS, Some(EAX), 0),
        0o001 => mk32(DS, Some(ECX), 0),
        0o002 => mk32(DS, Some(EDX), 0),
        0o003 => mk32(DS, Some(EBX), 0),
        0o004 => decode_sib(ctx, Imm32::None),
        0o005 => mk32(DS, None, ctx.read_imm32() as i32),
        0o006 => mk32(DS, Some(ESI), 0),
        0o007 => mk32(DS, Some(EDI), 0),

        0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
        0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
        0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
        0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
        0o104 => decode_sib(ctx, Imm32::Imm8),
        0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
        0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
        0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),

        0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
        0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
        0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
        0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
        0o204 => decode_sib(ctx, Imm32::Imm32),
        0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
        0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
        0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),

        _ => panic!("modrm byte >= 0xC0"),
    }
}

fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
    let sib_byte = ctx.read_imm8();
    let r = sib_byte & 7;
    let m = sib_byte >> 3 & 7;
    let shift = sib_byte >> 6 & 3;

    let second_reg = if m == 4 { None } else { Some(m as u32) };

    let segment;
    let reg;

    if r == 4 {
        segment = SS;
        reg = ESP;
    }
    else if r == 5 {
        if immediate == Imm32::None {
            return ModrmByte {
                segment: DS,
                first_reg: None,
                second_reg,
                shift,
                immediate: ctx.read_imm32() as i32,
                is_16: false,
            };
        }
        else {
            segment = SS;
            reg = EBP;
        }
    }
    else {
        segment = DS;
        reg = r as u32;
    }

    let immediate = match immediate {
        Imm32::None => 0,
        Imm32::Imm8 => ctx.read_imm8s() as i32,
        Imm32::Imm32 => ctx.read_imm32() as i32,
    };

    ModrmByte {
        segment,
        first_reg: Some(reg),
        second_reg,
        shift,
        immediate,
        is_16: false,
    }
}

pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte) {
    codegen::gen_profiler_stat_increment(
        ctx.builder,
        match modrm_byte {
            ModrmByte {
                first_reg: None,
                second_reg: None,
                ..
            } => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
            ModrmByte {
                first_reg: Some(_),
                second_reg: None,
                ..
            }
            | ModrmByte {
                first_reg: None,
                second_reg: Some(_),
                shift: 0,
                ..
            } => {
                if modrm_byte.immediate == 0 {
                    profiler::stat::MODRM_SIMPLE_REG
                }
                else {
                    profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
                }
            },
            _ => profiler::stat::MODRM_COMPLEX,
        },
    );

    let mut have_something_on_stack = false;

    if let Some(reg) = modrm_byte.first_reg {
        codegen::gen_get_reg32(ctx, reg);
        have_something_on_stack = true;
    }

    if let Some(reg) = modrm_byte.second_reg {
        codegen::gen_get_reg32(ctx, reg);
        if modrm_byte.shift != 0 {
            ctx.builder.const_i32(modrm_byte.shift.into());
            ctx.builder.shl_i32();
        }
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
        have_something_on_stack = true;
    }

    if modrm_byte.immediate != 0 || !have_something_on_stack {
        ctx.builder.const_i32(modrm_byte.immediate);
        if have_something_on_stack {
            ctx.builder.add_i32();
        }
    }

    if modrm_byte.is_16 {
        ctx.builder.const_i32(0xFFFF);
        ctx.builder.and_i32();
    }
    jit_add_seg_offset(ctx, modrm_byte.segment);
}

pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }

#[derive(PartialEq)]
enum Imm32 {
    None,
    Imm8,
    Imm32,
}

fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
    (segment == DS || segment == SS) && ctx.cpu.has_flat_segmentation()
}

pub fn jit_add_seg_offset(ctx: &mut JitContext, default_segment: u32) {
    let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
    let seg = if prefix != 0 { prefix - 1 } else { default_segment };

    if can_optimize_get_seg(ctx, seg) || prefix == SEG_PREFIX_ZERO {
        codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_OPTIMISED);
        return;
    }
    codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_NOT_OPTIMISED);

    if seg != CS && seg != SS {
        if cfg!(feature = "profiler") {
            ctx.builder.const_i32(seg as i32);
            ctx.builder.call_fn1("log_segment_null");
        }

        ctx.builder
            .load_fixed_u8(global_pointers::get_segment_is_null_offset(seg));
        ctx.builder.if_void();
        codegen::gen_trigger_gp(ctx, 0);
        ctx.builder.block_end();
    }

    ctx.builder
        .load_fixed_i32(global_pointers::get_seg_offset(seg));
    ctx.builder.add_i32();
}
<|endoftext|>