<commit_before>//! Module for working with the prime-counting function.
//!
//! This module has functions for computing the value of
//! the prime-counting function for both single and multiple
//! values.

use super::prime::prime_sieve;

/// Return the number of prime numbers less than or equal to `x`.
///
/// This function works by using a lookup table if `x` is very small
/// (less than 100), and otherwise using a recursive version of
/// Lehmer's Formula.
///
/// Note that this function can take a very long time to produce a result
/// if `x` is very large.
///
/// If multiple values of the prime-counting function are being calculated,
/// `prime_count_all()` is a better choice because it preserves its caches
/// between calculations. See the documentation for `prime_count_all` for
/// more information.
///
/// # Panics
///
/// Panics if `prime_sieve()` panics, see the documentation of
/// `prime_sieve()` for more information.
///
/// # Examples
///
/// ```
/// use reikna::prime_count::prime_count;
/// assert_eq!(prime_count(1_000), 168);
/// assert_eq!(prime_count(10_000), 1_229);
/// ```
pub fn prime_count(x: u64) -> u64 {
    match x {
        0 | 1 => 0,
        2     => 1,
        3 | 4 => 2,
        5     => 3,
        _     => lehmer(x, &prime_sieve((x as f64).sqrt() as u64 + 1),
                        &mut vec![vec![0u64; CACHE_SIZE]; CACHE_SIZE]),
    }
}

/// Calculate the value of the prime-counting function for each
/// value in `data`, and return a new `Vec<u64>` of the results.
///
/// The resulting vector has the same size as the input vector.
///
/// This function works in fundamentally the same way as `prime_count()`,
/// with the modification that caches are preserved between calculations.
/// This allows for much faster computation of multiple values.
///
/// # Panics
///
/// Panics if `prime_sieve()` panics, see the documentation of
/// `prime_sieve()` for more information.
///
/// # Examples
///
/// ```
/// use reikna::prime_count::prime_count_all;
/// assert_eq!(prime_count_all(&vec![1, 2, 3]), vec![0, 1, 2]);
/// assert_eq!(prime_count_all(&vec![100]), vec![25]);
/// ```
pub fn prime_count_all(data: &Vec<u64>) -> Vec<u64> {
    if data.len() == 0 {
        return Vec::new();
    }

    let mut counts: Vec<u64> = Vec::new();
    let mut phi_cache = vec![vec![0u64; CACHE_SIZE]; CACHE_SIZE];

    let mut largest_index = 0;
    let mut largest_val = 0;
    for i in 0..data.len() {
        if data[i] > largest_val {
            largest_index = i;
            largest_val = data[i];
        }
    }

    let primes = prime_sieve((data[largest_index] as f64).sqrt() as u64 + 1);
    let max_val = lehmer(largest_val, &primes, &mut phi_cache);

    for i in 0..data.len() {
        if i == largest_index {
            counts.push(max_val);
            continue;
        }

        match data[i] < 6 {
            true  => counts.push(prime_count(data[i])),
            false => counts.push(lehmer(data[i], &primes, &mut phi_cache)),
        }
    }

    counts
}

const CACHE_SIZE: usize = 1024;
type CacheT = Vec<Vec<u64>>;

const SMALL_PI: [u64; 100] =
[0 , 0 , 1 , 2 , 2 , 3 , 3 , 4 , 4 , 4 ,
 4 , 5 , 5 , 6 , 6 , 6 , 6 , 7 , 7 , 8 ,
 8 , 8 , 8 , 9 , 9 , 9 , 9 , 9 , 9 , 10,
 10, 11, 11, 11, 11, 11, 11, 12, 12, 12,
 12, 13, 13, 14, 14, 14, 14, 15, 15, 15,
 15, 15, 15, 16, 16, 16, 16, 16, 16, 17,
 17, 18, 18, 18, 18, 18, 18, 19, 19, 19,
 19, 20, 20, 21, 21, 21, 21, 21, 21, 22,
 22, 22, 22, 23, 23, 23, 23, 23, 23, 24,
 24, 24, 24, 24, 24, 24, 24, 25, 25, 25];

fn lehmer(x: u64, primes: &Vec<u64>, phi_cache: &mut CacheT) -> u64 {
    if x < 100 {
        return SMALL_PI[x as usize];
    }

    if x < primes[primes.len() - 1] {
        return num_below(x, primes);
    }

    let a = lehmer((x as f64).powf(0.25).round() as u64,
                     primes, phi_cache) + 1;
    let b = lehmer((x as f64).sqrt().round() as u64,
                         primes, phi_cache) + 1;
    let c = lehmer((x as f64).cbrt().round() as u64,
                     primes, phi_cache);

    let mut pi = phi(x, a - 1, primes, phi_cache) +
                 ((b + a - 4) * (b - a + 1)) / 2;

    for i in a..b {
        let x_tmp = x / primes[i as usize - 1];
        pi -= lehmer(x_tmp, primes, phi_cache);

        if i > c {
            continue;
        }

        let bi = lehmer((x_tmp as f64).sqrt() as u64, primes, phi_cache) + 1;
        for j in i..bi {
            pi += j - 1;
            pi -= lehmer(x_tmp / primes[j as usize - 1], primes, phi_cache);
        }
    }

    pi
}

fn phi(m: u64, n: u64, primes: &Vec<u64>, cache: &mut CacheT) -> u64 {
    if n == 0 || m == 0 {
        return m;
    }

    if n == 1 {
        return (m + 1) / 2;
    }

    if m <= primes[n as usize - 1] {
        return 1;
    }

    if m < CACHE_SIZE as u64 && n < CACHE_SIZE as u64 {
        if cache[m as usize][n as usize] == 0 {
            let val = phi(m, n - 1, primes, cache) -
                      phi(m / primes[n as usize - 1], n - 1, primes, cache);
            cache[m as usize][n as usize] = val;
        }

        return cache[m as usize][n as usize];
    }

    phi(m, n - 1, primes, cache) -
    phi(m / primes[n as usize - 1], n - 1, primes, cache)
}

fn num_below(x: u64, vec: &Vec<u64>) -> u64 {
    for i in 0..vec.len() {
        if vec[i] > x {
            return i as u64;
        }
    }

    vec.len() as u64
}

#[cfg(test)]
mod tests {

    use super::*;

#[test]
    fn t_prime_count() {
        assert_eq!(prime_count(0), 0);
        assert_eq!(prime_count(1), 0);
        assert_eq!(prime_count(2), 1);
        assert_eq!(prime_count(5), 3);
        assert_eq!(prime_count(10), 4);
        assert_eq!(prime_count(100), 25);
        assert_eq!(prime_count(1_000_000), 78_498);
        assert_eq!(prime_count(10_000_000), 664_579);
    }

#[test]
    fn t_prime_count_all() {
        assert_eq!(prime_count_all(&vec![0; 0]), vec![0; 0]);
        assert_eq!(prime_count_all(&vec![1, 2, 3, 4]), vec![0, 1, 2, 2]);
        assert_eq!(prime_count_all(&vec![10, 100, 1_000]), vec![4, 25, 168]);
        assert_eq!(prime_count_all(&vec![1, 2, 3, 4, 5, 6]).len(), 6);
    }

}
<commit_msg>add pi symbol to prime_count<commit_after>//! Module for working with the prime-counting function.
//!
//! This module has functions for computing the value of
//! the prime-counting function for both single and multiple
//! values.

use super::prime::prime_sieve;

/// Constant string of the uppercase Pi symbol,
/// often used to represent the prime-counting function.
pub const PI_SYMBOL: &'static str = "π";

/// Return the number of prime numbers less than or equal to `x`.
///
/// This function works by using a lookup table if `x` is very small
/// (less than 100), and otherwise using a recursive version of
/// Lehmer's Formula.
///
/// Note that this function can take a very long time to produce a result
/// if `x` is very large.
///
/// If multiple values of the prime-counting function are being calculated,
/// `prime_count_all()` is a better choice because it preserves its caches
/// between calculations. See the documentation for `prime_count_all` for
/// more information.
///
/// # Panics
///
/// Panics if `prime_sieve()` panics, see the documentation of
/// `prime_sieve()` for more information.
///
/// # Examples
///
/// ```
/// use reikna::prime_count::prime_count;
/// assert_eq!(prime_count(1_000), 168);
/// assert_eq!(prime_count(10_000), 1_229);
/// ```
pub fn prime_count(x: u64) -> u64 {
    match x {
        0 | 1 => 0,
        2     => 1,
        3 | 4 => 2,
        5     => 3,
        _     => lehmer(x, &prime_sieve((x as f64).sqrt() as u64 + 1),
                        &mut vec![vec![0u64; CACHE_SIZE]; CACHE_SIZE]),
    }
}

