<commit_before>//! # aHash
//!
//! This hashing algorithm is intended to be a high performance, (hardware specific), keyed hash function.
//! This can be seen as a DOS resistant alternative to `FxHash`, or a fast equivalent to `SipHash`.
//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key.
//! This allows it to be used in a `HashMap` without allowing for the possibility that an malicious user can
//! induce a collision.
//!
//! # How aHash works
//!
//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function.
//! It uses two rounds of AES per hash. So it should not be considered cryptographically secure.
#![cfg_attr(not(test), no_std)]
//#![feature(core_intrinsics)]
extern crate const_random;
#[cfg(all(test, feature = "no_panic"))]
extern crate no_panic;

#[macro_use]
mod convert;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
mod aes_hash;
mod fallback_hash;
#[cfg(test)]
mod hash_quality_test;

use const_random::const_random;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
#[cfg(all(test, feature = "no_panic"))]
use no_panic::no_panic;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
pub use crate::aes_hash::AHasher;

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
pub use crate::fallback_hash::AHasher;

/// A `HashMap` using `ABuildHasher` to hash the items.
//pub type AHashMap<K, V> = HashMap<K, V, ABuildHasher>;

///This constant come from Kunth's prng
const MULTIPLE: u64 = 6364136223846793005;

///Const random provides randomized starting key with no runtime cost.
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64));

/// Provides a default [Hasher] compile time generated constants for keys.
/// This is typically used in conjunction with [`BuildHasherDefault`] to create
/// [AHasher]s in order to hash the keys of the map.
///
/// # Example
/// ```
/// use std::hash::BuildHasherDefault;
/// use ahash::{AHasher, ABuildHasher};
/// use std::collections::HashMap;
///
/// let mut map: HashMap<i32, i32, ABuildHasher> = HashMap::default();
/// map.insert(12, 34);
/// ```
///
/// [BuildHasherDefault]: std::hash::BuildHasherDefault
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    /// Constructs a new [AHasher] with compile time generated constants for keys.
    /// This means the keys will be the same from one instance to another,
    /// but different from build to the next. So if it is possible for a potential
    /// attacker to have access to the compiled binary it would be better
    /// to specify keys generated at runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::AHasher;
    /// use std::hash::Hasher;
    ///
    /// let mut hasher_1 = AHasher::default();
    /// let mut hasher_2 = AHasher::default();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    /// ```
    #[inline]
    fn default() -> AHasher {
        AHasher::new_with_keys(const_random!(u64), const_random!(u64))
    }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [`HashMap`]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct ABuildHasher {
    k0: u64,
    k1: u64,
}

impl ABuildHasher {
    #[inline]
    pub fn new() -> ABuildHasher {
        //Using a self pointer. When running with ASLR this is a random value.
        let previous = SEED.load(Ordering::Relaxed) as u64;
        let stack_mem_loc = &previous as *const _ as u64;
        //This is similar to the update function in the fallback.
        //only one multiply is needed because memory locations are not under an attackers control.
        let current_seed = previous.wrapping_mul(MULTIPLE).wrapping_add(stack_mem_loc).rotate_left(31);
        SEED.store(current_seed as usize, Ordering::Relaxed);
        return ABuildHasher {
            k0: &SEED as *const _ as u64,
            k1: current_seed
        };
    }
}

impl Default for ABuildHasher {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for ABuildHasher {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on compile time generated constants and the location
    /// of the this object in memory. This means that two different [BuildHasher]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, ABuildHasher};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = ABuildHasher::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = ABuildHasher::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        let (k0, k1) = scramble_keys(self.k0, self.k1);
        return AHasher::new_with_keys(k0, k1);
    }
}

pub(crate) fn scramble_keys(k0: u64, k1: u64) -> (u64, u64) {
    //Scramble seeds (based on xoroshiro128+)
    //This is intentionally not similar the hash algorithm
    let result1 = k0.wrapping_add(k1);
    let k1 = k1 ^ k0;
    let k0 = k0.rotate_left(24) ^ k1 ^ (k1.wrapping_shl(16));
    let result2 = k0.wrapping_add(k1.rotate_left(37));
    return (result2, result1);
}

#[cfg(all(test, feature = "no_panic"))]
#[inline(never)]
#[no_panic]
//#[no_mangle]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
    use core::hash::Hasher;
    let builder = ABuildHasher::new();
    let mut hasher1 = builder.build_hasher();
    let mut hasher2 = builder.build_hasher();
    hasher1.write_i32(num);
    hasher2.write(string.as_bytes());
    (hasher1.finish(), hasher2.finish())
}

#[cfg(test)]
mod test {
    use crate::convert::Convert;
    use crate::*;
    use core::hash::BuildHasherDefault;
    use std::collections::HashMap;

    #[inline(never)]
    fn hash_test_final_wrapper(num: i32, string: &str) {
        hash_test_final(num, string);
    }

    #[cfg(feature = "no_panic")]
    #[test]
    fn test_no_panic() {
        hash_test_final_wrapper(2, "");
    }

    #[test]
    fn test_default_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }
    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, ABuildHasher>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>Add annotation<commit_after>//! # aHash
//!
//! This hashing algorithm is intended to be a high performance, (hardware specific), keyed hash function.
//! This can be seen as a DOS resistant alternative to `FxHash`, or a fast equivalent to `SipHash`.
//! It provides a high speed hash algorithm, but where the result is not predictable without knowing a Key.
//! This allows it to be used in a `HashMap` without allowing for the possibility that an malicious user can
//! induce a collision.
//!
//! # How aHash works
//!
//! aHash uses the hardware AES instruction on x86 processors to provide a keyed hash function.
//! It uses two rounds of AES per hash. So it should not be considered cryptographically secure.
#![cfg_attr(not(test), no_std)]
//#![feature(core_intrinsics)]
extern crate const_random;
#[cfg(all(test, feature = "no_panic"))]
extern crate no_panic;

#[macro_use]
mod convert;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
mod aes_hash;
mod fallback_hash;
#[cfg(test)]
mod hash_quality_test;

use const_random::const_random;
use core::hash::BuildHasher;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
#[cfg(all(test, feature = "no_panic"))]
use no_panic::no_panic;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
pub use crate::aes_hash::AHasher;

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes")))]
pub use crate::fallback_hash::AHasher;

/// A `HashMap` using `ABuildHasher` to hash the items.
//pub type AHashMap<K, V> = HashMap<K, V, ABuildHasher>;

///This constant come from Kunth's prng
const MULTIPLE: u64 = 6364136223846793005;

///Const random provides randomized starting key with no runtime cost.
static SEED: AtomicUsize = AtomicUsize::new(const_random!(u64));

/// Provides a default [Hasher] compile time generated constants for keys.
/// This is typically used in conjunction with [`BuildHasherDefault`] to create
/// [AHasher]s in order to hash the keys of the map.
///
/// # Example
/// ```
/// use std::hash::BuildHasherDefault;
/// use ahash::{AHasher, ABuildHasher};
/// use std::collections::HashMap;
///
/// let mut map: HashMap<i32, i32, ABuildHasher> = HashMap::default();
/// map.insert(12, 34);
/// ```
///
/// [BuildHasherDefault]: std::hash::BuildHasherDefault
/// [Hasher]: std::hash::Hasher
/// [HashMap]: std::collections::HashMap
impl Default for AHasher {
    /// Constructs a new [AHasher] with compile time generated constants for keys.
    /// This means the keys will be the same from one instance to another,
    /// but different from build to the next. So if it is possible for a potential
    /// attacker to have access to the compiled binary it would be better
    /// to specify keys generated at runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::AHasher;
    /// use std::hash::Hasher;
    ///
    /// let mut hasher_1 = AHasher::default();
    /// let mut hasher_2 = AHasher::default();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    /// ```
    #[inline]
    fn default() -> AHasher {
        AHasher::new_with_keys(const_random!(u64), const_random!(u64))
    }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [`HashMap`]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct ABuildHasher {
    k0: u64,
    k1: u64,
}

impl ABuildHasher {
    #[inline]
    pub fn new() -> ABuildHasher {
        //Using a self pointer. When running with ASLR this is a random value.
        let previous = SEED.load(Ordering::Relaxed) as u64;
        let stack_mem_loc = &previous as *const _ as u64;
        //This is similar to the update function in the fallback.
        //only one multiply is needed because memory locations are not under an attackers control.
        let current_seed = previous.wrapping_mul(MULTIPLE).wrapping_add(stack_mem_loc).rotate_left(31);
        SEED.store(current_seed as usize, Ordering::Relaxed);
        return ABuildHasher {
            k0: &SEED as *const _ as u64,
            k1: current_seed
        };
    }
}

impl Default for ABuildHasher {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for ABuildHasher {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on compile time generated constants and the location
    /// of the this object in memory. This means that two different [BuildHasher]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, ABuildHasher};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = ABuildHasher::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = ABuildHasher::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        let (k0, k1) = scramble_keys(self.k0, self.k1);
        return AHasher::new_with_keys(k0, k1);
    }
}

pub(crate) fn scramble_keys(k0: u64, k1: u64) -> (u64, u64) {
    //Scramble seeds (based on xoroshiro128+)
    //This is intentionally not similar the hash algorithm
    let result1 = k0.wrapping_add(k1);
    let k1 = k1 ^ k0;
    let k0 = k0.rotate_left(24) ^ k1 ^ (k1.wrapping_shl(16));
    let result2 = k0.wrapping_add(k1.rotate_left(37));
    return (result2, result1);
}

#[cfg(all(test, feature = "no_panic"))]
#[inline(never)]
#[no_panic]
//#[no_mangle]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
    use core::hash::Hasher;
    let builder = ABuildHasher::new();
    let mut hasher1 = builder.build_hasher();
    let mut hasher2 = builder.build_hasher();
    hasher1.write_i32(num);
    hasher2.write(string.as_bytes());
    (hasher1.finish(), hasher2.finish())
}

