<commit_before>pub mod rk4;

use std::ops::Add;

pub enum Method {
    RK2,
    RK4,
}

/**
```
use ode::{Method, Solver};

let ini_cond: Vec<f32> = vec![1., 2.];

// simple config
Solver::new(ini_cond.clone(), |t: &f32, _: &Vec<f32>| vec![2.*t] )
    .method(Method::RK4)
    .run();

// complex config
let mut s = Solver::new(ini_cond, |t: &f32, _: &Vec<f32>| vec![2.*t] );
s.method(Method::RK4);
let (times, pos) = s.run();
```
*/
pub struct Solver<T, F>
    where T: From<f32>,
          F: Fn(&T, &Vec<T>) -> Vec<T> {
    method: Method,
    weights: Vec<T>,
    weight_sum: T,
    step: T,
    initial_conditions: Vec<T>,
    function: F,
}

impl<T, F> Solver<T, F>
    where T: Add<Output = T> + Clone + From<u8> + From<f32>,
          F: Fn(&T, &Vec<T>) -> Vec<T> {

    pub fn new(initial_conditions: Vec<T>, function: F) -> Solver<T, F> {
        Solver {
            method: Method::RK4,
            weights: vec![T::from(1), T::from(2), T::from(2), T::from(1)],
            weight_sum: T::from(6),
            step: T::from(10e-3),
            initial_conditions: initial_conditions,
            function: function,
        }
    }

    /**
    Select the desired algorithm to solve the givem problem, also changing the
    default weights (see `change_weight()` for more details) applyed in each
    case; default values are:

    - `Method::RK2`: `vec![T::from(1), T::from(1)],`
    - `Method::RK4`: `vec![T::from(1), T::from(2), T::from(2), T::from(1)],`

    Defaults to `Method::RK4`.
    */
    pub fn method(&mut self, new_method: Method) -> &mut Solver<T, F> {
        match new_method {
            Method::RK2 => self.weights = vec![T::from(1), T::from(1)],
            Method::RK4 => self.weights = vec![T::from(1), T::from(2),
                                               T::from(2), T::from(1)],
        }

        self.weight_sum = self.weights.iter()
            .fold(T::from(0), |sum, i| sum + i.clone());
        self.method = new_method;
        self
    }

    /**
    Modify the default weighting applyed to each intermidiate point. Notice
    that, when changing
    */
    pub fn change_weight(&mut self, new_weights: Vec<T>) -> &mut Solver<T, F> {
        self.weights = new_weights;
        self
    }

    /**
    Validates the data passed to the solver. This is tipically called by `run()`
    before attempting to solve the passed function.
    */
    pub fn validate(&self) {
        // make sure the weights match with the method
        assert_eq!(self.weights.len(),
                   match self.method {
                       Method::RK2 => 2,
                       Method::RK4 => 4,
                   });
    }

    /**
    Check and run the solver, returning the results of the calculation.
    */
    pub fn run(&self) -> (Vec<T>, Vec<Vec<T>>) {
        self.validate();

        (Vec::new(), Vec::new())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let _ = rk4::solver(|t: &f32, _: &Vec<f32>| -> Vec<f32> {
            vec![2.*t]
        }, vec![0.], &[0., 0.], 1.0);
    }
}
<commit_msg>Move trait requirements to Number trait<commit_after>pub mod rk4;

use std::ops::Add;

pub enum Method {
    RK2,
    RK4,
}

/**
Basic requirements for a type to use the solver.
*/
pub trait Number<T> : Add<Output = T> + Clone + From<u8> + From<f32> {}

/**
Anything that implements the required traits already implements Number.
*/
impl<T> Number<T> for T
    where T: Add<Output = T> + Clone + From<u8> + From<f32> {}

/**
```
use ode::{Method, Solver};

let ini_cond: Vec<f32> = vec![1., 2.];

// simple config
Solver::new(ini_cond.clone(), |t: &f32, _: &Vec<f32>| vec![2.*t] )
    .method(Method::RK4)
    .run();

// complex config
let mut s = Solver::new(ini_cond, |t: &f32, _: &Vec<f32>| vec![2.*t] );
s.method(Method::RK4);
let (times, pos) = s.run();
```
*/
pub struct Solver<T, F>
    where T: Number<T>,
          F: Fn(&T, &Vec<T>) -> Vec<T> {
    method: Method,
    weights: Vec<T>,
    weight_sum: T,
    step: T,
    initial_conditions: Vec<T>,
    function: F,
}

impl<T, F> Solver<T, F>
    where T: Number<T>,
          F: Fn(&T, &Vec<T>) -> Vec<T> {

    pub fn new(initial_conditions: Vec<T>, function: F) -> Solver<T, F> {
        Solver {
            method: Method::RK4,
            weights: vec![T::from(1), T::from(2), T::from(2), T::from(1)],
            weight_sum: T::from(6),
            step: T::from(10e-3),
            initial_conditions: initial_conditions,
            function: function,
        }
    }

    /**
    Select the desired algorithm to solve the givem problem, also changing the
    default weights (see `change_weight()` for more details) applyed in each
    case; default values are:

    - `Method::RK2`: `vec![T::from(1), T::from(1)],`
    - `Method::RK4`: `vec![T::from(1), T::from(2), T::from(2), T::from(1)],`

    Defaults to `Method::RK4`.
    */
    pub fn method(&mut self, new_method: Method) -> &mut Solver<T, F> {
        match new_method {
            Method::RK2 => self.weights = vec![T::from(1), T::from(1)],
            Method::RK4 => self.weights = vec![T::from(1), T::from(2),
                                               T::from(2), T::from(1)],
        }

        self.weight_sum = self.weights.iter()
            .fold(T::from(0), |sum, i| sum + i.clone());
        self.method = new_method;
        self
    }

    /**
    Modify the default weighting applyed to each intermidiate point. Notice
    that, when changing
    */
    pub fn change_weight(&mut self, new_weights: Vec<T>) -> &mut Solver<T, F> {
        self.weights = new_weights;
        self
    }

    /**
    Validates the data passed to the solver. This is tipically called by `run()`
    before attempting to solve the passed function.
    */
    pub fn validate(&self) {
        // make sure the weights match with the method
        assert_eq!(self.weights.len(),
                   match self.method {
                       Method::RK2 => 2,
                       Method::RK4 => 4,
                   });
    }

    /**
    Check and run the solver, returning the results of the calculation.
    */
    pub fn run(&self) -> (Vec<T>, Vec<Vec<T>>) {
        self.validate();

        (Vec::new(), Vec::new())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let _ = rk4::solver(|t: &f32, _: &Vec<f32>| -> Vec<f32> {
            vec![2.*t]
        }, vec![0.], &[0., 0.], 1.0);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn puzzle(input: &str) -> usize {
    0
}

#[derive(PartialEq, Debug)]
pub struct Bot {
    chip1: Option<usize>,
    chip2: Option<usize>,
    low: Option<usize>,
    high: Option<usize>,
}

impl Bot {
    pub fn new() -> Bot {
        Bot { chip1: None, chip2: None, low: None, high: None }
    }

    pub fn has_two_chips(&self) -> bool {
        match (self.chip1, self.chip2) {
            (Some(_), Some(_)) => true,
            _ => false,
        }
    }

    pub fn receive_chip(&mut self, chip: usize) {
        if self.chip1.is_none() {
            self.chip1 = Some(chip);
        } else if self.chip2.is_none() {
            self.chip2 = Some(chip);
        } else {
            panic!("Cannot hold more than two chips");
        }
    }

    pub fn receive_command(&mut self, low_bot: usize, high_bot: usize) {
        self.low = Some(low_bot);
        self.high = Some(high_bot);
    }
}

pub struct BotRouter {
    bots: HashMap<usize, Bot>,
}

impl BotRouter {
    pub fn exec_command(&mut self, input: &str) {
        let pieces: Vec<&str> = input.split_whitespace().collect();

        if pieces[0] == "value" {
            self.value_to_bot(
                pieces[5].parse().expect("can't parse bot key"),
                pieces[1].parse().expect("can't parse chip value")
            );
        } else if pieces[0] == "bot" {
            self.command_to_bot(
                pieces[1].parse().expect("can't parse bot key"),
                pieces[6].parse().expect("can't parse low bot key"),
                pieces[11].parse().expect("can't parse high bot key"),
            );
        }
    }

    pub fn value_to_bot(&mut self, bot_key: usize, value: usize) {
        let bot = self.bots.entry(bot_key).or_insert(Bot::new());
        bot.receive_chip(value);
    }

    pub fn command_to_bot(&mut self, bot_key: usize,
                          low_bot_key: usize, high_bot_key: usize) {
        let bot = self.bots.entry(bot_key).or_insert(Bot::new());
        bot.receive_command(low_bot_key, high_bot_key);
    }
}

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

    #[test]
    fn new_bot_does_not_have_two_chips() {
        let bot = Bot::new();
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_a_chip_still_not_two() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_two_chips() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        bot.receive_chip(4);
        assert!(bot.has_two_chips());
    }

    #[test]
    fn router_can_give_values() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("value 5 goes to bot 2");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot { chip1: Some(5), chip2: None, low: None, high: None })
        );
    }

    #[test]
    fn router_can_give_commands_that_get_stored() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot {
                chip1: None,
                chip2: None,
                low: Some(1),
                high: Some(0),
            })
        );
    }

    // #[test]
    // fn router_adds_two_values_so_commands_get_executed() {
    //     let mut br = BotRouter { bots: HashMap::new() };
    //     br.exec_command("value 5 goes to bot 2");
    //     br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
    //     br.exec_command("value 2 goes to bot 2");
    //
    //     assert_eq!(
    //         br.bots.get(&2),
    //         Some(&Bot {
    //             chip1: None,
    //             chip2: None,
    //             commands: vec![]
    //         })
    //     );
    //
    //     assert_eq!(
    //         br.bots.get(&1),
    //         Some(&Bot {
    //             chip1: Some(2),
    //             chip2: None,
    //             commands: vec![]
    //         })
    //     );
    //
    //     assert_eq!(
    //         br.bots.get(&0),
    //         Some(&Bot {
    //             chip1: Some(5),
    //             chip2: None,
    //             commands: vec![]
    //         })
    //     );
    // }

    // #[test]
    // fn test_sample() {
    //     let mut br = BotRouter { bots: HashMap::new() };
    //     br.exec_command("value 5 goes to bot 2");
    //     br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
    //     br.exec_command("value 3 goes to bot 1");
    //     br.exec_command("bot 1 gives low to output 1 and high to bot 0");
    //     br.exec_command("bot 0 gives low to output 2 and high to output 0");
    //     br.exec_command("value 2 goes to bot 2");
    // }
}
<commit_msg>Execute commands when bot gets two chips<commit_after>use std::collections::HashMap;