/// Calculate the value of the prime-counting function for each
/// value in `data`, and return a new `Vec<u64>` of the results.
///
/// The resulting vector has the same size as the input vector.
///
/// This function works in fundamentally the same way as `prime_count()`,
/// with the modification that caches are preserved between calculations.
/// This allows for much faster computation of multiple values.
///
/// # Panics
///
/// Panics if `prime_sieve()` panics, see the documentation of
/// `prime_sieve()` for more information.
///
/// # Examples
///
/// ```
/// use reikna::prime_count::prime_count_all;
/// assert_eq!(prime_count_all(&vec![1, 2, 3]), vec![0, 1, 2]);
/// assert_eq!(prime_count_all(&vec![100]), vec![25]);
/// ```
pub fn prime_count_all(data: &Vec<u64>) -> Vec<u64> {
    if data.len() == 0 {
        return Vec::new();
    }

    let mut counts: Vec<u64> = Vec::new();
    let mut phi_cache = vec![vec![0u64; CACHE_SIZE]; CACHE_SIZE];

    let mut largest_index = 0;
    let mut largest_val = 0;
    for i in 0..data.len() {
        if data[i] > largest_val {
            largest_index = i;
            largest_val = data[i];
        }
    }

    let primes = prime_sieve((data[largest_index] as f64).sqrt() as u64 + 1);
    let max_val = lehmer(largest_val, &primes, &mut phi_cache);

    for i in 0..data.len() {
        if i == largest_index {
            counts.push(max_val);
            continue;
        }

        match data[i] < 6 {
            true  => counts.push(prime_count(data[i])),
            false => counts.push(lehmer(data[i], &primes, &mut phi_cache)),
        }
    }

    counts
}

const CACHE_SIZE: usize = 1024;
type CacheT = Vec<Vec<u64>>;

const SMALL_PI: [u64; 100] =
[0 , 0 , 1 , 2 , 2 , 3 , 3 , 4 , 4 , 4 ,
 4 , 5 , 5 , 6 , 6 , 6 , 6 , 7 , 7 , 8 ,
 8 , 8 , 8 , 9 , 9 , 9 , 9 , 9 , 9 , 10,
 10, 11, 11, 11, 11, 11, 11, 12, 12, 12,
 12, 13, 13, 14, 14, 14, 14, 15, 15, 15,
 15, 15, 15, 16, 16, 16, 16, 16, 16, 17,
 17, 18, 18, 18, 18, 18, 18, 19, 19, 19,
 19, 20, 20, 21, 21, 21, 21, 21, 21, 22,
 22, 22, 22, 23, 23, 23, 23, 23, 23, 24,
 24, 24, 24, 24, 24, 24, 24, 25, 25, 25];

fn lehmer(x: u64, primes: &Vec<u64>, phi_cache: &mut CacheT) -> u64 {
    if x < 100 {
        return SMALL_PI[x as usize];
    }

    if x < primes[primes.len() - 1] {
        return num_below(x, primes);
    }

    let a = lehmer((x as f64).powf(0.25).round() as u64,
                     primes, phi_cache) + 1;
    let b = lehmer((x as f64).sqrt().round() as u64,
                         primes, phi_cache) + 1;
    let c = lehmer((x as f64).cbrt().round() as u64,
                     primes, phi_cache);

    let mut pi = phi(x, a - 1, primes, phi_cache) +
                 ((b + a - 4) * (b - a + 1)) / 2;

    for i in a..b {
        let x_tmp = x / primes[i as usize - 1];
        pi -= lehmer(x_tmp, primes, phi_cache);

        if i > c {
            continue;
        }

        let bi = lehmer((x_tmp as f64).sqrt() as u64, primes, phi_cache) + 1;
        for j in i..bi {
            pi += j - 1;
            pi -= lehmer(x_tmp / primes[j as usize - 1], primes, phi_cache);
        }
    }

    pi
}

fn phi(m: u64, n: u64, primes: &Vec<u64>, cache: &mut CacheT) -> u64 {
    if n == 0 || m == 0 {
        return m;
    }

    if n == 1 {
        return (m + 1) / 2;
    }

    if m <= primes[n as usize - 1] {
        return 1;
    }

    if m < CACHE_SIZE as u64 && n < CACHE_SIZE as u64 {
        if cache[m as usize][n as usize] == 0 {
            let val = phi(m, n - 1, primes, cache) -
                      phi(m / primes[n as usize - 1], n - 1, primes, cache);
            cache[m as usize][n as usize] = val;
        }

        return cache[m as usize][n as usize];
    }

    phi(m, n - 1, primes, cache) -
    phi(m / primes[n as usize - 1], n - 1, primes, cache)
}

fn num_below(x: u64, vec: &Vec<u64>) -> u64 {
    for i in 0..vec.len() {
        if vec[i] > x {
            return i as u64;
        }
    }

    vec.len() as u64
}

#[cfg(test)]
mod tests {

    use super::*;

#[test]
    fn t_prime_count() {
        assert_eq!(prime_count(0), 0);
        assert_eq!(prime_count(1), 0);
        assert_eq!(prime_count(2), 1);
        assert_eq!(prime_count(5), 3);
        assert_eq!(prime_count(10), 4);
        assert_eq!(prime_count(100), 25);
        assert_eq!(prime_count(1_000_000), 78_498);
        assert_eq!(prime_count(10_000_000), 664_579);
    }

#[test]
    fn t_prime_count_all() {
        assert_eq!(prime_count_all(&vec![0; 0]), vec![0; 0]);
        assert_eq!(prime_count_all(&vec![1, 2, 3, 4]), vec![0, 1, 2, 2]);
        assert_eq!(prime_count_all(&vec![10, 100, 1_000]), vec![4, 25, 168]);
        assert_eq!(prime_count_all(&vec![1, 2, 3, 4, 5, 6]).len(), 6);
    }

}
<|endoftext|>


<commit_before>use std::fmt;

use super::Field;
use crate::common;
use crate::schema::Facet;
use crate::DateTime;
use byteorder::{BigEndian, ByteOrder};
use std::str;

/// Size (in bytes) of the buffer of a int field.
const INT_TERM_LEN: usize = 4 + 8;

/// Term represents the value that the token can take.
///
/// It actually wraps a `Vec<u8>`.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct Term<B = Vec<u8>>(B)
where
    B: AsRef<[u8]>;