#[cfg(test)]
mod test {
    use crate::convert::Convert;
    use crate::*;
    use core::hash::BuildHasherDefault;
    use std::collections::HashMap;

    #[cfg(feature = "no_panic")]
    #[inline(never)]
    fn hash_test_final_wrapper(num: i32, string: &str) {
        hash_test_final(num, string);
    }

    #[cfg(feature = "no_panic")]
    #[test]
    fn test_no_panic() {
        hash_test_final_wrapper(2, "");
    }

    #[test]
    fn test_default_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }
    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, ABuildHasher>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>


<commit_before>/// Compute the signed distance function from a line segment given as the _zero_ level set of a linear
/// function on an isosceles right-angle triangle.
///
/// Inputs are `u`, the values at the verteces. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the signed distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(u: [f64; 3]) -> Option<[f64; 3]> {
    let mut u = u;
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for u in u.iter_mut() {
            *u = -*u;
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            return None;
        } else {
            // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. {
                // 0
                return Some([u[0] / g_norm, i12, 1. - i02]);
            } else if gx > -gy {
                // 1
                return Some([i02, u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i02, i12, -u[2] / g_norm]);
            }
        }
    } else {
        // u[1] < 0.
        if u[2] >= 0. {
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. {
                // 0
                return Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12]);
            } else if -gx > gy {
                // 1
                return Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i01, i12, u[2] / g_norm]);
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            return Some([u[0] / g_norm, i10, i20]);
        }
    }
}

/// Initialize distance around the free boundary.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());

    for i in 0..d.len() {
        d[i] = std::f64::MAX;
    }

    for j in 1..dim.1 {
        for i in 1..dim.0 {
            let s = j * dim.0 + i;
            let r = triangle_dist([u[s - dim.0 - 1], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s - dim.0 - 1] = e[0].min(d[s - dim.0 - 1]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the Fast Sweeping algorithm.
///
/// `d` should be initialized to large values at the unknown nodes.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {
    // sweep in 4 directions
    for k in 1..5 {
        for q in 0..dim.1 {
            let j = if k == 3 || k == 4 {
                dim.1 - 1 - q
            } else {
                q
            };
            for p in 0..dim.0 {
                let i = if k == 2 || k == 3 {
                    dim.0 - 1 - p
                } else {
                    p
                };
                let s = j * dim.0 + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == dim.0 - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + dim.0]
                } else if j == dim.1 - 1 {
                    d[s - dim.0]
                } else {
                    d[s - dim.0].min(d[s + dim.0])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    extern crate ndarray;
    use self::quickcheck::quickcheck;
    use self::ndarray::prelude::*;

    #[test]
    fn it_works_for_x_axis_line() {
        fn prop(y: f64) -> bool {
            let n = 9;
            let y = (y - y.floor()) * 0.9 + 0.05;
            let ys = OwnedArray::linspace(0. - y, 1. - y, n);
            let u_array = ys.broadcast((n, n)).unwrap().t().to_owned();
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];

                init_dist(&mut d, &u, (n, n));
                fast_sweep_dist(&mut d, (n, n));

                for i in 0..d.len() {
                    if u[i] < 0. {
                        d[i] = -d[i];
                    }
                }

                OwnedArray::from_shape_vec((n, n), d).unwrap() * (1. / (n - 1) as f64)
            };
            d.all_close(&u_array, 0.00001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_y_axis_line() {
        fn prop(x: f64) -> bool {
            let n = 9;
            let x = (x - x.floor()) * 0.9 + 0.05;
            let xs = OwnedArray::linspace(0. - x, 1. - x, n);
            let u_array = xs.broadcast((n, n)).unwrap().to_owned();
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];

                init_dist(&mut d, &u, (n, n));
                fast_sweep_dist(&mut d, (n, n));

                for i in 0..d.len() {
                    if u[i] < 0. {
                        d[i] = -d[i];
                    }
                }

                OwnedArray::from_shape_vec((n, n), d).unwrap() * (1. / (n - 1) as f64)
            };

            d.all_close(&u_array, 0.00001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_is_nonnegative_on_triangle() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }
}
<commit_msg>Add `signed_distance` function<commit_after>//! Fast sweeping method for the signed distance function in 2D.
//!
//!

/// Compute the signed distance function from a line segment given as the _zero_ level set of a linear
/// function on an isosceles right-angle triangle.
///
/// Inputs are `u`, the values at the verteces. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the signed distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(u: [f64; 3]) -> Option<[f64; 3]> {
    let mut u = u;
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for u in u.iter_mut() {
            *u = -*u;
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            return None;
        } else {
            // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. {
                // 0
                return Some([u[0] / g_norm, i12, 1. - i02]);
            } else if gx > -gy {
                // 1
                return Some([i02, u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i02, i12, -u[2] / g_norm]);
            }
        }
    } else {
        // u[1] < 0.
        if u[2] >= 0. {
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. {
                // 0
                return Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12]);
            } else if -gx > gy {
                // 1
                return Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i01, i12, u[2] / g_norm]);
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            return Some([u[0] / g_norm, i10, i20]);
        }
    }
}

