<commit_before>extern crate rand;
use table::rand::Rng;

#[derive(Clone)]
pub struct Bucket {
    pointers: Vec<usize>,
    hash_sig: usize
}

impl Bucket {
    pub fn new(hash_sig: usize) -> Self {
        Bucket {
            pointers: Vec::new(),
            hash_sig: hash_sig
        }
    }
    pub fn push(&mut self, value: usize) {
        self.pointers.push(value);
    }
}

#[derive(Clone, Default)]
pub struct BucketChain {
    chain: Vec<Bucket>
}

impl BucketChain {
    pub fn new() -> Self {
        BucketChain{
            chain: Vec::new()
        }
    }
    pub fn get(&self, _index: usize) -> Option<&Bucket> {
        for bucket_ref in &self.chain {
            if bucket_ref.hash_sig == _index {
                return Some(bucket_ref);
            }
        }
        None
    }
    pub fn get_mut(&mut self, _index: usize) -> Option<&mut Bucket> {
        for bucket_ref in &mut self.chain {
            if bucket_ref.hash_sig == _index {
                return Some(bucket_ref);
            }
        }
        None
    }
    pub fn create_and_add_bucket(&mut self, bucket_sig: usize, value: usize) {
        let mut new_bucket = Bucket::new(bucket_sig);
        new_bucket.push(value);
        self.chain.push(new_bucket);
    }
}

const P: f64 = (0xFFFFFFFE as usize - 4) as f64;
pub struct LSHTable<'a, T: 'a, Q: 'a+?Sized>  {
    buckets: Vec<BucketChain>,
    data: &'a [T],
    hash_functions: &'a [Box<Q>],
    ri1: Vec<f64>,
    ri2: Vec<f64>,
    multiprobe_sequence: &'a [Vec<i32>]
}

impl<'a, T, Q: 'a+?Sized> LSHTable<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn new(data: &'a [T], hashes: &'a [Box<Q>], ms: &'a [Vec<i32>]) -> Self {
        LSHTable {
            buckets: vec![BucketChain::new(); data.len()],
            data: data,
            hash_functions: hashes,
            ri1: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            ri2: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            multiprobe_sequence: ms
        }
    }
    fn get_signature(&self, v: &'a T) -> Vec<f64> {
        self.hash_functions.iter().map(|x| {
            (*x)(v)
        }).collect()
    }
    pub fn new_build(data: &'a [T], hashes: &'a [Box<Q>], ms: &'a [Vec<i32>]) -> Self {
        let mut x_to_build = LSHTable::new(data, hashes, ms);
        for (i, v) in x_to_build.data.iter().enumerate() {
            let hash_sig = x_to_build.get_signature(v);
            let bucket_ind = hash_func_t1(&hash_sig, &x_to_build.ri1, P, x_to_build.buckets.len());
            let mut bucket_chain = &mut (x_to_build.buckets[bucket_ind]);
            let chain_ind = hash_func_t2(&hash_sig, &x_to_build.ri2, P );
            let mut bad = false;
            {
                let bucket_opt = bucket_chain.get_mut(chain_ind);
                match bucket_opt {
                    Some(bucket_ref) => bucket_ref.push(i),
                    None => bad = true
                };
            }
            if bad {
                bucket_chain.create_and_add_bucket(chain_ind, i);
            }
        }
        x_to_build
    }

    pub fn query_vec(&self, v: &'a T) -> Vec<&T> {
        let sig = self.get_signature(v);
        let sig_ind = hash_func_t1(&sig, &self.ri1, P, self.buckets.len());
        let chain_ind = hash_func_t2(&sig, &self.ri2, P );
        match self.buckets[sig_ind].get(chain_ind) {
           Some(bucket) => bucket.pointers.iter().map(|bucket_ind| {
                &self.data[*bucket_ind]
           }).collect(),
            None => Vec::new()
        }
    }

    fn perturb_signature(&self, sig: Vec<f64>, v: &T) -> Vec<Vec<f64>> {
        // precompute the multiprobe data...where?
        // don't worry about it, worry about this end for now
        // for j in M_list
        // get pi_j(that) from sig and v
        // add to output vector
        unimplemented!();
    }

    pub fn query_multiprobe(&self, v: &'a T) -> Vec<&T> {
        let sig = self.get_signature(v);
        let all_sigs = self.perturb_signature(sig, v);
        let mut output_vec = Vec::new();
        for s in &all_sigs {
            let sig_ind = hash_func_t1(s, &self.ri1, P, self.buckets.len());
            let chain_ind = hash_func_t2(s, &self.ri2, P);
            output_vec.append(
                &mut match self.buckets[sig_ind].get(chain_ind) {
                    Some(bucket) => bucket.pointers.iter().map(|bucket_ind| {
                        &self.data[*bucket_ind]
                    }).collect(),
                    None => Vec::new()
                });
        }
        output_vec
    }
}

fn hash_func_t1(signature: &[f64], rand_ints: &[f64], primes: f64, num_buckets: usize) -> usize {
    let total: usize = hash_func_t2(signature, rand_ints, primes);
    total % num_buckets
}

fn hash_func_t2(signature: &[f64], rand_ints: &[f64], primes: f64) -> usize {
    let mut counter: f64 = 0.0;
    for element in signature.iter().zip(rand_ints).map(|(a, b)| {(a * b)}) {
        counter = ((counter + element)) % primes;
    }
    counter as usize
}
#[cfg(test)]
mod tests {
    use super::LSHTable;
    #[test]
    fn test_init() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        let x = LSHTable::new(&test_data, &funcs, &ms);
    }
    #[test]
    fn test_new_build() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        let x = LSHTable::new_build(&test_data, &funcs, &ms);
    }

    #[test]
    fn test_query() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        let x = LSHTable::new_build(&test_data, &funcs, &ms);
        x.query_vec(&test_data[0]);
    }
}
<commit_msg>quantized and non-quantized signatures<commit_after>extern crate rand;
use table::rand::Rng;

#[derive(Clone)]
pub struct Bucket {
    pointers: Vec<usize>,
    hash_sig: usize
}

impl Bucket {
    pub fn new(hash_sig: usize) -> Self {
        Bucket {
            pointers: Vec::new(),
            hash_sig: hash_sig
        }
    }
    pub fn push(&mut self, value: usize) {
        self.pointers.push(value);
    }
}

#[derive(Clone, Default)]
pub struct BucketChain {
    chain: Vec<Bucket>
}

impl BucketChain {
    pub fn new() -> Self {
        BucketChain{
            chain: Vec::new()
        }
    }
    pub fn get(&self, _index: usize) -> Option<&Bucket> {
        for bucket_ref in &self.chain {
            if bucket_ref.hash_sig == _index {
                return Some(bucket_ref);
            }
        }
        None
    }
    pub fn get_mut(&mut self, _index: usize) -> Option<&mut Bucket> {
        for bucket_ref in &mut self.chain {
            if bucket_ref.hash_sig == _index {
                return Some(bucket_ref);
            }
        }
        None
    }
    pub fn create_and_add_bucket(&mut self, bucket_sig: usize, value: usize) {
        let mut new_bucket = Bucket::new(bucket_sig);
        new_bucket.push(value);
        self.chain.push(new_bucket);
    }
}

const P: f64 = (0xFFFFFFFE as usize - 4) as f64;
pub struct LSHTable<'a, T: 'a, Q: 'a+?Sized>  {
    buckets: Vec<BucketChain>,
    data: &'a [T],
    hash_functions: &'a [Box<Q>],
    ri1: Vec<f64>,
    ri2: Vec<f64>,
    multiprobe_sequence: &'a [Vec<i32>]
}

impl<'a, T, Q: 'a+?Sized> LSHTable<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn new(data: &'a [T], hashes: &'a [Box<Q>], ms: &'a [Vec<i32>]) -> Self {
        LSHTable {
            buckets: vec![BucketChain::new(); data.len()],
            data: data,
            hash_functions: hashes,
            ri1: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            ri2: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            multiprobe_sequence: ms
        }
    }
    fn get_signature(&self, v: &'a T) -> Vec<f64> {
        self.hash_functions.iter().map(|x| {
            (*x)(v)
        }).collect()
    }
    fn get_quantized_signature(&self, v: &'a T) -> Vec<f64> {
        self.hash_functions.iter().map(|x| {
            (*x)(v).floor()
        }).collect()
    }
    pub fn new_build(data: &'a [T], hashes: &'a [Box<Q>], ms: &'a [Vec<i32>]) -> Self {
        let mut x_to_build = LSHTable::new(data, hashes, ms);
        for (i, v) in x_to_build.data.iter().enumerate() {
            let hash_sig = x_to_build.get_quantized_signature(v);
            let bucket_ind = hash_func_t1(&hash_sig, &x_to_build.ri1, P, x_to_build.buckets.len());
            let mut bucket_chain = &mut (x_to_build.buckets[bucket_ind]);
            let chain_ind = hash_func_t2(&hash_sig, &x_to_build.ri2, P );
            let mut bad = false;
            {
                let bucket_opt = bucket_chain.get_mut(chain_ind);
                match bucket_opt {
                    Some(bucket_ref) => bucket_ref.push(i),
                    None => bad = true
                };
            }
            if bad {
                bucket_chain.create_and_add_bucket(chain_ind, i);
            }
        }
        x_to_build
    }

    pub fn query_vec(&self, v: &'a T) -> Vec<&T> {
        let sig = self.get_quantized_signature(v);
        let sig_ind = hash_func_t1(&sig, &self.ri1, P, self.buckets.len());
        let chain_ind = hash_func_t2(&sig, &self.ri2, P );
        match self.buckets[sig_ind].get(chain_ind) {
           Some(bucket) => bucket.pointers.iter().map(|bucket_ind| {
                &self.data[*bucket_ind]
           }).collect(),
            None => Vec::new()
        }
    }

    fn perturb_signature(&self, sig: &[f64], v: &T) -> Vec<Vec<f64>> {
        // the multi-probe sequence should just be a bunch of j
        // then we have pi_j FOR JUST THIS TABLE
        // that maps our list of j onto a vector of -1/+1 indexed by i
        unimplemented!();
    }

    pub fn query_multiprobe(&self, v: &'a T) -> Vec<&T> {
        let sig = self.get_signature(v);
        let qsig = self.get_quantized_signature(v);
        let all_sigs = self.perturb_signature(&sig, v);
        let mut output_vec = Vec::new();
        for s in &all_sigs {
            let sig_ind = hash_func_t1(s, &self.ri1, P, self.buckets.len());
            let chain_ind = hash_func_t2(s, &self.ri2, P);
            output_vec.append(
                &mut match self.buckets[sig_ind].get(chain_ind) {
                    Some(bucket) => bucket.pointers.iter().map(|bucket_ind| {
                        &self.data[*bucket_ind]
                    }).collect(),
                    None => Vec::new()
                });
        }
        output_vec
    }
}