impl Term {
    /// Builds a term given a field, and a i64-value
    ///
    /// Assuming the term has a field id of 1, and a i64 value of 3234,
    /// the Term will have 8 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 4 following bytes are encoding the u64 value.
    pub fn from_field_i64(field: Field, val: i64) -> Term {
        let val_u64: u64 = common::i64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a f64-value
    ///
    /// Assuming the term has a field id of 1, and a u64 value of 3234,
    /// the Term will have 8 bytes. <= this is wrong
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 4 following bytes are encoding the u64 value.
    pub fn from_field_f64(field: Field, val: f64) -> Term {
        let val_u64: u64 = common::f64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a DateTime value
    ///
    /// Assuming the term has a field id of 1, and a timestamp i64 value of 3234,
    /// the Term will have 8 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 4 following bytes are encoding the DateTime as i64 timestamp value.
    pub fn from_field_date(field: Field, val: &DateTime) -> Term {
        let val_timestamp = val.timestamp();
        Term::from_field_i64(field, val_timestamp)
    }

    /// Creates a `Term` given a facet.
    pub fn from_facet(field: Field, facet: &Facet) -> Term {
        let bytes = facet.encoded_str().as_bytes();
        let buffer = Vec::with_capacity(4 + bytes.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Builds a term given a field, and a string value
    ///
    /// Assuming the term has a field id of 2, and a text value of "abc",
    /// the Term will have 4 bytes.
    /// The first byte is 2, and the three following bytes are the utf-8
    /// representation of "abc".
    pub fn from_field_text(field: Field, text: &str) -> Term {
        let buffer = Vec::with_capacity(4 + text.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_text(text);
        term
    }

    /// Builds a term given a field, and a u64-value
    ///
    /// Assuming the term has a field id of 1, and a u64 value of 3234,
    /// the Term will have 8 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 4 following bytes are encoding the u64 value.
    pub fn from_field_u64(field: Field, val: u64) -> Term {
        let mut term = Term(vec![0u8; INT_TERM_LEN]);
        term.set_field(field);
        term.set_u64(val);
        term
    }

    /// Creates a new Term for a given field.
    pub(crate) fn for_field(field: Field) -> Term {
        let mut term = Term(Vec::with_capacity(100));
        term.set_field(field);
        term
    }

    /// Returns the field.
    pub fn set_field(&mut self, field: Field) {
        if self.0.len() < 4 {
            self.0.resize(4, 0u8);
        }
        BigEndian::write_u32(&mut self.0[0..4], field.0);
    }

    /// Sets a u64 value in the term.
    ///
    /// U64 are serialized using (8-byte) BigEndian
    /// representation.
    /// The use of BigEndian has the benefit of preserving
    /// the natural order of the values.
    pub fn set_u64(&mut self, val: u64) {
        self.0.resize(INT_TERM_LEN, 0u8);
        BigEndian::write_u64(&mut self.0[4..], val);
    }

    /// Sets a `i64` value in the term.
    pub fn set_i64(&mut self, val: i64) {
        self.set_u64(common::i64_to_u64(val));
    }

    /// Sets a `f64` value in the term.
    pub fn set_f64(&mut self, val: f64) {
        self.set_u64(common::f64_to_u64(val));
    }

    fn set_bytes(&mut self, bytes: &[u8]) {
        self.0.resize(4, 0u8);
        self.0.extend(bytes);
    }

    pub(crate) fn from_field_bytes(field: Field, bytes: &[u8]) -> Term {
        let mut term = Term::for_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Set the texts only, keeping the field untouched.
    pub fn set_text(&mut self, text: &str) {
        self.set_bytes(text.as_bytes());
    }
}

impl<B> Term<B>
where
    B: AsRef<[u8]>,
{
    /// Wraps a source of data
    pub fn wrap(data: B) -> Term<B> {
        Term(data)
    }

    /// Returns the field.
    pub fn field(&self) -> Field {
        Field(BigEndian::read_u32(&self.0.as_ref()[..4]))
    }

    /// Returns the `u64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `u64` field.
    pub fn get_u64(&self) -> u64 {
        BigEndian::read_u64(&self.0.as_ref()[4..])
    }

    /// Returns the `i64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `i64` field.
    pub fn get_i64(&self) -> i64 {
        common::u64_to_i64(BigEndian::read_u64(&self.0.as_ref()[4..]))
    }

    /// Returns the `f64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `i64` field.
    pub fn get_f64(&self) -> f64 {
        common::u64_to_f64(BigEndian::read_u64(&self.0.as_ref()[4..]))
    }

    /// Returns the text associated with the term.
    ///
    /// # Panics
    /// If the value is not valid utf-8. This may happen
    /// if the index is corrupted or if you try to
    /// call this method on a non-string type.
    pub fn text(&self) -> &str {
        str::from_utf8(self.value_bytes()).expect("Term does not contain valid utf-8.")
    }

    /// Returns the serialized value of the term.
    /// (this does not include the field.)
    ///
    /// If the term is a string, its value is utf-8 encoded.
    /// If the term is a u64, its value is encoded according
    /// to `byteorder::LittleEndian`.
    pub fn value_bytes(&self) -> &[u8] {
        &self.0.as_ref()[4..]
    }

    /// Returns the underlying `&[u8]`
    pub fn as_slice(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl<B> AsRef<[u8]> for Term<B>
where
    B: AsRef<[u8]>,
{
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for Term {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Term(field={},bytes={:?})",
            self.field().0,
            self.value_bytes()
        )
    }
}

#[cfg(test)]
mod tests {

    use crate::schema::*;

    #[test]
    pub fn test_term() {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let count_field = schema_builder.add_text_field("count", STRING);
        {
            let term = Term::from_field_text(title_field, "test");
            assert_eq!(term.field(), title_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 1u8]);
            assert_eq!(&term.as_slice()[4..], "test".as_bytes());
        }
        {
            let term = Term::from_field_u64(count_field, 983u64);
            assert_eq!(term.field(), count_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 2u8]);
            assert_eq!(term.as_slice().len(), 4 + 8);
            assert_eq!(term.as_slice()[4], 0u8);
            assert_eq!(term.as_slice()[5], 0u8);
            assert_eq!(term.as_slice()[6], 0u8);
            assert_eq!(term.as_slice()[7], 0u8);
            assert_eq!(term.as_slice()[8], 0u8);
            assert_eq!(term.as_slice()[9], 0u8);
            assert_eq!(term.as_slice()[10], (933u64 / 256u64) as u8);
            assert_eq!(term.as_slice()[11], (983u64 % 256u64) as u8);
        }
    }
}
<commit_msg>fix Term documentation (#655)<commit_after>use std::fmt;

use super::Field;
use crate::common;
use crate::schema::Facet;
use crate::DateTime;
use byteorder::{BigEndian, ByteOrder};
use std::str;

/// Size (in bytes) of the buffer of a int field.
const INT_TERM_LEN: usize = 4 + 8;

/// Term represents the value that the token can take.
///
/// It actually wraps a `Vec<u8>`.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct Term<B = Vec<u8>>(B)
where
    B: AsRef<[u8]>;

impl Term {
    /// Builds a term given a field, and a i64-value
    ///
    /// Assuming the term has a field id of 1, and a i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_i64(field: Field, val: i64) -> Term {
        let val_u64: u64 = common::i64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a f64-value
    ///
    /// Assuming the term has a field id of 1, and a f64 value of 1.5,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the f64 as a u64 value.
    pub fn from_field_f64(field: Field, val: f64) -> Term {
        let val_u64: u64 = common::f64_to_u64(val);
        Term::from_field_u64(field, val_u64)
    }

    /// Builds a term given a field, and a DateTime value
    ///
    /// Assuming the term has a field id of 1, and a timestamp i64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the DateTime as i64 timestamp value.
    pub fn from_field_date(field: Field, val: &DateTime) -> Term {
        let val_timestamp = val.timestamp();
        Term::from_field_i64(field, val_timestamp)
    }

    /// Creates a `Term` given a facet.
    pub fn from_facet(field: Field, facet: &Facet) -> Term {
        let bytes = facet.encoded_str().as_bytes();
        let buffer = Vec::with_capacity(4 + bytes.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Builds a term given a field, and a string value
    ///
    /// Assuming the term has a field id of 2, and a text value of "abc",
    /// the Term will have 4 bytes.
    /// The first byte is 2, and the three following bytes are the utf-8
    /// representation of "abc".
    pub fn from_field_text(field: Field, text: &str) -> Term {
        let buffer = Vec::with_capacity(4 + text.len());
        let mut term = Term(buffer);
        term.set_field(field);
        term.set_text(text);
        term
    }

    /// Builds a term given a field, and a u64-value
    ///
    /// Assuming the term has a field id of 1, and a u64 value of 3234,
    /// the Term will have 12 bytes.
    ///
    /// The first four byte are dedicated to storing the field id as a u64.
    /// The 8 following bytes are encoding the u64 value.
    pub fn from_field_u64(field: Field, val: u64) -> Term {
        let mut term = Term(vec![0u8; INT_TERM_LEN]);
        term.set_field(field);
        term.set_u64(val);
        term
    }

    /// Creates a new Term for a given field.
    pub(crate) fn for_field(field: Field) -> Term {
        let mut term = Term(Vec::with_capacity(100));
        term.set_field(field);
        term
    }

    /// Returns the field.
    pub fn set_field(&mut self, field: Field) {
        if self.0.len() < 4 {
            self.0.resize(4, 0u8);
        }
        BigEndian::write_u32(&mut self.0[0..4], field.0);
    }

    /// Sets a u64 value in the term.
    ///
    /// U64 are serialized using (8-byte) BigEndian
    /// representation.
    /// The use of BigEndian has the benefit of preserving
    /// the natural order of the values.
    pub fn set_u64(&mut self, val: u64) {
        self.0.resize(INT_TERM_LEN, 0u8);
        BigEndian::write_u64(&mut self.0[4..], val);
    }

    /// Sets a `i64` value in the term.
    pub fn set_i64(&mut self, val: i64) {
        self.set_u64(common::i64_to_u64(val));
    }

    /// Sets a `f64` value in the term.
    pub fn set_f64(&mut self, val: f64) {
        self.set_u64(common::f64_to_u64(val));
    }

    fn set_bytes(&mut self, bytes: &[u8]) {
        self.0.resize(4, 0u8);
        self.0.extend(bytes);
    }

    pub(crate) fn from_field_bytes(field: Field, bytes: &[u8]) -> Term {
        let mut term = Term::for_field(field);
        term.set_bytes(bytes);
        term
    }

    /// Set the texts only, keeping the field untouched.
    pub fn set_text(&mut self, text: &str) {
        self.set_bytes(text.as_bytes());
    }
}

impl<B> Term<B>
where
    B: AsRef<[u8]>,
{
    /// Wraps a source of data
    pub fn wrap(data: B) -> Term<B> {
        Term(data)
    }

    /// Returns the field.
    pub fn field(&self) -> Field {
        Field(BigEndian::read_u32(&self.0.as_ref()[..4]))
    }

    /// Returns the `u64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `u64` field.
    pub fn get_u64(&self) -> u64 {
        BigEndian::read_u64(&self.0.as_ref()[4..])
    }

    /// Returns the `i64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `i64` field.
    pub fn get_i64(&self) -> i64 {
        common::u64_to_i64(BigEndian::read_u64(&self.0.as_ref()[4..]))
    }

    /// Returns the `f64` value stored in a term.
    ///
    /// # Panics
    /// ... or returns an invalid value
    /// if the term is not a `f64` field.
    pub fn get_f64(&self) -> f64 {
        common::u64_to_f64(BigEndian::read_u64(&self.0.as_ref()[4..]))
    }

    /// Returns the text associated with the term.
    ///
    /// # Panics
    /// If the value is not valid utf-8. This may happen
    /// if the index is corrupted or if you try to
    /// call this method on a non-string type.
    pub fn text(&self) -> &str {
        str::from_utf8(self.value_bytes()).expect("Term does not contain valid utf-8.")
    }

    /// Returns the serialized value of the term.
    /// (this does not include the field.)
    ///
    /// If the term is a string, its value is utf-8 encoded.
    /// If the term is a u64, its value is encoded according
    /// to `byteorder::LittleEndian`.
    pub fn value_bytes(&self) -> &[u8] {
        &self.0.as_ref()[4..]
    }

    /// Returns the underlying `&[u8]`
    pub fn as_slice(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl<B> AsRef<[u8]> for Term<B>
where
    B: AsRef<[u8]>,
{
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for Term {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Term(field={},bytes={:?})",
            self.field().0,
            self.value_bytes()
        )
    }
}

#[cfg(test)]
mod tests {

    use crate::schema::*;

    #[test]
    pub fn test_term() {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let count_field = schema_builder.add_text_field("count", STRING);
        {
            let term = Term::from_field_text(title_field, "test");
            assert_eq!(term.field(), title_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 1u8]);
            assert_eq!(&term.as_slice()[4..], "test".as_bytes());
        }
        {
            let term = Term::from_field_u64(count_field, 983u64);
            assert_eq!(term.field(), count_field);
            assert_eq!(&term.as_slice()[0..4], &[0u8, 0u8, 0u8, 2u8]);
            assert_eq!(term.as_slice().len(), 4 + 8);
            assert_eq!(term.as_slice()[4], 0u8);
            assert_eq!(term.as_slice()[5], 0u8);
            assert_eq!(term.as_slice()[6], 0u8);
            assert_eq!(term.as_slice()[7], 0u8);
            assert_eq!(term.as_slice()[8], 0u8);
            assert_eq!(term.as_slice()[9], 0u8);
            assert_eq!(term.as_slice()[10], (933u64 / 256u64) as u8);
            assert_eq!(term.as_slice()[11], (983u64 % 256u64) as u8);
        }
    }
}
<|endoftext|>


<commit_before>use error::{Result, SassError, ErrorKind};
use evaluator::Evaluator;
use event::Event;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::mixin::{SassMixin, SassMixinParameter, SassMixinArgument};

use std::collections::HashMap;
use std::borrow::Cow::{self, Borrowed, Owned};

pub struct Substituter<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
    mixins:    HashMap<String, SassMixin<'vm>>,
}

impl<'vm, I> Substituter<'vm, I> {
    pub fn new(tokenizer: I) -> Substituter<'vm, I> {
        Substituter {
            tokenizer: tokenizer,
            variables: HashMap::new(),
            mixins:    HashMap::new(),
        }
    }

    fn replace_children_in_scope(
        &mut self,
        children: Vec<Event<'vm>>,
        passed_variables: Option<HashMap<String, ValuePart<'vm>>>,
        passed_mixins: Option<HashMap<String, SassMixin<'vm>>>) -> Result<Vec<Event<'vm>>> {

        let mut results = Vec::new();
        let mut local_variables = match passed_variables {
            Some(v) => v,
            None => self.variables.clone(),
        };
        let local_mixins = match passed_mixins {
            Some(m) => m,
            None => self.mixins.clone(),
        };

        for c in children.into_iter() {
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = try!(owned_evaluated_value(value, &local_variables));
                    debug!("variable name: {:?}, val: {:?}", name, val);
                    local_variables.insert((*name).to_string(), val);
                },
                Event::UnevaluatedProperty(name, value) => {
                    let mut ev = Evaluator::new_from_string(&value);
                    let ev_res = try!(ev.evaluate(&local_variables)).into_owned();

                    results.push(Event::Property(
                        name,
                        ev_res,
                    ));
                },
                Event::Rule(rule) => {
                    let res = try!(self.replace_children_in_scope(
                        rule.children, Some(local_variables.clone()), Some(local_mixins.clone())
                    ));
                    results.push(Event::Rule(SassRule {
                        children: res, ..rule
                    }));
                },
                Event::MixinCall(mixin_call) => {
                    let mixin_name = mixin_call.name.into_owned();
                    let mixin_definition = match local_mixins.get(&mixin_name) {
                        Some(mixin) => mixin,
                        None => return Err(SassError {
                            kind: ErrorKind::ExpectedMixin,
                            message: format!("Cannot find mixin named `{}`", mixin_name),
                        }),
                    };

                    let mut mixin_replacements = local_variables.clone();
                    mixin_replacements.extend(try!(collate_mixin_args(
                        &mixin_definition.parameters,
                        &mixin_call.arguments,
                    )));

                    let mut res = try!(self.replace_children_in_scope(
                        mixin_definition.children.clone(), Some(mixin_replacements), Some(local_mixins.clone())
                    ));

                    results.append(&mut res);
                },
                other => results.push(other),
            }
        }
        Ok(results)
    }
}

impl<'a, I> Iterator for Substituter<'a, I>
    where I: Iterator<Item = Result<Event<'a>>>
{
    type Item = Result<Event<'a>>;

    fn next(&mut self) -> Option<Result<Event<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(Event::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(Event::Mixin(mixin))) => {
                self.mixins.insert((mixin.name).to_string(), mixin);
                self.next()
            },
            Some(Ok(Event::Rule(sass_rule))) => {
                let replaced = match self.replace_children_in_scope(
                    sass_rule.children, None, None
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };
                debug!("variables now {:?}", self.variables);

                Some(Ok(Event::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            Some(Ok(Event::MixinCall(mixin_call))) => {
                let replaced = match self.replace_children_in_scope(
                    vec![Event::MixinCall(mixin_call)], None, None
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(Event::List(replaced)))
            },
            other => other,
        }
    }
}

fn collate_mixin_args<'a>(
    parameters: &Vec<SassMixinParameter<'a>>,
    arguments: &Vec<SassMixinArgument<'a>>) -> Result<HashMap<String, ValuePart<'a>>> {

    let mut named_arguments = HashMap::new();

    for a in arguments.iter() {
        match a.name {
            Some(ref name) => {
                named_arguments.insert(name.clone(), a.value.clone().into_owned());
            },
            None => {},
        }
    }

    let mut replacements = HashMap::new();

    for (i, p) in parameters.iter().enumerate() {
        let replacement_name = p.name.to_string();

        let replacement_value =
            try!(named_arguments.get(&p.name).and_then( |v| Some(v.to_string()) )
                .or(arguments.get(i).and_then( |a| Some(a.value.clone().into_owned()) ))
                .or(p.default.clone().and_then( |d| Some(d.into_owned()) ))
                .ok_or(SassError {
                    kind: ErrorKind::ExpectedMixinArgument,
                    message: format!("Cannot find argument for mixin parameter named `{}` in arguments `{:?}`", p.name, arguments),
                }));

        replacements.insert(replacement_name, ValuePart::String(Owned(replacement_value)));
    }

    Ok(replacements)
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}
<commit_msg>Handle sass variables set within mixins with !global<commit_after>use error::{Result, SassError, ErrorKind};
use evaluator::Evaluator;
use event::Event;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::mixin::{SassMixin, SassMixinParameter, SassMixinArgument};

use std::collections::HashMap;
use std::borrow::Cow::{self, Borrowed, Owned};

pub struct Substituter<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
    mixins:    HashMap<String, SassMixin<'vm>>,
}

impl<'vm, I> Substituter<'vm, I> {
    pub fn new(tokenizer: I) -> Substituter<'vm, I> {
        Substituter {
            tokenizer: tokenizer,
            variables: HashMap::new(),
            mixins:    HashMap::new(),
        }
    }

    fn replace_children_in_scope(
        &mut self,
        children: Vec<Event<'vm>>,
        passed_variables: Option<HashMap<String, ValuePart<'vm>>>,
        passed_mixins: Option<HashMap<String, SassMixin<'vm>>>) -> Result<Vec<Event<'vm>>> {

        let mut results = Vec::new();
        let mut local_variables = match passed_variables {
            Some(v) => v,
            None => HashMap::new(),
        };
        let local_mixins = match passed_mixins {
            Some(m) => m,
            None => self.mixins.clone(),
        };

        for c in children.into_iter() {
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let mut lvs = self.variables.clone();
                    lvs.extend(local_variables.clone());
                    let val = try!(owned_evaluated_value(value, &lvs));

                    let val = match val {
                        ValuePart::List(mut list) => {
                            match list.pop() {
                                Some(ValuePart::String(s)) => {
                                    if s == "!global" {
                                        self.variables.insert((*name).to_string(), ValuePart::List(list.clone()));
                                        ValuePart::List(list)
                                    } else {
                                        list.push(ValuePart::String(s));
                                        ValuePart::List(list)
                                    }
                                },
                                Some(other) => {
                                    list.push(other);
                                    ValuePart::List(list)
                                },
                                None => ValuePart::List(list)
                            }
                        }
                        other => other,
                    };

                    local_variables.insert((*name).to_string(), val);
                },
                Event::UnevaluatedProperty(name, value) => {
                    let mut lvs = self.variables.clone();
                    lvs.extend(local_variables.clone());

                    let mut ev = Evaluator::new_from_string(&value);
                    let ev_res = try!(ev.evaluate(&lvs)).into_owned();

                    results.push(Event::Property(
                        name,
                        ev_res,
                    ));
                },
                Event::Rule(rule) => {
                    let mut lvs = self.variables.clone();
                    lvs.extend(local_variables.clone());

                    let res = try!(self.replace_children_in_scope(
                        rule.children, Some(lvs), Some(local_mixins.clone())
                    ));
                    results.push(Event::Rule(SassRule {
                        children: res, ..rule
                    }));
                },
                Event::MixinCall(mixin_call) => {
                    let mixin_name = mixin_call.name.into_owned();
                    let mixin_definition = match local_mixins.get(&mixin_name) {
                        Some(mixin) => mixin,
                        None => return Err(SassError {
                            kind: ErrorKind::ExpectedMixin,
                            message: format!("Cannot find mixin named `{}`", mixin_name),
                        }),
                    };

                    let mut mixin_replacements = self.variables.clone();
                    mixin_replacements.extend(local_variables.clone());
                    mixin_replacements.extend(try!(collate_mixin_args(
                        &mixin_definition.parameters,
                        &mixin_call.arguments,
                    )));

                    let mut res = try!(self.replace_children_in_scope(
                        mixin_definition.children.clone(), Some(mixin_replacements), Some(local_mixins.clone())
                    ));

                    results.append(&mut res);
                },
                other => results.push(other),
            }
        }
        Ok(results)
    }
}

impl<'a, I> Iterator for Substituter<'a, I>
    where I: Iterator<Item = Result<Event<'a>>>
{
    type Item = Result<Event<'a>>;

    fn next(&mut self) -> Option<Result<Event<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(Event::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(Event::Mixin(mixin))) => {
                self.mixins.insert((mixin.name).to_string(), mixin);
                self.next()
            },
            Some(Ok(Event::Rule(sass_rule))) => {
                let replaced = match self.replace_children_in_scope(
                    sass_rule.children, None, None
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(Event::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            Some(Ok(Event::MixinCall(mixin_call))) => {
                let replaced = match self.replace_children_in_scope(
                    vec![Event::MixinCall(mixin_call)], None, None
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(Event::List(replaced)))
            },
            other => other,
        }
    }
}

fn collate_mixin_args<'a>(
    parameters: &Vec<SassMixinParameter<'a>>,
    arguments: &Vec<SassMixinArgument<'a>>) -> Result<HashMap<String, ValuePart<'a>>> {

    let mut named_arguments = HashMap::new();

    for a in arguments.iter() {
        match a.name {
            Some(ref name) => {
                named_arguments.insert(name.clone(), a.value.clone().into_owned());
            },
            None => {},
        }
    }

    let mut replacements = HashMap::new();

    for (i, p) in parameters.iter().enumerate() {
        let replacement_name = p.name.to_string();

        let replacement_value =
            try!(named_arguments.get(&p.name).and_then( |v| Some(v.to_string()) )
                .or(arguments.get(i).and_then( |a| Some(a.value.clone().into_owned()) ))
                .or(p.default.clone().and_then( |d| Some(d.into_owned()) ))
                .ok_or(SassError {
                    kind: ErrorKind::ExpectedMixinArgument,
                    message: format!("Cannot find argument for mixin parameter named `{}` in arguments `{:?}`", p.name, arguments),
                }));

        replacements.insert(replacement_name, ValuePart::String(Owned(replacement_value)));
    }

    Ok(replacements)
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}
<|endoftext|>


<commit_before>#![cfg(target_os = "linux")]

pub mod ffi;

use std::mem;
use std::ptr;
use std::ffi::CString;
use std::iter::Iterator;

use error::{RuntimeError, ErrorKind};

use super::x11::ffi::Display as X11Display;
use super::xcb::ffi::xcb_window_t;

use super::x11;
use super::utils::fn_ptr::{FnPtrLoader, FnPtr};

pub type EGLNativeDisplayType = *mut X11Display;
pub type EGLNativeWindowType = xcb_window_t;

pub struct Loader;

impl Loader {
   pub fn new() -> Self {
      Loader
   }
}

impl FnPtrLoader for Loader {
   fn get_proc_addr(&self, name: &str) -> FnPtr {
      let cname = CString::new(name).unwrap().as_ptr();

      let addr = unsafe {
         ffi::eglGetProcAddress(cname)
      };
      println!("{}: {:?}", name, addr);

      addr
   }
}

pub type NativeDisplay = x11::Display;

pub enum API {
    OpenGLES,
    OpenVG,
    OpenGL,
}

impl Into<ffi::EGLenum> for API {
   #[inline]
   fn into(self) -> ffi::EGLenum {
      match self {
         API::OpenGLES => ffi::EGL_OPENGL_ES_API,
         API::OpenVG => ffi::EGL_OPENVG_API,
         API::OpenGL => ffi::EGL_OPENGL_API,
      }
   }
}

pub struct Display {
   pub ptr: ffi::EGLDisplay
}

pub struct Config {
   pub ptr: ffi::EGLConfig
}

pub struct Context {
   pub ptr: ffi::EGLContext
}

pub struct Surface {
   pub ptr: ffi::EGLSurface
}

pub struct Version {
   pub major: ffi::EGLint,
   pub minor: ffi::EGLint,
}

pub fn bind_api(api: API) -> Result<(), RuntimeError> {
   let result = unsafe {
      ffi::eglBindAPI(api.into())
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglBindAPI failed".to_string()
      ));
   }

   Ok(())
}

pub fn initialize(display: &Display) -> Result<Version, RuntimeError> {
   let mut major: ffi::EGLint = unsafe {
      mem::uninitialized()
   };
   let mut minor: ffi::EGLint = unsafe {
      mem::uninitialized()
   };

   let result = unsafe {
      ffi::eglInitialize(display.ptr, &mut major, &mut minor)
   };

   match result {
      ffi::EGL_FALSE => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "eglInitialize failed".to_string()
         ));
      },
      ffi::EGL_BAD_DISPLAY => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Not an EGL display connection".to_string()
         ));
      },
      ffi::EGL_NOT_INITIALIZED => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Display cannot be initialized".to_string()
         ));
      },
      ffi::EGL_TRUE => {
         return Ok(Version {
            major: major,
            minor: minor
         });
      },
      _ => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Unknown eglInitialize error".to_string()
         ));
      }
   }
}