/// Initializes distance around the free boundary.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());

    for i in 0..d.len() {
        d[i] = std::f64::MAX;
    }

    for j in 1..dim.1 {
        for i in 1..dim.0 {
            let s = j * dim.0 + i;
            let r = triangle_dist([u[s - dim.0 - 1], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s - dim.0 - 1] = e[0].min(d[s - dim.0 - 1]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the Fast Sweeping algorithm.
///
/// `d` should be initialized to large values at the unknown nodes.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {
    assert_eq!(dim.0 * dim.1, d.len());
    // sweep in 4 directions
    for k in 1..5 {
        for q in 0..dim.1 {
            let j = if k == 3 || k == 4 {
                dim.1 - 1 - q
            } else {
                q
            };
            for p in 0..dim.0 {
                let i = if k == 2 || k == 3 {
                    dim.0 - 1 - p
                } else {
                    p
                };
                let s = j * dim.0 + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == dim.0 - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + dim.0]
                } else if j == dim.1 - 1 {
                    d[s - dim.0]
                } else {
                    d[s - dim.0].min(d[s + dim.0])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

/// Computes the signed distance from the _zero_ level set of the function given by the values of
/// `u` on a regular grid of dimensions `dim` to a preallocated array `d`.
///
/// `h` is the distance between neighboring nodes.
///
/// Returns `std::f64::MAX` if all `u` are positive (`-std::f64::MAX` if all `u` are negative).
pub fn signed_distance(d: &mut [f64], u: &[f64], dim: (usize, usize), h: f64) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());
                init_dist(d, u, dim);
                fast_sweep_dist(d, dim);

                for i in 0..d.len() {
                    if u[i] < 0. {
                        d[i] = -d[i] * h;
                    } else {
                        d[i] *= h;
                    }
                }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    extern crate ndarray;
    use self::quickcheck::quickcheck;
    use self::ndarray::prelude::*;

    #[test]
    fn it_works_for_x_axis_line() {
        fn prop(y: f64) -> bool {
            let n = 9;
            let y = (y - y.floor()) * 0.9 + 0.05;
            let ys = OwnedArray::linspace(0. - y, 1. - y, n);
            let u_array = ys.broadcast((n, n)).unwrap().t().to_owned();
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];
                signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d).unwrap()
            };
            d.all_close(&u_array, 0.00001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_y_axis_line() {
        fn prop(x: f64) -> bool {
            let n = 9;
            let x = (x - x.floor()) * 0.9 + 0.05;
            let xs = OwnedArray::linspace(0. - x, 1. - x, n);
            let u_array = xs.broadcast((n, n)).unwrap().to_owned();
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];
                signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d).unwrap()
            };

            d.all_close(&u_array, 0.00001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_is_nonnegative_on_triangle() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }
}
<|endoftext|>


<commit_before>//! ODBC types those representation is compatible with the ODBC C API.
//!
//! This layer has not been created using automatic code generation. It is incomplete, i.e. it does
//! not contain every symbol or constant defined in the ODBC C headers. Symbols which are
//! deprecated since ODBC 3 have been left out intentionally. While some extra type safety has been
//! added by grouping some of C's `#define` constants into `enum`-types it mostly offers the same
//! power (all) and safety guarantess(none) as the wrapped C-API.
//! ODBC 4.0 is still under development by Microsoft, so these symbols are deactivated by default
//! in the cargo.toml

pub use self::sqlreturn::*;
pub use self::info_type::*;
pub use self::fetch_orientation::*;
pub use self::attributes::*;
pub use self::c_data_type::*;
pub use self::input_output::*;
use std::os::raw::c_void;

mod sqlreturn;
mod info_type;
mod fetch_orientation;
mod attributes;
mod c_data_type;
mod input_output;

//These types can never be instantiated in Rust code.
pub enum Obj {}
pub enum Env {}
pub enum Dbc {}
pub enum Stmt {}

pub type SQLHANDLE = *mut Obj;
pub type SQLHENV = *mut Env;

/// The connection handle references storage of all information about the connection to the data
/// source, including status, transaction state, and error information.
pub type SQLHDBC = *mut Dbc;
pub type SQLHSTMT = *mut Stmt;

pub type SQLSMALLINT = i16;
pub type SQLUSMALLINT = u16;
pub type SQLINTEGER = i32;
pub type SQLUINTEGER = u32;
pub type SQLPOINTER = *mut c_void;
pub type SQLCHAR = u8;

#[cfg(target_pointer_width = "64")]
pub type SQLLEN = i64;
#[cfg(target_pointer_width = "32")]
pub type SQLLEN = SQLINTEGER;

#[cfg(target_pointer_width = "64")]
pub type SQLULEN = u64;
#[cfg(target_pointer_width = "32")]
pub type SQLULEN = SQLUINTEGER;

pub type SQLHWND = SQLPOINTER;

// flags for null-terminated string
pub const SQL_NTS: SQLSMALLINT = -3;
pub const SQL_NTSL: SQLINTEGER = -3;

/// Maximum message length
pub const SQL_MAX_MESSAGE_LENGTH: SQLSMALLINT = 512;
pub const SQL_SQLSTATE_SIZE: usize = 5;

// Special SQLGetData indicator values
pub const SQL_NULL_DATA: SQLLEN = -1;
pub const SQL_NO_TOTAL: SQLLEN = -4;

/// SQL Data Types
#[repr(i16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SqlDataType {
    SQL_UNKNOWN_TYPE = 0, // also called SQL_VARIANT_TYPE since odbc 4.0
    SQL_CHAR = 1,
    SQL_NUMERIC = 2,
    SQL_DECIMAL = 3,
    SQL_INTEGER = 4,
    SQL_SMALLINT = 5,
    SQL_FLOAT = 6,
    SQL_REAL = 7,
    SQL_DOUBLE = 8,
    SQL_DATETIME = 9,
    SQL_VARCHAR = 12,
    #[cfg(feature = "odbc_version_4")]
    SQL_UDT = 17,
    #[cfg(feature = "odbc_version_4")]
    SQL_ROW = 19,
    #[cfg(feature = "odbc_version_4")]
    SQL_ARRAY = 50,
    #[cfg(feature = "odbc_version_4")]
    SQL_MULTISET = 55,
}
pub use self::SqlDataType::*;

/// Represented in C headers as SQLSMALLINT
#[repr(i16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum HandleType {
    SQL_HANDLE_ENV = 1,
    SQL_HANDLE_DBC = 2,
    SQL_HANDLE_STMT = 3,
    SQL_HANDLE_DESC = 4,
}
pub use self::HandleType::*;

/// Options for `SQLDriverConnect`
#[repr(u16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SqlDriverConnectOption {
    SQL_DRIVER_NOPROMPT = 0,
    SQL_DRIVER_COMPLETE = 1,
    SQL_DRIVER_PROMPT = 2,
    SQL_DRIVER_COMPLETE_REQUIRED = 3,
}
pub use self::SqlDriverConnectOption::*;

#[cfg_attr(windows, link(name="odbc32"))]
#[cfg_attr(not(windows), link(name="odbc"))]
extern "C" {
    /// Allocates an environment, connection, statement, or descriptor handle.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLAllocHandle(handle_type: HandleType,
                          input_handle: SQLHANDLE,
                          output_Handle: *mut SQLHANDLE)
                          -> SQLRETURN;

    /// Frees resources associated with a specific environment, connection, statement, or
    /// descriptor handle.
    ///
    /// If `SQL_ERRQR` is returned the handle is still valid.
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLFreeHandle(handle_type: HandleType, handle: SQLHANDLE) -> SQLRETURN;

    /// Sets attributes that govern aspects of environments
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLSetEnvAttr(environment_handle: SQLHENV,
                         attribute: EnvironmentAttribute,
                         value: SQLPOINTER,
                         string_length: SQLINTEGER)
                         -> SQLRETURN;

    /// Closes the connection associated with a specific connection handle.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLDisconnect(connection_handle: SQLHDBC) -> SQLRETURN;

    pub fn SQLGetDiagRec(handle_type: HandleType,
                         handle: SQLHANDLE,
                         RecNumber: SQLSMALLINT,
                         state: *mut SQLCHAR,
                         native_error_ptr: *mut SQLINTEGER,
                         message_text: *mut SQLCHAR,
                         buffer_length: SQLSMALLINT,
                         text_length_ptr: *mut SQLSMALLINT)
                         -> SQLRETURN;

    pub fn SQLExecDirect(statement_handle: SQLHSTMT,
                         statement_text: *const SQLCHAR,
                         text_length: SQLINTEGER)
                         -> SQLRETURN;

    /// Returns the number of columns in a result set
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE` or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLNumResultCols(statement_handle: SQLHSTMT,
                            column_count_ptr: *mut SQLSMALLINT)
                            -> SQLRETURN;

    // Can be used since odbc version 3.8 to stream results
    pub fn SQLGetData(statement_handle: SQLHSTMT,
                      col_or_param_num: SQLUSMALLINT,
                      target_type: SqlCDataType,
                      target_value_ptr: SQLPOINTER,
                      buffer_length: SQLLEN,
                      str_len_or_ind_ptr: *mut SQLLEN)
                      -> SQLRETURN;

    /// SQLFetch fetches the next rowset of data from the result set and returns data for all bound
    /// columns.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, `SQL_NO_DATA` or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLFetch(statement_handle: SQLHSTMT) -> SQLRETURN;

    /// Returns general information about the driver and data source associated with a connection
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLGetInfo(connection_handle: SQLHDBC,
                      info_type: InfoType,
                      info_value_ptr: SQLPOINTER,
                      buffer_length: SQLSMALLINT,
                      string_length_ptr: *mut SQLSMALLINT)
                      -> SQLRETURN;

    /// SQLConnect establishes connections to a driver and a data source.
    ///
    /// The connection handle references storage of all information about the connection to the
    /// data source, including status, transaction state, and error information.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLConnect(connection_handle: SQLHDBC,
                      server_name: *const SQLCHAR,
                      name_length_1: SQLSMALLINT,
                      user_name: *const SQLCHAR,
                      name_length_2: SQLSMALLINT,
                      authentication: *const SQLCHAR,
                      name_length_3: SQLSMALLINT)
                      -> SQLRETURN;

    /// Returns the list of table, catalog, or schema names, and table types, stored in a specific
    /// data source. The driver returns the information as a result set
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLTables(statement_handle: SQLHSTMT,
                     catalog_name: *const SQLCHAR,
                     name_length_1: SQLSMALLINT,
                     schema_name: *const SQLCHAR,
                     name_length_2: SQLSMALLINT,
                     table_name: *const SQLCHAR,
                     name_length_3: SQLSMALLINT,
                     TableType: *const SQLCHAR,
                     name_length_4: SQLSMALLINT)
                     -> SQLRETURN;

    /// Returns information about a data source. This function is implemented only by the Driver
    /// Manager.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or `SQL_NO_DATA`
    pub fn SQLDataSources(environment_handle: SQLHENV,
                          direction: FetchOrientation,
                          server_name: *mut SQLCHAR,
                          buffer_length_1: SQLSMALLINT,
                          name_length_1: *mut SQLSMALLINT,
                          description: *mut SQLCHAR,
                          buffer_length_2: SQLSMALLINT,
                          name_length_2: *mut SQLSMALLINT)
                          -> SQLRETURN;

    /// An alternative to `SQLConnect`. It supports data sources that require more connection
    /// information than the three arguments in `SQLConnect`, dialog boxes to prompt the user for
    /// all connection information, and data sources that are not defined in the system information
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, `SQL_NO_DATA`,
    /// or `SQL_STILL_EXECUTING`
    pub fn SQLDriverConnect(connection_handle: SQLHDBC,
                            window_handle: SQLHWND,
                            in_connection_string: *const SQLCHAR,
                            string_length_1: SQLSMALLINT,
                            out_connection_string: *mut SQLCHAR,
                            buffer_length: SQLSMALLINT,
                            string_length_2: *mut SQLSMALLINT,
                            DriverCompletion: SqlDriverConnectOption)
                            -> SQLRETURN;

    /// Lists driver descriptions and driver attribute keywords. This function is implemented only
    /// by the Driver Manager.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or `SQL_NO_DATA`
    pub fn SQLDrivers(henv: SQLHENV,
                      direction: FetchOrientation,
                      driver_desc: *mut SQLCHAR,
                      driver_desc_max: SQLSMALLINT,
                      out_driver_desc: *mut SQLSMALLINT,
                      driver_attributes: *mut SQLCHAR,
                      drvr_attr_max: SQLSMALLINT,
                      out_drvr_attr: *mut SQLSMALLINT)
                      -> SQLRETURN;

    /// Closes a cursor that has been opened on a statement and discards pending results.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR` or `SQL_INVALID_HANDLE`
    pub fn SQLCloseCursor(hstmt: SQLHSTMT) -> SQLRETURN;

    /// Binds a buffer to a parameter marker in an SQL statement
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR` or `SQL_INVALID_HANDLE`
    pub fn SQLBindParameter(hstmt: SQLHSTMT,
                            parameter_number: SQLUSMALLINT,
                            input_output_type: InputOutput,
                            value_type: SqlCDataType,
                            parmeter_type: SqlDataType,
                            column_size: SQLULEN,
                            decimal_digits: SQLSMALLINT,
                            parameter_value_ptr: SQLPOINTER,
                            buffer_length: SQLLEN,
                            str_len_or_ind_ptr: *mut SQLLEN)
                            -> SQLRETURN;
}
<commit_msg>add SQLPrepare<commit_after>//! ODBC types those representation is compatible with the ODBC C API.
//!
//! This layer has not been created using automatic code generation. It is incomplete, i.e. it does
//! not contain every symbol or constant defined in the ODBC C headers. Symbols which are
//! deprecated since ODBC 3 have been left out intentionally. While some extra type safety has been
//! added by grouping some of C's `#define` constants into `enum`-types it mostly offers the same
//! power (all) and safety guarantess(none) as the wrapped C-API.
//! ODBC 4.0 is still under development by Microsoft, so these symbols are deactivated by default
//! in the cargo.toml