pub fn puzzle(input: &str) -> usize {
    0
}

#[derive(PartialEq, Debug)]
pub struct Bot {
    chip1: Option<usize>,
    chip2: Option<usize>,
    low: Option<usize>,
    high: Option<usize>,
}

impl Bot {
    pub fn new() -> Bot {
        Bot { chip1: None, chip2: None, low: None, high: None }
    }

    pub fn has_two_chips(&self) -> bool {
        match (self.chip1, self.chip2) {
            (Some(_), Some(_)) => true,
            _ => false,
        }
    }

    pub fn receive_chip(&mut self, chip: usize) -> Vec<(usize, usize)> {
        if self.chip1.is_none() {
            self.chip1 = Some(chip);
            vec![]
        } else if self.chip2.is_none() {
            self.chip2 = Some(chip);
            if let (Some(lo), Some(hi)) = (self.low, self.high) {
                let return_commands = if self.chip1 < self.chip2 {
                    vec![
                        (lo, self.chip1.unwrap()),
                        (hi, self.chip2.unwrap()),
                    ]
                } else {
                    vec![
                        (lo, self.chip2.unwrap()),
                        (hi, self.chip1.unwrap()),
                    ]
                };
                self.chip1 = None;
                self.chip2 = None;
                self.low = None;
                self.high = None;
                return_commands
            } else {
                vec![]
            }
        } else {
            panic!("Cannot hold more than two chips");
        }
    }

    pub fn receive_command(&mut self, low_bot: usize, high_bot: usize) {
        self.low = Some(low_bot);
        self.high = Some(high_bot);
    }
}

pub struct BotRouter {
    bots: HashMap<usize, Bot>,
}

impl BotRouter {
    pub fn exec_command(&mut self, input: &str) {
        let pieces: Vec<&str> = input.split_whitespace().collect();

        if pieces[0] == "value" {
            self.value_to_bot(
                pieces[5].parse().expect("can't parse bot key"),
                pieces[1].parse().expect("can't parse chip value")
            );
        } else if pieces[0] == "bot" {
            self.command_to_bot(
                pieces[1].parse().expect("can't parse bot key"),
                pieces[6].parse().expect("can't parse low bot key"),
                pieces[11].parse().expect("can't parse high bot key"),
            );
        }
    }

    pub fn value_to_bot(&mut self, bot_key: usize, value: usize) {
        let return_commands = self.bots
                                  .entry(bot_key)
                                  .or_insert(Bot::new())
                                  .receive_chip(value);
        for &(bot_key, chip_value) in return_commands.iter() {
            self.value_to_bot(bot_key, chip_value);
        }
    }

    pub fn command_to_bot(&mut self, bot_key: usize,
                          low_bot_key: usize, high_bot_key: usize) {
        let bot = self.bots.entry(bot_key).or_insert(Bot::new());
        bot.receive_command(low_bot_key, high_bot_key);
    }
}

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

    #[test]
    fn new_bot_does_not_have_two_chips() {
        let bot = Bot::new();
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_a_chip_still_not_two() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_two_chips() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        bot.receive_chip(4);
        assert!(bot.has_two_chips());
    }

    #[test]
    fn router_can_give_values() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("value 5 goes to bot 2");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot { chip1: Some(5), chip2: None, low: None, high: None })
        );
    }

    #[test]
    fn router_can_give_commands_that_get_stored() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot {
                chip1: None,
                chip2: None,
                low: Some(1),
                high: Some(0),
            })
        );
    }

    #[test]
    fn router_adds_two_values_so_commands_get_executed() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("value 5 goes to bot 2");
        br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
        br.exec_command("value 2 goes to bot 2");

        assert_eq!(
            br.bots.get(&2),
            Some(&Bot {
                chip1: None,
                chip2: None,
                low: None,
                high: None,
            })
        );

        assert_eq!(
            br.bots.get(&1),
            Some(&Bot {
                chip1: Some(2),
                chip2: None,
                low: None,
                high: None,
            })
        );

        assert_eq!(
            br.bots.get(&0),
            Some(&Bot {
                chip1: Some(5),
                chip2: None,
                low: None,
                high: None,
            })
        );
    }

    // #[test]
    // fn test_sample() {
    //     let mut br = BotRouter { bots: HashMap::new() };
    //     br.exec_command("value 5 goes to bot 2");
    //     br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
    //     br.exec_command("value 3 goes to bot 1");
    //     br.exec_command("bot 1 gives low to output 1 and high to bot 0");
    //     br.exec_command("bot 0 gives low to output 2 and high to output 0");
    //     br.exec_command("value 2 goes to bot 2");
    // }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

use std::sync::atomic;
use std::sync::atomic::Ordering;
use std::ptr;

const KEYSZ: usize = 16;
const INITIAL_SIZE: usize = 128;

type RawKey = [u8; 16];
type HashKey = Box<RawKey>;

#[derive(Debug)]
struct HashSlot {
    key: atomic::AtomicPtr<RawKey>,
    count: atomic::AtomicUsize,
}

impl HashSlot {
    pub fn new() -> HashSlot {
        HashSlot {
            key: atomic::AtomicPtr::new(ptr::null_mut()),
            count: atomic::AtomicUsize::new(0),
        }
    }
}

pub struct Counter {
    size: usize,
    used: atomic::AtomicUsize,
    slots: Vec<HashSlot>,
    prev: atomic::AtomicPtr<Counter>,
    next: atomic:: AtomicPtr<Counter>,
}