pub fn configs(display: &Display) -> Result<Vec<Config>, RuntimeError> {
   let mut num_config = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglGetConfigs(
         display.ptr,
         ptr::null_mut(),
         0,
         &mut num_config,
      )
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Getting configs count eglGetConfigs failed".to_string()
      ));
   }

   let mut config_ptrs = Vec::with_capacity(num_config as usize);

   let result = unsafe {
      ffi::eglGetConfigs(
         display.ptr,
         config_ptrs.as_mut_ptr(),
         config_ptrs.capacity() as ffi::EGLint,
         &mut num_config
      )
   };

   unsafe {
      config_ptrs.set_len(num_config as usize)
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglGetConfigs failed".to_string()
      ));
   }

   let configs = config_ptrs.iter().map(|&ptr| Config {ptr: ptr}).collect();

   for config in &configs {
      print_config(display, config);
   }

   Ok(configs)
}

pub fn choose_config(display: &Display) -> Result<Config, RuntimeError> {
   let config_attribs = [
      ffi::EGL_COLOR_BUFFER_TYPE,    ffi::EGL_RGB_BUFFER,
      ffi::EGL_BUFFER_SIZE,          24,
      ffi::EGL_RED_SIZE,             8,
      ffi::EGL_GREEN_SIZE,           8,
      ffi::EGL_BLUE_SIZE,            8,
      ffi::EGL_ALPHA_SIZE,           0,

      ffi::EGL_DEPTH_SIZE,           0,
      ffi::EGL_STENCIL_SIZE,         0,

      ffi::EGL_SAMPLE_BUFFERS,       0,
      ffi::EGL_SAMPLES,              0,

      ffi::EGL_SURFACE_TYPE,         ffi::EGL_WINDOW_BIT,
      ffi::EGL_RENDERABLE_TYPE,      ffi::EGL_OPENGL_BIT,

      ffi::EGL_NONE
   ];

   let mut num_config: ffi::EGLint = unsafe {
      mem::uninitialized()
   };

   let mut configs: [ffi::EGLConfig; 64] = unsafe {
      mem::uninitialized()
   };

   let result = unsafe {
      ffi::eglChooseConfig(
         display.ptr,
         config_attribs.as_ptr() as *const _,
         configs.as_mut_ptr() as *mut *mut _,
         64,
         &mut num_config
      )
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Choosing config failed".to_string()
      ));
   }

   if num_config == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Failed to find suitable EGLConfig".to_string()
      ));
   }

   Ok(Config {
      ptr: configs[0]
   })
}