pub use self::sqlreturn::*;
pub use self::info_type::*;
pub use self::fetch_orientation::*;
pub use self::attributes::*;
pub use self::c_data_type::*;
pub use self::input_output::*;
use std::os::raw::c_void;

mod sqlreturn;
mod info_type;
mod fetch_orientation;
mod attributes;
mod c_data_type;
mod input_output;

//These types can never be instantiated in Rust code.
pub enum Obj {}
pub enum Env {}
pub enum Dbc {}
pub enum Stmt {}

pub type SQLHANDLE = *mut Obj;
pub type SQLHENV = *mut Env;

/// The connection handle references storage of all information about the connection to the data
/// source, including status, transaction state, and error information.
pub type SQLHDBC = *mut Dbc;
pub type SQLHSTMT = *mut Stmt;

pub type SQLSMALLINT = i16;
pub type SQLUSMALLINT = u16;
pub type SQLINTEGER = i32;
pub type SQLUINTEGER = u32;
pub type SQLPOINTER = *mut c_void;
pub type SQLCHAR = u8;

#[cfg(target_pointer_width = "64")]
pub type SQLLEN = i64;
#[cfg(target_pointer_width = "32")]
pub type SQLLEN = SQLINTEGER;

#[cfg(target_pointer_width = "64")]
pub type SQLULEN = u64;
#[cfg(target_pointer_width = "32")]
pub type SQLULEN = SQLUINTEGER;

pub type SQLHWND = SQLPOINTER;

// flags for null-terminated string
pub const SQL_NTS: SQLSMALLINT = -3;
pub const SQL_NTSL: SQLINTEGER = -3;

/// Maximum message length
pub const SQL_MAX_MESSAGE_LENGTH: SQLSMALLINT = 512;
pub const SQL_SQLSTATE_SIZE: usize = 5;

// Special SQLGetData indicator values
pub const SQL_NULL_DATA: SQLLEN = -1;
pub const SQL_NO_TOTAL: SQLLEN = -4;

/// SQL Data Types
#[repr(i16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SqlDataType {
    SQL_UNKNOWN_TYPE = 0, // also called SQL_VARIANT_TYPE since odbc 4.0
    SQL_CHAR = 1,
    SQL_NUMERIC = 2,
    SQL_DECIMAL = 3,
    SQL_INTEGER = 4,
    SQL_SMALLINT = 5,
    SQL_FLOAT = 6,
    SQL_REAL = 7,
    SQL_DOUBLE = 8,
    SQL_DATETIME = 9,
    SQL_VARCHAR = 12,
    #[cfg(feature = "odbc_version_4")]
    SQL_UDT = 17,
    #[cfg(feature = "odbc_version_4")]
    SQL_ROW = 19,
    #[cfg(feature = "odbc_version_4")]
    SQL_ARRAY = 50,
    #[cfg(feature = "odbc_version_4")]
    SQL_MULTISET = 55,
}
pub use self::SqlDataType::*;

/// Represented in C headers as SQLSMALLINT
#[repr(i16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum HandleType {
    SQL_HANDLE_ENV = 1,
    SQL_HANDLE_DBC = 2,
    SQL_HANDLE_STMT = 3,
    SQL_HANDLE_DESC = 4,
}
pub use self::HandleType::*;

/// Options for `SQLDriverConnect`
#[repr(u16)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SqlDriverConnectOption {
    SQL_DRIVER_NOPROMPT = 0,
    SQL_DRIVER_COMPLETE = 1,
    SQL_DRIVER_PROMPT = 2,
    SQL_DRIVER_COMPLETE_REQUIRED = 3,
}
pub use self::SqlDriverConnectOption::*;