fn djb2_hash(key: &HashKey) -> usize {
    let start: usize = 5381;
    key.into_iter().take_while(|c| { **c != 0 }).fold(start, |hash, c| {
        (hash * 33) ^ (*c as usize)})
}

#[inline]
fn is_ascii(c: &u8) -> bool {
    return (*c > 47 && *c < 58) || (*c > 64 && *c < 91) || (*c > 96 && *c < 123);
}

fn clean_key(key: &str) -> HashKey {
    let mut cleaned: HashKey = Box::new([0; 16]);
    for (index, v) in key.bytes().take(16).filter(is_ascii).enumerate() {
        cleaned[index] = v;
    }
    return cleaned;
}

impl Counter {
    pub fn new() -> Counter {
        let mut slots: Vec<HashSlot> = Vec::with_capacity(INITIAL_SIZE);
        for _ in 0..INITIAL_SIZE {
            slots.push(HashSlot::new());
        }
        let counter: Counter = Counter {
            size: INITIAL_SIZE,
            used: atomic::AtomicUsize::new(0),
            slots: slots,
            prev: atomic::AtomicPtr::new(ptr::null_mut()),
            next: atomic::AtomicPtr::new(ptr::null_mut()),
        };
        return counter;
    }

    unsafe fn print_slot(&self, index: usize) {
        let slot = &self.slots[index];
        let key = slot.key.load(Ordering::Relaxed);
        println!("slot {}: {:?}", index, slot);
        if key.is_null() {
            println!("\t key=null")
        }
        else {
            println!("\t key={:?}", *key);
        }
    }

    unsafe fn unsafe_get(&self, key: HashKey) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        let raw_key = Box::into_raw(key);
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                return 0;
            }
            else if *other_key == *raw_key{
                return slot.count.load(Ordering::Relaxed);
            }
            index = (index + 1) % size;
        }
    }

    unsafe fn unsafe_incr(&mut self, mut key: HashKey, count: usize) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        let raw_key = Box::into_raw(key);
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                let res = slot.key.compare_exchange(other_key,
                                                    raw_key,
                                                    Ordering::Relaxed,
                                                    Ordering::Relaxed);
                let status = match res {
                    Ok(v) => v.is_null() || *v == *raw_key,
                    Err(v) => v.is_null() || *v == *raw_key,
                };
                if status {
                    self.used.fetch_add(1, Ordering::Relaxed);
                    //TODO(rossdylan) handle resizing
                    let added = slot.count.fetch_add(count, Ordering::Relaxed);
                    return added
                }
            }
            else if *other_key == *raw_key {
                return slot.count.fetch_add(count, Ordering::Relaxed);
            }
            index = (index + 1) % size
        }
    }

    pub fn incr(&mut self, key: &str, count: usize) -> usize {
        return unsafe { self.unsafe_incr(clean_key(key), count) };
    }

    pub fn get(&self, key: &str) -> usize {
        return unsafe { self.unsafe_get(clean_key(key)) };
    }
}

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

    #[test]
    fn increment() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        assert_eq!(res, 0);
    }

    #[test]
    fn get() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        let count = counter.get("foo");
        assert_eq!(count, 1);
    }

    #[bench]
    fn bench_incr(b: &mut Bencher) {
        let mut counter = Counter::new();
        b.iter(|| counter.incr("foo", 1))
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let mut counter = Counter::new();
        counter.incr("foo", 100);
        b.iter(|| counter.get("foo"))
    }
}
<commit_msg>Create a wrapper structure that places the actual counter in an UnsafeCell for shared mutable state acrossed threads<commit_after>#![feature(test)]
extern crate test;

use std::sync::atomic;
use std::sync::atomic::Ordering;
use std::cell::UnsafeCell;
use std::ptr;

const KEY_SIZE: usize = 16;
const INITIAL_SIZE: usize = 128;

type HashKey = [u8; KEY_SIZE];

#[derive(Debug)]
struct HashSlot {
    key: atomic::AtomicPtr<HashKey>,
    count: atomic::AtomicUsize,
}

/// The interior threadsafe counter struct. Everything here is atomic or
/// composed of atomics.
struct InnerCounter {
    size: usize,
    used: atomic::AtomicUsize,
    slots: Vec<HashSlot>,
    prev: atomic::AtomicPtr<Counter>,
    next: atomic:: AtomicPtr<Counter>,
}

/// The public Counter structure which contains the inner mutable state. This
/// allows us to put this straight into an Arc and safely share between threads
pub struct Counter {
    inner: UnsafeCell<InnerCounter>
}

/// An implementation of the djb2 hash using rust iterators over the contents
/// of the HashKey array.
pub fn djb2_hash(key: &HashKey) -> usize {
    let start: usize = 5381;
    key.into_iter().take_while(|c| { **c != 0 }).fold(start, |hash, c| {
        (hash * 33) ^ (*c as usize)})
}

/// A small inlined helper function that checks if a given character is ascii
#[inline]
fn is_ascii(c: &u8) -> bool {
    return (*c > 47 && *c < 58) || (*c > 64 && *c < 91) || (*c > 96 && *c < 123);
}

/// Clean a given key string. This involves stripping non ascii characters out
/// and limiting the key to 16 characters. The resulting key is stack allocated
/// so be careful with it. If you need it long term put it in a Box.
pub fn clean_key(key: &str) -> HashKey {
    let mut cleaned: HashKey = [0; KEY_SIZE]; // Stack allocate a temporary key.
    for (index, v) in key.bytes().take(KEY_SIZE).filter(is_ascii).enumerate() {
        cleaned[index] = v;
    }
    return cleaned;
}

impl HashSlot {
    /// Create a new HashSlot struct with the default values. The key is
    /// initially set to null so get/incr know this slot is empty.
    pub fn new() -> HashSlot {
        HashSlot {
            key: atomic::AtomicPtr::new(ptr::null_mut()),
            count: atomic::AtomicUsize::new(0),
        }
    }
}

impl InnerCounter {
    /// Create a new InnerCoutner. Sets up all the top level atomic values for
    /// keeping track of global hashmap state.
    pub fn new() -> InnerCounter {
        let mut slots: Vec<HashSlot> = Vec::with_capacity(INITIAL_SIZE);
        for _ in 0..INITIAL_SIZE {
            slots.push(HashSlot::new());
        }
        let counter: InnerCounter = InnerCounter {
            size: INITIAL_SIZE,
            used: atomic::AtomicUsize::new(0),
            slots: slots,
            prev: atomic::AtomicPtr::new(ptr::null_mut()),
            next: atomic::AtomicPtr::new(ptr::null_mut()),
        };
        return counter;
    }

    /// Debug method for printing out the contents of a HashSlot struct
    unsafe fn print_slot(&self, index: usize) {
        let slot = &self.slots[index];
        let key = slot.key.load(Ordering::Relaxed);
        println!("slot {}: {:?}", index, slot);
        if key.is_null() {
            println!("\t key=null")
        }
        else {
            println!("\t key={:?}", *key);
        }
    }

    /// Unsafe method for returning the value of a counter.
    pub unsafe fn unsafe_get(&self, key: HashKey) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                return 0;
            }
            else if *other_key == key{
                return slot.count.load(Ordering::Relaxed);
            }
            index = (index + 1) % size;
        }
    }

    /// Unsafe method for incrementing a counter by the given amount. Returns
    /// the previous value of the counter.
    pub unsafe fn unsafe_incr(&mut self, key: HashKey, count: usize) -> usize {
        let size = self.size;
        let mut index = djb2_hash(&key) % size;
        loop {
            let slot = &self.slots[index];
            let other_key = slot.key.load(Ordering::Relaxed);
            if other_key.is_null() {
                let boxed_key = Box::new(key);
                let res = slot.key.compare_exchange(other_key,
                                                    Box::into_raw(boxed_key),
                                                    Ordering::Relaxed,
                                                    Ordering::Relaxed);
                let status = match res {
                    Ok(v) => v.is_null() || *v == key,
                    Err(v) => v.is_null() || *v == key,
                };
                if status {
                    self.used.fetch_add(1, Ordering::Relaxed);
                    //TODO(rossdylan) handle resizing
                    let added = slot.count.fetch_add(count, Ordering::Relaxed);
                    return added
                }
            }
            else if *other_key == key {
                return slot.count.fetch_add(count, Ordering::Relaxed);
            }
            index = (index + 1) % size
        }
    }
}