pub fn config_attrib(
   display: &Display,
   config: &Config,
   attribute: ffi::EGLint
) -> Result<ffi::EGLint, RuntimeError> {

   let mut value: ffi::EGLint = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglGetConfigAttrib(display.ptr, config.ptr, attribute, &mut value)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglGetConfigAttrib failed".to_string()
      ));
   }

   Ok(value)
}

pub fn print_config(display: &Display, config: &Config) {
   println!("-------------------------");

   pattr(display, config, "EGL_CONFIG_ID", ffi::EGL_CONFIG_ID);
   pattr(display, config, "EGL_COLOR_BUFFER_TYPE", ffi::EGL_COLOR_BUFFER_TYPE);
   pattr(display, config, "EGL_RENDERABLE_TYPE", ffi::EGL_RENDERABLE_TYPE);
   pattr(display, config, "EGL_SURFACE_TYPE", ffi::EGL_SURFACE_TYPE);
   pattr(display, config, "EGL_TRANSPARENT_TYPE", ffi::EGL_TRANSPARENT_TYPE);
   pattr(display, config, "EGL_NATIVE_VISUAL_TYPE", ffi::EGL_NATIVE_VISUAL_TYPE);
   pattr(display, config, "EGL_NATIVE_VISUAL_ID", ffi::EGL_NATIVE_VISUAL_ID);
   pattr(display, config, "EGL_BUFFER_SIZE", ffi::EGL_BUFFER_SIZE);
   pattr(display, config, "EGL_LUMINANCE_SIZE", ffi::EGL_LUMINANCE_SIZE);
   pattr(display, config, "EGL_DEPTH_SIZE", ffi::EGL_DEPTH_SIZE);
   pattr(display, config, "EGL_STENCIL_SIZE", ffi::EGL_STENCIL_SIZE);
   pattr(display, config, "EGL_RED_SIZE", ffi::EGL_RED_SIZE);
   pattr(display, config, "EGL_GREEN_SIZE", ffi::EGL_GREEN_SIZE);
   pattr(display, config, "EGL_BLUE_SIZE", ffi::EGL_BLUE_SIZE);
   pattr(display, config, "EGL_ALPHA_SIZE", ffi::EGL_ALPHA_SIZE);
   pattr(display, config, "EGL_ALPHA_MASK_SIZE", ffi::EGL_ALPHA_MASK_SIZE);
   pattr(display, config, "EGL_BIND_TO_TEXTURE_RGB", ffi::EGL_BIND_TO_TEXTURE_RGB);
   pattr(display, config, "EGL_BIND_TO_TEXTURE_RGBA", ffi::EGL_BIND_TO_TEXTURE_RGBA);
   pattr(display, config, "EGL_CONFIG_CAVEAT", ffi::EGL_CONFIG_CAVEAT);
   pattr(display, config, "EGL_CONFORMANT", ffi::EGL_CONFORMANT);
   pattr(display, config, "EGL_LEVEL", ffi::EGL_LEVEL);
   pattr(display, config, "EGL_MAX_PBUFFER_WIDTH", ffi::EGL_MAX_PBUFFER_WIDTH);
   pattr(display, config, "EGL_MAX_PBUFFER_HEIGHT", ffi::EGL_MAX_PBUFFER_HEIGHT);
   pattr(display, config, "EGL_MAX_PBUFFER_PIXELS", ffi::EGL_MAX_PBUFFER_PIXELS);
   pattr(display, config, "EGL_MAX_SWAP_INTERVAL", ffi::EGL_MAX_SWAP_INTERVAL);
   pattr(display, config, "EGL_MIN_SWAP_INTERVAL", ffi::EGL_MIN_SWAP_INTERVAL);
   pattr(display, config, "EGL_NATIVE_RENDERABLE", ffi::EGL_NATIVE_RENDERABLE);
   pattr(display, config, "EGL_SAMPLE_BUFFERS", ffi::EGL_SAMPLE_BUFFERS);
   pattr(display, config, "EGL_SAMPLES", ffi::EGL_SAMPLES);
   pattr(display, config, "EGL_TRANSPARENT_RED_VALUE", ffi::EGL_TRANSPARENT_RED_VALUE);
   pattr(display, config, "EGL_TRANSPARENT_GREEN_VALUE", ffi::EGL_TRANSPARENT_GREEN_VALUE);
   pattr(display, config, "EGL_TRANSPARENT_BLUE_VALUE", ffi::EGL_TRANSPARENT_BLUE_VALUE);

   println!("");
}