#[cfg_attr(windows, link(name="odbc32"))]
#[cfg_attr(not(windows), link(name="odbc"))]
extern "C" {
    /// Allocates an environment, connection, statement, or descriptor handle.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLAllocHandle(handle_type: HandleType,
                          input_handle: SQLHANDLE,
                          output_Handle: *mut SQLHANDLE)
                          -> SQLRETURN;

    /// Frees resources associated with a specific environment, connection, statement, or
    /// descriptor handle.
    ///
    /// If `SQL_ERRQR` is returned the handle is still valid.
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLFreeHandle(handle_type: HandleType, handle: SQLHANDLE) -> SQLRETURN;

    /// Sets attributes that govern aspects of environments
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLSetEnvAttr(environment_handle: SQLHENV,
                         attribute: EnvironmentAttribute,
                         value: SQLPOINTER,
                         string_length: SQLINTEGER)
                         -> SQLRETURN;

    /// Closes the connection associated with a specific connection handle.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLDisconnect(connection_handle: SQLHDBC) -> SQLRETURN;

    pub fn SQLGetDiagRec(handle_type: HandleType,
                         handle: SQLHANDLE,
                         RecNumber: SQLSMALLINT,
                         state: *mut SQLCHAR,
                         native_error_ptr: *mut SQLINTEGER,
                         message_text: *mut SQLCHAR,
                         buffer_length: SQLSMALLINT,
                         text_length_ptr: *mut SQLSMALLINT)
                         -> SQLRETURN;

    /// Executes a preparable statement, using the current values of the parameter marker variables
    /// if any parameters exist in the statement. This is the fastest way to submit an SQL
    /// statement for one-time execution
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_NEED_DATA`, `SQL_STILL_EXECUTING`, `SQL_ERROR`
    /// , `SQL_NO_DATA`, `SQL_INVALID_HANDLE`, or `SQL_PARAM_DATA_AVAILABLE`.
    pub fn SQLExecDirect(statement_handle: SQLHSTMT,
                         statement_text: *const SQLCHAR,
                         text_length: SQLINTEGER)
                         -> SQLRETURN;

    /// Returns the number of columns in a result set
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE` or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLNumResultCols(statement_handle: SQLHSTMT,
                            column_count_ptr: *mut SQLSMALLINT)
                            -> SQLRETURN;

    // Can be used since odbc version 3.8 to stream results
    pub fn SQLGetData(statement_handle: SQLHSTMT,
                      col_or_param_num: SQLUSMALLINT,
                      target_type: SqlCDataType,
                      target_value_ptr: SQLPOINTER,
                      buffer_length: SQLLEN,
                      str_len_or_ind_ptr: *mut SQLLEN)
                      -> SQLRETURN;

    /// SQLFetch fetches the next rowset of data from the result set and returns data for all bound
    /// columns.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, `SQL_NO_DATA` or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLFetch(statement_handle: SQLHSTMT) -> SQLRETURN;

    /// Returns general information about the driver and data source associated with a connection
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, or `SQL_INVALID_HANDLE`
    pub fn SQLGetInfo(connection_handle: SQLHDBC,
                      info_type: InfoType,
                      info_value_ptr: SQLPOINTER,
                      buffer_length: SQLSMALLINT,
                      string_length_ptr: *mut SQLSMALLINT)
                      -> SQLRETURN;

    /// SQLConnect establishes connections to a driver and a data source.
    ///
    /// The connection handle references storage of all information about the connection to the
    /// data source, including status, transaction state, and error information.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLConnect(connection_handle: SQLHDBC,
                      server_name: *const SQLCHAR,
                      name_length_1: SQLSMALLINT,
                      user_name: *const SQLCHAR,
                      name_length_2: SQLSMALLINT,
                      authentication: *const SQLCHAR,
                      name_length_3: SQLSMALLINT)
                      -> SQLRETURN;

    /// Returns the list of table, catalog, or schema names, and table types, stored in a specific
    /// data source. The driver returns the information as a result set
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLTables(statement_handle: SQLHSTMT,
                     catalog_name: *const SQLCHAR,
                     name_length_1: SQLSMALLINT,
                     schema_name: *const SQLCHAR,
                     name_length_2: SQLSMALLINT,
                     table_name: *const SQLCHAR,
                     name_length_3: SQLSMALLINT,
                     TableType: *const SQLCHAR,
                     name_length_4: SQLSMALLINT)
                     -> SQLRETURN;

    /// Returns information about a data source. This function is implemented only by the Driver
    /// Manager.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or `SQL_NO_DATA`
    pub fn SQLDataSources(environment_handle: SQLHENV,
                          direction: FetchOrientation,
                          server_name: *mut SQLCHAR,
                          buffer_length_1: SQLSMALLINT,
                          name_length_1: *mut SQLSMALLINT,
                          description: *mut SQLCHAR,
                          buffer_length_2: SQLSMALLINT,
                          name_length_2: *mut SQLSMALLINT)
                          -> SQLRETURN;

    /// An alternative to `SQLConnect`. It supports data sources that require more connection
    /// information than the three arguments in `SQLConnect`, dialog boxes to prompt the user for
    /// all connection information, and data sources that are not defined in the system information
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, `SQL_NO_DATA`,
    /// or `SQL_STILL_EXECUTING`
    pub fn SQLDriverConnect(connection_handle: SQLHDBC,
                            window_handle: SQLHWND,
                            in_connection_string: *const SQLCHAR,
                            string_length_1: SQLSMALLINT,
                            out_connection_string: *mut SQLCHAR,
                            buffer_length: SQLSMALLINT,
                            string_length_2: *mut SQLSMALLINT,
                            DriverCompletion: SqlDriverConnectOption)
                            -> SQLRETURN;

    /// Lists driver descriptions and driver attribute keywords. This function is implemented only
    /// by the Driver Manager.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or `SQL_NO_DATA`
    pub fn SQLDrivers(henv: SQLHENV,
                      direction: FetchOrientation,
                      driver_desc: *mut SQLCHAR,
                      driver_desc_max: SQLSMALLINT,
                      out_driver_desc: *mut SQLSMALLINT,
                      driver_attributes: *mut SQLCHAR,
                      drvr_attr_max: SQLSMALLINT,
                      out_drvr_attr: *mut SQLSMALLINT)
                      -> SQLRETURN;

    /// Closes a cursor that has been opened on a statement and discards pending results.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR` or `SQL_INVALID_HANDLE`
    pub fn SQLCloseCursor(hstmt: SQLHSTMT) -> SQLRETURN;

    /// Binds a buffer to a parameter marker in an SQL statement
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR` or `SQL_INVALID_HANDLE`
    pub fn SQLBindParameter(hstmt: SQLHSTMT,
                            parameter_number: SQLUSMALLINT,
                            input_output_type: InputOutput,
                            value_type: SqlCDataType,
                            parmeter_type: SqlDataType,
                            column_size: SQLULEN,
                            decimal_digits: SQLSMALLINT,
                            parameter_value_ptr: SQLPOINTER,
                            buffer_length: SQLLEN,
                            str_len_or_ind_ptr: *mut SQLLEN)
                            -> SQLRETURN;

    /// Prepares an SQL string for execution
    ///
    /// Compiles the statement and generates an acccess plan.
    ///
    /// # Returns
    /// `SQL_SUCCESS`, `SQL_SUCCESS_WITH_INFO`, `SQL_ERROR`, `SQL_INVALID_HANDLE`, or
    /// `SQL_STILL_EXECUTING`
    pub fn SQLPrepare(hstmt: SQLHSTMT, statement_text: * const SQLCHAR, text_length: SQLINTEGER);
}
<|endoftext|>


<commit_before>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate hyper;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate select;
extern crate url;

use std::cmp;
use std::fmt::Write;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use select::document::Document;
use select::predicate::{Attr, Name};
use url::Url;

lazy_static! {
    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( / \d+\.\d+)?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default)]
pub struct Menu(LinkedHashMap<String, Vec<String>>);

impl Menu {
    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> String {
        let mut output = String::default();

        for (ref category, ref items) in &self.0 {
            writeln!(output, "*{}*\n", category).unwrap();

            for item in items.iter() {
                writeln!(output, "• {}", item).unwrap();
            }

            writeln!(output, "").unwrap();
        }

        if output.is_empty() {
            writeln!(output, "There is no menu today ¯\\_(ツ)_/¯").unwrap();
        }

        writeln!(output,
                 "> Made with :cnr: by @anrussell. Source available at \
                  https://github.com/euclio/nourishbot.")
            .unwrap();

        output
    }
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!("http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                       nsf/weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
                        monday.format("%m-%d-%Y"),
                        days_from_monday + 1))
        .unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);

    let mut menu: LinkedHashMap<String, Vec<String>> = LinkedHashMap::new();

    let mut last_category = None;

    let menu_node = document.find(Attr("id", "center_text")).first().unwrap();
    for node in menu_node.find(Name("div")).iter() {
        let text = node.text().trim().to_owned();

        if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
            continue;
        }

        if let Some("font-weight:bold;") = node.attr("style") {
            let category = text.to_lower_case().to_title_case();

            // Filter out breakfast.
            if category != "Breakfast Special" {
                last_category = Some(text.to_lower_case().to_title_case());
            }
        } else {
            if let Some(ref category) = last_category {
                if menu.contains_key(category) {
                    let mut entries = menu.get_mut(category).unwrap();
                    entries.push(text);
                } else {
                    menu.insert(category.to_owned(), vec![text]);
                }

            }
        }
    }

    Menu(menu)
}

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

    use chrono::NaiveDate;

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).serialize());
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).serialize());

    }
}
<commit_msg>add per-ounce to price regex<commit_after>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate hyper;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate select;
extern crate url;

use std::cmp;
use std::fmt::Write;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use select::document::Document;
use select::predicate::{Attr, Name};
use url::Url;

lazy_static! {
    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( ?/ ?(\d+\.\d+|[a-z]+))?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default)]
pub struct Menu(LinkedHashMap<String, Vec<String>>);

impl Menu {
    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> String {
        let mut output = String::default();

        for (ref category, ref items) in &self.0 {
            writeln!(output, "*{}*\n", category).unwrap();

            for item in items.iter() {
                writeln!(output, "• {}", item).unwrap();
            }

            writeln!(output, "").unwrap();
        }

        if output.is_empty() {
            writeln!(output, "There is no menu today ¯\\_(ツ)_/¯").unwrap();
        }

        writeln!(output,
                 "> Made with :cnr: by @anrussell. Source available at \
                  https://github.com/euclio/nourishbot.")
            .unwrap();

        output
    }
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!("http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                       nsf/weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
                        monday.format("%m-%d-%Y"),
                        days_from_monday + 1))
        .unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);

    let mut menu: LinkedHashMap<String, Vec<String>> = LinkedHashMap::new();

    let mut last_category = None;

    let menu_node = document.find(Attr("id", "center_text")).first().unwrap();
    for node in menu_node.find(Name("div")).iter() {
        let text = node.text().trim().to_owned();

        if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
            continue;
        }

        if let Some("font-weight:bold;") = node.attr("style") {
            let category = text.to_lower_case().to_title_case();

            // Filter out breakfast.
            if category != "Breakfast Special" {
                last_category = Some(text.to_lower_case().to_title_case());
            }
        } else {
            if let Some(ref category) = last_category {
                if menu.contains_key(category) {
                    let mut entries = menu.get_mut(category).unwrap();
                    entries.push(text);
                } else {
                    menu.insert(category.to_owned(), vec![text]);
                }

            }
        }
    }

    Menu(menu)
}

#[cfg(test)]
mod tests {
    use super::{PRICE_RE, url_for_date};

    use chrono::NaiveDate;

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).serialize());
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).serialize());

    }

    #[test]
    fn price_regex() {
        let patterns = ["7.50", "0.25/oz", "2.15 / 2.65"];

        for pattern in &patterns {
            assert!(PRICE_RE.is_match(pattern), pattern.clone());
        }
    }
}
<|endoftext|>


<commit_before>// https://github.com/rust-lang/rust/issues/27585;
// after that, https://github.com/BurntSushi/byteorder/pull/40.
#![feature(read_exact)]

#[macro_use] extern crate log;
extern crate byteorder;

mod protocol;

pub use protocol::{Error, Result, Version, PixelFormat};

use std::io::Read;
use std::net::{TcpStream, Shutdown};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use protocol::Message;

#[derive(Debug)]
pub enum AuthMethod {
    None,
    /* more to come */
    Unused
}

#[derive(Debug)]
pub enum AuthChoice {
    None,
    /* more to come */
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Rect {
    pub left:   u16,
    pub top:    u16,
    pub width:  u16,
    pub height: u16
}

#[derive(Debug)]
pub enum ClientEvent {
    Disconnected,
    Resize(u16, u16),
    PutPixels(Rect, Vec<u8>),
    CopyPixels { src: Rect, dst: Rect },
    SetCursor { size: (u16, u16), hotspot: (u16, u16), pixels: Vec<u8>, mask_bits: Vec<u8> },
    Clipboard(String),
    Bell,
}

macro_rules! send_or_return {
    ($chan:expr, $data:expr) => ({
        match $chan.send($data) {
            Ok(()) => (),
            Err(_) => return Err(Error::UnexpectedEOF)
        }
    })
}

impl ClientEvent {
    fn pump_one(stream: &mut TcpStream, format: &protocol::PixelFormat,
                tx_events: &mut Sender<ClientEvent>) -> Result<()> {
        let packet = try!(protocol::S2C::read_from(stream));
        debug!("<- {:?}", packet);
        match packet {
            protocol::S2C::FramebufferUpdate { count } => {
                for _ in 0..count {
                    let rectangle = try!(protocol::Rectangle::read_from(stream));
                    debug!("<- {:?}", rectangle);
                    let event = match rectangle.encoding {
                        protocol::Encoding::Raw => {
                            let mut pixels = vec![0; (rectangle.width as usize) *
                                                     (rectangle.height as usize) *
                                                     (format.bits_per_pixel as usize / 8)];
                            try!(stream.read_exact(&mut pixels));
                            ClientEvent::PutPixels(Rect {
                                left:   rectangle.x_position,
                                top:    rectangle.y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            }, pixels)
                        },
                        protocol::Encoding::CopyRect => {
                            let copy_rect = try!(protocol::CopyRect::read_from(stream));
                            let src = Rect {
                                left:   copy_rect.src_x_position,
                                top:    copy_rect.src_y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            };
                            let dst = Rect {
                                left:   rectangle.x_position,
                                top:    rectangle.y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            };
                            ClientEvent::CopyPixels { src: src, dst: dst }
                        },
                        protocol::Encoding::Cursor => {
                            let mut pixels    = vec![0; (rectangle.width as usize) *
                                                        (rectangle.height as usize) *
                                                        (format.bits_per_pixel as usize / 8)];
                            try!(stream.read_exact(&mut pixels));
                            let mut mask_bits = vec![0; ((rectangle.width as usize + 7) / 8) *
                                                        (rectangle.height as usize)];
                            try!(stream.read_exact(&mut mask_bits));
                            ClientEvent::SetCursor {
                                size:      (rectangle.width, rectangle.height),
                                hotspot:   (rectangle.x_position, rectangle.y_position),
                                pixels:    pixels,
                                mask_bits: mask_bits
                            }
                        },
                        protocol::Encoding::DesktopSize =>
                            ClientEvent::Resize(rectangle.width, rectangle.height),
                        _ => return Err(Error::UnexpectedValue("encoding"))
                    };
                    send_or_return!(tx_events, event)
                }
            },
            protocol::S2C::Bell =>
                send_or_return!(tx_events, ClientEvent::Bell),
            protocol::S2C::CutText(text) =>
                send_or_return!(tx_events, ClientEvent::Clipboard(text)),
            _ => return Err(Error::UnexpectedValue("server to client packet"))
        };
        Ok(())
    }

    fn pump(mut stream: TcpStream, format: protocol::PixelFormat) -> Receiver<ClientEvent> {
        let (mut tx_events, rx_events) = channel();
        thread::spawn(move || {
            loop {
                match ClientEvent::pump_one(&mut stream, &format, &mut tx_events) {
                    Ok(()) => (),
                    Err(Error::UnexpectedEOF) => break,
                    Err(error) => panic!("cannot pump VNC client events: {}", error)
                }
            }
        });
        rx_events
    }
}

pub struct ClientBuilder {
    shared:       bool,
    copy_rect:    bool,
    set_cursor:   bool,
    resize:       bool,
}

impl ClientBuilder {
    pub fn new() -> ClientBuilder {
        ClientBuilder {
            shared:       false,
            copy_rect:    false,
            set_cursor:   false,
            resize:       false,
        }
    }

    pub fn shared    (mut self, value: bool) -> ClientBuilder { self.shared = value; self }
    pub fn copy_rect (mut self, value: bool) -> ClientBuilder { self.copy_rect = value; self }
    pub fn set_cursor(mut self, value: bool) -> ClientBuilder { self.set_cursor = value; self }
    pub fn resize    (mut self, value: bool) -> ClientBuilder { self.resize = value; self }

    pub fn from_tcp_stream<Auth>(self, mut stream: TcpStream, auth: Auth) -> Result<Client>
            where Auth: FnOnce(&[AuthMethod]) -> Option<AuthChoice> {
        let version = try!(protocol::Version::read_from(&mut stream));
        debug!("<- Version::{:?}", version);
        debug!("-> Version::{:?}", version);
        try!(protocol::Version::write_to(&version, &mut stream));

        let security_types = match version {
            Version::Rfb33 => {
                let security_type = try!(protocol::SecurityType::read_from(&mut stream));
                debug!("<- SecurityType::{:?}", security_type);
                if security_type == protocol::SecurityType::Invalid {
                    let reason = try!(String::read_from(&mut stream));
                    debug!("<- {:?}", reason);
                    return Err(Error::Server(reason))
                }
                vec![security_type]
            },
            _ => {
                let security_types = try!(protocol::SecurityTypes::read_from(&mut stream));
                debug!("<- {:?}", security_types);
                if security_types.0.len() == 0 {
                    let reason = try!(String::read_from(&mut stream));
                    debug!("<- {:?}", reason);
                    return Err(Error::Server(reason))
                }
                security_types.0
            }
        };

        let mut auth_methods = Vec::new();
        for security_type in security_types {
            match security_type {
                protocol::SecurityType::None =>
                    auth_methods.push(AuthMethod::None),
                _ => ()
            }
        }

        let auth_choice = try!(auth(&auth_methods).ok_or(Error::AuthenticationUnavailable));

        match version {
            Version::Rfb33 => (),
            _ => {
                let used_security_type = match auth_choice {
                    AuthChoice::None => protocol::SecurityType::None,
                };
                debug!("-> SecurityType::{:?}", used_security_type);
                try!(protocol::SecurityType::write_to(&used_security_type, &mut stream));
            }
        }

        let mut skip_security_result = false;
        match &(auth_choice, version) {
            &(AuthChoice::None, Version::Rfb33) |
            &(AuthChoice::None, Version::Rfb37) => skip_security_result = true,
            _ => ()
        }

        if !skip_security_result {
            let security_result = try!(protocol::SecurityResult::read_from(&mut stream));
            if security_result == protocol::SecurityResult::Failed {
                match version {
                    Version::Rfb33 | Version::Rfb37 =>
                        return Err(Error::AuthenticationFailure(String::from(""))),
                    Version::Rfb38 => {
                        let reason = try!(String::read_from(&mut stream));
                        debug!("<- {:?}", reason);
                        return Err(Error::AuthenticationFailure(reason))
                    }
                }
            }
        }

        let client_init = protocol::ClientInit { shared: self.shared };
        debug!("-> {:?}", client_init);
        try!(protocol::ClientInit::write_to(&client_init, &mut stream));

        let server_init = try!(protocol::ServerInit::read_from(&mut stream));
        debug!("<- {:?}", server_init);

        let events = ClientEvent::pump(stream.try_clone().unwrap(),
                                       server_init.pixel_format.clone());

        let mut encodings = vec![protocol::Encoding::Raw];
        if self.copy_rect  { encodings.push(protocol::Encoding::CopyRect) }
        if self.set_cursor { encodings.push(protocol::Encoding::Cursor) }
        if self.resize     { encodings.push(protocol::Encoding::DesktopSize) }

        let set_encodings = protocol::C2S::SetEncodings(encodings);
        debug!("-> {:?}", set_encodings);
        try!(protocol::C2S::write_to(&set_encodings, &mut stream));

        Ok(Client {
            stream:  stream,
            events:  events,
            version: version,
            name:    server_init.name,
            size:    (server_init.framebuffer_width, server_init.framebuffer_height),
            format:  server_init.pixel_format
        })
    }
}

pub struct Client {
    stream:  TcpStream,
    events:  Receiver<ClientEvent>,
    version: Version,
    name:    String,
    size:    (u16, u16),
    format:  PixelFormat
}

impl Client {
    pub fn version(&self) -> Version { self.version }
    pub fn name(&self) -> &str { &self.name }
    pub fn size(&self) -> (u16, u16) { self.size }
    pub fn format(&self) -> PixelFormat { self.format.clone() }

    fn enable_encodings(&mut self, encodings: &[protocol::Encoding]) -> Result<()> {
        let set_encodings = protocol::C2S::SetEncodings(Vec::from(encodings));
        debug!("-> {:?}", set_encodings);
        try!(protocol::C2S::write_to(&set_encodings, &mut self.stream));
        Ok(())
    }

    pub fn enable_copy_pixels(&mut self) -> Result<()> {
        self.enable_encodings(&[protocol::Encoding::CopyRect])
    }

    pub fn enable_cursor(&mut self) -> Result<()> {
        self.enable_encodings(&[protocol::Encoding::Cursor])
    }

    pub fn enable_resize(&mut self) -> Result<()> {
        self.enable_encodings(&[protocol::Encoding::DesktopSize])
    }

    pub fn request_update(&mut self, rect: Rect, incremental: bool) -> Result<()> {
        let update_req = protocol::C2S::FramebufferUpdateRequest {
            incremental: incremental,
            x_position:  rect.left,
            y_position:  rect.top,
            width:       rect.width,
            height:      rect.height
        };
        trace!("-> {:?}", update_req);
        try!(protocol::C2S::write_to(&update_req, &mut self.stream));
        Ok(())
    }

    pub fn send_key_event(&mut self, down: bool, key: u32) -> Result<()> {
        let key_event = protocol::C2S::KeyEvent {
            down: down,
            key:  key
        };
        debug!("-> {:?}", key_event);
        try!(protocol::C2S::write_to(&key_event, &mut self.stream));
        Ok(())
    }

    pub fn send_pointer_event(&mut self, buttons: u8, x: u16, y: u16) -> Result<()> {
        let pointer_event = protocol::C2S::PointerEvent {
            button_mask: buttons,
            x_position:  x,
            y_position:  y
        };
        debug!("-> {:?}", pointer_event);
        try!(protocol::C2S::write_to(&pointer_event, &mut self.stream));
        Ok(())
    }

    pub fn update_clipboard(&mut self, text: &str) -> Result<()> {
        let cut_text = protocol::C2S::CutText(String::from(text));
        debug!("-> {:?}", cut_text);
        try!(protocol::C2S::write_to(&cut_text, &mut self.stream));
        Ok(())
    }

    pub fn poll_event(&mut self) -> Option<ClientEvent> {
        match self.events.try_recv() {
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => Some(ClientEvent::Disconnected),
            Ok(ClientEvent::Resize(width, height)) => {
                self.size = (width, height);
                Some(ClientEvent::Resize(width, height))
            }
            Ok(event) => Some(event)
        }
    }

    pub fn poll_iter(&mut self) -> ClientEventPollIterator {
        ClientEventPollIterator { client: self }
    }

    pub fn disconnect(self) -> Result<()> {
        try!(self.stream.shutdown(Shutdown::Both));
        Ok(())
    }
}

pub struct ClientEventPollIterator<'a> {
    client:  &'a mut Client
}

impl<'a> Iterator for ClientEventPollIterator<'a> {
    type Item = ClientEvent;

    fn next(&mut self) -> Option<Self::Item> { self.client.poll_event() }
}
<commit_msg>Remove useless functions.<commit_after>// https://github.com/rust-lang/rust/issues/27585;
// after that, https://github.com/BurntSushi/byteorder/pull/40.
#![feature(read_exact)]

#[macro_use] extern crate log;
extern crate byteorder;

mod protocol;

pub use protocol::{Error, Result, Version, PixelFormat};

use std::io::Read;
use std::net::{TcpStream, Shutdown};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use protocol::Message;

#[derive(Debug)]
pub enum AuthMethod {
    None,
    /* more to come */
    Unused
}

#[derive(Debug)]
pub enum AuthChoice {
    None,
    /* more to come */
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Rect {
    pub left:   u16,
    pub top:    u16,
    pub width:  u16,
    pub height: u16
}

#[derive(Debug)]
pub enum ClientEvent {
    Disconnected,
    Resize(u16, u16),
    PutPixels(Rect, Vec<u8>),
    CopyPixels { src: Rect, dst: Rect },
    SetCursor { size: (u16, u16), hotspot: (u16, u16), pixels: Vec<u8>, mask_bits: Vec<u8> },
    Clipboard(String),
    Bell,
}

macro_rules! send_or_return {
    ($chan:expr, $data:expr) => ({
        match $chan.send($data) {
            Ok(()) => (),
            Err(_) => return Err(Error::UnexpectedEOF)
        }
    })
}

impl ClientEvent {
    fn pump_one(stream: &mut TcpStream, format: &protocol::PixelFormat,
                tx_events: &mut Sender<ClientEvent>) -> Result<()> {
        let packet = try!(protocol::S2C::read_from(stream));
        debug!("<- {:?}", packet);
        match packet {
            protocol::S2C::FramebufferUpdate { count } => {
                for _ in 0..count {
                    let rectangle = try!(protocol::Rectangle::read_from(stream));
                    debug!("<- {:?}", rectangle);
                    let event = match rectangle.encoding {
                        protocol::Encoding::Raw => {
                            let mut pixels = vec![0; (rectangle.width as usize) *
                                                     (rectangle.height as usize) *
                                                     (format.bits_per_pixel as usize / 8)];
                            try!(stream.read_exact(&mut pixels));
                            ClientEvent::PutPixels(Rect {
                                left:   rectangle.x_position,
                                top:    rectangle.y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            }, pixels)
                        },
                        protocol::Encoding::CopyRect => {
                            let copy_rect = try!(protocol::CopyRect::read_from(stream));
                            let src = Rect {
                                left:   copy_rect.src_x_position,
                                top:    copy_rect.src_y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            };
                            let dst = Rect {
                                left:   rectangle.x_position,
                                top:    rectangle.y_position,
                                width:  rectangle.width,
                                height: rectangle.height
                            };
                            ClientEvent::CopyPixels { src: src, dst: dst }
                        },
                        protocol::Encoding::Cursor => {
                            let mut pixels    = vec![0; (rectangle.width as usize) *
                                                        (rectangle.height as usize) *
                                                        (format.bits_per_pixel as usize / 8)];
                            try!(stream.read_exact(&mut pixels));
                            let mut mask_bits = vec![0; ((rectangle.width as usize + 7) / 8) *
                                                        (rectangle.height as usize)];
                            try!(stream.read_exact(&mut mask_bits));
                            ClientEvent::SetCursor {
                                size:      (rectangle.width, rectangle.height),
                                hotspot:   (rectangle.x_position, rectangle.y_position),
                                pixels:    pixels,
                                mask_bits: mask_bits
                            }
                        },
                        protocol::Encoding::DesktopSize =>
                            ClientEvent::Resize(rectangle.width, rectangle.height),
                        _ => return Err(Error::UnexpectedValue("encoding"))
                    };
                    send_or_return!(tx_events, event)
                }
            },
            protocol::S2C::Bell =>
                send_or_return!(tx_events, ClientEvent::Bell),
            protocol::S2C::CutText(text) =>
                send_or_return!(tx_events, ClientEvent::Clipboard(text)),
            _ => return Err(Error::UnexpectedValue("server to client packet"))
        };
        Ok(())
    }

    fn pump(mut stream: TcpStream, format: protocol::PixelFormat) -> Receiver<ClientEvent> {
        let (mut tx_events, rx_events) = channel();
        thread::spawn(move || {
            loop {
                match ClientEvent::pump_one(&mut stream, &format, &mut tx_events) {
                    Ok(()) => (),
                    Err(Error::UnexpectedEOF) => break,
                    Err(error) => panic!("cannot pump VNC client events: {}", error)
                }
            }
        });
        rx_events
    }
}

pub struct ClientBuilder {
    shared:       bool,
    copy_rect:    bool,
    set_cursor:   bool,
    resize:       bool,
}

impl ClientBuilder {
    pub fn new() -> ClientBuilder {
        ClientBuilder {
            shared:       false,
            copy_rect:    false,
            set_cursor:   false,
            resize:       false,
        }
    }

    pub fn shared    (mut self, value: bool) -> ClientBuilder { self.shared = value; self }
    pub fn copy_rect (mut self, value: bool) -> ClientBuilder { self.copy_rect = value; self }
    pub fn set_cursor(mut self, value: bool) -> ClientBuilder { self.set_cursor = value; self }
    pub fn resize    (mut self, value: bool) -> ClientBuilder { self.resize = value; self }

    pub fn from_tcp_stream<Auth>(self, mut stream: TcpStream, auth: Auth) -> Result<Client>
            where Auth: FnOnce(&[AuthMethod]) -> Option<AuthChoice> {
        let version = try!(protocol::Version::read_from(&mut stream));
        debug!("<- Version::{:?}", version);
        debug!("-> Version::{:?}", version);
        try!(protocol::Version::write_to(&version, &mut stream));

        let security_types = match version {
            Version::Rfb33 => {
                let security_type = try!(protocol::SecurityType::read_from(&mut stream));
                debug!("<- SecurityType::{:?}", security_type);
                if security_type == protocol::SecurityType::Invalid {
                    let reason = try!(String::read_from(&mut stream));
                    debug!("<- {:?}", reason);
                    return Err(Error::Server(reason))
                }
                vec![security_type]
            },
            _ => {
                let security_types = try!(protocol::SecurityTypes::read_from(&mut stream));
                debug!("<- {:?}", security_types);
                if security_types.0.len() == 0 {
                    let reason = try!(String::read_from(&mut stream));
                    debug!("<- {:?}", reason);
                    return Err(Error::Server(reason))
                }
                security_types.0
            }
        };

        let mut auth_methods = Vec::new();
        for security_type in security_types {
            match security_type {
                protocol::SecurityType::None =>
                    auth_methods.push(AuthMethod::None),
                _ => ()
            }
        }

        let auth_choice = try!(auth(&auth_methods).ok_or(Error::AuthenticationUnavailable));

        match version {
            Version::Rfb33 => (),
            _ => {
                let used_security_type = match auth_choice {
                    AuthChoice::None => protocol::SecurityType::None,
                };
                debug!("-> SecurityType::{:?}", used_security_type);
                try!(protocol::SecurityType::write_to(&used_security_type, &mut stream));
            }
        }

        let mut skip_security_result = false;
        match &(auth_choice, version) {
            &(AuthChoice::None, Version::Rfb33) |
            &(AuthChoice::None, Version::Rfb37) => skip_security_result = true,
            _ => ()
        }

        if !skip_security_result {
            let security_result = try!(protocol::SecurityResult::read_from(&mut stream));
            if security_result == protocol::SecurityResult::Failed {
                match version {
                    Version::Rfb33 | Version::Rfb37 =>
                        return Err(Error::AuthenticationFailure(String::from(""))),
                    Version::Rfb38 => {
                        let reason = try!(String::read_from(&mut stream));
                        debug!("<- {:?}", reason);
                        return Err(Error::AuthenticationFailure(reason))
                    }
                }
            }
        }

        let client_init = protocol::ClientInit { shared: self.shared };
        debug!("-> {:?}", client_init);
        try!(protocol::ClientInit::write_to(&client_init, &mut stream));

        let server_init = try!(protocol::ServerInit::read_from(&mut stream));
        debug!("<- {:?}", server_init);

        let events = ClientEvent::pump(stream.try_clone().unwrap(),
                                       server_init.pixel_format.clone());

        let mut encodings = vec![protocol::Encoding::Raw];
        if self.copy_rect  { encodings.push(protocol::Encoding::CopyRect) }
        if self.set_cursor { encodings.push(protocol::Encoding::Cursor) }
        if self.resize     { encodings.push(protocol::Encoding::DesktopSize) }

        let set_encodings = protocol::C2S::SetEncodings(encodings);
        debug!("-> {:?}", set_encodings);
        try!(protocol::C2S::write_to(&set_encodings, &mut stream));

        Ok(Client {
            stream:  stream,
            events:  events,
            version: version,
            name:    server_init.name,
            size:    (server_init.framebuffer_width, server_init.framebuffer_height),
            format:  server_init.pixel_format
        })
    }
}

pub struct Client {
    stream:  TcpStream,
    events:  Receiver<ClientEvent>,
    version: Version,
    name:    String,
    size:    (u16, u16),
    format:  PixelFormat
}

impl Client {
    pub fn version(&self) -> Version { self.version }
    pub fn name(&self) -> &str { &self.name }
    pub fn size(&self) -> (u16, u16) { self.size }
    pub fn format(&self) -> PixelFormat { self.format.clone() }

    pub fn request_update(&mut self, rect: Rect, incremental: bool) -> Result<()> {
        let update_req = protocol::C2S::FramebufferUpdateRequest {
            incremental: incremental,
            x_position:  rect.left,
            y_position:  rect.top,
            width:       rect.width,
            height:      rect.height
        };
        trace!("-> {:?}", update_req);
        try!(protocol::C2S::write_to(&update_req, &mut self.stream));
        Ok(())
    }

    pub fn send_key_event(&mut self, down: bool, key: u32) -> Result<()> {
        let key_event = protocol::C2S::KeyEvent {
            down: down,
            key:  key
        };
        debug!("-> {:?}", key_event);
        try!(protocol::C2S::write_to(&key_event, &mut self.stream));
        Ok(())
    }

    pub fn send_pointer_event(&mut self, buttons: u8, x: u16, y: u16) -> Result<()> {
        let pointer_event = protocol::C2S::PointerEvent {
            button_mask: buttons,
            x_position:  x,
            y_position:  y
        };
        debug!("-> {:?}", pointer_event);
        try!(protocol::C2S::write_to(&pointer_event, &mut self.stream));
        Ok(())
    }

    pub fn update_clipboard(&mut self, text: &str) -> Result<()> {
        let cut_text = protocol::C2S::CutText(String::from(text));
        debug!("-> {:?}", cut_text);
        try!(protocol::C2S::write_to(&cut_text, &mut self.stream));
        Ok(())
    }

    pub fn poll_event(&mut self) -> Option<ClientEvent> {
        match self.events.try_recv() {
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => Some(ClientEvent::Disconnected),
            Ok(ClientEvent::Resize(width, height)) => {
                self.size = (width, height);
                Some(ClientEvent::Resize(width, height))
            }
            Ok(event) => Some(event)
        }
    }

    pub fn poll_iter(&mut self) -> ClientEventPollIterator {
        ClientEventPollIterator { client: self }
    }

    pub fn disconnect(self) -> Result<()> {
        try!(self.stream.shutdown(Shutdown::Both));
        Ok(())
    }
}

pub struct ClientEventPollIterator<'a> {
    client:  &'a mut Client
}

impl<'a> Iterator for ClientEventPollIterator<'a> {
    type Item = ClientEvent;

    fn next(&mut self) -> Option<Self::Item> { self.client.poll_event() }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv;

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *const *mut PamHandle) -> c_int;

    pub fn pam_end(pamh: *mut PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<commit_msg>Testing a changed signature<commit_after>extern crate libc;

use libc::{c_char, c_int};

#[repr(C)]
#[derive(Copy)]
pub struct PamHandle;

#[repr(C)]
#[derive(Copy)]
pub struct PamConv;

extern "C" {
    /* --------------             pam_appl.h            ------------- */
    /* -------------- The Linux-PAM Framework layer API ------------- */

    pub fn pam_start(service_name: *const c_char, user: *const c_char,
        pam_conversation: *const PamConv, pamh: *const PamHandle) -> c_int;

    pub fn pam_end(pamh: *mut PamHandle, pam_status: c_int) -> c_int;

    /* Authentication API's */
    pub fn pam_authenticate(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_setcred(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Account Management API's */
    pub fn pam_acct_mgmt(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Session Management API's */
    pub fn pam_open_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    pub fn pam_close_session(pamh: *mut PamHandle, flags: c_int) -> c_int;

    /* Password Management API's */
    pub fn pam_chauthtok(pamh: *mut PamHandle, flags: c_int) -> c_int;
}
<|endoftext|>