impl Drop for InnerCounter {
    /// Custom drop implementation to go through and explicitly re-box all the
    /// heap memory used to store keys within the Vec<HashSlot>. During the
    /// first call to unsafe_incr() the key is copied into a Box so it will
    /// persist.
    fn drop(&mut self) {
        for hs in &self.slots {
            let key = hs.key.load(Ordering::Relaxed);
            if !key.is_null() {
                let _: Box<HashKey> = unsafe { Box::from_raw(key) };
            }
        }
    }
}

unsafe impl Sync for Counter {}
unsafe impl Send for Counter {}

impl Counter {
    /// Create a new counter, which is has an UnsafeCell wrapping the actual
    /// counter implementation.
    pub fn new() -> Counter {
        Counter {
            inner: UnsafeCell::new(InnerCounter::new())
        }
    }

    /// Extract the mutable reference to the counter implementation and
    /// increment the given key.
    pub fn incr(&self, key: &str, count: usize) -> usize {
        return unsafe {
            (*self.inner.get()).unsafe_incr(clean_key(key), count)
        };
    }

    /// Extract the mutable reference to the counter implementation and
    /// return the current counter value for the given key.
    pub fn get(&self, key: &str) -> usize {
        return unsafe {
            (*self.inner.get()).unsafe_get(clean_key(key))
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use std::thread;
    use std::sync::Arc;

    #[test]
    fn increment() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        assert_eq!(res, 0);
    }

    #[test]
    fn sequential_increment() {
        let mut counter = Counter::new();
        for _ in 0..100000 {
            counter.incr("foo", 1);
        }
        assert_eq!(counter.get("foo"), 100000);
    }
    #[test]
    fn concurrent_increment() {
        let counter = Counter::new();
        let shared = Arc::new(counter);
        let nthreads = 8;
        let nincr = 10000;
        let mut children = vec![];
        for _ in 0..nthreads {
            let c = shared.clone();
            children.push(thread::spawn(move|| {
                for _ in 0..nincr {
                    c.incr("foo", 1);
                }
            }));
        }
        for t in children {
            t.join();
        }
        assert_eq!(shared.get("foo"), nincr * nthreads);
    }

    #[test]
    fn get() {
        let mut counter = Counter::new();
        let res = counter.incr("foo", 1);
        let count = counter.get("foo");
        assert_eq!(count, 1);
    }

    #[bench]
    fn bench_clean_key(b: &mut Bencher) {
        b.iter(|| clean_key("foobar"));
    }

    #[bench]
    fn bench_djb2_hash(b: &mut Bencher) {
        let key = clean_key("foobar");
        b.iter(|| djb2_hash(&key));
    }

    #[bench]
    fn bench_incr(b: &mut Bencher) {
        let mut counter = Counter::new();
        b.iter(|| counter.incr("foo", 1))
    }

    #[bench]
    fn bench_existing_incr(b: &mut Bencher) {
        let mut counter = Counter::new();
        counter.incr("foo", 1);
        b.iter(|| counter.incr("foo", 1));
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let mut counter = Counter::new();
        counter.incr("foo", 100);
        b.iter(|| counter.get("foo"))
    }
}
<|endoftext|>


<commit_before>//! Modified 2016 Garrett Berg <vitiral@gmail.com>
//! Copyright 2015 Dawid Ciężarkiewicz
//! See LICENSE-MPL
//!
//! Non-thread-shareable, simple and efficient Circular Buffer
//! implementation that can store N elements when full (typical circular
//! buffer implementations store N-1) without using separate flags.
//!
//! Uses only `core` so can be used in `#[no_std]` projects by using
//! `no_std` feature.
#![no_std]
#![feature(const_fn)]
#![feature(test)]

use core::option::Option::{self, Some, None};
use core::marker::PhantomData;

extern crate test as test;

const CBUF_DATA_BIT: usize = !((usize::max_value() << 1) >> 1);

/// Circular Buffer
///
/// Turns a slice into a Circular buffer with head and tail indexes.
#[derive(Debug)]
pub struct CBuf<'a, T: 'a> {
    buf: &'a mut [T],
    ctrl: CBufControl<T>,
}

/// Circular Buffer Control
///
/// Implements the actual logic of Circular Buffer, but requires passing &[T]
/// to `get` and `put`.
#[derive(Debug)]
pub struct CBufControl<T> {
    head: usize,
    tail: usize,
    phantom: PhantomData<T>,
}

#[cfg(not(feature = "no_std"))]
impl<'a, T: Clone> CBuf<'a, T>
    where T: Clone
{
    /// Create new CBuf
    ///
    /// Length (not capacity) will be used to store elements
    /// in the circular buffer.
    pub fn new(buf: &'a mut [T]) -> CBuf<T> {
        debug_assert!(buf.len() < CBUF_DATA_BIT);

        CBuf {
            buf: buf,
            ctrl: CBufControl::new(),
        }
    }

    /// Is buffer full?
    #[inline]
    pub fn is_full(&self) -> bool {
        self.ctrl.is_full()
    }

    /// Is buffer empty?
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.ctrl.is_empty()
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn peek(&mut self) -> Option<T> {
        self.ctrl.peek(self.buf)
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn peek_unchecked(&mut self) -> T {
        self.ctrl.peek_unchecked(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn get(&mut self) -> Option<T> {
        self.ctrl.get(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn get_unchecked(&mut self) -> T {
        self.ctrl.get_unchecked(self.buf)
    }

    /// Add element the buffer
    ///
    /// Ignores the write if buffer is full.
    #[inline]
    pub fn put(&mut self, val: T) {
        self.ctrl.put(self.buf, val)
    }

    /// Add element the buffer
    ///
    /// Makes the buffer misbehave if it's full.
    #[inline]
    pub fn put_unchecked(&mut self, val: T) {
        self.ctrl.put_unchecked(self.buf, val)
    }
}

impl<T: Clone> CBufControl<T> {
    pub fn new() -> CBufControl<T> {
        CBufControl {
            tail: 0,
            head: 0,
            phantom: PhantomData,
        }
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_full(&self) -> bool {
        (self.head ^ self.tail) == CBUF_DATA_BIT
    }

    /// See corresponding method of CBuf
    pub fn get(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.get_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn get_unchecked(&mut self, buf: &[T]) -> T {
        let val = buf[self.tail & !CBUF_DATA_BIT].clone();

        self.tail += 1;

        if (self.tail & !CBUF_DATA_BIT) >= buf.len() {
            self.tail = (self.tail - buf.len()) ^ CBUF_DATA_BIT;
        }

        val
    }

    /// See corresponding method of CBuf
    pub fn peek(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.peek_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn peek_unchecked(&mut self, buf: &[T]) -> T {
        buf[self.tail & !CBUF_DATA_BIT].clone()
    }

    /// See corresponding method of CBuf
    pub fn put(&mut self, buf: &mut [T], val: T) {
        if self.is_full() {
            return;
        }
        self.put_unchecked(buf, val)
    }

    /// See corresponding method of CBuf
    pub fn put_unchecked(&mut self, buf: &mut [T], val: T) {
        buf[self.head & !CBUF_DATA_BIT] = val;

        self.head += 1;

        if (self.head & !CBUF_DATA_BIT) >= buf.len() {
            self.head = (self.head - buf.len()) ^ CBUF_DATA_BIT;
        }
    }
}

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

    #[test]
    fn basic_ctl() {
        let mut buf = &mut [0u8, 2];
        let mut cbuf = CBufControl::<u8>::new();

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(buf, 3);
        cbuf.put(buf, 4);
        cbuf.put(buf, 42); // will have no effect
        cbuf.put(buf, 42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek(buf).unwrap(), 3);
        cbuf.peek(buf).unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get(buf).unwrap(), 3);
        assert_eq!(cbuf.get(buf).unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get(buf).is_none());
        assert!(cbuf.get(buf).is_none());
        cbuf.put(buf, 42);
        assert_eq!(cbuf.get(buf).unwrap(), 42);
    }

    #[test]
    fn basic_cbuf() {
        let mut buf = &mut [0u8, 0u8];
        let mut cbuf = CBuf::new(buf);

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(3);
        cbuf.put(4);
        cbuf.put(42); // will have no effect
        cbuf.put(42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek().unwrap(), 3);
        cbuf.peek().unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get().unwrap(), 3);
        assert_eq!(cbuf.get().unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get().is_none());
        assert!(cbuf.get().is_none());
        cbuf.put(42);
        assert_eq!(cbuf.get().unwrap(), 42);
    }

    #[test]
    fn patterns() {
        let mut buf = [0u8, 7];
        let mut cbuf = CBufControl::<u8>::new();

        let mut cur_len = 0;
        let mut put_val = 0;
        let mut get_val = 0;

        for pattern in 0..256 {
            if cur_len == 0 {
                assert!(cbuf.is_empty());
            }
            if cur_len == buf.len() {
                assert!(cbuf.is_full());
            }

            for bit_i in 0..8 {
                match pattern & (1 << bit_i) == 0 {
                    true => {
                        if cbuf.is_empty() {
                            assert!(cbuf.peek(&buf).is_none());
                            assert!(cbuf.get(&buf).is_none());
                        } else {
                            assert!(cbuf.peek(&buf).unwrap() == get_val);
                            let val = cbuf.get(&buf).unwrap();
                            assert!(val == get_val);
                            get_val = get_val.wrapping_add(1);
                            cur_len -= 1;
                        }
                    }
                    false => {
                        if cbuf.is_full() {
                            cbuf.put(&mut buf, put_val);
                            assert!(cbuf.is_full());
                        } else {
                            cbuf.put(&mut buf, put_val);
                            put_val = put_val.wrapping_add(1);
                            cur_len += 1;
                        }
                    }
                }
            }
        }
    }

    #[bench]
    pub fn put_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put(0u8);
            cbuf.get();
        });

        test::black_box(cbuf.get());
    }

    #[bench]
    pub fn put_unchecked_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put_unchecked(0u8);
            cbuf.get_unchecked();
        });

        test::black_box(cbuf.get());
    }
}
<commit_msg>panic if buf has len==0<commit_after>//! Modified 2016 Garrett Berg <vitiral@gmail.com>
//! Copyright 2015 Dawid Ciężarkiewicz
//! See LICENSE-MPL
//!
//! Non-thread-shareable, simple and efficient Circular Buffer
//! implementation that can store N elements when full (typical circular
//! buffer implementations store N-1) without using separate flags.
//!
//! Uses only `core` so can be used in `#[no_std]` projects by using
//! `no_std` feature.
#![no_std]
#![feature(const_fn)]
#![feature(test)]

