<commit_before>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_escape];

macro_rules! impl_vec(
    ($Vec:ident { $($field:ident),+ }) => (
        impl<T> $Vec<T> {
            #[inline]
            pub fn new($($field: T),+) -> $Vec<T> {
                $Vec { $($field: $field),+ }
            }
        }
    )
)

macro_rules! impl_vec_clonable(
    ($Vec:ident) => (
        impl<T:Clone> $Vec<T> {
            #[inline]
            pub fn from_value(value: T) -> $Vec<T> {
                vec_from_value!($Vec)
            }
        }
    )
)

macro_rules! vec_from_value(
    (Vec2) => (Vec2::new(value.clone(), value.clone()));
    (Vec3) => (Vec3::new(value.clone(), value.clone(), value.clone()));
    (Vec4) => (Vec4::new(value.clone(), value.clone(), value.clone(), value.clone()));
)

macro_rules! impl_vec_numeric(
    ($Vec:ident) => (
        impl<T:Clone + Num> $Vec<T> {
            #[inline] pub fn identity() -> $Vec<T> { $Vec::from_value(one!(T)) }
            #[inline] pub fn zero() -> $Vec<T> { $Vec::from_value(zero!(T)) }

            #[inline] pub fn add_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x + value)) }
            #[inline] pub fn sub_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x - value)) }
            #[inline] pub fn mul_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x * value)) }
            #[inline] pub fn div_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x / value)) }
            #[inline] pub fn rem_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x % value)) }

            #[inline] pub fn add_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a + b)) }
            #[inline] pub fn sub_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a - b)) }
            #[inline] pub fn mul_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a * b)) }
            #[inline] pub fn div_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a / b)) }
            #[inline] pub fn rem_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a % b)) }

            #[inline] pub fn neg_self(&mut self) { self.map_mut(|x| *x = -*x) }
            #[inline] pub fn add_self_t(&mut self, value: T) { self.map_mut(|x| *x += value.clone()) }
            #[inline] pub fn sub_self_t(&mut self, value: T) { self.map_mut(|x| *x -= value.clone()) }
            #[inline] pub fn mul_self_t(&mut self, value: T) { self.map_mut(|x| *x *= value.clone()) }
            #[inline] pub fn div_self_t(&mut self, value: T) { self.map_mut(|x| *x /= value.clone()) }
            #[inline] pub fn rem_self_t(&mut self, value: T) { self.map_mut(|x| *x %= value.clone()) }

            #[inline] pub fn add_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a += b) }
            #[inline] pub fn sub_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a -= b) }
            #[inline] pub fn mul_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a *= b) }
            #[inline] pub fn div_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a /= b) }
            #[inline] pub fn rem_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a %= b) }

            #[inline] pub fn dot(&self, other: &$Vec<T>) -> T { vec_dot!($Vec) }
        }
    )
)

macro_rules! vec_dot(
    (Vec2) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1)
    );
    (Vec3) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1) +
        *self.index(2) * *other.index(2)
    );
    (Vec4) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1) +
        *self.index(2) * *other.index(2) +
        *self.index(3) * *other.index(3)
    );
)

macro_rules! impl_vec_neg(
    ($Vec:ident) => (
        impl<T:Clone + Num> Neg<$Vec<T>> for $Vec<T> {
            #[inline]
            pub fn neg(&self) -> $Vec<T> {
                $Vec::from_slice(self.map(|&x| -x))
            }
        }
    )
)

macro_rules! impl_vec_euclidean(
    ($Vec:ident) => (
        impl<T:Clone + Real> $Vec<T> {
            #[inline]
            pub fn length2(&self) -> T {
                self.dot(self)
            }

            #[inline]
            pub fn length(&self) -> T {
                self.length2().sqrt()
            }

            #[inline]
            pub fn distance2(&self, other: &$Vec<T>) -> T {
                other.sub_v(self).length2()
            }

            #[inline]
            pub fn distance(&self, other: &$Vec<T>) -> T {
                other.distance2(self).sqrt()
            }

            #[inline]
            pub fn angle(&self, other: &$Vec<T>) -> T {
                vec_angle!($Vec)
            }

            #[inline]
            pub fn normalize(&self) -> $Vec<T> {
                self.mul_t(one!(T)/self.length())
            }

            #[inline]
            pub fn normalize_to(&self, length: T) -> $Vec<T> {
                self.mul_t(length / self.length())
            }

            #[inline]
            pub fn lerp(&self, other: &$Vec<T>, amount: T) -> $Vec<T> {
                self.add_v(&other.sub_v(self).mul_t(amount))
            }

            #[inline]
            pub fn normalize_self(&mut self) {
                let rlen = self.length().recip();
                self.mul_self_t(rlen);
            }

            #[inline]
            pub fn normalize_self_to(&mut self, length: T) {
                let n = length / self.length();
                self.mul_self_t(n);
            }

            pub fn lerp_self(&mut self, other: &$Vec<T>, amount: T) {
                let v = other.sub_v(self).mul_t(amount);
                self.add_self_v(&v);
            }
        }
    )
)

macro_rules! vec_angle(
    (Vec2) => (self.perp_dot(other).atan2(&self.dot(other)));
    (Vec3) => (self.cross(other).length().atan2(&self.dot(other)));
    (Vec4) => ((self.dot(other) / (self.length() * other.length())).acos());
)

macro_rules! impl_vec_ord(
    ($Vec:ident) => (
        impl<T:Clone + Ord> $Vec<T> {
            #[inline] pub fn lt_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x < value)) }
            #[inline] pub fn le_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x <= value)) }
            #[inline] pub fn ge_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x >= value)) }
            #[inline] pub fn gt_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x > value)) }

            #[inline] pub fn lt_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a < b)) }
            #[inline] pub fn le_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a <= b)) }
            #[inline] pub fn ge_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a >= b)) }
            #[inline] pub fn gt_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a > b)) }
        }
    )
)

macro_rules! impl_vec_eq(
    ($Vec:ident) => (
        impl<T:Clone + Eq> $Vec<T> {
            #[inline] pub fn eq_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x == value)) }
            #[inline] pub fn ne_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x != value)) }

            #[inline] pub fn eq_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a == b)) }
            #[inline] pub fn ne_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a != b)) }
        }
    )
)

macro_rules! impl_vec_bool(
    ($Vec:ident) => (
        impl $Vec<bool> {
            #[inline]
            pub fn any(&self) -> bool { vec_any!($Vec) }

            #[inline]
            pub fn all(&self) -> bool { vec_all!($Vec) }

            #[inline]
            pub fn not(&self) -> $Vec<bool> {
                $Vec::from_slice(self.map(|&x| !x))
            }
        }
    )
)

macro_rules! vec_any(
    (Vec2) => (*self.index(0) || *self.index(1));
    (Vec3) => (*self.index(0) || *self.index(1) || *self.index(2));
    (Vec4) => (*self.index(0) || *self.index(1) || *self.index(2) || *self.index(3));
)

macro_rules! vec_all(
    (Vec2) => (*self.index(0) && *self.index(1));
    (Vec3) => (*self.index(0) && *self.index(1) && *self.index(2));
    (Vec4) => (*self.index(0) && *self.index(1) && *self.index(2) && *self.index(3));
)

macro_rules! impl_vec_not(
    ($Vec:ident) => (
        impl<T:Clone + Not<T>> Not<$Vec<T>> for $Vec<T> {
            pub fn not(&self) -> $Vec<T> {
                $Vec::from_slice(self.map(|&x| !x))
            }
        }
    )
)
<commit_msg>fixes += operator etc<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_escape];

macro_rules! impl_vec(
    ($Vec:ident { $($field:ident),+ }) => (
        impl<T> $Vec<T> {
            #[inline]
            pub fn new($($field: T),+) -> $Vec<T> {
                $Vec { $($field: $field),+ }
            }
        }
    )
)

macro_rules! impl_vec_clonable(
    ($Vec:ident) => (
        impl<T:Clone> $Vec<T> {
            #[inline]
            pub fn from_value(value: T) -> $Vec<T> {
                vec_from_value!($Vec)
            }
        }
    )
)

macro_rules! vec_from_value(
    (Vec2) => (Vec2::new(value.clone(), value.clone()));
    (Vec3) => (Vec3::new(value.clone(), value.clone(), value.clone()));
    (Vec4) => (Vec4::new(value.clone(), value.clone(), value.clone(), value.clone()));
)

macro_rules! impl_vec_numeric(
    ($Vec:ident) => (
        impl<T:Clone + Num> $Vec<T> {
            #[inline] pub fn identity() -> $Vec<T> { $Vec::from_value(one!(T)) }
            #[inline] pub fn zero() -> $Vec<T> { $Vec::from_value(zero!(T)) }

            #[inline] pub fn add_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x + value)) }
            #[inline] pub fn sub_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x - value)) }
            #[inline] pub fn mul_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x * value)) }
            #[inline] pub fn div_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x / value)) }
            #[inline] pub fn rem_t(&self, value: T) -> $Vec<T> { $Vec::from_slice(self.map(|&x| x % value)) }

            #[inline] pub fn add_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a + b)) }
            #[inline] pub fn sub_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a - b)) }
            #[inline] pub fn mul_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a * b)) }
            #[inline] pub fn div_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a / b)) }
            #[inline] pub fn rem_v(&self, other: &$Vec<T>) -> $Vec<T> { $Vec::from_slice(self.zip(other, |&a, &b| a % b)) }

            #[inline] pub fn neg_self(&mut self) { self.map_mut(|x| *x = -*x) }
            #[inline] pub fn add_self_t(&mut self, value: T) { self.map_mut(|x| *x = *x + value.clone()) }
            #[inline] pub fn sub_self_t(&mut self, value: T) { self.map_mut(|x| *x = *x - value.clone()) }
            #[inline] pub fn mul_self_t(&mut self, value: T) { self.map_mut(|x| *x = *x * value.clone()) }
            #[inline] pub fn div_self_t(&mut self, value: T) { self.map_mut(|x| *x = *x / value.clone()) }
            #[inline] pub fn rem_self_t(&mut self, value: T) { self.map_mut(|x| *x = *x % value.clone()) }

            #[inline] pub fn add_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a =*a + b) }
            #[inline] pub fn sub_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a =*a - b) }
            #[inline] pub fn mul_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a =*a * b) }
            #[inline] pub fn div_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a =*a / b) }
            #[inline] pub fn rem_self_v(&mut self, other: &$Vec<T>) { self.zip_mut(other, |a, &b| *a =*a % b) }

            #[inline] pub fn dot(&self, other: &$Vec<T>) -> T { vec_dot!($Vec) }
        }
    )
)