fn hash_func_t1(signature: &[f64], rand_ints: &[f64], primes: f64, num_buckets: usize) -> usize {
    let total: usize = hash_func_t2(signature, rand_ints, primes);
    total % num_buckets
}

fn hash_func_t2(signature: &[f64], rand_ints: &[f64], primes: f64) -> usize {
    let mut counter: f64 = 0.0;
    for element in signature.iter().zip(rand_ints).map(|(a, b)| {(a * b)}) {
        counter = ((counter + element)) % primes;
    }
    counter as usize
}
#[cfg(test)]
mod tests {
    use super::LSHTable;

    // fn to gen multiprobe sequence
    #[test]
    fn test_init() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        // get actual multiprobe sequence into ms instead
        let x = LSHTable::new(&test_data, &funcs, &ms);
    }
    #[test]
    fn test_new_build() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        let x = LSHTable::new_build(&test_data, &funcs, &ms);
    }

    #[test]
    fn test_query() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let ms = vec![vec![1i32,2,3]];
        // get actual multiprobe sequence into ms instead
        let x = LSHTable::new_build(&test_data, &funcs, &ms);
        x.query_vec(&test_data[0]);
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![crate_type = "bin"]
extern crate rust_js;
extern crate test;
extern crate collections;
use rust_js::lexer::Lexer;
use rust_js::parser::{Parser, VerboseResult};
use rust_js::exec::{Executor, Interpreter};
use rust_js::js::value::{Value, ValueData, VNull, VNumber, VString};

fn run(script:&str) -> Value {
	let mut lexer = Lexer::new();
	lexer.lex_str(script.to_owned()).v_unwrap();
	let mut parser = Parser::new(lexer.tokens);
	let result = parser.parse_all().v_unwrap();
	let mut engine : ~Interpreter = Executor::new();
	let result : Result<Value, Value> = engine.run(result);
	return result.unwrap();
}
fn assert_eq(a:ValueData, b:Value) -> () {
	if a != *b.borrow() {
		fail!("Expected {}, got {}", a, b.borrow());
	}
}
#[test]
fn test_array_comma() {
	assert_eq(VNull, run("[ , 'home', , 'school'][0]"));
}
#[test]
fn test_escape() {
	assert_eq(VString(~"Newline:'"), run("'Newline:\\\''"));
}
#[test]
fn test_to_string() {
	assert_eq(VString(~"117"), run("117+''"));
	assert_eq(VString(~"0.12"), run("0.12+''"));
	assert_eq(VString(~"null"), run("null+''"));
	assert_eq(VString(~"undefined"), run("unexisty+''"));
}
#[test]
fn test_num_op() {
	assert_eq(VNumber(10.0), run("((4 + 2) / 3) * 5"));
}
#[test]
fn test_hello_world() {
	assert_eq(VString(~"Hello, world!"), run("'Hello, world!'"));
}
#[test]
fn test_function() {
	assert_eq(VString(~"Function!"), run("(function(a){return a + '!'})('Function')"))
}
#[test]
fn test_constructor() {
	assert_eq(VString(~"Hello"), run("function Text(phrase) { this.phrase = phrase; }; text = new Text('Hello'); text.phrase"));
}
#[test]
fn test_json() {
	assert_eq(VNumber(~"42"), run("JSON.parse(JSON.stringify({num: 42})).num"))
}<commit_msg>Correct JSON test<commit_after>#![feature(globs)]
#![crate_type = "bin"]
extern crate rust_js;
extern crate test;
extern crate collections;
use rust_js::lexer::Lexer;
use rust_js::parser::{Parser, VerboseResult};
use rust_js::exec::{Executor, Interpreter};
use rust_js::js::value::{Value, ValueData, VNull, VNumber, VString};

fn run(script:&str) -> Value {
	let mut lexer = Lexer::new();
	lexer.lex_str(script.to_owned()).v_unwrap();
	let mut parser = Parser::new(lexer.tokens);
	let result = parser.parse_all().v_unwrap();
	let mut engine : ~Interpreter = Executor::new();
	let result : Result<Value, Value> = engine.run(result);
	return result.unwrap();
}
fn assert_eq(a:ValueData, b:Value) -> () {
	if a != *b.borrow() {
		fail!("Expected {}, got {}", a, b.borrow());
	}
}
#[test]
fn test_array_comma() {
	assert_eq(VNull, run("[ , 'home', , 'school'][0]"));
}
#[test]
fn test_escape() {
	assert_eq(VString(~"Newline:'"), run("'Newline:\\\''"));
}
#[test]
fn test_to_string() {
	assert_eq(VString(~"117"), run("117+''"));
	assert_eq(VString(~"0.12"), run("0.12+''"));
	assert_eq(VString(~"null"), run("null+''"));
	assert_eq(VString(~"undefined"), run("unexisty+''"));
}
#[test]
fn test_num_op() {
	assert_eq(VNumber(10.0), run("((4 + 2) / 3) * 5"));
}
#[test]
fn test_hello_world() {
	assert_eq(VString(~"Hello, world!"), run("'Hello, world!'"));
}
#[test]
fn test_function() {
	assert_eq(VString(~"Function!"), run("(function(a){return a + '!'})('Function')"))
}
#[test]
fn test_constructor() {
	assert_eq(VString(~"Hello"), run("function Text(phrase) { this.phrase = phrase; }; text = new Text('Hello'); text.phrase"));
}
#[test]
fn test_json() {
	assert_eq(VNumber(42), run("JSON.parse(JSON.stringify({num: 42})).num"))
}<|endoftext|>


<commit_before>//! Timing and measurement functions.
//!
//! ggez does not try to do any framerate limitation by default. If
//! you want to run at anything other than full-bore max speed all the
//! time, call [`thread::yield_now()`](https://doc.rust-lang.org/std/thread/fn.yield_now.html)
//! (or [`timer::yield_now()`](fn.yield_now.html) which does the same
//! thing) to yield to the OS so it has a chance to breathe before continuing
//! with your game. This should prevent it from using 100% CPU as much unless it
//! really needs to.  Enabling vsync by setting
//! [`conf.window_setup.vsync`](../conf/struct.WindowSetup.html#structfield.vsync)
//! in your [`Conf`](../conf/struct.Conf.html) object is generally the best
//! way to cap your displayed framerate.
//!
//! For a more detailed tutorial in how to handle frame timings in games,
//! see <http://gafferongames.com/game-physics/fix-your-timestep/>

use crate::context::Context;

use std::cmp;
use std::f64;
use std::thread;
use std::time;

/// A simple buffer that fills
/// up to a limit and then holds the last
/// N items that have been inserted into it,
/// overwriting old ones in a round-robin fashion.
///
/// It's not quite a ring buffer 'cause you can't
/// remove items from it, it just holds the last N
/// things.
#[derive(Debug, Clone)]
struct LogBuffer<T>
where
    T: Clone,
{
    head: usize,
    size: usize,
    contents: Vec<T>,
}

impl<T> LogBuffer<T>
where
    T: Clone + Copy,
{
    fn new(size: usize, init_val: T) -> LogBuffer<T> {
        let v = vec![init_val; size];
        LogBuffer {
            head: 0,
            size,
            contents: v,
        }
    }

    /// Pushes a new item into the `LogBuffer`, overwriting
    /// the oldest item in it.
    fn push(&mut self, item: T) {
        self.head = (self.head + 1) % self.contents.len();
        self.contents[self.head] = item;
        self.size = cmp::min(self.size + 1, self.contents.len());
    }

    /// Returns a slice pointing at the contents of the buffer.
    /// They are in *no particular order*, and if not all the
    /// slots are filled, the empty slots will be present but
    /// contain the initial value given to [`new()`](#method.new).
    ///
    /// We're only using this to log FPS for a short time,
    /// so we don't care for the second or so when it's inaccurate.
    fn contents(&self) -> &[T] {
        &self.contents
    }

    /// Returns the most recent value in the buffer.
    fn latest(&self) -> T {
        self.contents[self.head]
    }
}