pub fn pattr(display: &Display, config: &Config, name: &str, attribute: ffi::EGLenum) {
   println!(
      "{}: {}", name, config_attrib(display, config, attribute as ffi::EGLint).unwrap()
   );
}

pub fn create_context(display: &Display, config: &Config) -> Result<Context, RuntimeError> {
   let context_attribs = [ffi::EGL_NONE];

   let context = unsafe {
      ffi::eglCreateContext(
         display.ptr,
         config.ptr as *mut _,
         ffi::EGL_NO_CONTEXT as *mut _,
         context_attribs.as_ptr() as *const _,
      )
   };
   if context.is_null() {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglCreateContext failed".to_string()
      ));
   }

   Ok(Context {
      ptr: context
   })
}

pub fn create_window_surface(
   display: &Display,
   config: &Config,
   window: &EGLNativeWindowType
) -> Result<Surface, RuntimeError> {

   let surface_attribs = [
      ffi::EGL_RENDER_BUFFER, ffi::EGL_BACK_BUFFER,
      ffi::EGL_NONE
   ];

   let surface = unsafe {
      ffi::eglCreateWindowSurface(
         display.ptr,
         config.ptr as *mut _,
         *window,
         surface_attribs.as_ptr() as *const _,
      )
   };
   if surface.is_null() {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglCreateWindowSurface failed".to_string()
      ));
   }

   Ok(Surface {
      ptr: surface
   })
}

pub fn make_current(
   display: &Display,
   draw: &Surface,
   read: &Surface,
   context: &Context,
) -> Result<(), RuntimeError> {

   let made_current = unsafe {
      ffi::eglMakeCurrent(
         display.ptr,
         draw.ptr,
         read.ptr,
         context.ptr
      )
   };

   if made_current != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglMakeCurrent failed".to_string()
      ));
   }

   Ok(())
}

pub fn query_context(
   display: &Display,
   context: &Context,
) -> Result<(), RuntimeError> {

   let mut render_buffer: ffi::EGLint = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglQueryContext(
         display.ptr,
         context.ptr,
         ffi::EGL_RENDER_BUFFER as i32,
         &mut render_buffer
      )
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglQueyContext (EGL_RENDER_BUFFER) failed".to_string()
      ));
   }

   if render_buffer == ffi::EGL_SINGLE_BUFFER as i32 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "EGL surface is single buffered".to_string()
      ));
   }

   Ok(())
}

pub fn swap_buffers(
   display: &Display,
   surface: &Surface
) -> Result<(), RuntimeError> {

   let result = unsafe {
      ffi::eglSwapBuffers(display.ptr, surface.ptr)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglSwapBuffers failed".to_string()
      ));
   }

   Ok(())
}

pub fn swap_interval(
   display: &Display,
   interval: ffi::c_int
) -> Result<(), RuntimeError> {

   let result = unsafe {
      ffi::eglSwapInterval(display.ptr, interval)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglSwapInterval failed".to_string()
      ));
   }

   Ok(())
}

impl Display {
   pub fn from_native(native_display: &NativeDisplay) -> Result<Self, RuntimeError> {
      let ptr = unsafe {
         ffi::eglGetDisplay(native_display.ptr)
      };

      if ptr.is_null() {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "eglGetDisplay failed".to_string()
         ));
      }

      Ok(Display {
         ptr: ptr,
      })
   }
}
<commit_msg>Choosing 32-bit color EGL window surface<commit_after>#![cfg(target_os = "linux")]

pub mod ffi;

use std::mem;
use std::ptr;
use std::ffi::CString;
use std::iter::Iterator;

use error::{RuntimeError, ErrorKind};

use super::x11::ffi::Display as X11Display;
use super::xcb::ffi::xcb_window_t;

use super::x11;
use super::utils::fn_ptr::{FnPtrLoader, FnPtr};

pub type EGLNativeDisplayType = *mut X11Display;
pub type EGLNativeWindowType = xcb_window_t;

pub struct Loader;

impl Loader {
   pub fn new() -> Self {
      Loader
   }
}

impl FnPtrLoader for Loader {
   fn get_proc_addr(&self, name: &str) -> FnPtr {
      let cname = CString::new(name).unwrap().as_ptr();

      let addr = unsafe {
         ffi::eglGetProcAddress(cname)
      };
      println!("{}: {:?}", name, addr);

      addr
   }
}

pub type NativeDisplay = x11::Display;

pub enum API {
    OpenGLES,
    OpenVG,
    OpenGL,
}

impl Into<ffi::EGLenum> for API {
   #[inline]
   fn into(self) -> ffi::EGLenum {
      match self {
         API::OpenGLES => ffi::EGL_OPENGL_ES_API,
         API::OpenVG => ffi::EGL_OPENVG_API,
         API::OpenGL => ffi::EGL_OPENGL_API,
      }
   }
}

pub struct Display {
   pub ptr: ffi::EGLDisplay
}

pub struct Config {
   pub ptr: ffi::EGLConfig
}

pub struct Context {
   pub ptr: ffi::EGLContext
}

pub struct Surface {
   pub ptr: ffi::EGLSurface
}

pub struct Version {
   pub major: ffi::EGLint,
   pub minor: ffi::EGLint,
}

pub fn bind_api(api: API) -> Result<(), RuntimeError> {
   let result = unsafe {
      ffi::eglBindAPI(api.into())
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglBindAPI failed".to_string()
      ));
   }

   Ok(())
}

pub fn initialize(display: &Display) -> Result<Version, RuntimeError> {
   let mut major: ffi::EGLint = unsafe {
      mem::uninitialized()
   };
   let mut minor: ffi::EGLint = unsafe {
      mem::uninitialized()
   };

   let result = unsafe {
      ffi::eglInitialize(display.ptr, &mut major, &mut minor)
   };

   match result {
      ffi::EGL_FALSE => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "eglInitialize failed".to_string()
         ));
      },
      ffi::EGL_BAD_DISPLAY => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Not an EGL display connection".to_string()
         ));
      },
      ffi::EGL_NOT_INITIALIZED => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Display cannot be initialized".to_string()
         ));
      },
      ffi::EGL_TRUE => {
         return Ok(Version {
            major: major,
            minor: minor
         });
      },
      _ => {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "Unknown eglInitialize error".to_string()
         ));
      }
   }
}