macro_rules! vec_dot(
    (Vec2) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1)
    );
    (Vec3) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1) +
        *self.index(2) * *other.index(2)
    );
    (Vec4) => (
        *self.index(0) * *other.index(0) +
        *self.index(1) * *other.index(1) +
        *self.index(2) * *other.index(2) +
        *self.index(3) * *other.index(3)
    );
)

macro_rules! impl_vec_neg(
    ($Vec:ident) => (
        impl<T:Clone + Num> Neg<$Vec<T>> for $Vec<T> {
            #[inline]
            pub fn neg(&self) -> $Vec<T> {
                $Vec::from_slice(self.map(|&x| -x))
            }
        }
    )
)

macro_rules! impl_vec_euclidean(
    ($Vec:ident) => (
        impl<T:Clone + Real> $Vec<T> {
            #[inline]
            pub fn length2(&self) -> T {
                self.dot(self)
            }

            #[inline]
            pub fn length(&self) -> T {
                self.length2().sqrt()
            }

            #[inline]
            pub fn distance2(&self, other: &$Vec<T>) -> T {
                other.sub_v(self).length2()
            }

            #[inline]
            pub fn distance(&self, other: &$Vec<T>) -> T {
                other.distance2(self).sqrt()
            }

            #[inline]
            pub fn angle(&self, other: &$Vec<T>) -> T {
                vec_angle!($Vec)
            }

            #[inline]
            pub fn normalize(&self) -> $Vec<T> {
                self.mul_t(one!(T)/self.length())
            }

            #[inline]
            pub fn normalize_to(&self, length: T) -> $Vec<T> {
                self.mul_t(length / self.length())
            }

            #[inline]
            pub fn lerp(&self, other: &$Vec<T>, amount: T) -> $Vec<T> {
                self.add_v(&other.sub_v(self).mul_t(amount))
            }

            #[inline]
            pub fn normalize_self(&mut self) {
                let rlen = self.length().recip();
                self.mul_self_t(rlen);
            }

            #[inline]
            pub fn normalize_self_to(&mut self, length: T) {
                let n = length / self.length();
                self.mul_self_t(n);
            }

            pub fn lerp_self(&mut self, other: &$Vec<T>, amount: T) {
                let v = other.sub_v(self).mul_t(amount);
                self.add_self_v(&v);
            }
        }
    )
)

macro_rules! vec_angle(
    (Vec2) => (self.perp_dot(other).atan2(&self.dot(other)));
    (Vec3) => (self.cross(other).length().atan2(&self.dot(other)));
    (Vec4) => ((self.dot(other) / (self.length() * other.length())).acos());
)

macro_rules! impl_vec_ord(
    ($Vec:ident) => (
        impl<T:Clone + Ord> $Vec<T> {
            #[inline] pub fn lt_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x < value)) }
            #[inline] pub fn le_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x <= value)) }
            #[inline] pub fn ge_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x >= value)) }
            #[inline] pub fn gt_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x > value)) }

            #[inline] pub fn lt_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a < b)) }
            #[inline] pub fn le_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a <= b)) }
            #[inline] pub fn ge_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a >= b)) }
            #[inline] pub fn gt_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a > b)) }
        }
    )
)

macro_rules! impl_vec_eq(
    ($Vec:ident) => (
        impl<T:Clone + Eq> $Vec<T> {
            #[inline] pub fn eq_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x == value)) }
            #[inline] pub fn ne_t(&self, value: T) -> $Vec<bool> { $Vec::from_slice(self.map(|&x| x != value)) }

            #[inline] pub fn eq_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a == b)) }
            #[inline] pub fn ne_v(&self, other: &$Vec<T>) -> $Vec<bool> { $Vec::from_slice(self.zip(other, |&a, &b| a != b)) }
        }
    )
)

macro_rules! impl_vec_bool(
    ($Vec:ident) => (
        impl $Vec<bool> {
            #[inline]
            pub fn any(&self) -> bool { vec_any!($Vec) }

            #[inline]
            pub fn all(&self) -> bool { vec_all!($Vec) }

            #[inline]
            pub fn not(&self) -> $Vec<bool> {
                $Vec::from_slice(self.map(|&x| !x))
            }
        }
    )
)

macro_rules! vec_any(
    (Vec2) => (*self.index(0) || *self.index(1));
    (Vec3) => (*self.index(0) || *self.index(1) || *self.index(2));
    (Vec4) => (*self.index(0) || *self.index(1) || *self.index(2) || *self.index(3));
)

macro_rules! vec_all(
    (Vec2) => (*self.index(0) && *self.index(1));
    (Vec3) => (*self.index(0) && *self.index(1) && *self.index(2));
    (Vec4) => (*self.index(0) && *self.index(1) && *self.index(2) && *self.index(3));
)

macro_rules! impl_vec_not(
    ($Vec:ident) => (
        impl<T:Clone + Not<T>> Not<$Vec<T>> for $Vec<T> {
            pub fn not(&self) -> $Vec<T> {
                $Vec::from_slice(self.map(|&x| !x))
            }
        }
    )
)
<|endoftext|>


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

use std::ops::{Deref, DerefMut};

use crate::{
    views::{ChangeSet, IndexAddress, View, IndexType, metadata::index_metadata},
    BinaryKey, BinaryValue, Entry, Fork, IndexAccess, KeySetIndex, ListIndex, MapIndex, ObjectHash,
    ProofListIndex, ProofMapIndex, Snapshot,
};

pub trait AnyObject<T: IndexAccess> {
    fn view(self) -> View<T>;
    fn object_type(&self) -> IndexType;
}

impl<T, V> AnyObject<T> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn view(self) -> View<T> {
        self.base
    }

    fn object_type(&self) -> IndexType {
        IndexType::List
    }
}

impl<T, K> AnyObject<T> for KeySetIndex<T, K>
where
    T: IndexAccess,
    K: BinaryKey,
{
    fn view(self) -> View<T> {
        self.base
    }

    fn object_type(&self) -> IndexType {
        IndexType::KeySet
    }
}

pub trait FromView<T: IndexAccess>
where
    Self: Sized,
{
    ///TODO: add documentation [ECR-2820]
    fn get(view: View<T>) -> Option<Self>;

    ///TODO: add documentation [ECR-2820]
    fn create(view: View<T>) -> Self;
}

impl<T, V> FromView<T> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, V> FromView<T> for Entry<T, V>
where
    T: IndexAccess,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K> FromView<T> for KeySetIndex<T, K>
where
    T: IndexAccess,
    K: BinaryKey,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, V> FromView<T> for ProofListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K, V> FromView<T> for ProofMapIndex<T, K, V>
where
    T: IndexAccess,
    K: BinaryKey + ObjectHash,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K, V> FromView<T> for MapIndex<T, K, V>
where
    T: IndexAccess,
    K: BinaryKey,
    V: BinaryValue,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

pub trait ObjectAccess: IndexAccess {
    fn create_view<I: Into<IndexAddress>>(&self, address: I) -> View<Self>;

    fn get_object<I, T>(&self, address: I) -> Option<Ref<T>>
    where
        I: Into<IndexAddress>,
        T: FromView<Self>,
    {
        T::get(self.create_view(address)).map(|value| Ref { value })
    }
}

impl ObjectAccess for &Box<dyn Snapshot> {
    //TODO: check if view creation here is redundant
    fn create_view<I: Into<IndexAddress>>(&self, address: I) -> View<Self> {
        let address = address.into();
        View::new(self, address)
    }
}

impl Fork {
    ///TODO: add documentation [ECR-2820]
    pub fn create_object<'a, T>(&'a self) -> T
    where
        T: FromView<&'a Self>,
    {
        let mut pool_length = self.pool_length.borrow_mut();
        let address = IndexAddress::with_root("temp").append_bytes(&pool_length.clone());
        *pool_length += 1;
        let view = View::new(self, address);
        //TODO: don't create redundant metadata
        T::create(view)
    }

    ///TODO: add documentation [ECR-2820]
    pub fn get_object<'a, T, I>(&'a self, address: I) -> Option<Ref<T>>
    where
        T: FromView<&'a Self>,
        I: Into<IndexAddress>,
    {
        let view = View::new(self, address);
        T::get(view).map(|value| Ref { value })
    }

    ///TODO: add documentation [ECR-2820]
    pub fn get_object_mut<'a, T, I>(&'a self, address: I) -> Option<RefMut<T>>
    where
        T: FromView<&'a Self>,
        I: Into<IndexAddress>,
    {
        let view = View::new(self, address);
        T::get(view).map(|value| RefMut { value })
    }

    pub fn insert<I: Into<IndexAddress>, T: IndexAccess, A: AnyObject<T>>(
        &self,
        address: I,
        object: A,
    ) {
        let index_type = object.object_type();
        let view = object.view();
        let (new_address, _state) = index_metadata::<_, u64>(self, &address.into(), index_type);
        self.working_patch.clear(&view.address);

        let mut changes = self.working_patch.changes_mut(&new_address);
        let view_changes = view.changes.as_ref().unwrap().clone();

        changes.data.extend(view_changes.data);
    }
}

#[derive(Debug)]
///TODO: add documentation [ECR-2820]
pub struct Ref<T> {
    value: T,
}

#[derive(Debug)]
///TODO: add documentation [ECR-2820]
pub struct RefMut<T> {
    value: T,
}