/// A structure that contains our time-tracking state.
#[derive(Debug)]
pub struct TimeContext {
    init_instant: time::Instant,
    last_instant: time::Instant,
    frame_durations: LogBuffer<time::Duration>,
    residual_update_dt: time::Duration,
    frame_count: usize,
}

// How many frames we log update times for.
const TIME_LOG_FRAMES: usize = 200;

impl TimeContext {
    /// Creates a new `TimeContext` and initializes the start to this instant.
    pub fn new() -> TimeContext {
        // This fills the empty log-buffer with 60 fps frame times,
        // which is kind of silly but smooths out the initial time claiming
        // 1000's of fps until the log buffer actually fills.
        // TODO: Would be better to make the log buffer know its proper length
        // or filter out placeholders or something, but eh.
        let initial_dt = time::Duration::from_millis(16);
        TimeContext {
            init_instant: time::Instant::now(),
            last_instant: time::Instant::now(),
            frame_durations: LogBuffer::new(TIME_LOG_FRAMES, initial_dt),
            residual_update_dt: time::Duration::from_secs(0),
            frame_count: 0,
        }
    }

    /// Update the state of the `TimeContext` to record that
    /// another frame has taken place.  Necessary for the FPS
    /// tracking and [`check_update_time()`](fn.check_update_time.html)
    /// functions to work.
    ///
    /// It's usually not necessary to call this function yourself,
    /// [`event::run()`](../event/fn.run.html) will do it for you.
    pub fn tick(&mut self) {
        let now = time::Instant::now();
        let time_since_last = now - self.last_instant;
        self.frame_durations.push(time_since_last);
        self.last_instant = now;
        self.frame_count += 1;

        self.residual_update_dt += time_since_last;
    }
}

impl Default for TimeContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Get the time between the start of the last frame and the current one;
/// in other words, the length of the last frame.
pub fn delta(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    tc.frame_durations.latest()
}

/// Gets the average time of a frame, averaged
/// over the last 200 frames.
pub fn average_delta(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    let init = time::Duration::new(0, 0);
    let sum = tc
        .frame_durations
        .contents()
        .iter()
        .fold(init, |d1, d2| d1 + *d2);
    sum / (tc.frame_durations.size as u32)
}

/// A convenience function to convert a Rust `Duration` type
/// to a (less precise but more useful) `f64`.
///
/// Does not make sure that the `Duration` is within the bounds
/// of the `f64`.
pub fn duration_to_f64(d: time::Duration) -> f64 {
    let seconds = d.as_secs() as f64;
    let nanos = f64::from(d.subsec_nanos());
    seconds + (nanos * 1e-9)
}

/// A convenience function to create a Rust `Duration` type
/// from a (less precise but more useful) `f64`.
///
/// Only handles positive numbers correctly.
pub fn f64_to_duration(t: f64) -> time::Duration {
    debug_assert!(t >= 0.0, "f64_to_duration passed a negative number!");
    let seconds = t.trunc();
    let nanos = t.fract() * 1e9;
    time::Duration::new(seconds as u64, nanos as u32)
}

/// Returns a `Duration` representing how long each
/// frame should be to match the given fps.
///
/// Approximately.
fn fps_as_duration(fps: u32) -> time::Duration {
    let target_dt_seconds = 1.0 / f64::from(fps);
    f64_to_duration(target_dt_seconds)
}

/// Gets the FPS of the game, averaged over the last
/// 200 frames.
pub fn fps(ctx: &Context) -> f64 {
    let duration_per_frame = average_delta(ctx);
    let seconds_per_frame = duration_to_f64(duration_per_frame);
    1.0 / seconds_per_frame
}

/// Returns the time since the game was initialized,
/// as reported by the system clock.
pub fn time_since_start(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    time::Instant::now() - tc.init_instant
}

/// This function will return true if the time since the
/// last [`update()`](../event/trait.EventHandler.html#tymethod.update)
/// call has been equal to or greater to
/// the update FPS indicated by the `target_fps`.
/// It keeps track of fractional frames, so if you want
/// 60 fps (16.67 ms/frame) and the game stutters so that
/// there is 40 ms between `update()` calls, this will return
/// `true` twice, and take the remaining 6.67 ms into account
/// in the next frame.
///
/// The intention is to for it to be called in a while loop
/// in your `update()` callback:
///
/// ```rust
/// # use ggez::*;
/// # fn update_game_physics() -> GameResult { Ok(()) }
/// # struct State;
/// # impl ggez::event::EventHandler for State {
/// fn update(&mut self, ctx: &mut Context) -> GameResult {
///     while(timer::check_update_time(ctx, 60)) {
///         update_game_physics()?;
///     }
///     Ok(())
/// }
/// # fn draw(&mut self, _ctx: &mut Context) -> GameResult { Ok(()) }
/// # }
/// ```
pub fn check_update_time(ctx: &mut Context, target_fps: u32) -> bool {
    let timedata = &mut ctx.timer_context;

    let target_dt = fps_as_duration(target_fps);
    if timedata.residual_update_dt > target_dt {
        timedata.residual_update_dt -= target_dt;
        true
    } else {
        false
    }
}

/// Returns the fractional amount of a frame not consumed
/// by  [`check_update_time()`](fn.check_update_time.html).
/// For example, if the desired
/// update frame time is 40 ms (25 fps), and 45 ms have
/// passed since the last frame, [`check_update_time()`](fn.check_update_time.html)
/// will return `true` and `remaining_update_time()` will
/// return 5 ms -- the amount of time "overflowing" from one
/// frame to the next.
///
/// The intention is for it to be called in your
/// [`draw()`](../event/trait.EventHandler.html#tymethod.draw) callback
/// to interpolate physics states for smooth rendering.
/// (see <http://gafferongames.com/game-physics/fix-your-timestep/>)
pub fn remaining_update_time(ctx: &mut Context) -> time::Duration {
    ctx.timer_context.residual_update_dt
}

/// Pauses the current thread for the target duration.
/// Just calls [`std::thread::sleep()`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
/// so it's as accurate as that is (which is usually not very).
pub fn sleep(duration: time::Duration) {
    thread::sleep(duration);
}

/// Yields the current timeslice to the OS.
///
/// This just calls [`std::thread::yield_now()`](https://doc.rust-lang.org/std/thread/fn.yield_now.html)
/// but it's handy to have here.
pub fn yield_now() {
    thread::yield_now();
}

/// Gets the number of times the game has gone through its event loop.
///
/// Specifically, the number of times that [`TimeContext::tick()`](struct.TimeContext.html#method.tick)
/// has been called by it.
pub fn ticks(ctx: &Context) -> usize {
    ctx.timer_context.frame_count
}
<commit_msg>Fix minor todo's in timer.rs<commit_after>//! Timing and measurement functions.
//!
//! ggez does not try to do any framerate limitation by default. If
//! you want to run at anything other than full-bore max speed all the
//! time, call [`thread::yield_now()`](https://doc.rust-lang.org/std/thread/fn.yield_now.html)
//! (or [`timer::yield_now()`](fn.yield_now.html) which does the same
//! thing) to yield to the OS so it has a chance to breathe before continuing
//! with your game. This should prevent it from using 100% CPU as much unless it
//! really needs to.  Enabling vsync by setting
//! [`conf.window_setup.vsync`](../conf/struct.WindowSetup.html#structfield.vsync)
//! in your [`Conf`](../conf/struct.Conf.html) object is generally the best
//! way to cap your displayed framerate.
//!
//! For a more detailed tutorial in how to handle frame timings in games,
//! see <http://gafferongames.com/game-physics/fix-your-timestep/>

use crate::context::Context;

use std::cmp;
use std::f64;
use std::thread;
use std::time;

/// A simple buffer that fills
/// up to a limit and then holds the last
/// N items that have been inserted into it,
/// overwriting old ones in a round-robin fashion.
///
/// It's not quite a ring buffer 'cause you can't
/// remove items from it, it just holds the last N
/// things.
#[derive(Debug, Clone)]
struct LogBuffer<T>
where
    T: Clone,
{
    head: usize,
    size: usize,
    /// The number of actual samples inserted, used for
    /// smarter averaging.
    samples: usize,
    contents: Vec<T>,
}

impl<T> LogBuffer<T>
where
    T: Clone + Copy,
{

    fn new(size: usize, init_val: T) -> LogBuffer<T> {
        LogBuffer {
            head: 0,
            size,
            contents: vec![init_val; size],
            // Never divide by 0
            samples: 1,
        }
    }

    /// Pushes a new item into the `LogBuffer`, overwriting
    /// the oldest item in it.
    fn push(&mut self, item: T) {
        self.head = (self.head + 1) % self.contents.len();
        self.contents[self.head] = item;
        self.size = cmp::min(self.size + 1, self.contents.len());
        self.samples += 1;
    }

    /// Returns a slice pointing at the contents of the buffer.
    /// They are in *no particular order*, and if not all the
    /// slots are filled, the empty slots will be present but
    /// contain the initial value given to [`new()`](#method.new).
    ///
    /// We're only using this to log FPS for a short time,
    /// so we don't care for the second or so when it's inaccurate.
    fn contents(&self) -> &[T] {
        if self.samples > self.size {
            &self.contents
        } else {
            &self.contents[..self.samples]
        }
    }

    /// Returns the most recent value in the buffer.
    fn latest(&self) -> T {
        self.contents[self.head]
    }
}