use core::option::Option::{self, Some, None};
use core::marker::PhantomData;

extern crate test as test;

const CBUF_DATA_BIT: usize = !((usize::max_value() << 1) >> 1);

/// Circular Buffer
///
/// Turns a slice into a Circular buffer with head and tail indexes.
#[derive(Debug)]
pub struct CBuf<'a, T: 'a> {
    buf: &'a mut [T],
    ctrl: CBufControl<T>,
}

/// Circular Buffer Control
///
/// Implements the actual logic of Circular Buffer, but requires passing &[T]
/// to `get` and `put`.
#[derive(Debug)]
pub struct CBufControl<T> {
    head: usize,
    tail: usize,
    phantom: PhantomData<T>,
}

#[cfg(not(feature = "no_std"))]
impl<'a, T: Clone> CBuf<'a, T>
    where T: Clone
{
    /// Create new CBuf
    ///
    /// Length (not capacity) will be used to store elements
    /// in the circular buffer.
    ///
    /// panics if buf.len() == 0
    pub fn new(buf: &'a mut [T]) -> CBuf<T> {
        debug_assert!(buf.len() < CBUF_DATA_BIT);
        if buf.len() == 0 {
            panic!("len==0")
        }

        CBuf {
            buf: buf,
            ctrl: CBufControl::new(),
        }
    }

    /// Is buffer full?
    #[inline]
    pub fn is_full(&self) -> bool {
        self.ctrl.is_full()
    }

    /// Is buffer empty?
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.ctrl.is_empty()
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn peek(&mut self) -> Option<T> {
        self.ctrl.peek(self.buf)
    }

    /// Peek next element from the CBuf without removing it
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn peek_unchecked(&mut self) -> T {
        self.ctrl.peek_unchecked(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Returns `None` if buffer is empty.
    #[inline]
    pub fn get(&mut self) -> Option<T> {
        self.ctrl.get(self.buf)
    }

    /// Remove one element from the CBuf
    ///
    /// Makes the buffer misbehave if it's empty.
    #[inline]
    pub fn get_unchecked(&mut self) -> T {
        self.ctrl.get_unchecked(self.buf)
    }

    /// Add element the buffer
    ///
    /// Ignores the write if buffer is full.
    #[inline]
    pub fn put(&mut self, val: T) {
        self.ctrl.put(self.buf, val)
    }

    /// Add element the buffer
    ///
    /// Makes the buffer misbehave if it's full.
    #[inline]
    pub fn put_unchecked(&mut self, val: T) {
        self.ctrl.put_unchecked(self.buf, val)
    }
}

impl<T: Clone> CBufControl<T> {
    pub fn new() -> CBufControl<T> {
        CBufControl {
            tail: 0,
            head: 0,
            phantom: PhantomData,
        }
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.head == self.tail
    }

    /// See corresponding method of CBuf
    #[inline]
    pub fn is_full(&self) -> bool {
        (self.head ^ self.tail) == CBUF_DATA_BIT
    }

    /// See corresponding method of CBuf
    pub fn get(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.get_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn get_unchecked(&mut self, buf: &[T]) -> T {
        let val = buf[self.tail & !CBUF_DATA_BIT].clone();

        self.tail += 1;

        if (self.tail & !CBUF_DATA_BIT) >= buf.len() {
            self.tail = (self.tail - buf.len()) ^ CBUF_DATA_BIT;
        }

        val
    }

    /// See corresponding method of CBuf
    pub fn peek(&mut self, buf: &[T]) -> Option<T> {
        if self.is_empty() {
            return None;
        }
        Some(self.peek_unchecked(buf))
    }

    /// See corresponding method of CBuf
    pub fn peek_unchecked(&mut self, buf: &[T]) -> T {
        buf[self.tail & !CBUF_DATA_BIT].clone()
    }

    /// See corresponding method of CBuf
    pub fn put(&mut self, buf: &mut [T], val: T) {
        if self.is_full() {
            return;
        }
        self.put_unchecked(buf, val)
    }

    /// See corresponding method of CBuf
    pub fn put_unchecked(&mut self, buf: &mut [T], val: T) {
        buf[self.head & !CBUF_DATA_BIT] = val;

        self.head += 1;

        if (self.head & !CBUF_DATA_BIT) >= buf.len() {
            self.head = (self.head - buf.len()) ^ CBUF_DATA_BIT;
        }
    }
}

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

    #[test]
    fn basic_ctl() {
        let mut buf = &mut [0u8, 2];
        let mut cbuf = CBufControl::<u8>::new();

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(buf, 3);
        cbuf.put(buf, 4);
        cbuf.put(buf, 42); // will have no effect
        cbuf.put(buf, 42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek(buf).unwrap(), 3);
        cbuf.peek(buf).unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get(buf).unwrap(), 3);
        assert_eq!(cbuf.get(buf).unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get(buf).is_none());
        assert!(cbuf.get(buf).is_none());
        cbuf.put(buf, 42);
        assert_eq!(cbuf.get(buf).unwrap(), 42);
    }

    #[test]
    fn basic_cbuf() {
        let mut buf = &mut [0u8, 0u8];
        let mut cbuf = CBuf::new(buf);

        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        cbuf.put(3);
        cbuf.put(4);
        cbuf.put(42); // will have no effect
        cbuf.put(42); // will have no effect
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.peek().unwrap(), 3);
        cbuf.peek().unwrap();
        assert!(!cbuf.is_empty());
        assert!(cbuf.is_full());

        assert_eq!(cbuf.get().unwrap(), 3);
        assert_eq!(cbuf.get().unwrap(), 4);
        assert!(cbuf.is_empty());
        assert!(!cbuf.is_full());

        assert!(cbuf.get().is_none());
        assert!(cbuf.get().is_none());
        cbuf.put(42);
        assert_eq!(cbuf.get().unwrap(), 42);
    }

    #[test]
    fn patterns() {
        let mut buf = [0u8, 7];
        let mut cbuf = CBufControl::<u8>::new();

        let mut cur_len = 0;
        let mut put_val = 0;
        let mut get_val = 0;

        for pattern in 0..256 {
            if cur_len == 0 {
                assert!(cbuf.is_empty());
            }
            if cur_len == buf.len() {
                assert!(cbuf.is_full());
            }

            for bit_i in 0..8 {
                match pattern & (1 << bit_i) == 0 {
                    true => {
                        if cbuf.is_empty() {
                            assert!(cbuf.peek(&buf).is_none());
                            assert!(cbuf.get(&buf).is_none());
                        } else {
                            assert!(cbuf.peek(&buf).unwrap() == get_val);
                            let val = cbuf.get(&buf).unwrap();
                            assert!(val == get_val);
                            get_val = get_val.wrapping_add(1);
                            cur_len -= 1;
                        }
                    }
                    false => {
                        if cbuf.is_full() {
                            cbuf.put(&mut buf, put_val);
                            assert!(cbuf.is_full());
                        } else {
                            cbuf.put(&mut buf, put_val);
                            put_val = put_val.wrapping_add(1);
                            cur_len += 1;
                        }
                    }
                }
            }
        }
    }

    #[bench]
    pub fn put_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put(0u8);
            cbuf.get();
        });

        test::black_box(cbuf.get());
    }

    #[bench]
    pub fn put_unchecked_and_get(b: &mut Bencher) {
        let buf = &mut [0u8; 256];
        let mut cbuf = CBuf::new(buf);

        b.iter(|| {
            cbuf.put_unchecked(0u8);
            cbuf.get_unchecked();
        });

        test::black_box(cbuf.get());
    }
}
<|endoftext|>