impl<T> Deref for Ref<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> Deref for RefMut<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> DerefMut for RefMut<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        db::Database,
        views::refs::{ObjectAccess, Ref, RefMut},
        KeySetIndex, ListIndex, TemporaryDB,
    };

    #[test]
    fn basic_object_refs() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let mut index: ListIndex<_, u32> = fork.create_object();
            index.push(1);
            fork.insert("index", index);
        }

        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let index: Ref<ListIndex<_, u32>> = snapshot.get_object("index").unwrap();

        assert_eq!(index.get(0), Some(1));
    }

    #[test]
    fn get_non_existent_index() {
        let db = TemporaryDB::new();
        let snapshot = &db.snapshot();
        let index: Option<Ref<ListIndex<_, u32>>> = snapshot.get_object("index");

        assert!(index.is_none());
    }

    #[test]
    fn fork_get_mut() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let list: ListIndex<_, u32> = fork.create_object();
            fork.insert("index", list);
        }

        db.merge(fork.into_patch()).unwrap();

        let fork = db.fork();
        {
            let mut list: RefMut<ListIndex<_, u32>> = fork.get_object_mut("index").unwrap();
            list.push(1);
        }

        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let list: Ref<ListIndex<_, u32>> = snapshot.get_object("index").unwrap();

        assert_eq!(list.get(0), Some(1));
    }

    #[test]
    fn fork_multiple_insert() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let mut index1: KeySetIndex<_, u32> = fork.create_object();
            let mut index2: KeySetIndex<_, u32> = fork.create_object();
            index1.insert(1);
            index2.insert(2);
            fork.insert("index1", index1);
            fork.insert("index2", index2);
        }
        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let index1: Ref<KeySetIndex<_, u32>> = snapshot.get_object("index1").unwrap();
        let index2: Ref<KeySetIndex<_, u32>> = snapshot.get_object("index2").unwrap();

        dbg!(index1.contains(&1));
        dbg!(index2.contains(&2));
    }

}
<commit_msg>Fix fmt.<commit_after>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ops::{Deref, DerefMut};

use crate::{
    views::{metadata::index_metadata, ChangeSet, IndexAddress, IndexType, View},
    BinaryKey, BinaryValue, Entry, Fork, IndexAccess, KeySetIndex, ListIndex, MapIndex, ObjectHash,
    ProofListIndex, ProofMapIndex, Snapshot,
};

pub trait AnyObject<T: IndexAccess> {
    fn view(self) -> View<T>;
    fn object_type(&self) -> IndexType;
}

impl<T, V> AnyObject<T> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn view(self) -> View<T> {
        self.base
    }

    fn object_type(&self) -> IndexType {
        IndexType::List
    }
}

impl<T, K> AnyObject<T> for KeySetIndex<T, K>
where
    T: IndexAccess,
    K: BinaryKey,
{
    fn view(self) -> View<T> {
        self.base
    }

    fn object_type(&self) -> IndexType {
        IndexType::KeySet
    }
}

pub trait FromView<T: IndexAccess>
where
    Self: Sized,
{
    ///TODO: add documentation [ECR-2820]
    fn get(view: View<T>) -> Option<Self>;

    ///TODO: add documentation [ECR-2820]
    fn create(view: View<T>) -> Self;
}

impl<T, V> FromView<T> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, V> FromView<T> for Entry<T, V>
where
    T: IndexAccess,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K> FromView<T> for KeySetIndex<T, K>
where
    T: IndexAccess,
    K: BinaryKey,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, V> FromView<T> for ProofListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K, V> FromView<T> for ProofMapIndex<T, K, V>
where
    T: IndexAccess,
    K: BinaryKey + ObjectHash,
    V: BinaryValue + ObjectHash,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

impl<T, K, V> FromView<T> for MapIndex<T, K, V>
where
    T: IndexAccess,
    K: BinaryKey,
    V: BinaryValue,
{
    fn get(view: View<T>) -> Option<Self> {
        Self::get_from_view(view)
    }

    fn create(view: View<T>) -> Self {
        Self::create_from_view(view)
    }
}

pub trait ObjectAccess: IndexAccess {
    fn create_view<I: Into<IndexAddress>>(&self, address: I) -> View<Self>;

    fn get_object<I, T>(&self, address: I) -> Option<Ref<T>>
    where
        I: Into<IndexAddress>,
        T: FromView<Self>,
    {
        T::get(self.create_view(address)).map(|value| Ref { value })
    }
}

impl ObjectAccess for &Box<dyn Snapshot> {
    //TODO: check if view creation here is redundant
    fn create_view<I: Into<IndexAddress>>(&self, address: I) -> View<Self> {
        let address = address.into();
        View::new(self, address)
    }
}

impl Fork {
    ///TODO: add documentation [ECR-2820]
    pub fn create_object<'a, T>(&'a self) -> T
    where
        T: FromView<&'a Self>,
    {
        let mut pool_length = self.pool_length.borrow_mut();
        let address = IndexAddress::with_root("temp").append_bytes(&pool_length.clone());
        *pool_length += 1;
        let view = View::new(self, address);
        //TODO: don't create redundant metadata
        T::create(view)
    }

    ///TODO: add documentation [ECR-2820]
    pub fn get_object<'a, T, I>(&'a self, address: I) -> Option<Ref<T>>
    where
        T: FromView<&'a Self>,
        I: Into<IndexAddress>,
    {
        let view = View::new(self, address);
        T::get(view).map(|value| Ref { value })
    }

    ///TODO: add documentation [ECR-2820]
    pub fn get_object_mut<'a, T, I>(&'a self, address: I) -> Option<RefMut<T>>
    where
        T: FromView<&'a Self>,
        I: Into<IndexAddress>,
    {
        let view = View::new(self, address);
        T::get(view).map(|value| RefMut { value })
    }

    ///TODO: add documentation [ECR-2820]
    pub fn insert<I: Into<IndexAddress>, T: IndexAccess, A: AnyObject<T>>(
        &self,
        address: I,
        object: A,
    ) {
        let index_type = object.object_type();
        let view = object.view();
        let (new_address, _state) = index_metadata::<_, u64>(self, &address.into(), index_type);
        self.working_patch.clear(&view.address);

        let mut changes = self.working_patch.changes_mut(&new_address);
        let view_changes = view.changes.as_ref().unwrap().clone();

        changes.data.extend(view_changes.data);
    }
}

#[derive(Debug)]
///TODO: add documentation [ECR-2820]
pub struct Ref<T> {
    value: T,
}

#[derive(Debug)]
///TODO: add documentation [ECR-2820]
pub struct RefMut<T> {
    value: T,
}

impl<T> Deref for Ref<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> Deref for RefMut<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> DerefMut for RefMut<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        db::Database,
        views::refs::{ObjectAccess, Ref, RefMut},
        KeySetIndex, ListIndex, TemporaryDB,
    };

    #[test]
    fn basic_object_refs() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let mut index: ListIndex<_, u32> = fork.create_object();
            index.push(1);
            fork.insert("index", index);
        }

        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let index: Ref<ListIndex<_, u32>> = snapshot.get_object("index").unwrap();

        assert_eq!(index.get(0), Some(1));
    }

    #[test]
    fn get_non_existent_index() {
        let db = TemporaryDB::new();
        let snapshot = &db.snapshot();
        let index: Option<Ref<ListIndex<_, u32>>> = snapshot.get_object("index");

        assert!(index.is_none());
    }

    #[test]
    fn fork_get_mut() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let list: ListIndex<_, u32> = fork.create_object();
            fork.insert("index", list);
        }

        db.merge(fork.into_patch()).unwrap();

        let fork = db.fork();
        {
            let mut list: RefMut<ListIndex<_, u32>> = fork.get_object_mut("index").unwrap();
            list.push(1);
        }

        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let list: Ref<ListIndex<_, u32>> = snapshot.get_object("index").unwrap();

        assert_eq!(list.get(0), Some(1));
    }

    #[test]
    fn fork_multiple_insert() {
        let db = TemporaryDB::new();
        let fork = db.fork();
        {
            let mut index1: KeySetIndex<_, u32> = fork.create_object();
            let mut index2: KeySetIndex<_, u32> = fork.create_object();
            index1.insert(1);
            index2.insert(2);
            fork.insert("index1", index1);
            fork.insert("index2", index2);
        }
        db.merge(fork.into_patch()).unwrap();

        let snapshot = &db.snapshot();
        let index1: Ref<KeySetIndex<_, u32>> = snapshot.get_object("index1").unwrap();
        let index2: Ref<KeySetIndex<_, u32>> = snapshot.get_object("index2").unwrap();

        dbg!(index1.contains(&1));
        dbg!(index2.contains(&2));
    }

}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Arithmetic/Integer
// not_tested

#![allow(unused_imports)]
use std::io::stdio::stdin;
use std::from_str::from_str;
use std::io::BufferedReader;

fn main() {
    let input = BufferedReader::new(stdin()).read_line().unwrap();
    let words = input.as_slice().words().take(2)
                            .map(from_str)
                            .collect::<Vec<Option<int>>>();

    let (a, b) = match words.as_slice() {
            [Some(x), Some(y)] => (x, y),
            _                  => fail!("Please enter 2 integers")
    };

    println!("a + b = {}", a + b);
    println!("a - b = {}", a - b);
    println!("a * b = {}", a * b);
    println!("a / b = {}", a / b);
    println!("a % b = {}", a % b);
}
<commit_msg>`from_str` is in the prelude. No need to `use` it.<commit_after>// Implements http://rosettacode.org/wiki/Arithmetic/Integer
// not_tested

#![allow(unused_imports)]
use std::io::stdio::stdin;
use std::io::BufferedReader;

fn main() {
    let input = BufferedReader::new(stdin()).read_line().unwrap();
    let words = input.as_slice().words().take(2)
                            .map(from_str)
                            .collect::<Vec<Option<int>>>();

    let (a, b) = match words.as_slice() {
            [Some(x), Some(y)] => (x, y),
            _                  => fail!("Please enter 2 integers")
    };

    println!("a + b = {}", a + b);
    println!("a - b = {}", a - b);
    println!("a * b = {}", a * b);
    println!("a / b = {}", a / b);
    println!("a % b = {}", a % b);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    // let out_dir = env::var("OUT_DIR").unwrap();
    let current_dir = env::current_dir().unwrap();

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("qmlbind");

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    Command::new("qmake").current_dir(&libqmlbind_dir).output().unwrap();
    Command::new("make").current_dir(&libqmlbind_dir).output().unwrap();
    Command::new("make").arg("staticlib").current_dir(&libqmlbind_build_dir).output().unwrap();

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qt_lib_dir = qt_dir.join("lib").to_str().unwrap().to_string();

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir);

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<commit_msg>libqmlbind-sys: Use 'build' as build directory instead of 'qmlbind'<commit_after>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    // let out_dir = env::var("OUT_DIR").unwrap();
    let current_dir = env::current_dir().unwrap();

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    Command::new("qmake").current_dir(&libqmlbind_dir).output().unwrap();
    Command::new("make").current_dir(&libqmlbind_dir).output().unwrap();
    Command::new("make").arg("staticlib").current_dir(&libqmlbind_build_dir).output().unwrap();

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qt_lib_dir = qt_dir.join("lib").to_str().unwrap().to_string();

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir);

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<|endoftext|>