/// A structure that contains our time-tracking state.
#[derive(Debug)]
pub struct TimeContext {
    init_instant: time::Instant,
    last_instant: time::Instant,
    frame_durations: LogBuffer<time::Duration>,
    residual_update_dt: time::Duration,
    frame_count: usize,
}

// How many frames we log update times for.
const TIME_LOG_FRAMES: usize = 200;

impl TimeContext {
    /// Creates a new `TimeContext` and initializes the start to this instant.
    pub fn new() -> TimeContext {
        let initial_dt = time::Duration::from_millis(16);
        TimeContext {
            init_instant: time::Instant::now(),
            last_instant: time::Instant::now(),
            frame_durations: LogBuffer::new(TIME_LOG_FRAMES, initial_dt),
            residual_update_dt: time::Duration::from_secs(0),
            frame_count: 0,
        }
    }

    /// Update the state of the `TimeContext` to record that
    /// another frame has taken place.  Necessary for the FPS
    /// tracking and [`check_update_time()`](fn.check_update_time.html)
    /// functions to work.
    ///
    /// It's usually not necessary to call this function yourself,
    /// [`event::run()`](../event/fn.run.html) will do it for you.
    pub fn tick(&mut self) {
        let now = time::Instant::now();
        let time_since_last = now - self.last_instant;
        self.frame_durations.push(time_since_last);
        self.last_instant = now;
        self.frame_count += 1;

        self.residual_update_dt += time_since_last;
    }
}

impl Default for TimeContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Get the time between the start of the last frame and the current one;
/// in other words, the length of the last frame.
pub fn delta(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    tc.frame_durations.latest()
}

/// Gets the average time of a frame, averaged
/// over the last 200 frames.
pub fn average_delta(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    let sum: time::Duration = tc
        .frame_durations
        .contents()
        .iter()
        .sum();
    // If our buffer is actually full, divide by its size.
    // Otherwise divide by the number of samples we've added
    if tc.frame_durations.samples > tc.frame_durations.size {
        sum / (tc.frame_durations.size as u32)
    } else {
        sum / (tc.frame_durations.samples as u32)
    }
}

/// A convenience function to convert a Rust `Duration` type
/// to a (less precise but more useful) `f64`.
///
/// Does not make sure that the `Duration` is within the bounds
/// of the `f64`.
pub fn duration_to_f64(d: time::Duration) -> f64 {
    let seconds = d.as_secs() as f64;
    let nanos = f64::from(d.subsec_nanos());
    seconds + (nanos * 1e-9)
}

/// A convenience function to create a Rust `Duration` type
/// from a (less precise but more useful) `f64`.
///
/// Only handles positive numbers correctly.
pub fn f64_to_duration(t: f64) -> time::Duration {
    debug_assert!(t >= 0.0, "f64_to_duration passed a negative number!");
    let seconds = t.trunc();
    let nanos = t.fract() * 1e9;
    time::Duration::new(seconds as u64, nanos as u32)
}

/// Returns a `Duration` representing how long each
/// frame should be to match the given fps.
///
/// Approximately.
fn fps_as_duration(fps: u32) -> time::Duration {
    let target_dt_seconds = 1.0 / f64::from(fps);
    f64_to_duration(target_dt_seconds)
}

/// Gets the FPS of the game, averaged over the last
/// 200 frames.
pub fn fps(ctx: &Context) -> f64 {
    let duration_per_frame = average_delta(ctx);
    let seconds_per_frame = duration_to_f64(duration_per_frame);
    1.0 / seconds_per_frame
}

/// Returns the time since the game was initialized,
/// as reported by the system clock.
pub fn time_since_start(ctx: &Context) -> time::Duration {
    let tc = &ctx.timer_context;
    time::Instant::now() - tc.init_instant
}

/// This function will return true if the time since the
/// last [`update()`](../event/trait.EventHandler.html#tymethod.update)
/// call has been equal to or greater to
/// the update FPS indicated by the `target_fps`.
/// It keeps track of fractional frames, so if you want
/// 60 fps (16.67 ms/frame) and the game stutters so that
/// there is 40 ms between `update()` calls, this will return
/// `true` twice, and take the remaining 6.67 ms into account
/// in the next frame.
///
/// The intention is to for it to be called in a while loop
/// in your `update()` callback:
///
/// ```rust
/// # use ggez::*;
/// # fn update_game_physics() -> GameResult { Ok(()) }
/// # struct State;
/// # impl ggez::event::EventHandler for State {
/// fn update(&mut self, ctx: &mut Context) -> GameResult {
///     while(timer::check_update_time(ctx, 60)) {
///         update_game_physics()?;
///     }
///     Ok(())
/// }
/// # fn draw(&mut self, _ctx: &mut Context) -> GameResult { Ok(()) }
/// # }
/// ```
pub fn check_update_time(ctx: &mut Context, target_fps: u32) -> bool {
    let timedata = &mut ctx.timer_context;

    let target_dt = fps_as_duration(target_fps);
    if timedata.residual_update_dt > target_dt {
        timedata.residual_update_dt -= target_dt;
        true
    } else {
        false
    }
}

/// Returns the fractional amount of a frame not consumed
/// by  [`check_update_time()`](fn.check_update_time.html).
/// For example, if the desired
/// update frame time is 40 ms (25 fps), and 45 ms have
/// passed since the last frame, [`check_update_time()`](fn.check_update_time.html)
/// will return `true` and `remaining_update_time()` will
/// return 5 ms -- the amount of time "overflowing" from one
/// frame to the next.
///
/// The intention is for it to be called in your
/// [`draw()`](../event/trait.EventHandler.html#tymethod.draw) callback
/// to interpolate physics states for smooth rendering.
/// (see <http://gafferongames.com/game-physics/fix-your-timestep/>)
pub fn remaining_update_time(ctx: &mut Context) -> time::Duration {
    ctx.timer_context.residual_update_dt
}

/// Pauses the current thread for the target duration.
/// Just calls [`std::thread::sleep()`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
/// so it's as accurate as that is (which is usually not very).
pub fn sleep(duration: time::Duration) {
    thread::sleep(duration);
}

/// Yields the current timeslice to the OS.
///
/// This just calls [`std::thread::yield_now()`](https://doc.rust-lang.org/std/thread/fn.yield_now.html)
/// but it's handy to have here.
pub fn yield_now() {
    thread::yield_now();
}

/// Gets the number of times the game has gone through its event loop.
///
/// Specifically, the number of times that [`TimeContext::tick()`](struct.TimeContext.html#method.tick)
/// has been called by it.
pub fn ticks(ctx: &Context) -> usize {
    ctx.timer_context.frame_count
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher};

use super::{Result, LuaError};

#[derive(Debug)]
pub struct LuaState {
last_id: Cell<usize>
}

impl LuaState {
    pub fn new() -> LuaState {
        return LuaState { last_id: Cell::new(0) }
    }

    pub fn get_ref_id(&self) -> usize {
        self.last_id.set(self.last_id.get()+1);
        return self.last_id.get();
    }
}

#[derive(Debug,Eq)]
struct CoreTable {
    pub ref_id: usize,
        pub map: RefCell<HashMap<LuaValue, LuaValue>>,
        pub vector: RefCell<Vec<LuaValue>>,
}

impl CoreTable {
}

impl PartialEq for CoreTable {
    fn eq(&self, other: &CoreTable) -> bool {
        return self.ref_id == other.ref_id
    }
}

impl Hash for CoreTable {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.ref_id.hash(state);
    }
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
pub struct LuaTable {
content: Rc<CoreTable>
}

impl LuaTable {
    pub fn new(id: usize) -> LuaTable {
        LuaTable {
             content: Rc::new(
                 CoreTable {
                      ref_id: id,
                       map: RefCell::new(HashMap::new()),
                        vector: RefCell::new(Vec::new()) }) }
    }

    pub fn with_capacity(id: usize, capacity: usize) -> LuaTable {
        LuaTable {
            content: Rc::new(
                CoreTable {
                    ref_id: id,
                    map: RefCell::new(HashMap::new()),
                    vector: RefCell::new(Vec::with_capacity(capacity))
                    })
        }
    }

    pub fn sequence_border(&self) -> usize {
        return self.content.vector.borrow().len();
    }

    pub fn set(&self, key: &LuaValue, value: &LuaValue) -> Result<()> {
        match *key {
            LuaValue::Nil => Err(LuaError::IndexError("Using nil as a table index".to_owned())),
                LuaValue::Float(f) => {
                    if f.is_nan() {
                        Err(LuaError::IndexError("Using NaN as a table index".to_owned()))
                    } else {
                        let round = f.round();
                        if round == f {
                            self.set(&LuaValue::Integer(round as isize), value)?
                        } else {
                            self.map_set(key, value)
                        };
                        Ok(())
                    }
                },
                LuaValue::Integer(i) => {
                    if i < 1 || (i as usize) > self.content.vector.borrow().len()+1 {
                        self.map_set(key, value);
                    } else {
                        self.sequence_set(i, value);
                    }
                    Ok(())
                }
            _ => {
                self.map_set(key, value);
                Ok(())
            }
        }
    }

    fn map_set(&self, key: &LuaValue, value: &LuaValue) {
        let mut map = self.content.map.borrow_mut();
        match *value {
            LuaValue::Nil => {map.remove(key); () },
                _ =>{ map.insert(key.clone(), value.clone()); () }
        }
    }