pub fn configs(display: &Display) -> Result<Vec<Config>, RuntimeError> {
   let mut num_config = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglGetConfigs(
         display.ptr,
         ptr::null_mut(),
         0,
         &mut num_config,
      )
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Getting configs count eglGetConfigs failed".to_string()
      ));
   }

   let mut config_ptrs = Vec::with_capacity(num_config as usize);

   let result = unsafe {
      ffi::eglGetConfigs(
         display.ptr,
         config_ptrs.as_mut_ptr(),
         config_ptrs.capacity() as ffi::EGLint,
         &mut num_config
      )
   };

   unsafe {
      config_ptrs.set_len(num_config as usize)
   };

   if result == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglGetConfigs failed".to_string()
      ));
   }

   let configs = config_ptrs.iter().map(|&ptr| Config {ptr: ptr}).collect();

   for config in &configs {
      print_config(display, config);
   }

   Ok(configs)
}

pub fn choose_config(display: &Display) -> Result<Config, RuntimeError> {
   let config_attribs = [
      ffi::EGL_COLOR_BUFFER_TYPE,    ffi::EGL_RGB_BUFFER,
      ffi::EGL_BUFFER_SIZE,          32,
      ffi::EGL_RED_SIZE,             8,
      ffi::EGL_GREEN_SIZE,           8,
      ffi::EGL_BLUE_SIZE,            8,
      ffi::EGL_ALPHA_SIZE,           8,

      ffi::EGL_DEPTH_SIZE,           0,
      ffi::EGL_STENCIL_SIZE,         0,

      ffi::EGL_SAMPLE_BUFFERS,       0,
      ffi::EGL_SAMPLES,              0,

      ffi::EGL_SURFACE_TYPE,         ffi::EGL_WINDOW_BIT,
      ffi::EGL_RENDERABLE_TYPE,      ffi::EGL_OPENGL_BIT,

      ffi::EGL_NONE
   ];

   let mut num_config: ffi::EGLint = unsafe {
      mem::uninitialized()
   };

   let mut configs: [ffi::EGLConfig; 64] = unsafe {
      mem::uninitialized()
   };

   let result = unsafe {
      ffi::eglChooseConfig(
         display.ptr,
         config_attribs.as_ptr() as *const _,
         configs.as_mut_ptr() as *mut *mut _,
         64,
         &mut num_config
      )
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Choosing config failed".to_string()
      ));
   }

   if num_config == 0 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "Failed to find suitable EGLConfig".to_string()
      ));
   }

   Ok(Config {
      ptr: configs[0]
   })
}

pub fn config_attrib(
   display: &Display,
   config: &Config,
   attribute: ffi::EGLint
) -> Result<ffi::EGLint, RuntimeError> {

   let mut value: ffi::EGLint = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglGetConfigAttrib(display.ptr, config.ptr, attribute, &mut value)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglGetConfigAttrib failed".to_string()
      ));
   }

   Ok(value)
}

pub fn print_config(display: &Display, config: &Config) {
   println!("-------------------------");

   pattr(display, config, "EGL_CONFIG_ID", ffi::EGL_CONFIG_ID);
   pattr(display, config, "EGL_COLOR_BUFFER_TYPE", ffi::EGL_COLOR_BUFFER_TYPE);
   pattr(display, config, "EGL_RENDERABLE_TYPE", ffi::EGL_RENDERABLE_TYPE);
   pattr(display, config, "EGL_SURFACE_TYPE", ffi::EGL_SURFACE_TYPE);
   pattr(display, config, "EGL_TRANSPARENT_TYPE", ffi::EGL_TRANSPARENT_TYPE);
   pattr(display, config, "EGL_NATIVE_VISUAL_TYPE", ffi::EGL_NATIVE_VISUAL_TYPE);
   pattr(display, config, "EGL_NATIVE_VISUAL_ID", ffi::EGL_NATIVE_VISUAL_ID);
   pattr(display, config, "EGL_BUFFER_SIZE", ffi::EGL_BUFFER_SIZE);
   pattr(display, config, "EGL_LUMINANCE_SIZE", ffi::EGL_LUMINANCE_SIZE);
   pattr(display, config, "EGL_DEPTH_SIZE", ffi::EGL_DEPTH_SIZE);
   pattr(display, config, "EGL_STENCIL_SIZE", ffi::EGL_STENCIL_SIZE);
   pattr(display, config, "EGL_RED_SIZE", ffi::EGL_RED_SIZE);
   pattr(display, config, "EGL_GREEN_SIZE", ffi::EGL_GREEN_SIZE);
   pattr(display, config, "EGL_BLUE_SIZE", ffi::EGL_BLUE_SIZE);
   pattr(display, config, "EGL_ALPHA_SIZE", ffi::EGL_ALPHA_SIZE);
   pattr(display, config, "EGL_ALPHA_MASK_SIZE", ffi::EGL_ALPHA_MASK_SIZE);
   pattr(display, config, "EGL_BIND_TO_TEXTURE_RGB", ffi::EGL_BIND_TO_TEXTURE_RGB);
   pattr(display, config, "EGL_BIND_TO_TEXTURE_RGBA", ffi::EGL_BIND_TO_TEXTURE_RGBA);
   pattr(display, config, "EGL_CONFIG_CAVEAT", ffi::EGL_CONFIG_CAVEAT);
   pattr(display, config, "EGL_CONFORMANT", ffi::EGL_CONFORMANT);
   pattr(display, config, "EGL_LEVEL", ffi::EGL_LEVEL);
   pattr(display, config, "EGL_MAX_PBUFFER_WIDTH", ffi::EGL_MAX_PBUFFER_WIDTH);
   pattr(display, config, "EGL_MAX_PBUFFER_HEIGHT", ffi::EGL_MAX_PBUFFER_HEIGHT);
   pattr(display, config, "EGL_MAX_PBUFFER_PIXELS", ffi::EGL_MAX_PBUFFER_PIXELS);
   pattr(display, config, "EGL_MAX_SWAP_INTERVAL", ffi::EGL_MAX_SWAP_INTERVAL);
   pattr(display, config, "EGL_MIN_SWAP_INTERVAL", ffi::EGL_MIN_SWAP_INTERVAL);
   pattr(display, config, "EGL_NATIVE_RENDERABLE", ffi::EGL_NATIVE_RENDERABLE);
   pattr(display, config, "EGL_SAMPLE_BUFFERS", ffi::EGL_SAMPLE_BUFFERS);
   pattr(display, config, "EGL_SAMPLES", ffi::EGL_SAMPLES);
   pattr(display, config, "EGL_TRANSPARENT_RED_VALUE", ffi::EGL_TRANSPARENT_RED_VALUE);
   pattr(display, config, "EGL_TRANSPARENT_GREEN_VALUE", ffi::EGL_TRANSPARENT_GREEN_VALUE);
   pattr(display, config, "EGL_TRANSPARENT_BLUE_VALUE", ffi::EGL_TRANSPARENT_BLUE_VALUE);

   println!("");
}

pub fn pattr(display: &Display, config: &Config, name: &str, attribute: ffi::EGLenum) {
   println!(
      "{}: {}", name, config_attrib(display, config, attribute as ffi::EGLint).unwrap()
   );
}

pub fn create_context(display: &Display, config: &Config) -> Result<Context, RuntimeError> {
   let context_attribs = [ffi::EGL_NONE];

   let context = unsafe {
      ffi::eglCreateContext(
         display.ptr,
         config.ptr as *mut _,
         ffi::EGL_NO_CONTEXT as *mut _,
         context_attribs.as_ptr() as *const _,
      )
   };
   if context.is_null() {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglCreateContext failed".to_string()
      ));
   }

   Ok(Context {
      ptr: context
   })
}

pub fn create_window_surface(
   display: &Display,
   config: &Config,
   window: &EGLNativeWindowType
) -> Result<Surface, RuntimeError> {

   let surface_attribs = [
      ffi::EGL_RENDER_BUFFER, ffi::EGL_BACK_BUFFER,
      ffi::EGL_NONE
   ];

   let surface = unsafe {
      ffi::eglCreateWindowSurface(
         display.ptr,
         config.ptr as *mut _,
         *window,
         surface_attribs.as_ptr() as *const _,
      )
   };
   if surface.is_null() {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglCreateWindowSurface failed".to_string()
      ));
   }

   Ok(Surface {
      ptr: surface
   })
}

pub fn make_current(
   display: &Display,
   draw: &Surface,
   read: &Surface,
   context: &Context,
) -> Result<(), RuntimeError> {

   let made_current = unsafe {
      ffi::eglMakeCurrent(
         display.ptr,
         draw.ptr,
         read.ptr,
         context.ptr
      )
   };

   if made_current != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglMakeCurrent failed".to_string()
      ));
   }

   Ok(())
}

pub fn query_context(
   display: &Display,
   context: &Context,
) -> Result<(), RuntimeError> {

   let mut render_buffer: ffi::EGLint = unsafe { mem::uninitialized() };

   let result = unsafe {
      ffi::eglQueryContext(
         display.ptr,
         context.ptr,
         ffi::EGL_RENDER_BUFFER as i32,
         &mut render_buffer
      )
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglQueyContext (EGL_RENDER_BUFFER) failed".to_string()
      ));
   }

   if render_buffer == ffi::EGL_SINGLE_BUFFER as i32 {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "EGL surface is single buffered".to_string()
      ));
   }

   Ok(())
}