<commit_before>extern crate native;

use self::native::NativeTaskBuilder;
use std::task::TaskBuilder;
use std::sync::atomics::AtomicBool;
use std::ptr;
use super::{event, ffi};
use super::{MonitorID, Window};
use {Event, Hints};

/// Stores the current window and its events dispatcher.
///
/// We only have one window per thread. We still store the HWND in case where we
///  receive an event for another window.
local_data_key!(WINDOW: (ffi::HWND, Sender<Event>))

pub fn new_window(dimensions: Option<(uint, uint)>, title: &str,
    _hints: &Hints, monitor: Option<MonitorID>)
    -> Result<Window, String>
{
    use std::mem;
    use std::os;

    // initializing variables to be sent to the task
    let title = title.utf16_units().collect::<Vec<u16>>().append_one(0);    // title to utf16
    //let hints = hints.clone();
    let (tx, rx) = channel();

    // GetMessage must be called in the same thread as CreateWindow,
    //  so we create a new thread dedicated to this window.
    // This is the only safe method. Using `nosend` wouldn't work for non-native runtime.
    TaskBuilder::new().native().spawn(proc() {
        // registering the window class
        let class_name = {
            let class_name: Vec<u16> = "Window Class".utf16_units().collect::<Vec<u16>>()
                .append_one(0);

            let class = ffi::WNDCLASSEX {
                cbSize: mem::size_of::<ffi::WNDCLASSEX>() as ffi::UINT,
                style: ffi::CS_HREDRAW | ffi::CS_VREDRAW,
                lpfnWndProc: callback,
                cbClsExtra: 0,
                cbWndExtra: 0,
                hInstance: unsafe { ffi::GetModuleHandleW(ptr::null()) },
                hIcon: ptr::mut_null(),
                hCursor: ptr::mut_null(),
                hbrBackground: ptr::mut_null(),
                lpszMenuName: ptr::null(),
                lpszClassName: class_name.as_ptr(),
                hIconSm: ptr::mut_null(),
            };

            // We ignore errors because registering the same window class twice would trigger
            //  an error, and because errors here are detected during CreateWindowEx anyway.
            // Also since there is no weird element in the struct, there is no reason for this
            //  call to fail.
            unsafe { ffi::RegisterClassExW(&class) };

            class_name
        };

        // building a RECT object with coordinates
        let mut rect = ffi::RECT {
            left: 0, right: dimensions.map(|(w, _)| w as ffi::LONG).unwrap_or(1024),
            top: 0, bottom: dimensions.map(|(_, h)| h as ffi::LONG).unwrap_or(768),
        };

        // switching to fullscreen if necessary
        // this means adjusting the window's position so that it overlaps the right monitor,
        //  and change the monitor's resolution if necessary
        if monitor.is_some() {
            let monitor = monitor.as_ref().unwrap();

            // adjusting the rect
            {
                let pos = monitor.get_position();
                rect.left += pos.val0() as ffi::LONG;
                rect.right += pos.val0() as ffi::LONG;
                rect.top += pos.val1() as ffi::LONG;
                rect.bottom += pos.val1() as ffi::LONG;
            }

            // changing device settings
            let mut screen_settings: ffi::DEVMODE = unsafe { mem::zeroed() };
            screen_settings.dmSize = mem::size_of::<ffi::DEVMODE>() as ffi::WORD;
            screen_settings.dmPelsWidth = 1024;
            screen_settings.dmPelsHeight = 768;
            screen_settings.dmBitsPerPel = 32;
            screen_settings.dmFields = ffi::DM_BITSPERPEL | ffi::DM_PELSWIDTH | ffi::DM_PELSHEIGHT;

            let result = unsafe { ffi::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(),
                &mut screen_settings, ptr::mut_null(), ffi::CDS_FULLSCREEN, ptr::mut_null()) };
            if result != ffi::DISP_CHANGE_SUCCESSFUL {
                tx.send(Err(format!("ChangeDisplaySettings failed: {}", result)));
                return;
            }
        }

        // computing the style and extended style of the window
        let (ex_style, style) = if monitor.is_some() {
            (ffi::WS_EX_APPWINDOW, ffi::WS_POPUP | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN)
        } else {
            (ffi::WS_EX_APPWINDOW | ffi::WS_EX_WINDOWEDGE,
                ffi::WS_OVERLAPPEDWINDOW | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN)
        };

        // adjusting the window coordinates using the style
        unsafe { ffi::AdjustWindowRectEx(&mut rect, style, 0, ex_style) };

        // creating the window
        let handle = unsafe {
            let handle = ffi::CreateWindowExW(ex_style, class_name.as_ptr(),
                title.as_ptr() as ffi::LPCWSTR,
                style | ffi::WS_VISIBLE | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN,
                if monitor.is_some() { 0 } else { ffi::CW_USEDEFAULT},
                if monitor.is_some() { 0 } else { ffi::CW_USEDEFAULT},
                rect.right - rect.left, rect.bottom - rect.top,
                ptr::mut_null(), ptr::mut_null(), ffi::GetModuleHandleW(ptr::null()),
                ptr::mut_null());

            if handle.is_null() {
                use std::os;
                tx.send(Err(format!("CreateWindowEx function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }

            handle
        };

        // calling SetForegroundWindow if fullscreen
        if monitor.is_some() {
            unsafe { ffi::SetForegroundWindow(handle) };
        }

        // filling the WINDOW task-local storage
        let events_receiver = {
            let (tx, rx) = channel();
            WINDOW.replace(Some((handle, tx)));
            rx
        };

        // Getting the HDC of the window
        let hdc = {
            let hdc = unsafe { ffi::GetDC(handle) };
            if hdc.is_null() {
                tx.send(Err(format!("GetDC function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
            hdc
        };

        // getting the pixel format that we will use
        // TODO: use something cleaner which uses hints
        let pixel_format = {
            let mut output: ffi::PIXELFORMATDESCRIPTOR = unsafe { mem::uninitialized() };

            if unsafe { ffi::DescribePixelFormat(hdc, 1,
                mem::size_of::<ffi::PIXELFORMATDESCRIPTOR>() as ffi::UINT, &mut output) } == 0
            {
                tx.send(Err(format!("DescribePixelFormat function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }

            output
        };

        // calling SetPixelFormat
        unsafe {
            if ffi::SetPixelFormat(hdc, 1, &pixel_format) == 0 {
                tx.send(Err(format!("SetPixelFormat function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
        }

        // creating the OpenGL context
        let context = {
            let ctxt = unsafe { ffi::wglCreateContext(hdc) };
            if ctxt.is_null() {
                tx.send(Err(format!("wglCreateContext function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
            ctxt
        };

        // loading the opengl32 module
        let gl_library = {
            let name = "opengl32.dll".utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr();
            let lib = unsafe { ffi::LoadLibraryW(name) };
            if lib.is_null() {
                tx.send(Err(format!("LoadLibrary function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
            lib
        };

        // building the struct
        tx.send(Ok(Window{
            window: handle,
            hdc: hdc,
            context: context,
            gl_library: gl_library,
            events_receiver: events_receiver,
            is_closed: AtomicBool::new(false),
        }));

        // now that the `Window` struct is initialized, the main `Window::new()` function will
        //  return and this events loop will run in parallel
        loop {
            let mut msg = unsafe { mem::uninitialized() };

            if unsafe { ffi::GetMessageW(&mut msg, ptr::mut_null(), 0, 0) } == 0 {
                break;
            }

            unsafe { ffi::TranslateMessage(&msg) };
            unsafe { ffi::DispatchMessageW(&msg) };     // calls `callback` (see below)
        }
    });

    rx.recv()
}

/// Checks that the window is the good one, and if so send the event to it.
fn send_event(window: ffi::HWND, event: Event) {
    let stored = match WINDOW.get() {
        None => return,
        Some(v) => v
    };

    let &(ref win, ref sender) = stored.deref();

    if win != &window {
        return;
    }

    sender.send_opt(event).ok();  // ignoring if closed
}

/// This is the callback that is called by `DispatchMessage` in the events loop.
///
/// Returning 0 tells the Win32 API that the message has been processed.
extern "stdcall" fn callback(window: ffi::HWND, msg: ffi::UINT,
    wparam: ffi::WPARAM, lparam: ffi::LPARAM) -> ffi::LRESULT
{
    match msg {
        ffi::WM_DESTROY => {
            use Closed;
            unsafe { ffi::PostQuitMessage(0); }
            send_event(window, Closed);
            0
        },

        ffi::WM_SIZE => {
            use Resized;
            let w = ffi::LOWORD(lparam as ffi::DWORD) as uint;
            let h = ffi::HIWORD(lparam as ffi::DWORD) as uint;
            send_event(window, Resized(w, h));
            0
        },

        ffi::WM_MOVE => {
            use events::Moved;
            let x = ffi::LOWORD(lparam as ffi::DWORD) as i16 as int;
            let y = ffi::HIWORD(lparam as ffi::DWORD) as i16 as int;
            send_event(window, Moved(x, y));
            0
        },

        ffi::WM_CHAR => {
            use std::mem;
            use events::ReceivedCharacter;
            let chr: char = unsafe { mem::transmute(wparam) };
            send_event(window, ReceivedCharacter(chr));
            0
        },

        ffi::WM_MOUSEMOVE => {
            use CursorPositionChanged;

            let x = ffi::GET_X_LPARAM(lparam) as uint;
            let y = ffi::GET_Y_LPARAM(lparam) as uint;

            send_event(window, CursorPositionChanged(x, y));

            0
        },

        ffi::WM_KEYDOWN => {
            use events::Pressed;
            let element = event::vkeycode_to_element(wparam);
            if element.is_some() {
                send_event(window, Pressed(element.unwrap()));
            }
            0
        },

        ffi::WM_KEYUP => {
            use events::Released;
            let element = event::vkeycode_to_element(wparam);
            if element.is_some() {
                send_event(window, Released(element.unwrap()));
            }
            0
        },

        ffi::WM_LBUTTONDOWN => {
            use events::{Pressed, Button0};
            send_event(window, Pressed(Button0));
            0
        },

        ffi::WM_LBUTTONUP => {
            use events::{Released, Button0};
            send_event(window, Released(Button0));
            0
        },

        ffi::WM_RBUTTONDOWN => {
            use events::{Pressed, Button1};
            send_event(window, Pressed(Button1));
            0
        },

        ffi::WM_RBUTTONUP => {
            use events::{Released, Button1};
            send_event(window, Released(Button1));
            0
        },

        ffi::WM_MBUTTONDOWN => {
            use events::{Pressed, Button2};
            send_event(window, Pressed(Button2));
            0
        },

        ffi::WM_MBUTTONUP => {
            use events::{Released, Button2};
            send_event(window, Released(Button2));
            0
        },

        ffi::WM_SETFOCUS => {
            use events::Focused;
            send_event(window, Focused(true));
            0
        },

        ffi::WM_KILLFOCUS => {
            use events::Focused;
            send_event(window, Focused(false));
            0
        },

        _ => unsafe {
            ffi::DefWindowProcW(window, msg, wparam, lparam)
        }
    }
}

/*fn hints_to_pixelformat(hints: &Hints) -> ffi::PIXELFORMATDESCRIPTOR {
    use std::mem;

    ffi::PIXELFORMATDESCRIPTOR {
        nSize: size_of::<ffi::PIXELFORMATDESCRIPTOR>(),
        nVersion: 1,
        dwFlags:
            if hints.stereo { PFD_STEREO } else { 0 },
        iPixelType: PFD_TYPE_RGBA,
        cColorBits: hints.red_bits + hints.green_bits + hints.blue_bits,
        cRedBits:

    pub nSize: WORD,
    pub nVersion: WORD,
    pub dwFlags: DWORD,
    pub iPixelType: BYTE,
    pub cColorBits: BYTE,
    pub cRedBits: BYTE,
    pub cRedShift: BYTE,
    pub cGreenBits: BYTE,
    pub cGreenShift: BYTE,
    pub cBlueBits: BYTE,
    pub cBlueShift: BYTE,
    pub cAlphaBits: BYTE,
    pub cAlphaShift: BYTE,
    pub cAccumBits: BYTE,
    pub cAccumRedBits: BYTE,
    pub cAccumGreenBits: BYTE,
    pub cAccumBlueBits: BYTE,
    pub cAccumAlphaBits: BYTE,
    pub cDepthBits: BYTE,
    pub cStencilBits: BYTE,
    pub cAuxBuffers: BYTE,
    pub iLayerType: BYTE,
    pub bReserved: BYTE,
    pub dwLayerMask: DWORD,
    pub dwVisibleMask: DWORD,
    pub dwDamageMask: DWORD,
    }
}*/
<commit_msg>Now using wglCreateContextAttribs when available<commit_after>extern crate native;

use self::native::NativeTaskBuilder;
use std::task::TaskBuilder;
use std::sync::atomics::AtomicBool;
use std::ptr;
use super::{event, ffi};
use super::{MonitorID, Window};
use {Event, Hints};

/// Stores the current window and its events dispatcher.
///
/// We only have one window per thread. We still store the HWND in case where we
///  receive an event for another window.
local_data_key!(WINDOW: (ffi::HWND, Sender<Event>))

pub fn new_window(dimensions: Option<(uint, uint)>, title: &str,
    _hints: &Hints, monitor: Option<MonitorID>)
    -> Result<Window, String>
{
    use std::mem;
    use std::os;

    // initializing variables to be sent to the task
    let title = title.utf16_units().collect::<Vec<u16>>().append_one(0);    // title to utf16
    //let hints = hints.clone();
    let (tx, rx) = channel();

    // GetMessage must be called in the same thread as CreateWindow,
    //  so we create a new thread dedicated to this window.
    // This is the only safe method. Using `nosend` wouldn't work for non-native runtime.
    TaskBuilder::new().native().spawn(proc() {
        // registering the window class
        let class_name = {
            let class_name: Vec<u16> = "Window Class".utf16_units().collect::<Vec<u16>>()
                .append_one(0);

            let class = ffi::WNDCLASSEX {
                cbSize: mem::size_of::<ffi::WNDCLASSEX>() as ffi::UINT,
                style: ffi::CS_HREDRAW | ffi::CS_VREDRAW,
                lpfnWndProc: callback,
                cbClsExtra: 0,
                cbWndExtra: 0,
                hInstance: unsafe { ffi::GetModuleHandleW(ptr::null()) },
                hIcon: ptr::mut_null(),
                hCursor: ptr::mut_null(),
                hbrBackground: ptr::mut_null(),
                lpszMenuName: ptr::null(),
                lpszClassName: class_name.as_ptr(),
                hIconSm: ptr::mut_null(),
            };

            // We ignore errors because registering the same window class twice would trigger
            //  an error, and because errors here are detected during CreateWindowEx anyway.
            // Also since there is no weird element in the struct, there is no reason for this
            //  call to fail.
            unsafe { ffi::RegisterClassExW(&class) };

            class_name
        };

        // building a RECT object with coordinates
        let mut rect = ffi::RECT {
            left: 0, right: dimensions.map(|(w, _)| w as ffi::LONG).unwrap_or(1024),
            top: 0, bottom: dimensions.map(|(_, h)| h as ffi::LONG).unwrap_or(768),
        };

        // switching to fullscreen if necessary
        // this means adjusting the window's position so that it overlaps the right monitor,
        //  and change the monitor's resolution if necessary
        if monitor.is_some() {
            let monitor = monitor.as_ref().unwrap();

            // adjusting the rect
            {
                let pos = monitor.get_position();
                rect.left += pos.val0() as ffi::LONG;
                rect.right += pos.val0() as ffi::LONG;
                rect.top += pos.val1() as ffi::LONG;
                rect.bottom += pos.val1() as ffi::LONG;
            }

            // changing device settings
            let mut screen_settings: ffi::DEVMODE = unsafe { mem::zeroed() };
            screen_settings.dmSize = mem::size_of::<ffi::DEVMODE>() as ffi::WORD;
            screen_settings.dmPelsWidth = 1024;
            screen_settings.dmPelsHeight = 768;
            screen_settings.dmBitsPerPel = 32;
            screen_settings.dmFields = ffi::DM_BITSPERPEL | ffi::DM_PELSWIDTH | ffi::DM_PELSHEIGHT;

            let result = unsafe { ffi::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(),
                &mut screen_settings, ptr::mut_null(), ffi::CDS_FULLSCREEN, ptr::mut_null()) };
            if result != ffi::DISP_CHANGE_SUCCESSFUL {
                tx.send(Err(format!("ChangeDisplaySettings failed: {}", result)));
                return;
            }
        }

        // computing the style and extended style of the window
        let (ex_style, style) = if monitor.is_some() {
            (ffi::WS_EX_APPWINDOW, ffi::WS_POPUP | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN)
        } else {
            (ffi::WS_EX_APPWINDOW | ffi::WS_EX_WINDOWEDGE,
                ffi::WS_OVERLAPPEDWINDOW | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN)
        };

        // adjusting the window coordinates using the style
        unsafe { ffi::AdjustWindowRectEx(&mut rect, style, 0, ex_style) };

        // getting the address of wglCreateContextAttribs and the pixel format
        //  that we will use
        let (create_context_attribs, pixel_format) = {
            // creating a dummy invisible window for GL initialization
            let dummy_window = unsafe {
                let handle = ffi::CreateWindowExW(ex_style, class_name.as_ptr(),
                    title.as_ptr() as ffi::LPCWSTR,
                    style | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN,
                    ffi::CW_USEDEFAULT, ffi::CW_USEDEFAULT,
                    rect.right - rect.left, rect.bottom - rect.top,
                    ptr::mut_null(), ptr::mut_null(), ffi::GetModuleHandleW(ptr::null()),
                    ptr::mut_null());

                if handle.is_null() {
                    use std::os;
                    tx.send(Err(format!("CreateWindowEx function failed: {}",
                        os::error_string(os::errno() as uint))));
                    return;
                }

                handle
            };

            // getting the HDC of the dummy window
            let dummy_hdc = {
                let hdc = unsafe { ffi::GetDC(dummy_window) };
                if hdc.is_null() {
                    tx.send(Err(format!("GetDC function failed: {}",
                        os::error_string(os::errno() as uint))));
                    return;
                }
                hdc
            };

            // getting the pixel format that we will use
            // TODO: use something cleaner which uses hints
            let pixel_format = {
                let mut output: ffi::PIXELFORMATDESCRIPTOR = unsafe { mem::uninitialized() };

                if unsafe { ffi::DescribePixelFormat(dummy_hdc, 1,
                    mem::size_of::<ffi::PIXELFORMATDESCRIPTOR>() as ffi::UINT, &mut output) } == 0
                {
                    tx.send(Err(format!("DescribePixelFormat function failed: {}",
                        os::error_string(os::errno() as uint))));
                    return;
                }

                output
            };

            // calling SetPixelFormat
            unsafe {
                if ffi::SetPixelFormat(dummy_hdc, 1, &pixel_format) == 0 {
                    tx.send(Err(format!("SetPixelFormat function failed: {}",
                        os::error_string(os::errno() as uint))));
                    return;
                }
            }

            // creating the dummy OpenGL context
            let dummy_context = {
                let ctxt = unsafe { ffi::wglCreateContext(dummy_hdc) };
                if ctxt.is_null() {
                    tx.send(Err(format!("wglCreateContext function failed: {}",
                        os::error_string(os::errno() as uint))));
                    return;
                }
                ctxt
            };

            // making context current
            unsafe { ffi::wglMakeCurrent(dummy_hdc, dummy_context); }

            // getting the pointer to wglCreateContextAttribs
            let mut addr = unsafe { ffi::wglGetProcAddress(b"wglCreateContextAttribs".as_ptr()
                as *const i8) } as *const ();

            if addr.is_null() {
                addr = unsafe { ffi::wglGetProcAddress(b"wglCreateContextAttribsARB".as_ptr()
                    as *const i8) } as *const ();
            }

            // removing current context
            unsafe { ffi::wglMakeCurrent(ptr::mut_null(), ptr::mut_null()); }

            // destroying the context and the window
            unsafe { ffi::wglDeleteContext(dummy_context); }
            unsafe { ffi::DestroyWindow(dummy_window); }

            // returning the address
            if addr.is_null() {
                (None, pixel_format)
            } else {
                use libc;
                let addr: extern "system" fn(ffi::HDC, ffi::HGLRC, *const libc::c_int) -> ffi::HGLRC
                    = unsafe { mem::transmute(addr) };
                (Some(addr), pixel_format)
            }
        };

        // creating the real window this time
        let real_window = unsafe {
            let handle = ffi::CreateWindowExW(ex_style, class_name.as_ptr(),
                title.as_ptr() as ffi::LPCWSTR,
                style | ffi::WS_VISIBLE | ffi::WS_CLIPSIBLINGS | ffi::WS_CLIPCHILDREN,
                if monitor.is_some() { 0 } else { ffi::CW_USEDEFAULT},
                if monitor.is_some() { 0 } else { ffi::CW_USEDEFAULT},
                rect.right - rect.left, rect.bottom - rect.top,
                ptr::mut_null(), ptr::mut_null(), ffi::GetModuleHandleW(ptr::null()),
                ptr::mut_null());

            if handle.is_null() {
                use std::os;
                tx.send(Err(format!("CreateWindowEx function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }

            handle
        };

        // getting the HDC of the window
        let hdc = {
            let hdc = unsafe { ffi::GetDC(real_window) };
            if hdc.is_null() {
                tx.send(Err(format!("GetDC function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
            hdc
        };

        // calling SetPixelFormat
        unsafe {
            if ffi::SetPixelFormat(hdc, 1, &pixel_format) == 0 {
                tx.send(Err(format!("SetPixelFormat function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
        }

        // creating the OpenGL context
        let context = {
            use libc;

            let attributes: [libc::c_int, ..1] = [
                0
            ];

            let ctxt = unsafe {
                match create_context_attribs {
                    None => ffi::wglCreateContext(hdc),
                    Some(ptr) => ptr(hdc, ptr::mut_null(), attributes.as_ptr())
                }
            };

            if ctxt.is_null() {
                tx.send(Err(format!("OpenGL context creation failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }

            ctxt
        };

        // calling SetForegroundWindow if fullscreen
        if monitor.is_some() {
            unsafe { ffi::SetForegroundWindow(real_window) };
        }

        // filling the WINDOW task-local storage
        let events_receiver = {
            let (tx, rx) = channel();
            WINDOW.replace(Some((real_window, tx)));
            rx
        };

        // loading the opengl32 module
        let gl_library = {
            let name = "opengl32.dll".utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr();
            let lib = unsafe { ffi::LoadLibraryW(name) };
            if lib.is_null() {
                tx.send(Err(format!("LoadLibrary function failed: {}",
                    os::error_string(os::errno() as uint))));
                return;
            }
            lib
        };

        // building the struct
        tx.send(Ok(Window{
            window: real_window,
            hdc: hdc,
            context: context,
            gl_library: gl_library,
            events_receiver: events_receiver,
            is_closed: AtomicBool::new(false),
        }));

        // now that the `Window` struct is initialized, the main `Window::new()` function will
        //  return and this events loop will run in parallel
        loop {
            let mut msg = unsafe { mem::uninitialized() };

            if unsafe { ffi::GetMessageW(&mut msg, ptr::mut_null(), 0, 0) } == 0 {
                break;
            }

            unsafe { ffi::TranslateMessage(&msg) };
            unsafe { ffi::DispatchMessageW(&msg) };     // calls `callback` (see below)
        }
    });

    rx.recv()
}

/// Checks that the window is the good one, and if so send the event to it.
fn send_event(window: ffi::HWND, event: Event) {
    let stored = match WINDOW.get() {
        None => return,
        Some(v) => v
    };

    let &(ref win, ref sender) = stored.deref();

    if win != &window {
        return;
    }

    sender.send_opt(event).ok();  // ignoring if closed
}

/// This is the callback that is called by `DispatchMessage` in the events loop.
///
/// Returning 0 tells the Win32 API that the message has been processed.
extern "stdcall" fn callback(window: ffi::HWND, msg: ffi::UINT,
    wparam: ffi::WPARAM, lparam: ffi::LPARAM) -> ffi::LRESULT
{
    match msg {
        ffi::WM_DESTROY => {
            use Closed;

            match WINDOW.get() {
                None => (),
                Some(v) => {
                    let &(ref win, _) = v.deref();

                    if win == &window {
                        unsafe { ffi::PostQuitMessage(0); }
                    }
                }
            };

            send_event(window, Closed);
            0
        },

        ffi::WM_SIZE => {
            use Resized;
            let w = ffi::LOWORD(lparam as ffi::DWORD) as uint;
            let h = ffi::HIWORD(lparam as ffi::DWORD) as uint;
            send_event(window, Resized(w, h));
            0
        },

        ffi::WM_MOVE => {
            use events::Moved;
            let x = ffi::LOWORD(lparam as ffi::DWORD) as i16 as int;
            let y = ffi::HIWORD(lparam as ffi::DWORD) as i16 as int;
            send_event(window, Moved(x, y));
            0
        },

        ffi::WM_CHAR => {
            use std::mem;
            use events::ReceivedCharacter;
            let chr: char = unsafe { mem::transmute(wparam) };
            send_event(window, ReceivedCharacter(chr));
            0
        },

        ffi::WM_MOUSEMOVE => {
            use CursorPositionChanged;

            let x = ffi::GET_X_LPARAM(lparam) as uint;
            let y = ffi::GET_Y_LPARAM(lparam) as uint;

            send_event(window, CursorPositionChanged(x, y));

            0
        },

        ffi::WM_KEYDOWN => {
            use events::Pressed;
            let element = event::vkeycode_to_element(wparam);
            if element.is_some() {
                send_event(window, Pressed(element.unwrap()));
            }
            0
        },

        ffi::WM_KEYUP => {
            use events::Released;
            let element = event::vkeycode_to_element(wparam);
            if element.is_some() {
                send_event(window, Released(element.unwrap()));
            }
            0
        },

        ffi::WM_LBUTTONDOWN => {
            use events::{Pressed, Button0};
            send_event(window, Pressed(Button0));
            0
        },

        ffi::WM_LBUTTONUP => {
            use events::{Released, Button0};
            send_event(window, Released(Button0));
            0
        },

        ffi::WM_RBUTTONDOWN => {
            use events::{Pressed, Button1};
            send_event(window, Pressed(Button1));
            0
        },

        ffi::WM_RBUTTONUP => {
            use events::{Released, Button1};
            send_event(window, Released(Button1));
            0
        },

        ffi::WM_MBUTTONDOWN => {
            use events::{Pressed, Button2};
            send_event(window, Pressed(Button2));
            0
        },

        ffi::WM_MBUTTONUP => {
            use events::{Released, Button2};
            send_event(window, Released(Button2));
            0
        },

        ffi::WM_SETFOCUS => {
            use events::Focused;
            send_event(window, Focused(true));
            0
        },

        ffi::WM_KILLFOCUS => {
            use events::Focused;
            send_event(window, Focused(false));
            0
        },

        _ => unsafe {
            ffi::DefWindowProcW(window, msg, wparam, lparam)
        }
    }
}

/*fn hints_to_pixelformat(hints: &Hints) -> ffi::PIXELFORMATDESCRIPTOR {
    use std::mem;

    ffi::PIXELFORMATDESCRIPTOR {
        nSize: size_of::<ffi::PIXELFORMATDESCRIPTOR>(),
        nVersion: 1,
        dwFlags:
            if hints.stereo { PFD_STEREO } else { 0 },
        iPixelType: PFD_TYPE_RGBA,
        cColorBits: hints.red_bits + hints.green_bits + hints.blue_bits,
        cRedBits:

    pub nSize: WORD,
    pub nVersion: WORD,
    pub dwFlags: DWORD,
    pub iPixelType: BYTE,
    pub cColorBits: BYTE,
    pub cRedBits: BYTE,
    pub cRedShift: BYTE,
    pub cGreenBits: BYTE,
    pub cGreenShift: BYTE,
    pub cBlueBits: BYTE,
    pub cBlueShift: BYTE,
    pub cAlphaBits: BYTE,
    pub cAlphaShift: BYTE,
    pub cAccumBits: BYTE,
    pub cAccumRedBits: BYTE,
    pub cAccumGreenBits: BYTE,
    pub cAccumBlueBits: BYTE,
    pub cAccumAlphaBits: BYTE,
    pub cDepthBits: BYTE,
    pub cStencilBits: BYTE,
    pub cAuxBuffers: BYTE,
    pub iLayerType: BYTE,
    pub bReserved: BYTE,
    pub dwLayerMask: DWORD,
    pub dwVisibleMask: DWORD,
    pub dwDamageMask: DWORD,
    }
}*/
<|endoftext|>


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

use std::collections::HashSet;
use std::{ffi, fmt, mem, str};
use gl;
use gfx_core::Capabilities;

/// A version number for a specific component of an OpenGL implementation
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Version {
    pub is_embedded: bool,
    pub major: u32,
    pub minor: u32,
    pub revision: Option<u32>,
    pub vendor_info: &'static str,
}

impl Version {
    /// Create a new OpenGL version number
    pub fn new(major: u32, minor: u32, revision: Option<u32>,
               vendor_info: &'static str) -> Version {
        Version {
            is_embedded: false,
            major: major,
            minor: minor,
            revision: revision,
            vendor_info: vendor_info,
        }
    }
    /// Create a new OpenGL ES version number
    pub fn new_embedded(major: u32, minor: u32, vendor_info: &'static str) -> Version {
        Version {
            is_embedded: true,
            major: major,
            minor: minor,
            revision: None,
            vendor_info: vendor_info,
        }
    }

    /// According to the OpenGL specification, the version information is
    /// expected to follow the following syntax:
    ///
    /// ~~~bnf
    /// <major>       ::= <number>
    /// <minor>       ::= <number>
    /// <revision>    ::= <number>
    /// <vendor-info> ::= <string>
    /// <release>     ::= <major> "." <minor> ["." <release>]
    /// <version>     ::= <release> [" " <vendor-info>]
    /// ~~~
    ///
    /// Note that this function is intentionally lenient in regards to parsing,
    /// and will try to recover at least the first two version numbers without
    /// resulting in an `Err`.
    pub fn parse(mut src: &'static str) -> Result<Version, &'static str> {
        let es_sig = " ES ";
        let is_es = match src.rfind(es_sig) {
            Some(pos) => {
                src = &src[pos + es_sig.len() ..];
                true
            },
            None => false,
        };
        let (version, vendor_info) = match src.find(' ') {
            Some(i) => (&src[..i], &src[i+1..]),
            None => (src, ""),
        };

        // TODO: make this even more lenient so that we can also accept
        // `<major> "." <minor> [<???>]`
        let mut it = version.split('.');
        let major = it.next().and_then(|s| s.parse().ok());
        let minor = it.next().and_then(|s| s.parse().ok());
        let revision = it.next().and_then(|s| s.parse().ok());

        match (major, minor, revision) {
            (Some(major), Some(minor), revision) => Ok(Version {
                is_embedded: is_es,
                major: major,
                minor: minor,
                revision: revision,
                vendor_info: vendor_info,
            }),
            (_, _, _) => Err(src),
        }
    }
}

impl fmt::Debug for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (self.major, self.minor, self.revision, self.vendor_info) {
            (major, minor, Some(revision), "") =>
                write!(f, "{}.{}.{}", major, minor, revision),
            (major, minor, None, "") =>
                write!(f, "{}.{}", major, minor),
            (major, minor, Some(revision), vendor_info) =>
                write!(f, "{}.{}.{}, {}", major, minor, revision, vendor_info),
            (major, minor, None, vendor_info) =>
                write!(f, "{}.{}, {}", major, minor, vendor_info),
        }
    }
}

const EMPTY_STRING: &'static str = "";

/// Get a statically allocated string from the implementation using
/// `glGetString`. Fails if it `GLenum` cannot be handled by the
/// implementation's `gl.GetString` function.
fn get_string(gl: &gl::Gl, name: gl::types::GLenum) -> &'static str {
    let ptr = unsafe { gl.GetString(name) } as *const i8;
    if !ptr.is_null() {
        // This should be safe to mark as statically allocated because
        // GlGetString only returns static strings.
        unsafe { c_str_as_static_str(ptr) }
    } else {
        error!("Invalid GLenum passed to `get_string`: {:x}", name);
        EMPTY_STRING
    }
}

fn get_usize(gl: &gl::Gl, name: gl::types::GLenum) -> usize {
    let mut value = 0 as gl::types::GLint;
    unsafe { gl.GetIntegerv(name, &mut value) };
    value as usize
}

unsafe fn c_str_as_static_str(c_str: *const i8) -> &'static str {
    mem::transmute(str::from_utf8(ffi::CStr::from_ptr(c_str as *const _).to_bytes()).unwrap())
}

/// A unique platform identifier that does not change between releases
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct PlatformName {
    /// The company responsible for the OpenGL implementation
    pub vendor: &'static str,
    /// The name of the renderer
    pub renderer: &'static str,
}

impl PlatformName {
    fn get(gl: &gl::Gl) -> PlatformName {
        PlatformName {
            vendor: get_string(gl, gl::VENDOR),
            renderer: get_string(gl, gl::RENDERER),
        }
    }
}

/// Private capabilities that don't need to be exposed.
#[derive(Debug)]
pub struct PrivateCaps {
    pub array_buffer_supported: bool,
    pub frame_buffer_supported: bool,
    pub immutable_storage_supported: bool,
    pub sampler_objects_supported: bool,
    pub program_interface_supported: bool,
}

/// OpenGL implementation information
#[derive(Debug)]
pub struct Info {
    /// The platform identifier
    pub platform_name: PlatformName,
    /// The OpenGL API vesion number
    pub version: Version,
    /// The GLSL vesion number
    pub shading_language: Version,
    /// The extensions supported by the implementation
    pub extensions: HashSet<&'static str>,
}

impl Info {
    fn get(gl: &gl::Gl) -> Info {
        let platform_name = PlatformName::get(gl);
        let version = Version::parse(get_string(gl, gl::VERSION)).unwrap();
        let shading_language = Version::parse(get_string(gl, gl::SHADING_LANGUAGE_VERSION)).unwrap();
        let extensions = if version >= Version::new(3, 0, None, "") {
            let num_exts = get_usize(gl, gl::NUM_EXTENSIONS) as gl::types::GLuint;
            (0..num_exts)
                .map(|i| unsafe { c_str_as_static_str(gl.GetStringi(gl::EXTENSIONS, i) as *const i8) })
                .collect()
        } else {
            // Fallback
            get_string(gl, gl::EXTENSIONS).split(' ').collect()
        };
        Info {
            platform_name: platform_name,
            version: version,
            shading_language: shading_language,
            extensions: extensions,
        }
    }

    pub fn is_version_supported(&self, major: u32, minor: u32) -> bool {
        !self.version.is_embedded && self.version >= Version::new(major, minor, None, "")
    }

    /// Returns `true` if the implementation supports the extension
    pub fn is_extension_supported(&self, s: &'static str) -> bool {
        self.extensions.contains(&s)
    }

    pub fn is_version_or_extension_supported(&self, major: u32, minor: u32, ext: &'static str) -> bool {
        self.is_version_supported(major, minor) || self.is_extension_supported(ext)
    }
}

/// Load the information pertaining to the driver and the corresponding device
/// capabilities.
pub fn get(gl: &gl::Gl) -> (Info, Capabilities, PrivateCaps) {
    let info = Info::get(gl);
    let caps = Capabilities {
        max_vertex_count: get_usize(gl, gl::MAX_ELEMENTS_VERTICES),
        max_index_count:  get_usize(gl, gl::MAX_ELEMENTS_INDICES),
        max_texture_size: get_usize(gl, gl::MAX_TEXTURE_SIZE),

        instance_base_supported:           info.is_version_or_extension_supported(4, 2, "GL_ARB_base_instance"),
        instance_call_supported:           info.is_version_or_extension_supported(3, 1, "GL_ARB_draw_instanced"),
        instance_rate_supported:           info.is_version_or_extension_supported(3, 3, "GL_ARB_instanced_arrays"),
        vertex_base_supported:             info.is_version_or_extension_supported(3, 2, "GL_ARB_draw_elements_base_vertex"),
        srgb_color_supported:              info.is_version_or_extension_supported(3, 2, "GL_ARB_framebuffer_sRGB"),
        constant_buffer_supported:         info.is_version_or_extension_supported(3, 1, "GL_ARB_uniform_buffer_object"),
        unordered_access_view_supported:   info.is_version_or_extension_supported(4, 0, "XXX"), //TODO
        separate_blending_slots_supported: info.is_version_or_extension_supported(4, 0, "GL_ARB_draw_buffers_blend"),
    };
    let private = PrivateCaps {
        array_buffer_supported:            info.is_version_or_extension_supported(3, 0, "GL_ARB_vertex_array_object"),
        frame_buffer_supported:            info.is_version_or_extension_supported(3, 0, "GL_ARB_framebuffer_object"),
        immutable_storage_supported:       info.is_version_or_extension_supported(4, 2, "GL_ARB_texture_storage"),
        sampler_objects_supported:         info.is_version_or_extension_supported(3, 3, "GL_ARB_sampler_objects"),
        program_interface_supported:       info.is_version_or_extension_supported(4, 3, "GL_ARB_program_interface_query"),
    };
    (info, caps, private)
}

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

    #[test]
    fn test_version_parse() {
        assert_eq!(Version::parse("1"), Err("1"));
        assert_eq!(Version::parse("1."), Err("1."));
        assert_eq!(Version::parse("1 h3l1o. W0rld"), Err("1 h3l1o. W0rld"));
        assert_eq!(Version::parse("1. h3l1o. W0rld"), Err("1. h3l1o. W0rld"));
        assert_eq!(Version::parse("1.2.3"), Ok(Version::new(1, 2, Some(3), "")));
        assert_eq!(Version::parse("1.2"), Ok(Version::new(1, 2, None, "")));
        assert_eq!(Version::parse("1.2 h3l1o. W0rld"), Ok(Version::new(1, 2, None, "h3l1o. W0rld")));
        assert_eq!(Version::parse("1.2.h3l1o. W0rld"), Ok(Version::new(1, 2, None, "W0rld")));
        assert_eq!(Version::parse("1.2. h3l1o. W0rld"), Ok(Version::new(1, 2, None, "h3l1o. W0rld")));
        assert_eq!(Version::parse("1.2.3.h3l1o. W0rld"), Ok(Version::new(1, 2, Some(3), "W0rld")));
        assert_eq!(Version::parse("1.2.3 h3l1o. W0rld"), Ok(Version::new(1, 2, Some(3), "h3l1o. W0rld")));
        assert_eq!(Version::parse("OpenGL ES 3.1"), Ok(Version::new_embedded(3, 1, "")));
        assert_eq!(Version::parse("OpenGL ES 2.0 Google Nexus"), Ok(Version::new_embedded(2, 0, "Google Nexus")));
        assert_eq!(Version::parse("GLSL ES 1.1"), Ok(Version::new_embedded(1, 1, "")));
    }
}
<commit_msg>[gl] FBO capability for ES<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashSet;
use std::{ffi, fmt, mem, str};
use gl;
use gfx_core::Capabilities;

/// A version number for a specific component of an OpenGL implementation
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Version {
    pub is_embedded: bool,
    pub major: u32,
    pub minor: u32,
    pub revision: Option<u32>,
    pub vendor_info: &'static str,
}

impl Version {
    /// Create a new OpenGL version number
    pub fn new(major: u32, minor: u32, revision: Option<u32>,
               vendor_info: &'static str) -> Version {
        Version {
            is_embedded: false,
            major: major,
            minor: minor,
            revision: revision,
            vendor_info: vendor_info,
        }
    }
    /// Create a new OpenGL ES version number
    pub fn new_embedded(major: u32, minor: u32, vendor_info: &'static str) -> Version {
        Version {
            is_embedded: true,
            major: major,
            minor: minor,
            revision: None,
            vendor_info: vendor_info,
        }
    }

    /// According to the OpenGL specification, the version information is
    /// expected to follow the following syntax:
    ///
    /// ~~~bnf
    /// <major>       ::= <number>
    /// <minor>       ::= <number>
    /// <revision>    ::= <number>
    /// <vendor-info> ::= <string>
    /// <release>     ::= <major> "." <minor> ["." <release>]
    /// <version>     ::= <release> [" " <vendor-info>]
    /// ~~~
    ///
    /// Note that this function is intentionally lenient in regards to parsing,
    /// and will try to recover at least the first two version numbers without
    /// resulting in an `Err`.
    pub fn parse(mut src: &'static str) -> Result<Version, &'static str> {
        let es_sig = " ES ";
        let is_es = match src.rfind(es_sig) {
            Some(pos) => {
                src = &src[pos + es_sig.len() ..];
                true
            },
            None => false,
        };
        let (version, vendor_info) = match src.find(' ') {
            Some(i) => (&src[..i], &src[i+1..]),
            None => (src, ""),
        };

        // TODO: make this even more lenient so that we can also accept
        // `<major> "." <minor> [<???>]`
        let mut it = version.split('.');
        let major = it.next().and_then(|s| s.parse().ok());
        let minor = it.next().and_then(|s| s.parse().ok());
        let revision = it.next().and_then(|s| s.parse().ok());

        match (major, minor, revision) {
            (Some(major), Some(minor), revision) => Ok(Version {
                is_embedded: is_es,
                major: major,
                minor: minor,
                revision: revision,
                vendor_info: vendor_info,
            }),
            (_, _, _) => Err(src),
        }
    }
}

impl fmt::Debug for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (self.major, self.minor, self.revision, self.vendor_info) {
            (major, minor, Some(revision), "") =>
                write!(f, "{}.{}.{}", major, minor, revision),
            (major, minor, None, "") =>
                write!(f, "{}.{}", major, minor),
            (major, minor, Some(revision), vendor_info) =>
                write!(f, "{}.{}.{}, {}", major, minor, revision, vendor_info),
            (major, minor, None, vendor_info) =>
                write!(f, "{}.{}, {}", major, minor, vendor_info),
        }
    }
}

const EMPTY_STRING: &'static str = "";

/// Get a statically allocated string from the implementation using
/// `glGetString`. Fails if it `GLenum` cannot be handled by the
/// implementation's `gl.GetString` function.
fn get_string(gl: &gl::Gl, name: gl::types::GLenum) -> &'static str {
    let ptr = unsafe { gl.GetString(name) } as *const i8;
    if !ptr.is_null() {
        // This should be safe to mark as statically allocated because
        // GlGetString only returns static strings.
        unsafe { c_str_as_static_str(ptr) }
    } else {
        error!("Invalid GLenum passed to `get_string`: {:x}", name);
        EMPTY_STRING
    }
}

fn get_usize(gl: &gl::Gl, name: gl::types::GLenum) -> usize {
    let mut value = 0 as gl::types::GLint;
    unsafe { gl.GetIntegerv(name, &mut value) };
    value as usize
}

unsafe fn c_str_as_static_str(c_str: *const i8) -> &'static str {
    mem::transmute(str::from_utf8(ffi::CStr::from_ptr(c_str as *const _).to_bytes()).unwrap())
}

/// A unique platform identifier that does not change between releases
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct PlatformName {
    /// The company responsible for the OpenGL implementation
    pub vendor: &'static str,
    /// The name of the renderer
    pub renderer: &'static str,
}

impl PlatformName {
    fn get(gl: &gl::Gl) -> PlatformName {
        PlatformName {
            vendor: get_string(gl, gl::VENDOR),
            renderer: get_string(gl, gl::RENDERER),
        }
    }
}

/// Private capabilities that don't need to be exposed.
#[derive(Debug)]
pub struct PrivateCaps {
    pub array_buffer_supported: bool,
    pub frame_buffer_supported: bool,
    pub immutable_storage_supported: bool,
    pub sampler_objects_supported: bool,
    pub program_interface_supported: bool,
}

/// OpenGL implementation information
#[derive(Debug)]
pub struct Info {
    /// The platform identifier
    pub platform_name: PlatformName,
    /// The OpenGL API vesion number
    pub version: Version,
    /// The GLSL vesion number
    pub shading_language: Version,
    /// The extensions supported by the implementation
    pub extensions: HashSet<&'static str>,
}

impl Info {
    fn get(gl: &gl::Gl) -> Info {
        let platform_name = PlatformName::get(gl);
        let version = Version::parse(get_string(gl, gl::VERSION)).unwrap();
        let shading_language = Version::parse(get_string(gl, gl::SHADING_LANGUAGE_VERSION)).unwrap();
        let extensions = if version >= Version::new(3, 0, None, "") {
            let num_exts = get_usize(gl, gl::NUM_EXTENSIONS) as gl::types::GLuint;
            (0..num_exts)
                .map(|i| unsafe { c_str_as_static_str(gl.GetStringi(gl::EXTENSIONS, i) as *const i8) })
                .collect()
        } else {
            // Fallback
            get_string(gl, gl::EXTENSIONS).split(' ').collect()
        };
        Info {
            platform_name: platform_name,
            version: version,
            shading_language: shading_language,
            extensions: extensions,
        }
    }

    pub fn is_version_supported(&self, major: u32, minor: u32) -> bool {
        !self.version.is_embedded && self.version >= Version::new(major, minor, None, "")
    }

    pub fn is_embedded_version_supported(&self, major: u32, minor: u32) -> bool {
        self.version.is_embedded && self.version >= Version::new(major, minor, None, "")
    }

    /// Returns `true` if the implementation supports the extension
    pub fn is_extension_supported(&self, s: &'static str) -> bool {
        self.extensions.contains(&s)
    }

    pub fn is_version_or_extension_supported(&self, major: u32, minor: u32, ext: &'static str) -> bool {
        self.is_version_supported(major, minor) || self.is_extension_supported(ext)
    }
}

/// Load the information pertaining to the driver and the corresponding device
/// capabilities.
pub fn get(gl: &gl::Gl) -> (Info, Capabilities, PrivateCaps) {
    let info = Info::get(gl);
    let caps = Capabilities {
        max_vertex_count: get_usize(gl, gl::MAX_ELEMENTS_VERTICES),
        max_index_count:  get_usize(gl, gl::MAX_ELEMENTS_INDICES),
        max_texture_size: get_usize(gl, gl::MAX_TEXTURE_SIZE),

        instance_base_supported:           info.is_version_or_extension_supported(4, 2, "GL_ARB_base_instance"),
        instance_call_supported:           info.is_version_or_extension_supported(3, 1, "GL_ARB_draw_instanced"),
        instance_rate_supported:           info.is_version_or_extension_supported(3, 3, "GL_ARB_instanced_arrays"),
        vertex_base_supported:             info.is_version_or_extension_supported(3, 2, "GL_ARB_draw_elements_base_vertex"),
        srgb_color_supported:              info.is_version_or_extension_supported(3, 2, "GL_ARB_framebuffer_sRGB"),
        constant_buffer_supported:         info.is_version_or_extension_supported(3, 1, "GL_ARB_uniform_buffer_object"),
        unordered_access_view_supported:   info.is_version_or_extension_supported(4, 0, "XXX"), //TODO
        separate_blending_slots_supported: info.is_version_or_extension_supported(4, 0, "GL_ARB_draw_buffers_blend"),
    };
    let private = PrivateCaps {
        array_buffer_supported:            info.is_version_or_extension_supported(3, 0, "GL_ARB_vertex_array_object"),
        frame_buffer_supported:            info.is_version_or_extension_supported(3, 0, "GL_ARB_framebuffer_object") |
                                           info.is_embedded_version_supported(2, 0),
        immutable_storage_supported:       info.is_version_or_extension_supported(4, 2, "GL_ARB_texture_storage"),
        sampler_objects_supported:         info.is_version_or_extension_supported(3, 3, "GL_ARB_sampler_objects"),
        program_interface_supported:       info.is_version_or_extension_supported(4, 3, "GL_ARB_program_interface_query"),
    };
    (info, caps, private)
}

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

    #[test]
    fn test_version_parse() {
        assert_eq!(Version::parse("1"), Err("1"));
        assert_eq!(Version::parse("1."), Err("1."));
        assert_eq!(Version::parse("1 h3l1o. W0rld"), Err("1 h3l1o. W0rld"));
        assert_eq!(Version::parse("1. h3l1o. W0rld"), Err("1. h3l1o. W0rld"));
        assert_eq!(Version::parse("1.2.3"), Ok(Version::new(1, 2, Some(3), "")));
        assert_eq!(Version::parse("1.2"), Ok(Version::new(1, 2, None, "")));
        assert_eq!(Version::parse("1.2 h3l1o. W0rld"), Ok(Version::new(1, 2, None, "h3l1o. W0rld")));
        assert_eq!(Version::parse("1.2.h3l1o. W0rld"), Ok(Version::new(1, 2, None, "W0rld")));
        assert_eq!(Version::parse("1.2. h3l1o. W0rld"), Ok(Version::new(1, 2, None, "h3l1o. W0rld")));
        assert_eq!(Version::parse("1.2.3.h3l1o. W0rld"), Ok(Version::new(1, 2, Some(3), "W0rld")));
        assert_eq!(Version::parse("1.2.3 h3l1o. W0rld"), Ok(Version::new(1, 2, Some(3), "h3l1o. W0rld")));
        assert_eq!(Version::parse("OpenGL ES 3.1"), Ok(Version::new_embedded(3, 1, "")));
        assert_eq!(Version::parse("OpenGL ES 2.0 Google Nexus"), Ok(Version::new_embedded(2, 0, "Google Nexus")));
        assert_eq!(Version::parse("GLSL ES 1.1"), Ok(Version::new_embedded(1, 1, "")));
    }
}
<|endoftext|>