<commit_before>//! Functions to find the difference between two texts (strings).
//! Usage
//! ----------
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! difference = "2.0"
//! ```
//!
//! Now you can use the crate in your code
//! ```ignore
//! extern crate difference;
//! ```
//!
//! ## Examples
//!
//! See [Examples.md](Examples.md) for more examples.
//!
//! ```rust
//! use difference::{Difference, Changeset};
//!
//! let changeset = Changeset::new("test", "tent", "");
//!
//! assert_eq!(changeset.diffs, vec![
//!   Difference::Same("te".to_string()),
//!   Difference::Rem("s".to_string()),
//!   Difference::Add("n".to_string()),
//!   Difference::Same("t".to_string())
//! ]);
//! ```

#![crate_name = "difference"]
#![doc(html_root_url = "http://docs.rs/difference")]
#![deny(missing_docs)]
#![deny(warnings)]

mod lcs;
mod merge;
mod display;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String),
}

/// The information about a full changeset
pub struct Changeset {
    /// An ordered vector of `Difference` objects, coresponding
    /// to the differences within the text
    pub diffs: Vec<Difference>,
    /// The split used when creating the `Changeset`
    /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
    pub split: String,
    /// The edit distance of the `Changeset`
    pub distance: i32,
}

impl Changeset {
    /// Calculates the edit distance and the changeset for two given strings.
    /// The first string is assumed to be the "original", the second to be an
    /// edited version of the first. The third parameter specifies how to split
    /// the input strings, leading to a more or less exact comparison.
    ///
    /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
    ///
    /// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
    /// a `Vec` containing `Difference`s.
    ///
    /// # Examples
    ///
    /// ```
    /// use difference::{Changeset, Difference};
    ///
    /// let changeset = Changeset::new("test", "tent", "");
    ///
    /// assert_eq!(changeset.diffs, vec![
    ///     Difference::Same("te".to_string()),
    ///     Difference::Rem("s".to_string()),
    ///     Difference::Add("n".to_string()),
    ///     Difference::Same("t".to_string())
    /// ]);
    /// ```
    pub fn new(orig: &str, edit: &str, split: &str) -> Changeset {
        let (dist, common) = lcs(orig, edit, split);
        Changeset {
            diffs: merge(orig, edit, &common, split),
            split: split.to_string(),
            distance: dist,
        }
    }
}

/// **This function is deprecated, please use `Changeset::new` instead**
///
/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
/// use difference::diff;
/// use difference::Difference;
///
/// let (dist, changeset) = diff("test", "tent", "");
///
/// assert_eq!(changeset, vec![
///     Difference::Same("te".to_string()),
///     Difference::Rem("s".to_string()),
///     Difference::Add("n".to_string()),
///     Difference::Same("t".to_string())
/// ]);
/// ```
#[deprecated(since = "1.0.0", note = "please use `Changeset::new` instead")]
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let ch = Changeset::new(orig, edit, split);
    (ch.distance, ch.diffs)
}

/// Assert the difference between two strings. Works like diff, but takes
/// a fourth parameter that is the expected edit distance (e.g. 0 if you want to
/// test for equality).
///
/// To include this macro use:
///
/// ```
/// #[macro_use(assert_diff)]
/// extern crate difference;
/// # fn main() { }
/// ```
///
/// Remember that edit distance might not be equal to your understanding of difference,
/// for example the words "Rust" and "Dust" have an edit distance of 2 because two changes (a
/// removal and an addition) are required to make them look the same.
///
/// Will print an error with a colorful diff in case of failure.
#[macro_export]
macro_rules! assert_diff {
    ($orig:expr , $edit:expr, $split: expr, $expected: expr) => ({
        let orig = $orig;
        let edit = $edit;

        let changeset = $crate::Changeset::new(orig, edit, &($split));
        if changeset.distance != $expected {
            println!("{}", changeset);
            panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \
                    diffset above",
                   orig,
                   edit,
                   changeset.distance,
                   &($expected))
        }
    })
}

/// **This function is deprecated, `Changeset` now implements the `Display` trait instead**
///
/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use difference::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
#[deprecated(since = "1.0.0", note = "`Changeset` now implements the `Display` trait instead")]
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let ch = Changeset::new(orig, edit, split);
    println!("{}", ch);
}

#[test]
fn test_diff() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(changeset.distance, 4);

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Roses are red, violets are blue,".to_string()),
            Difference::Rem("I wrote this library,".to_string()),
            Difference::Add("I wrote this documentation,".to_string()),
            Difference::Same("just for you.".to_string()),
            Difference::Rem("(It's true).".to_string()),
            Difference::Add("(It's quite true).".to_string()),
        ]
    );
}

#[test]
fn test_diff_brief() {
    let text1 = "Hello\nworld";
    let text2 = "Ola\nmundo";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello\nworld".to_string()),
            Difference::Add("Ola\nmundo".to_string()),
        ]
    );
}

#[test]
fn test_diff_smaller_line_count_on_left() {
    let text1 = "Hello\nworld";
    let text2 = "Ola\nworld\nHow is it\ngoing?";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello".to_string()),
            Difference::Add("Ola".to_string()),
            Difference::Same("world".to_string()),
            Difference::Add("How is it\ngoing?".to_string()),
        ]
    );
}

#[test]
fn test_diff_smaller_line_count_on_right() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Ola\nworld";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello".to_string()),
            Difference::Add("Ola".to_string()),
            Difference::Same("world".to_string()),
            Difference::Rem("What a \nbeautiful\nday!".to_string()),
        ]
    );
}

#[test]
fn test_diff_similar_text_with_smaller_line_count_on_right() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Hello\nwoRLd";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Hello".to_string()),
            Difference::Rem("world\nWhat a \nbeautiful\nday!".to_string()),
            Difference::Add("woRLd".to_string()),
        ]
    );
}

#[test]
fn test_diff_similar_text_with_similar_line_count() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Hello\nwoRLd\nbeautiful";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Hello".to_string()),
            Difference::Rem("world\nWhat a ".to_string()),
            Difference::Add("woRLd".to_string()),
            Difference::Same("beautiful".to_string()),
            Difference::Rem("day!".to_string()),
        ]
    );
}