pub fn swap_buffers(
   display: &Display,
   surface: &Surface
) -> Result<(), RuntimeError> {

   let result = unsafe {
      ffi::eglSwapBuffers(display.ptr, surface.ptr)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglSwapBuffers failed".to_string()
      ));
   }

   Ok(())
}

pub fn swap_interval(
   display: &Display,
   interval: ffi::c_int
) -> Result<(), RuntimeError> {

   let result = unsafe {
      ffi::eglSwapInterval(display.ptr, interval)
   };

   if result != ffi::EGL_TRUE {
      return Err(RuntimeError::new(
         ErrorKind::EGL,
         "eglSwapInterval failed".to_string()
      ));
   }

   Ok(())
}

impl Display {
   pub fn from_native(native_display: &NativeDisplay) -> Result<Self, RuntimeError> {
      let ptr = unsafe {
         ffi::eglGetDisplay(native_display.ptr)
      };

      if ptr.is_null() {
         return Err(RuntimeError::new(
            ErrorKind::EGL,
            "eglGetDisplay failed".to_string()
         ));
      }

      Ok(Display {
         ptr: ptr,
      })
   }
}
<|endoftext|>


<commit_before>///! Basic commands tests.
use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
use config::EditMode;
use consts::KeyPress;
use error::ReadlineError;

#[test]
fn home_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hi", ""),
                &[KeyPress::Esc, KeyPress::Home, KeyPress::Enter],
                ("", "Hi"),
            );
        }
    }
}

#[test]
fn end_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(*mode, ("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::End, KeyPress::Enter],
                ("Hi", ""),
            );
        }
    }
}

#[test]
fn left_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Left, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Bye", ""),
                &[KeyPress::Esc, KeyPress::Left, KeyPress::Enter],
                ("B", "ye"),
            );
        }
    }
}

#[test]
fn right_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Right, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Right, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("B", "ye"),
            &[KeyPress::Right, KeyPress::Enter],
            ("By", "e"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Right, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::Right, KeyPress::Enter],
                ("H", "i"),
            );
        }
    }
}

#[test]
fn enter_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Enter], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Enter], "a");
        assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Enter], "Hi");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Enter], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Enter],
                "a",
            );
            assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
        }
    }
}

#[test]
fn newline_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Ctrl('J')], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Ctrl('J')], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('J')],
                "a",
            );
        }
    }
}

#[test]
fn eof_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('D')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Eof));
    }
    assert_line(
        EditMode::Emacs,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D')],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('D')],
        "a",
    );
    assert_line_with_initial(
        EditMode::Emacs,
        ("", "Hi"),
        &[KeyPress::Ctrl('D'), KeyPress::Enter],
        "i",
    );
    assert_line_with_initial(EditMode::Vi, ("", "Hi"), &[KeyPress::Ctrl('D')], "Hi");
    assert_line_with_initial(
        EditMode::Vi,
        ("", "Hi"),
        &[KeyPress::Esc, KeyPress::Ctrl('D')],
        "Hi",
    );
}

#[test]
fn interrupt_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Interrupted));

        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline_with_initial(">>", ("Hi", ""));
        assert_matches!(err, Err(ReadlineError::Interrupted));
        if *mode == EditMode::Vi {
            // vi command mode
            let mut editor = init_editor(*mode, &[KeyPress::Esc, KeyPress::Ctrl('C')]);
            let err = editor.readline_with_initial(">>", ("Hi", ""));
            assert_matches!(err, Err(ReadlineError::Interrupted));
        }
    }
}

#[test]
fn delete_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", ""),
            &[KeyPress::Delete, KeyPress::Enter],
            ("a", ""),
        );
        assert_cursor(
            *mode,
            ("", "a"),
            &[KeyPress::Delete, KeyPress::Enter],
            ("", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "a"),
                &[KeyPress::Esc, KeyPress::Delete, KeyPress::Enter],
                ("", ""),
            );
        }
    }
}

#[test]
fn ctrl_t() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", "b"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("ba", ""),
        );
        assert_cursor(
            *mode,
            ("ab", "cd"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("acb", "d"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("ab", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('T'), KeyPress::Enter],
                ("ba", ""),
            );
        }
    }
}

#[test]
fn ctrl_u() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("start of line ", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        assert_cursor(
            *mode,
            ("", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("start of line ", "end"),
                &[KeyPress::Esc, KeyPress::Ctrl('U'), KeyPress::Enter],
                ("", " end"),
            );
        }
    }
}

#[test]
fn ctrl_v() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
            ("\t", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", ""),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('V'),
                    KeyPress::Char('\t'),
                    KeyPress::Enter,
                ],
                ("\t", ""),
            );
        }
    }
}

#[test]
fn ctrl_w() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("", "world"),
        );
        assert_cursor(
            *mode,
            ("Hello, world.", ""),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("Hello, ", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, world.", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('W'), KeyPress::Enter],
                ("Hello, ", "."),
            );
        }
    }
}

#[test]
fn ctrl_y() {
    for mode in &[EditMode::Emacs /* FIXME, EditMode::Vi */] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
    }
}

#[test]
fn ctrl__() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, ", "world"),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('W'),
                    KeyPress::Ctrl('_'),
                    KeyPress::Enter,
                ],
                ("Hello,", " world"),
            );
        }
    }
}
<commit_msg>Try to fix tests on windows<commit_after>///! Basic commands tests.
use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
use config::EditMode;
use consts::KeyPress;
use error::ReadlineError;

#[test]
fn home_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hi", ""),
                &[KeyPress::Esc, KeyPress::Home, KeyPress::Enter],
                ("", "Hi"),
            );
        }
    }
}

#[test]
fn end_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(*mode, ("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::End, KeyPress::Enter],
                ("Hi", ""),
            );
        }
    }
}

#[test]
fn left_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Left, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Bye", ""),
                &[KeyPress::Esc, KeyPress::Left, KeyPress::Enter],
                ("B", "ye"),
            );
        }
    }
}

#[test]
fn right_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Right, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Right, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("B", "ye"),
            &[KeyPress::Right, KeyPress::Enter],
            ("By", "e"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Right, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::Right, KeyPress::Enter],
                ("H", "i"),
            );
        }
    }
}

#[test]
fn enter_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Enter], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Enter], "a");
        assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Enter], "Hi");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Enter], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Enter],
                "a",
            );
            assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
        }
    }
}

#[test]
fn newline_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Ctrl('J')], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Ctrl('J')], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('J')],
                "a",
            );
        }
    }
}

#[test]
fn eof_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('D')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Eof));
    }
    assert_line(
        EditMode::Emacs,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D')],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('D')],
        "a",
    );
    assert_line_with_initial(
        EditMode::Emacs,
        ("", "Hi"),
        &[KeyPress::Ctrl('D'), KeyPress::Enter],
        "i",
    );
    assert_line_with_initial(EditMode::Vi, ("", "Hi"), &[KeyPress::Ctrl('D')], "Hi");
    assert_line_with_initial(
        EditMode::Vi,
        ("", "Hi"),
        &[KeyPress::Esc, KeyPress::Ctrl('D')],
        "Hi",
    );
}

#[test]
fn interrupt_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Interrupted));

        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline_with_initial(">>", ("Hi", ""));
        assert_matches!(err, Err(ReadlineError::Interrupted));
        if *mode == EditMode::Vi {
            // vi command mode
            let mut editor = init_editor(*mode, &[KeyPress::Esc, KeyPress::Ctrl('C')]);
            let err = editor.readline_with_initial(">>", ("Hi", ""));
            assert_matches!(err, Err(ReadlineError::Interrupted));
        }
    }
}

#[test]
fn delete_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", ""),
            &[KeyPress::Delete, KeyPress::Enter],
            ("a", ""),
        );
        assert_cursor(
            *mode,
            ("", "a"),
            &[KeyPress::Delete, KeyPress::Enter],
            ("", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "a"),
                &[KeyPress::Esc, KeyPress::Delete, KeyPress::Enter],
                ("", ""),
            );
        }
    }
}

#[test]
fn ctrl_t() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", "b"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("ba", ""),
        );
        assert_cursor(
            *mode,
            ("ab", "cd"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("acb", "d"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("ab", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('T'), KeyPress::Enter],
                ("ba", ""),
            );
        }
    }
}

#[test]
fn ctrl_u() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("start of line ", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        assert_cursor(
            *mode,
            ("", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("start of line ", "end"),
                &[KeyPress::Esc, KeyPress::Ctrl('U'), KeyPress::Enter],
                ("", " end"),
            );
        }
    }
}

#[cfg(unix)]
#[test]
fn ctrl_v() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
            ("\t", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", ""),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('V'),
                    KeyPress::Char('\t'),
                    KeyPress::Enter,
                ],
                ("\t", ""),
            );
        }
    }
}

#[test]
fn ctrl_w() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("", "world"),
        );
        assert_cursor(
            *mode,
            ("Hello, world.", ""),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("Hello, ", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, world.", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('W'), KeyPress::Enter],
                ("Hello, ", "."),
            );
        }
    }
}

#[test]
fn ctrl_y() {
    for mode in &[EditMode::Emacs /* FIXME, EditMode::Vi */] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
    }
}

#[test]
fn ctrl__() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, ", "world"),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('W'),
                    KeyPress::Ctrl('_'),
                    KeyPress::Enter,
                ],
                ("Hello,", " world"),
            );
        }
    }
}
<|endoftext|>