    fn sequence_set(&self, idx: isize, value: &LuaValue) {
        let mut seq = self.content.vector.borrow_mut();
        assert!(idx >= 1);

        let idx = (idx-1) as usize;
        if idx == seq.len() {
            seq.push(value.clone());
        }
    }
}

#[derive(Debug,PartialEq,Clone)]
pub enum LuaValue {
    Nil,
        Integer(isize),
        Float(f64),
        Boolean(bool),
        Str(String),
        Table(LuaTable)
}

// This trait is there to say that the equality is symmetric, reflexive and transitive,
// which isn't the case for floats (NaN != NaN). However, for now these properties are
// only used in the table hashmap, and the specs say that a Lua table won't ever have NaN
// as an index, so...
// WARNING: This is gonna bite me in the rear.
impl Eq for LuaValue { }

impl Hash for LuaValue {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            &LuaValue::Nil => 0.hash(state),
                &LuaValue::Integer(ref i) => i.hash(state),
                &LuaValue::Float(ref f) => f.to_bits().hash(state),
                &LuaValue::Boolean(ref b) => b.hash(state),
                &LuaValue::Str(ref s) => s.hash(state),
                &LuaValue::Table(ref t) => t.hash(state),
        }
    }
}
<commit_msg>Introduce the notion of lexical scope<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher};

use std::collections::vec_deque::VecDeque;
use std::collections::BTreeMap;

use super::{Result, LuaError};

type Scope = Rc<BTreeMap<String, LuaValue>>;

#[derive(Debug)]
pub struct LuaState {
     last_id: Cell<usize>,
     global: LuaTable,
     scope_stack: VecDeque<Scope>,
}

impl LuaState {
    pub fn new() -> LuaState {
        let global = LuaTable::new(0);
        let mut initial_scope = Rc::new(BTreeMap::new());
        Rc::get_mut(&mut initial_scope).unwrap().insert("_ENV".to_owned(), LuaValue::Table(global.clone()));

        let mut scope_stack = VecDeque::new();
        scope_stack.push_back(initial_scope);
        return LuaState {
            last_id: Cell::new(0),
            global,
            scope_stack
        }
    }

    pub fn get_ref_id(&self) -> usize {
        self.last_id.set(self.last_id.get()+1);
        return self.last_id.get();
    }
}

#[derive(Debug,Eq)]
struct CoreTable {
    pub ref_id: usize,
        pub map: RefCell<HashMap<LuaValue, LuaValue>>,
        pub vector: RefCell<Vec<LuaValue>>,
}

impl CoreTable {
}

impl PartialEq for CoreTable {
    fn eq(&self, other: &CoreTable) -> bool {
        return self.ref_id == other.ref_id
    }
}

impl Hash for CoreTable {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.ref_id.hash(state);
    }
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
pub struct LuaTable {
content: Rc<CoreTable>
}

impl LuaTable {
    pub fn new(id: usize) -> LuaTable {
        LuaTable {
             content: Rc::new(
                 CoreTable {
                      ref_id: id,
                       map: RefCell::new(HashMap::new()),
                        vector: RefCell::new(Vec::new()) }) }
    }

    pub fn with_capacity(id: usize, capacity: usize) -> LuaTable {
        LuaTable {
            content: Rc::new(
                CoreTable {
                    ref_id: id,
                    map: RefCell::new(HashMap::new()),
                    vector: RefCell::new(Vec::with_capacity(capacity))
                    })
        }
    }

    pub fn sequence_border(&self) -> usize {
        return self.content.vector.borrow().len();
    }

    pub fn set(&self, key: &LuaValue, value: &LuaValue) -> Result<()> {
        match *key {
            LuaValue::Nil => Err(LuaError::IndexError("Using nil as a table index".to_owned())),
                LuaValue::Float(f) => {
                    if f.is_nan() {
                        Err(LuaError::IndexError("Using NaN as a table index".to_owned()))
                    } else {
                        let round = f.round();
                        if round == f {
                            self.set(&LuaValue::Integer(round as isize), value)?
                        } else {
                            self.map_set(key, value)
                        };
                        Ok(())
                    }
                },
                LuaValue::Integer(i) => {
                    if i < 1 || (i as usize) > self.content.vector.borrow().len()+1 {
                        self.map_set(key, value);
                    } else {
                        self.sequence_set(i, value);
                    }
                    Ok(())
                }
            _ => {
                self.map_set(key, value);
                Ok(())
            }
        }
    }

    fn map_set(&self, key: &LuaValue, value: &LuaValue) {
        let mut map = self.content.map.borrow_mut();
        match *value {
            LuaValue::Nil => {map.remove(key); () },
                _ =>{ map.insert(key.clone(), value.clone()); () }
        }
    }

    fn sequence_set(&self, idx: isize, value: &LuaValue) {
        let mut seq = self.content.vector.borrow_mut();
        assert!(idx >= 1);

        let idx = (idx-1) as usize;
        if idx == seq.len() {
            seq.push(value.clone());
        }
    }
}

#[derive(Debug,PartialEq,Clone)]
pub enum LuaValue {
    Nil,
        Integer(isize),
        Float(f64),
        Boolean(bool),
        Str(String),
        Table(LuaTable)
}

// This trait is there to say that the equality is symmetric, reflexive and transitive,
// which isn't the case for floats (NaN != NaN). However, for now these properties are
// only used in the table hashmap, and the specs say that a Lua table won't ever have NaN
// as an index, so...
// WARNING: This is gonna bite me in the rear.
impl Eq for LuaValue { }

impl Hash for LuaValue {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            &LuaValue::Nil => 0.hash(state),
                &LuaValue::Integer(ref i) => i.hash(state),
                &LuaValue::Float(ref f) => f.to_bits().hash(state),
                &LuaValue::Boolean(ref b) => b.hash(state),
                &LuaValue::Str(ref s) => s.hash(state),
                &LuaValue::Table(ref t) => t.hash(state),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Types defined by Linux-PAM
//!
//! This modules contains struct and enum definitions used by `pam-sys`.

use libc::{c_char, c_int, c_void};

use std::fmt::{Display, Error, Formatter};

type ConvClosure = (extern "C" fn (c_int, *mut *mut PamMessage, *mut *mut PamResponse, *mut c_void) -> c_int);

/// Opaque struct internal to Linux-PAM
///
/// From `_pam_types.h`:
///
/// "This is a blind structure. Users aren't allowed to see
/// inside a `pam_handle_t`, so we don't define struct `pam_handle` here.
/// This is defined in a file private to the PAM library.
/// (i.e., it's private to PAM service modules, too!)"
pub enum PamHandle {}

/// Message struct to transfer authentication data to the user
///
/// From `_pam_types.h`:
///
/// "Used to pass prompting text, error messages, or other informatory text to the user.
/// This structure is allocated and freed by the PAM library (or loaded module)."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamMessage {
    pub msg_style:  c_int,
    pub msg:        *const c_char
}

/// Response struct to transfer the user's response back to Linux-PAM
///
/// From `_pam_types.h`:
///
/// "Used to return the user's response to the PAM library.
/// This structure is allocated by the application program,
/// and free()'d by the Linux-PAM library (or calling module)."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamResponse {
    pub resp:           *mut c_char,
    /// currently un-used, zero expected
    pub resp_retcode:   c_int
}

/// Conversation structure containing the `converse` function and authentication data
///
/// From `_pam_types.h`:
///
/// "The actual conversation structure itself"
#[repr(C)]
pub struct PamConversation {
    /* int (*conv)(int num_msg, const struct pam_message **msg,
		struct pam_response **resp, void *appdata_ptr); */
    pub conv:       Option<ConvClosure>,
    //pub conv:       *const c_void,
    pub data_ptr:   *mut c_void
}

/// Special struct for the `PAM_XAUTHDATA` pam item
///
/// From `_pam_types.h`:
///
/// "Used by the `PAM_XAUTHDATA` pam item. Contains X authentication
/// data used by modules to connect to the user's X display.
/// Note: this structure is intentionally compatible with `xcb_auth_info_t`."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamXAuthData {
    pub namelen:    c_int,
    pub name:       *mut c_char,
    pub datalen:    c_int,
    pub data:       *mut c_char
}