#[test]
#[should_panic]
fn test_assert_diff_panic() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    assert_diff!(text1, text2, "\n'", 0);
}

#[test]
fn test_assert_diff() {
    let text1 = "Roses are red, violets are blue";

    let text2 = "Roses are green, violets are blue";

    assert_diff!(text1, text2, " ", 2);
}
<commit_msg>Fix markdown warnings when building with new markdown renderer.<commit_after>//! Functions to find the difference between two texts (strings).
//!
//! Usage
//! ----------
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! difference = "2.0"
//! ```
//!
//! Now you can use the crate in your code
//!
//! ```ignore
//! extern crate difference;
//! ```
//!
//! ## Examples
//!
//! See [Examples.md](Examples.md) for more examples.
//!
//! ```rust
//! use difference::{Difference, Changeset};
//!
//! let changeset = Changeset::new("test", "tent", "");
//!
//! assert_eq!(changeset.diffs, vec![
//!   Difference::Same("te".to_string()),
//!   Difference::Rem("s".to_string()),
//!   Difference::Add("n".to_string()),
//!   Difference::Same("t".to_string())
//! ]);
//! ```

#![crate_name = "difference"]
#![doc(html_root_url = "http://docs.rs/difference")]
#![deny(missing_docs)]
#![deny(warnings)]

mod lcs;
mod merge;
mod display;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String),
}

/// The information about a full changeset
pub struct Changeset {
    /// An ordered vector of `Difference` objects, coresponding
    /// to the differences within the text
    pub diffs: Vec<Difference>,
    /// The split used when creating the `Changeset`
    /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
    pub split: String,
    /// The edit distance of the `Changeset`
    pub distance: i32,
}

impl Changeset {
    /// Calculates the edit distance and the changeset for two given strings.
    /// The first string is assumed to be the "original", the second to be an
    /// edited version of the first. The third parameter specifies how to split
    /// the input strings, leading to a more or less exact comparison.
    ///
    /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
    ///
    /// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
    /// a `Vec` containing `Difference`s.
    ///
    /// # Examples
    ///
    /// ```
    /// use difference::{Changeset, Difference};
    ///
    /// let changeset = Changeset::new("test", "tent", "");
    ///
    /// assert_eq!(changeset.diffs, vec![
    ///     Difference::Same("te".to_string()),
    ///     Difference::Rem("s".to_string()),
    ///     Difference::Add("n".to_string()),
    ///     Difference::Same("t".to_string())
    /// ]);
    /// ```
    pub fn new(orig: &str, edit: &str, split: &str) -> Changeset {
        let (dist, common) = lcs(orig, edit, split);
        Changeset {
            diffs: merge(orig, edit, &common, split),
            split: split.to_string(),
            distance: dist,
        }
    }
}

/// **This function is deprecated, please use `Changeset::new` instead**
///
/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
/// use difference::diff;
/// use difference::Difference;
///
/// let (dist, changeset) = diff("test", "tent", "");
///
/// assert_eq!(changeset, vec![
///     Difference::Same("te".to_string()),
///     Difference::Rem("s".to_string()),
///     Difference::Add("n".to_string()),
///     Difference::Same("t".to_string())
/// ]);
/// ```
#[deprecated(since = "1.0.0", note = "please use `Changeset::new` instead")]
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let ch = Changeset::new(orig, edit, split);
    (ch.distance, ch.diffs)
}

/// Assert the difference between two strings. Works like diff, but takes
/// a fourth parameter that is the expected edit distance (e.g. 0 if you want to
/// test for equality).
///
/// To include this macro use:
///
/// ```
/// #[macro_use(assert_diff)]
/// extern crate difference;
/// # fn main() { }
/// ```
///
/// Remember that edit distance might not be equal to your understanding of difference,
/// for example the words "Rust" and "Dust" have an edit distance of 2 because two changes (a
/// removal and an addition) are required to make them look the same.
///
/// Will print an error with a colorful diff in case of failure.
#[macro_export]
macro_rules! assert_diff {
    ($orig:expr , $edit:expr, $split: expr, $expected: expr) => ({
        let orig = $orig;
        let edit = $edit;

        let changeset = $crate::Changeset::new(orig, edit, &($split));
        if changeset.distance != $expected {
            println!("{}", changeset);
            panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \
                    diffset above",
                   orig,
                   edit,
                   changeset.distance,
                   &($expected))
        }
    })
}

/// **This function is deprecated, `Changeset` now implements the `Display` trait instead**
///
/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use difference::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
#[deprecated(since = "1.0.0", note = "`Changeset` now implements the `Display` trait instead")]
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let ch = Changeset::new(orig, edit, split);
    println!("{}", ch);
}

#[test]
fn test_diff() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(changeset.distance, 4);

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Roses are red, violets are blue,".to_string()),
            Difference::Rem("I wrote this library,".to_string()),
            Difference::Add("I wrote this documentation,".to_string()),
            Difference::Same("just for you.".to_string()),
            Difference::Rem("(It's true).".to_string()),
            Difference::Add("(It's quite true).".to_string()),
        ]
    );
}

#[test]
fn test_diff_brief() {
    let text1 = "Hello\nworld";
    let text2 = "Ola\nmundo";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello\nworld".to_string()),
            Difference::Add("Ola\nmundo".to_string()),
        ]
    );
}

#[test]
fn test_diff_smaller_line_count_on_left() {
    let text1 = "Hello\nworld";
    let text2 = "Ola\nworld\nHow is it\ngoing?";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello".to_string()),
            Difference::Add("Ola".to_string()),
            Difference::Same("world".to_string()),
            Difference::Add("How is it\ngoing?".to_string()),
        ]
    );
}

#[test]
fn test_diff_smaller_line_count_on_right() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Ola\nworld";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Rem("Hello".to_string()),
            Difference::Add("Ola".to_string()),
            Difference::Same("world".to_string()),
            Difference::Rem("What a \nbeautiful\nday!".to_string()),
        ]
    );
}

#[test]
fn test_diff_similar_text_with_smaller_line_count_on_right() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Hello\nwoRLd";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Hello".to_string()),
            Difference::Rem("world\nWhat a \nbeautiful\nday!".to_string()),
            Difference::Add("woRLd".to_string()),
        ]
    );
}

#[test]
fn test_diff_similar_text_with_similar_line_count() {
    let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!";
    let text2 = "Hello\nwoRLd\nbeautiful";

    let changeset = Changeset::new(text1, text2, "\n");

    assert_eq!(
        changeset.diffs,
        vec![
            Difference::Same("Hello".to_string()),
            Difference::Rem("world\nWhat a ".to_string()),
            Difference::Add("woRLd".to_string()),
            Difference::Same("beautiful".to_string()),
            Difference::Rem("day!".to_string()),
        ]
    );
}

#[test]
#[should_panic]
fn test_assert_diff_panic() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    assert_diff!(text1, text2, "\n'", 0);
}

#[test]
fn test_assert_diff() {
    let text1 = "Roses are red, violets are blue";

    let text2 = "Roses are green, violets are blue";

    assert_diff!(text1, text2, " ", 2);
}
<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

extern crate cairo_sys as ffi;
extern crate libc;
extern crate glib;
extern crate c_vec;

pub use ffi::enums;
pub use ffi::cairo_rectangle_t as Rectangle;

pub use context::{
    Context,
    RectangleVec,
};

pub use paths::{
    Path,
    PathSegments,
    PathSegment
};

pub use enums::{
    Status,
    Antialias,
    Content,
    Extend,
    FillRule,
    Filter,
    LineCap,
    LineJoin,
    Operator,
    PathDataType,
    Format,
    SurfaceType,
};

pub use error::{
    BorrowError,
    IoError,
};

pub use patterns::{
    //Traits
    Pattern,
    Gradient,

    //Structs
    LinearGradient,
    RadialGradient,
    SolidPattern,
    SurfacePattern,
};

#[cfg(feature = "v1_12")]
pub use patterns::{
    Mesh,
    MeshCorner,
};

pub use fonts::{
    FontFace,
    FontSlant,
    FontWeight,
    ScaledFont,
    FontOptions,

    Glyph,
    FontExtents,
    TextExtents,
    TextCluster,
};