/// The Linux-PAM return values
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamReturnCode {
    /// Successful function return
    SUCCESS                 = 0,

    /// dlopen() failure when dynamically loading a service module
    OPEN_ERR                = 1,

    /// Symbol not found
    SYMBOL_ERR              = 2,

    /// Error in service module
    SERVICE_ERR             = 3,

    /// System error
    SYSTEM_ERR              = 4,

    /// Memory buffer error
    BUF_ERR                 = 5,

    /// Permission denied
    PERM_DENIED             = 6,

    /// Authentication failure
    AUTH_ERR                = 7,

    /// Can not access authentication data due to insufficient credentials
    CRED_INSUFFICIENT       = 8,

    /// Underlying authentication service can not retrieve authentication information
    AUTHINFO_UNAVAIL        = 9,

    /// User not known to the underlying authentication module
    USER_UNKNOWN            = 10,

    /// An authentication service has maintained a retry count which has been reached.
    /// No further retries should be attempted
    MAXTRIES                = 11,

    /// New authentication token required.
    /// This is normally returned if the machine security policies require
    /// that the password should be changed beccause the password is NULL or it has aged
    NEW_AUTHTOK_REQD        = 12,

    /// User account has expired
    ACCT_EXPIRED            = 13,

    /// Can not make/remove an entry for the specified session
    SESSION_ERR             = 14,

    /// Underlying authentication service can not retrieve user credentials unavailable
    CRED_UNAVAIL            = 15,

    /// User credentials expired
    CRED_EXPIRED            = 16,

    /// Failure setting user credentials
    CRED_ERR                = 17,

    /// No module specific data is present
    NO_MODULE_DATA          = 18,

    /// Conversation error
    CONV_ERR                = 19,

    /// Authentication token manipulation error
    AUTHTOK_ERR             = 20,

    /// Authentication information cannot be recovered
    AUTHTOK_RECOVERY_ERR    = 21,

    /// Authentication token lock busy
    AUTHTOK_LOCK_BUSY       = 22,

    /// Authentication token aging disabled
    AUTHTOK_DISABLE_AGING   = 23,

    /// Preliminary check by password service
    TRY_AGAIN               = 24,

    /// Ignore underlying account module regardless of whether
    /// the control flag is required, optional, or sufficient
    IGNORE                  = 25,

    /// Critical error (?module fail now request)
    AUTHTOK_EXPIRED         = 27,

    /// user's authentication token has expired
    ABORT                   = 26,

    /// module is not known
    MODULE_UNKNOWN          = 28,

    /// Bad item passed to pam_*_item()
    BAD_ITEM                = 29,

    /// conversation function is event driven and data is not available yet
    CONV_AGAIN              = 30,

    /// please call this function again to complete authentication stack.
    /// Before calling again, verify that conversation is completed
    INCOMPLETE              = 31
}

impl Display for PamReturnCode {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

impl From<i32> for PamReturnCode {
    fn from(status: i32) -> PamReturnCode {
        match status {
            0   => PamReturnCode::SUCCESS               ,
            1   => PamReturnCode::OPEN_ERR              ,
            2   => PamReturnCode::SYMBOL_ERR            ,
            3   => PamReturnCode::SERVICE_ERR           ,
            4   => PamReturnCode::SYSTEM_ERR            ,
            5   => PamReturnCode::BUF_ERR               ,
            6   => PamReturnCode::PERM_DENIED           ,
            7   => PamReturnCode::AUTH_ERR              ,
            8   => PamReturnCode::CRED_INSUFFICIENT     ,
            9   => PamReturnCode::AUTHINFO_UNAVAIL      ,
            10  => PamReturnCode::USER_UNKNOWN          ,
            11  => PamReturnCode::MAXTRIES              ,
            12  => PamReturnCode::NEW_AUTHTOK_REQD      ,
            13  => PamReturnCode::ACCT_EXPIRED          ,
            14  => PamReturnCode::SESSION_ERR           ,
            15  => PamReturnCode::CRED_UNAVAIL          ,
            16  => PamReturnCode::CRED_EXPIRED          ,
            17  => PamReturnCode::CRED_ERR              ,
            18  => PamReturnCode::NO_MODULE_DATA        ,
            19  => PamReturnCode::CONV_ERR              ,
            20  => PamReturnCode::AUTHTOK_ERR           ,
            21  => PamReturnCode::AUTHTOK_RECOVERY_ERR  ,
            22  => PamReturnCode::AUTHTOK_LOCK_BUSY     ,
            23  => PamReturnCode::AUTHTOK_DISABLE_AGING ,
            24  => PamReturnCode::TRY_AGAIN             ,
            25  => PamReturnCode::IGNORE                ,
            26  => PamReturnCode::ABORT                 ,
            27  => PamReturnCode::AUTHTOK_EXPIRED       ,
            28  => PamReturnCode::MODULE_UNKNOWN        ,
            29  => PamReturnCode::BAD_ITEM              ,
            30  => PamReturnCode::CONV_AGAIN            ,
            31  => PamReturnCode::INCOMPLETE            ,
            _   => PamReturnCode::SYSTEM_ERR
        }
    }
}

/// The Linux-PAM flags
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamFlag {
    /// Authentication service should not generate any messages
    SILENT                  = 0x8000,

    /// The authentication service should return AUTH_ERROR
    /// if the user has a null authentication token
    /// (used by pam_authenticate{,_secondary}())
    DISALLOW_NULL_AUTHTOK   = 0x0001,

    /// Set user credentials for an authentication service
    /// (used for pam_setcred())
    ESTABLISH_CRED          = 0x0002,

    /// Delete user credentials associated with an authentication service
    /// (used for pam_setcred())
    DELETE_CRED             = 0x0004,

    /// Reinitialize user credentials
    /// (used for pam_setcred())
    REINITIALIZE_CRED       = 0x0008,

    /// Extend lifetime of user credentials
    /// (used for pam_setcred())
    REFRESH_CRED            = 0x0010,

    /// The password service should only update those passwords that have aged.
    /// If this flag is not passed, the password service should update all passwords.
    /// (used by pam_chauthtok)
    CHANGE_EXPIRED_AUTHTOK  = 0x0020,

    NONE                    = 0x0000
}

impl Display for PamFlag {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM item types
///
/// These defines are used by `pam_set_item()` `and pam_get_item()`.
/// Please check the spec which are allowed for use by applications
/// and which are only allowed for use by modules.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamItemType {
    /// The service name
    SERVICE         = 1,

    /// The user name
    USER            = 2,

    /// The tty name
    TTY             = 3,

    /// The remote host name
    RHOST           = 4,

    /// The pam_conv structure
    CONV            = 5,

    /// The authentication token (password)
    AUTHTOK         = 6,

    /// The old authentication token
    OLDAUTHTOK      = 7,

    /// The remote user name
    RUSER           = 8,

    /// the prompt for getting a username Linux-PAM extensions
    USER_PROMPT     = 9,

    /// app supplied function to override failure delays
    FAIL_DELAY      = 10,

    /// X display name
    XDISPLAY        = 11,

    /// X server authentication data
    XAUTHDATA       = 12,

    /// The type for pam_get_authtok
    AUTHTOK_TYPE    = 13
}

impl Display for PamItemType {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM message styles
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamMessageStyle {
    PROMPT_ECHO_OFF = 1,
    PROMPT_ECHO_ON  = 2,
    ERROR_MSG       = 3,
    TEXT_INFO       = 4
}

impl Display for PamMessageStyle {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

impl From<i32> for PamMessageStyle {
    fn from(style: i32) -> PamMessageStyle {
        match style {
            1 => PamMessageStyle::PROMPT_ECHO_OFF,
            2 => PamMessageStyle::PROMPT_ECHO_ON,
            3 => PamMessageStyle::ERROR_MSG,
            4 => PamMessageStyle::TEXT_INFO,
            _ => PamMessageStyle::ERROR_MSG
        }
    }
}
<commit_msg>[types.rs] Added missing doc comment to ConvClosure<commit_after>// Copyright (C) 2015 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Types defined by Linux-PAM
//!
//! This modules contains struct and enum definitions used by `pam-sys`.

use libc::{c_char, c_int, c_void};

use std::fmt::{Display, Error, Formatter};

/// Type alias for the PAM "conversation function" used as part of the `PamConversation` struct
type ConvClosure = (extern "C" fn (c_int, *mut *mut PamMessage, *mut *mut PamResponse, *mut c_void) -> c_int);

/// Opaque struct internal to Linux-PAM
///
/// From `_pam_types.h`:
///
/// "This is a blind structure. Users aren't allowed to see
/// inside a `pam_handle_t`, so we don't define struct `pam_handle` here.
/// This is defined in a file private to the PAM library.
/// (i.e., it's private to PAM service modules, too!)"
pub enum PamHandle {}

/// Message struct to transfer authentication data to the user
///
/// From `_pam_types.h`:
///
/// "Used to pass prompting text, error messages, or other informatory text to the user.
/// This structure is allocated and freed by the PAM library (or loaded module)."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamMessage {
    pub msg_style:  c_int,
    pub msg:        *const c_char
}

/// Response struct to transfer the user's response back to Linux-PAM
///
/// From `_pam_types.h`:
///
/// "Used to return the user's response to the PAM library.
/// This structure is allocated by the application program,
/// and free()'d by the Linux-PAM library (or calling module)."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamResponse {
    pub resp:           *mut c_char,
    /// currently un-used, zero expected
    pub resp_retcode:   c_int
}

/// Conversation structure containing the `converse` function and authentication data
///
/// From `_pam_types.h`:
///
/// "The actual conversation structure itself"
#[repr(C)]
pub struct PamConversation {
    /* int (*conv)(int num_msg, const struct pam_message **msg,
		struct pam_response **resp, void *appdata_ptr); */
    pub conv:       Option<ConvClosure>,
    pub data_ptr:   *mut c_void
}

/// Special struct for the `PAM_XAUTHDATA` pam item
///
/// From `_pam_types.h`:
///
/// "Used by the `PAM_XAUTHDATA` pam item. Contains X authentication
/// data used by modules to connect to the user's X display.
/// Note: this structure is intentionally compatible with `xcb_auth_info_t`."
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PamXAuthData {
    pub namelen:    c_int,
    pub name:       *mut c_char,
    pub datalen:    c_int,
    pub data:       *mut c_char
}

/// The Linux-PAM return values
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamReturnCode {
    /// Successful function return
    SUCCESS                 = 0,

    /// dlopen() failure when dynamically loading a service module
    OPEN_ERR                = 1,

    /// Symbol not found
    SYMBOL_ERR              = 2,

    /// Error in service module
    SERVICE_ERR             = 3,

    /// System error
    SYSTEM_ERR              = 4,

    /// Memory buffer error
    BUF_ERR                 = 5,

    /// Permission denied
    PERM_DENIED             = 6,

    /// Authentication failure
    AUTH_ERR                = 7,

    /// Can not access authentication data due to insufficient credentials
    CRED_INSUFFICIENT       = 8,

    /// Underlying authentication service can not retrieve authentication information
    AUTHINFO_UNAVAIL        = 9,

    /// User not known to the underlying authentication module
    USER_UNKNOWN            = 10,

    /// An authentication service has maintained a retry count which has been reached.
    /// No further retries should be attempted
    MAXTRIES                = 11,

    /// New authentication token required.
    /// This is normally returned if the machine security policies require
    /// that the password should be changed beccause the password is NULL or it has aged
    NEW_AUTHTOK_REQD        = 12,

    /// User account has expired
    ACCT_EXPIRED            = 13,

    /// Can not make/remove an entry for the specified session
    SESSION_ERR             = 14,

    /// Underlying authentication service can not retrieve user credentials unavailable
    CRED_UNAVAIL            = 15,

    /// User credentials expired
    CRED_EXPIRED            = 16,

    /// Failure setting user credentials
    CRED_ERR                = 17,

    /// No module specific data is present
    NO_MODULE_DATA          = 18,

    /// Conversation error
    CONV_ERR                = 19,

    /// Authentication token manipulation error
    AUTHTOK_ERR             = 20,

    /// Authentication information cannot be recovered
    AUTHTOK_RECOVERY_ERR    = 21,

    /// Authentication token lock busy
    AUTHTOK_LOCK_BUSY       = 22,

    /// Authentication token aging disabled
    AUTHTOK_DISABLE_AGING   = 23,

    /// Preliminary check by password service
    TRY_AGAIN               = 24,

    /// Ignore underlying account module regardless of whether
    /// the control flag is required, optional, or sufficient
    IGNORE                  = 25,

    /// Critical error (?module fail now request)
    AUTHTOK_EXPIRED         = 27,

    /// user's authentication token has expired
    ABORT                   = 26,

    /// module is not known
    MODULE_UNKNOWN          = 28,

    /// Bad item passed to pam_*_item()
    BAD_ITEM                = 29,

    /// conversation function is event driven and data is not available yet
    CONV_AGAIN              = 30,

    /// please call this function again to complete authentication stack.
    /// Before calling again, verify that conversation is completed
    INCOMPLETE              = 31
}

impl Display for PamReturnCode {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

impl From<i32> for PamReturnCode {
    fn from(status: i32) -> PamReturnCode {
        match status {
            0   => PamReturnCode::SUCCESS               ,
            1   => PamReturnCode::OPEN_ERR              ,
            2   => PamReturnCode::SYMBOL_ERR            ,
            3   => PamReturnCode::SERVICE_ERR           ,
            4   => PamReturnCode::SYSTEM_ERR            ,
            5   => PamReturnCode::BUF_ERR               ,
            6   => PamReturnCode::PERM_DENIED           ,
            7   => PamReturnCode::AUTH_ERR              ,
            8   => PamReturnCode::CRED_INSUFFICIENT     ,
            9   => PamReturnCode::AUTHINFO_UNAVAIL      ,
            10  => PamReturnCode::USER_UNKNOWN          ,
            11  => PamReturnCode::MAXTRIES              ,
            12  => PamReturnCode::NEW_AUTHTOK_REQD      ,
            13  => PamReturnCode::ACCT_EXPIRED          ,
            14  => PamReturnCode::SESSION_ERR           ,
            15  => PamReturnCode::CRED_UNAVAIL          ,
            16  => PamReturnCode::CRED_EXPIRED          ,
            17  => PamReturnCode::CRED_ERR              ,
            18  => PamReturnCode::NO_MODULE_DATA        ,
            19  => PamReturnCode::CONV_ERR              ,
            20  => PamReturnCode::AUTHTOK_ERR           ,
            21  => PamReturnCode::AUTHTOK_RECOVERY_ERR  ,
            22  => PamReturnCode::AUTHTOK_LOCK_BUSY     ,
            23  => PamReturnCode::AUTHTOK_DISABLE_AGING ,
            24  => PamReturnCode::TRY_AGAIN             ,
            25  => PamReturnCode::IGNORE                ,
            26  => PamReturnCode::ABORT                 ,
            27  => PamReturnCode::AUTHTOK_EXPIRED       ,
            28  => PamReturnCode::MODULE_UNKNOWN        ,
            29  => PamReturnCode::BAD_ITEM              ,
            30  => PamReturnCode::CONV_AGAIN            ,
            31  => PamReturnCode::INCOMPLETE            ,
            _   => PamReturnCode::SYSTEM_ERR
        }
    }
}

/// The Linux-PAM flags
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamFlag {
    /// Authentication service should not generate any messages
    SILENT                  = 0x8000,

    /// The authentication service should return AUTH_ERROR
    /// if the user has a null authentication token
    /// (used by pam_authenticate{,_secondary}())
    DISALLOW_NULL_AUTHTOK   = 0x0001,

    /// Set user credentials for an authentication service
    /// (used for pam_setcred())
    ESTABLISH_CRED          = 0x0002,

    /// Delete user credentials associated with an authentication service
    /// (used for pam_setcred())
    DELETE_CRED             = 0x0004,

    /// Reinitialize user credentials
    /// (used for pam_setcred())
    REINITIALIZE_CRED       = 0x0008,

    /// Extend lifetime of user credentials
    /// (used for pam_setcred())
    REFRESH_CRED            = 0x0010,

    /// The password service should only update those passwords that have aged.
    /// If this flag is not passed, the password service should update all passwords.
    /// (used by pam_chauthtok)
    CHANGE_EXPIRED_AUTHTOK  = 0x0020,

    NONE                    = 0x0000
}

impl Display for PamFlag {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM item types
///
/// These defines are used by `pam_set_item()` `and pam_get_item()`.
/// Please check the spec which are allowed for use by applications
/// and which are only allowed for use by modules.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamItemType {
    /// The service name
    SERVICE         = 1,

    /// The user name
    USER            = 2,

    /// The tty name
    TTY             = 3,

    /// The remote host name
    RHOST           = 4,

    /// The pam_conv structure
    CONV            = 5,

    /// The authentication token (password)
    AUTHTOK         = 6,

    /// The old authentication token
    OLDAUTHTOK      = 7,

    /// The remote user name
    RUSER           = 8,

    /// the prompt for getting a username Linux-PAM extensions
    USER_PROMPT     = 9,

    /// app supplied function to override failure delays
    FAIL_DELAY      = 10,

    /// X display name
    XDISPLAY        = 11,

    /// X server authentication data
    XAUTHDATA       = 12,