pub use matrices::{
    Matrix,
    MatrixTrait,
};

pub use rectangle::RectangleInt;

pub use surface::Surface;

pub use image_surface::{
    ImageSurface,
    ImageSurfaceData,
};

#[cfg(feature = "xcb")]
pub use xcb::{
    XCBConnection,
    XCBSurface,
    Device,
    XCBDrawable,
    XCBPixmap,
    XCBRenderPictFormInfo,
    XCBScreen,
    XCBVisualType,
};

pub mod prelude;

mod fonts;
mod context;
mod error;
mod image_surface;
#[cfg(feature = "png")]
mod image_surface_png;
mod paths;
mod patterns;
mod rectangle;
mod surface;
mod matrices;
#[cfg(feature = "xcb")]
mod xcb;

#[cfg(windows)]
mod win32_surface;

#[cfg(windows)]
pub use win32_surface::Win32Surface;
<commit_msg>Added missing enum<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

extern crate cairo_sys as ffi;
extern crate libc;
extern crate glib;
extern crate c_vec;

pub use ffi::enums;
pub use ffi::cairo_rectangle_t as Rectangle;

pub use context::{
    Context,
    RectangleVec,
};

pub use paths::{
    Path,
    PathSegments,
    PathSegment
};

pub use enums::{
    Status,
    Antialias,
    Content,
    Extend,
    FillRule,
    Filter,
    LineCap,
    LineJoin,
    Operator,
    PathDataType,
    Format,
    SurfaceType,
};

pub use error::{
    BorrowError,
    IoError,
};

pub use patterns::{
    //Traits
    Pattern,
    Gradient,

    //Structs
    LinearGradient,
    RadialGradient,
    SolidPattern,
    SurfacePattern,
};

#[cfg(feature = "v1_12")]
pub use patterns::{
    Mesh,
    MeshCorner,
};

pub use fonts::{
    FontFace,
    FontType,
    FontSlant,
    FontWeight,
    ScaledFont,
    FontOptions,

    Glyph,
    FontExtents,
    TextExtents,
    TextCluster,
};

pub use matrices::{
    Matrix,
    MatrixTrait,
};

pub use rectangle::RectangleInt;

pub use surface::Surface;

pub use image_surface::{
    ImageSurface,
    ImageSurfaceData,
};

#[cfg(feature = "xcb")]
pub use xcb::{
    XCBConnection,
    XCBSurface,
    Device,
    XCBDrawable,
    XCBPixmap,
    XCBRenderPictFormInfo,
    XCBScreen,
    XCBVisualType,
};

pub mod prelude;

mod fonts;
mod context;
mod error;
mod image_surface;
#[cfg(feature = "png")]
mod image_surface_png;
mod paths;
mod patterns;
mod rectangle;
mod surface;
mod matrices;
#[cfg(feature = "xcb")]
mod xcb;

#[cfg(windows)]
mod win32_surface;

#[cfg(windows)]
pub use win32_surface::Win32Surface;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

/*
 * TODO: refactor to remove every use of callbacks in relm widgets, taking advantage of async
 * callback.
 * FIXME: the commands in the config file are not executed.
 * TODO: take advantage of IntoOption and IntoPair.
 * TODO: automatically connect the AppClose message to Quit if it exists.
 * TODO: smart selection (select all on first time, select all except the prefix on the second).
 * TODO: shortcut to move the cursor at the other end of the selection.
 * TODO: thread example (using a oneshot).
 * TODO: generate async gtk methods as returning futures.
 * TODO: change all unneeded &mut self to &self.
 * TODO: set the size of the status bar according to the size of the font.
 * TODO: different event for activate event of special commands.
 * TODO: use the gtk::Statusbar widget?
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(missing_docs)]
#![feature(proc_macro, unboxed_closures)]

#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate futures_glib;
extern crate gdk;
extern crate glib;
extern crate gtk;
extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mg_settings;
extern crate pango;
#[macro_use]
extern crate relm;
extern crate relm_attributes;
#[macro_use]
extern crate relm_derive;

mod app;
pub mod completion;
mod key_converter;

/// Map mode prefix (i.e. "i") to the mode name (i.e. "insert").
pub type Modes = &'static [(&'static str, &'static str)];
/// Map variable names to a function returning the value of this variable.

pub use app::{Mg, parse_config};
pub use app::Msg::{
    Alert,
    AppClose,
    CustomCommand,
    DarkTheme,
    DeleteCompletionItem,
    Error,
    Info,
    Message,
    ModeChanged,
    Question,
    SetMode,
    SetSetting,
    SettingChanged,
    Title,
    Variables,
    Warning,
};
pub use app::dialog::{DialogBuilder, DialogResult, input, question};
pub use app::settings::{DefaultConfig, NoSettings};
pub use app::status_bar::{StatusBar, StatusBarItem};
pub use completion::Completers;

#[macro_export]
macro_rules! hash {
    ($($ident:expr => $value:expr,)*) => {{
        let mut hash_map: ::mg::Completers = ::std::collections::HashMap::new();
        $(hash_map.insert($ident, $value);)*
        hash_map
    }};
}

#[macro_export]
macro_rules! char_slice {
    ($( $val:expr ),*) => {{
        static SLICE: &'static [char] = &[$($val),*];
        SLICE
    }};
}

#[macro_export]
macro_rules! static_slice {
    ($( $val:expr ),* ; $typ:ty) => {{
        static SLICE: &'static [$typ] = &[$($val),*];
        SLICE
    }};
}
<commit_msg>Add missing imports<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * 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.
 */

/*
 * TODO: refactor to remove every use of callbacks in relm widgets, taking advantage of async
 * callback.
 * FIXME: the commands in the config file are not executed.
 * TODO: take advantage of IntoOption and IntoPair.
 * TODO: automatically connect the AppClose message to Quit if it exists.
 * TODO: smart selection (select all on first time, select all except the prefix on the second).
 * TODO: shortcut to move the cursor at the other end of the selection.
 * TODO: thread example (using a oneshot).
 * TODO: generate async gtk methods as returning futures.
 * TODO: change all unneeded &mut self to &self.
 * TODO: set the size of the status bar according to the size of the font.
 * TODO: different event for activate event of special commands.
 * TODO: use the gtk::Statusbar widget?
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(missing_docs)]
#![feature(proc_macro, unboxed_closures)]

#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate futures_glib;
extern crate gdk;
extern crate glib;
extern crate gtk;
extern crate libc;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mg_settings;
extern crate pango;
#[macro_use]
extern crate relm;
extern crate relm_attributes;
#[macro_use]
extern crate relm_derive;

mod app;
pub mod completion;
mod key_converter;

/// Map mode prefix (i.e. "i") to the mode name (i.e. "insert").
pub type Modes = &'static [(&'static str, &'static str)];
/// Map variable names to a function returning the value of this variable.

pub use app::{Mg, parse_config};
pub use app::Msg::{
    Alert,
    AppClose,
    Completers,
    CompletionViewChange,
    CustomCommand,
    DarkTheme,
    DeleteCompletionItem,
    Error,
    Info,
    Message,
    ModeChanged,
    Question,
    SetMode,
    SetSetting,
    SettingChanged,
    Title,
    Variables,
    Warning,
};
pub use app::dialog::{DialogBuilder, DialogResult, input, question};
pub use app::settings::{DefaultConfig, NoSettings};
pub use app::status_bar::{StatusBar, StatusBarItem};

#[macro_export]
macro_rules! hash {
    ($($ident:expr => $value:expr,)*) => {{
        let mut hash_map: ::mg::Completers = ::std::collections::HashMap::new();
        $(hash_map.insert($ident, $value);)*
        hash_map
    }};
}

#[macro_export]
macro_rules! char_slice {
    ($( $val:expr ),*) => {{
        static SLICE: &'static [char] = &[$($val),*];
        SLICE
    }};
}

#[macro_export]
macro_rules! static_slice {
    ($( $val:expr ),* ; $typ:ty) => {{
        static SLICE: &'static [$typ] = &[$($val),*];
        SLICE
    }};
}
<|endoftext|>