    /// The type for pam_get_authtok
    AUTHTOK_TYPE    = 13
}

impl Display for PamItemType {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM message styles
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PamMessageStyle {
    PROMPT_ECHO_OFF = 1,
    PROMPT_ECHO_ON  = 2,
    ERROR_MSG       = 3,
    TEXT_INFO       = 4
}

impl Display for PamMessageStyle {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

impl From<i32> for PamMessageStyle {
    fn from(style: i32) -> PamMessageStyle {
        match style {
            1 => PamMessageStyle::PROMPT_ECHO_OFF,
            2 => PamMessageStyle::PROMPT_ECHO_ON,
            3 => PamMessageStyle::ERROR_MSG,
            4 => PamMessageStyle::TEXT_INFO,
            _ => PamMessageStyle::ERROR_MSG
        }
    }
}
<|endoftext|>


<commit_before>use std::num::Float;
use std::num::pow;

/// Clamp a value between a given min and max.
pub fn clamp<T: Float + PartialOrd>(n: T, min: T, max: T) -> T {
    if n < min { min } else if n > max { max } else { n }
}

/// Clamp a f32 between 0f32 and 1f32.
pub fn clampf32(f: f32) -> f32 {
    if f < 0f32 { 0f32 } else if f > 1f32 { 1f32 } else { f }
}

/// Compare two f64s and return an Ordering.
pub fn compare_f64s(a: f64, b: f64) -> Ordering {
    if a > b { Greater }
    else if a < b { Less }
    else { Equal }
}

/// Get value percentage between max and min.
pub fn percentage<T: Float + Copy + FromPrimitive + ToPrimitive>
    (value: T, min: T, max: T) -> f32 {
    let v = value.to_f32().unwrap();
    let mn = min.to_f32().unwrap();
    let mx = max.to_f32().unwrap();
    (v - mn) / (mx - mn)
}

/// Adjust the value to the given percentage.
pub fn value_from_perc<T: Float + Copy + FromPrimitive + ToPrimitive>
    (perc: f32, min: T, max: T) -> T {
    min + FromPrimitive::from_f32((max - min).to_f32().unwrap() * perc).unwrap()
}

/// Map a value from a given range to a new given range.
pub fn map_range<X: Float + Copy + FromPrimitive + ToPrimitive,
                 Y: Float + Copy + FromPrimitive + ToPrimitive>
(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y {
    let (val_f, in_min_f, in_max_f, out_min_f, out_max_f) = (
        val.to_f64().unwrap(),
        in_min.to_f64().unwrap(),
        in_max.to_f64().unwrap(),
        out_min.to_f64().unwrap(),
        out_max.to_f64().unwrap(),
    );
    FromPrimitive::from_f64(
        (val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f
    ).unwrap()
}

/// Get a suitable string from the value, its max and the pixel range.
pub fn val_to_string<T: ToString + ToPrimitive>
(val: T, max: T, val_rng: T, pixel_range: uint) -> String {
    let mut s = val.to_string();
    let decimal = s.as_slice().chars().position(|ch| ch == '.');
    match decimal {
        None => s,
        Some(idx) => {
            // Find the minimum string length by determing
            // what power of ten both the max and range are.
            let val_rng_f = val_rng.to_f64().unwrap();
            let max_f = max.to_f64().unwrap();
            let mut n = 0f64;
            let mut pow_ten = 0f64;
            while pow_ten < val_rng_f || pow_ten < max_f {
                pow_ten = (10f64).powf(n);
                n += 1.0
            }
            let min_string_len = n as uint + 1u;

            // Find out how many pixels there are to actually use
            // and judge a reasonable precision from this.
            let mut n = 1u;
            while pow(10u, n) < pixel_range { n += 1u }
            let precision = n;

            // Truncate the length to the pixel precision as
            // long as this doesn't cause it to be smaller
            // than the necessary decimal place.
            let mut truncate_len = min_string_len + (precision - 1u);
            if idx + precision < truncate_len { truncate_len = idx + precision }
            if s.len() > truncate_len { s.truncate(truncate_len) }
            s
        }
    }
}

<commit_msg>Remove compiler warning for pow<commit_after>use std::num::Float;
use std::num::Int;

/// Clamp a value between a given min and max.
pub fn clamp<T: Float + PartialOrd>(n: T, min: T, max: T) -> T {
    if n < min { min } else if n > max { max } else { n }
}

/// Clamp a f32 between 0f32 and 1f32.
pub fn clampf32(f: f32) -> f32 {
    if f < 0f32 { 0f32 } else if f > 1f32 { 1f32 } else { f }
}

/// Compare two f64s and return an Ordering.
pub fn compare_f64s(a: f64, b: f64) -> Ordering {
    if a > b { Greater }
    else if a < b { Less }
    else { Equal }
}

/// Get value percentage between max and min.
pub fn percentage<T: Float + Copy + FromPrimitive + ToPrimitive>
    (value: T, min: T, max: T) -> f32 {
    let v = value.to_f32().unwrap();
    let mn = min.to_f32().unwrap();
    let mx = max.to_f32().unwrap();
    (v - mn) / (mx - mn)
}

/// Adjust the value to the given percentage.
pub fn value_from_perc<T: Float + Copy + FromPrimitive + ToPrimitive>
    (perc: f32, min: T, max: T) -> T {
    min + FromPrimitive::from_f32((max - min).to_f32().unwrap() * perc).unwrap()
}

/// Map a value from a given range to a new given range.
pub fn map_range<X: Float + Copy + FromPrimitive + ToPrimitive,
                 Y: Float + Copy + FromPrimitive + ToPrimitive>
(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y {
    let (val_f, in_min_f, in_max_f, out_min_f, out_max_f) = (
        val.to_f64().unwrap(),
        in_min.to_f64().unwrap(),
        in_max.to_f64().unwrap(),
        out_min.to_f64().unwrap(),
        out_max.to_f64().unwrap(),
    );
    FromPrimitive::from_f64(
        (val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f
    ).unwrap()
}

/// Get a suitable string from the value, its max and the pixel range.
pub fn val_to_string<T: ToString + ToPrimitive>
(val: T, max: T, val_rng: T, pixel_range: uint) -> String {
    let mut s = val.to_string();
    let decimal = s.as_slice().chars().position(|ch| ch == '.');
    match decimal {
        None => s,
        Some(idx) => {
            // Find the minimum string length by determing
            // what power of ten both the max and range are.
            let val_rng_f = val_rng.to_f64().unwrap();
            let max_f = max.to_f64().unwrap();
            let mut n = 0f64;
            let mut pow_ten = 0f64;
            while pow_ten < val_rng_f || pow_ten < max_f {
                pow_ten = (10f64).powf(n);
                n += 1.0
            }
            let min_string_len = n as uint + 1u;

            // Find out how many pixels there are to actually use
            // and judge a reasonable precision from this.
            let mut n = 1u;
            while 10u.pow(n) < pixel_range { n += 1u }
            let precision = n;

            // Truncate the length to the pixel precision as
            // long as this doesn't cause it to be smaller
            // than the necessary decimal place.
            let mut truncate_len = min_string_len + (precision - 1u);
            if idx + precision < truncate_len { truncate_len = idx + precision }
            if s.len() > truncate_len { s.truncate(truncate_len) }
            s
        }
    }
}

<|endoftext|>


<commit_before>use iron::prelude::*;
use maud::{Markup, PreEscaped};

use user::User;

static STYLES: &'static str = r#"
html {
    box-sizing: border-box;
    font: 150%/1.5 "Liberation Serif", "Times New Roman", serif;
    background: linear-gradient(to bottom, #445 0%, #001 100%);
}

* {
    box-sizing: inherit;
}

body {
    margin: 0 auto;
    max-width: 30rem;
    min-height: 100vh;
    padding: 0.5rem 1.5rem;
    box-shadow: 0 0 0 8px #ccc, 0 0 0 16px #999, 0 0 0 20px #666;
    background: #fff;
}

a {
    text-decoration: none;
    color: #910;
}

a:hover, a:active {
    text-shadow: 0 0 2px #fff, 0 0 8px #d60;
}

h1 {
    margin: 0 0 1rem;
    font-family: "Comic Sans MS", sans-serif;
    font-size: 3rem;
    letter-spacing: 0.75rem;
}

h1 a {
    color: #f90;
    text-shadow: 2px 2px #000, -2px -2px #faa;
    text-transform: uppercase;
}

h1 a:hover, h1 a:active {
    text-shadow: 8px 8px #000, -8px -8px #faa;
}

table {
    border-spacing: 0.5rem;
}

th {
    text-align: right;
    vertical-align: top;
}
"#;

pub fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    let url = r.url.clone().into_generic_url();
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(title) = title {
                    (title) " - "
                }
                "Karkinos"
            }
            style (PreEscaped(STYLES))
            body {
                h1 a href="/" "🦀Karkinos"
                @if let Some(title) = title {
                    h2 a href=(url.path()) title="Link to this page" (title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        p {
            b "Karkinos"
            " is a list of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            "."
        }
        p {
            "It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but with a different interface."
        }
    })
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "<< Back to home page"
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    let title = if let Some(ref name) = user.name {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    };
    layout(r, Some(&title), html! {
        table {
            @if let Some(ref x) = user.name {
                tr {
                    th "Name"
                    td (x)
                }
            }
            @if let Some(ref x) = user.irc {
                tr {
                    th "IRC nick"
                    td (x)
                }
            }
            @if !user.irc_channels.is_empty() {
                tr {
                    th "IRC channels"
                    td @for (i, channel) in user.irc_channels.iter().enumerate() {
                        @if i > 0 { ", " }
                        "#" (channel)
                    }
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.notes {
                tr {
                    th "Notes"
                    td style="white-space: pre-line" (x)
                }
            }
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "<< Back to home page"
    })
}
<commit_msg>Add remaining user fields<commit_after>use iron::prelude::*;
use maud::{Markup, PreEscaped};

use user::User;

static STYLES: &'static str = r#"
html {
    box-sizing: border-box;
    font: 150%/1.5 "Liberation Serif", "Times New Roman", serif;
    background: linear-gradient(to bottom, #445 0%, #001 100%);
}

* {
    box-sizing: inherit;
}

body {
    margin: 0 auto;
    max-width: 30rem;
    min-height: 100vh;
    padding: 0.5rem 1.5rem;
    box-shadow: 0 0 0 8px #ccc, 0 0 0 16px #999, 0 0 0 20px #666;
    background: #fff;
}

a {
    text-decoration: none;
    color: #910;
}

a:hover, a:active {
    text-shadow: 0 0 2px #fff, 0 0 8px #d60;
}

h1 {
    margin: 0 0 1rem;
    font-family: "Comic Sans MS", sans-serif;
    font-size: 3rem;
    letter-spacing: 0.75rem;
}

h1 a {
    color: #f90;
    text-shadow: 2px 2px #000, -2px -2px #faa;
    text-transform: uppercase;
}

h1 a:hover, h1 a:active {
    text-shadow: 8px 8px #000, -8px -8px #faa;
}

table {
    border-spacing: 0.5rem;
}

th {
    text-align: right;
    vertical-align: top;
}
"#;

pub fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    let url = r.url.clone().into_generic_url();
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(title) = title {
                    (title) " - "
                }
                "Karkinos"
            }
            style (PreEscaped(STYLES))
            body {
                h1 a href="/" "🦀Karkinos"
                @if let Some(title) = title {
                    h2 a href=(url.path()) title="Link to this page" (title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        p {
            b "Karkinos"
            " is a list of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            "."
        }
        p {
            "It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but with a different interface."
        }
    })
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "<< Back to home page"
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    let title = if let Some(ref name) = user.name {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    };
    layout(r, Some(&title), html! {
        table {
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            p style="white-space: pre-line" (x)
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "<< Back to home page"
    })
}
<|endoftext|>