<commit_before>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml 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.

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;
use rust_num::{Float, Zero};
use rust_num::traits::cast;

use structure::Angle;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians.
///
/// This type is marked as `#[repr(C, packed)]`.
#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }

/// An angle, in degrees.
///
/// This type is marked as `#[repr(C, packed)]`.
#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        Rad::new(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> $Angle<S> {
            #[inline]
            pub fn new(value: S) -> $Angle<S> {
                $Angle { s: value }
            }
        }

        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn zero() -> $Angle<S> {
                $Angle::new(S::zero())
            }

            #[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }

            #[inline] fn sin(self) -> S { Rad::from(self).s.sin() }
            #[inline] fn cos(self) -> S { Rad::from(self).s.cos() }
            #[inline] fn tan(self) -> S { Rad::from(self).s.tan() }
            #[inline] fn sin_cos(self) -> (S, S) { Rad::from(self).s.sin_cos() }

            #[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
            #[inline] fn acos(a: S) -> $Angle<S> { Rad::new(a.acos()).into() }
            #[inline] fn atan(a: S) -> $Angle<S> { Rad::new(a.atan()).into() }
            #[inline] fn atan2(a: S, b: S) -> $Angle<S> { Rad::new(a.atan2(b)).into() }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
        });
        impl_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
        });
        impl_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
        });
        impl_assignment_operator!(<S: BaseFloat> AddAssign<$Angle<S> > for $Angle<S> {
            fn add_assign(&mut self, other) { self.s + other.s; }
        });
        impl_assignment_operator!(<S: BaseFloat> SubAssign<$Angle<S> > for $Angle<S> {
            fn sub_assign(&mut self, other) { self.s - other.s; }
        });
        impl_assignment_operator!(<S: BaseFloat> RemAssign<$Angle<S> > for $Angle<S> {
            fn rem_assign(&mut self, other) { self.s % other.s; }
        });

        impl_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
        });
        impl_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
        });
        impl_assignment_operator!(<S: BaseFloat> MulAssign<S> for $Angle<S> {
            fn mul_assign(&mut self, scalar) { self.s * scalar; }
        });
        impl_assignment_operator!(<S: BaseFloat> DivAssign<S> for $Angle<S> {
            fn div_assign(&mut self, scalar) { self.s / scalar; }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                $Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
            }
        }

        impl<S: fmt::Debug> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<commit_msg>Fix assignment operators for angles<commit_after>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml 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.

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;
use rust_num::{Float, Zero};
use rust_num::traits::cast;

use structure::Angle;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians.
///
/// This type is marked as `#[repr(C, packed)]`.
#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }

/// An angle, in degrees.
///
/// This type is marked as `#[repr(C, packed)]`.
#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        Rad::new(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> $Angle<S> {
            #[inline]
            pub fn new(value: S) -> $Angle<S> {
                $Angle { s: value }
            }
        }

        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn zero() -> $Angle<S> {
                $Angle::new(S::zero())
            }

            #[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }

            #[inline] fn sin(self) -> S { Rad::from(self).s.sin() }
            #[inline] fn cos(self) -> S { Rad::from(self).s.cos() }
            #[inline] fn tan(self) -> S { Rad::from(self).s.tan() }
            #[inline] fn sin_cos(self) -> (S, S) { Rad::from(self).s.sin_cos() }

            #[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
            #[inline] fn acos(a: S) -> $Angle<S> { Rad::new(a.acos()).into() }
            #[inline] fn atan(a: S) -> $Angle<S> { Rad::new(a.atan()).into() }
            #[inline] fn atan2(a: S, b: S) -> $Angle<S> { Rad::new(a.atan2(b)).into() }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
        });
        impl_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
        });
        impl_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
        });
        impl_assignment_operator!(<S: BaseFloat> AddAssign<$Angle<S> > for $Angle<S> {
            fn add_assign(&mut self, other) { self.s += other.s; }
        });
        impl_assignment_operator!(<S: BaseFloat> SubAssign<$Angle<S> > for $Angle<S> {
            fn sub_assign(&mut self, other) { self.s -= other.s; }
        });
        impl_assignment_operator!(<S: BaseFloat> RemAssign<$Angle<S> > for $Angle<S> {
            fn rem_assign(&mut self, other) { self.s %= other.s; }
        });

        impl_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
        });
        impl_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
        });
        impl_assignment_operator!(<S: BaseFloat> MulAssign<S> for $Angle<S> {
            fn mul_assign(&mut self, scalar) { self.s *= scalar; }
        });
        impl_assignment_operator!(<S: BaseFloat> DivAssign<S> for $Angle<S> {
            fn div_assign(&mut self, scalar) { self.s /= scalar; }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                $Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
            }
        }

        impl<S: fmt::Debug> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<|endoftext|>


<commit_before>use std::prelude::v1::*;
use std::mem::{transmute};
use libc;
use rand;
use std::mem::size_of;

// The types we want to test:
use super::{ZoneAllocator, SlabPage, SlabAllocator, SlabPageProvider};

#[cfg(target_arch="x86_64")]
use x86::paging::{BASE_PAGE_SIZE};

use test::Bencher;

/// Page allocator based on mmap/munmap system calls for backing slab memory.
struct MmapPageProvider {
    currently_allocated: usize
}

impl MmapPageProvider {
    pub fn new() -> MmapPageProvider {
        MmapPageProvider{ currently_allocated: 0 }
    }
}

impl MmapPageProvider {
    pub fn currently_allocated(&self) -> usize {
        self.currently_allocated
    }
}

impl<'a> SlabPageProvider<'a> for MmapPageProvider {

    /// Allocates a new SlabPage from the system.
    ///
    /// Uses `mmap` to map a page and casts it to a SlabPage.
    fn allocate_slabpage(&mut self) -> Option<&'a mut SlabPage<'a>> {
        let mut addr: libc::c_void = libc::c_void::__variant1;
        let len: libc::size_t = BASE_PAGE_SIZE;
        let prot = libc::PROT_READ | libc::PROT_WRITE;
        let flags = libc::MAP_PRIVATE | libc::MAP_ANON;
        let fd = -1;
        let offset = 0;
        let r = unsafe { libc::mmap(&mut addr, len as libc::size_t, prot, flags, fd, offset) };
        if r == libc::MAP_FAILED {
            return None;
        }
        else {
            let mut slab_page: &'a mut SlabPage = unsafe { transmute(r as usize) };
            self.currently_allocated += 1;
            return Some(slab_page);
        }
    }

    /// Release a SlabPage back to the system.slab_page
    ///
    /// Uses `munmap` to release the page back to the OS.
    fn release_slabpage(&mut self, p: &'a mut SlabPage<'a>) {
        let addr: *mut libc::c_void = unsafe { transmute(p) };
        let len: libc::size_t = BASE_PAGE_SIZE;
        let r = unsafe { libc::munmap(addr, len) };
        if r != 0 {
            panic!("munmap failed!");
        }
        self.currently_allocated -= 1;
    }

}

#[test]
fn type_size() {
    assert!(BASE_PAGE_SIZE as usize == size_of::<SlabPage>(),
               "SlabPage should be exactly the size of a single page.");
}

#[test]
fn test_mmap_allocator() {
    let mut mmap = MmapPageProvider::new();
    match mmap.allocate_slabpage() {
        Some(sp) =>  {
            assert!(!sp.is_full(), "Got empty slab");
            mmap.release_slabpage(sp)
        },
        None => panic!("failed to allocate slabpage")
    }
}

macro_rules! test_slab_allocation {
    ( $test:ident, $size:expr, $alignment:expr, $allocations:expr  ) => {
        #[test]
        fn $test() {
            let mut mmap = MmapPageProvider::new();

            {
                let mut sa: SlabAllocator = SlabAllocator::new($size, Some(&mut mmap));
                let alignment = $alignment;

                let mut objects: Vec<*mut u8> = Vec::new();
                let mut vec: Vec<(usize, &mut [usize; $size / 8])> = Vec::new();

                for _ in 0..$allocations {
                    match sa.allocate(alignment) {
                        None => panic!("OOM is unlikely."),
                        Some(obj) => {
                            unsafe { vec.push( (rand::random::<usize>(), transmute(obj)) ) };
                            objects.push(obj)
                        }
                    }
                }

                // Write the objects with a random pattern
                for item in vec.iter_mut() {
                    let (pattern, ref mut obj) = *item;
                    for i in 0..obj.len() {
                        obj[i] = pattern;
                    }
                }

                for item in vec.iter() {
                    let (pattern, ref obj) = *item;
                    for i in 0..obj.len() {
                        assert!( (obj[i]) == pattern, "No two allocations point to the same memory.");
                    }
                }

                // Make sure we can correctly deallocate:
                let pages_allocated = sa.slabs.elements;

                // Deallocate all the objects
                for item in objects.iter_mut() {
                    sa.deallocate(*item);
                }

                objects.clear();

                // then allocate everything again,
                for idx in 0..$allocations {
                    match sa.allocate(alignment) {
                        None => panic!("OOM is unlikely."),
                        Some(obj) => {
                            unsafe { vec.push( (rand::random::<usize>(), transmute(obj)) ) };
                            objects.push(obj)
                        }
                    }
                }

                // and make sure we do not request more pages than what we had previously
                // println!("{} {}", pages_allocated, sa.slabs.elements);
                assert!(pages_allocated == sa.slabs.elements,
                        "Did not use more memory for 2nd allocation run.");

                // Deallocate everything once more
                for item in objects.iter_mut() {
                    sa.deallocate(*item);
                }
            }

            // Check that we released everything to our page allocator:
            assert!(mmap.currently_allocated() == 0, "Released all pages to underlying memory manager.");
        }

    };
}

macro_rules! test_slab_allocation_panic {
    ( $test:ident, $size:expr, $alignment:expr, $allocations:expr  ) => {
        test_slab_allocation!($test, $size, $alignment, $allocations);
    };
}

test_slab_allocation!(test_slab_allocation8192_size8_alignment1, 8, 1, 512);
test_slab_allocation!(test_slab_allocation4096_size8_alignment8, 8, 8, 4096);
test_slab_allocation!(test_slab_allocation500_size8_alignment64, 8, 64, 500);
test_slab_allocation!(test_slab_allocation4096_size12_alignment1, 12, 1, 4096);
test_slab_allocation!(test_slab_allocation4096_size13_alignment1, 13, 1, 4096);
test_slab_allocation!(test_slab_allocation2000_size14_alignment1, 14, 1, 2000);
test_slab_allocation!(test_slab_allocation4096_size15_alignment1, 15, 1, 4096);
test_slab_allocation!(test_slab_allocation8000_size16_alignment1, 16, 1, 8000);
test_slab_allocation!(test_slab_allocation1024_size24_alignment1, 24, 1, 1024);
test_slab_allocation!(test_slab_allocation3090_size32_alignment1, 32, 1, 3090);
test_slab_allocation!(test_slab_allocation4096_size64_alignment1, 64, 1, 4096);
test_slab_allocation!(test_slab_allocation1000_size512_alignment1, 512, 1, 1000);
test_slab_allocation!(test_slab_allocation4096_size1024_alignment1, 1024, 1, 4096);
test_slab_allocation!(test_slab_allocation10_size2048_alignment1, 2048, 1, 10);

#[test]
#[should_panic]
fn invalid_alignment() {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(10, Some(&mut mmap));

    sa.allocate(3);
}

#[test]
fn test_readme() {
    let object_size = 12;
    let alignment = 4;
    let mut mmap = MmapPageProvider::new();
    let mut zone = ZoneAllocator::new(Some(&mut mmap));

    let allocated = zone.allocate(object_size, alignment);
    allocated.map(|ptr| { zone.deallocate(ptr, object_size, alignment) });
}

#[test]
fn test_readme2() {
    let object_size = 10;
    let alignment = 8;
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(object_size, Some(&mut mmap));
    sa.allocate(alignment);
}

#[bench]
fn bench_allocate(b: &mut Bencher) {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(8, Some(&mut mmap));

    b.iter(|| sa.allocate(4));
}

#[bench]
fn bench_allocate_big(b: &mut Bencher) {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(512, Some(&mut mmap));

    b.iter(|| sa.allocate(1));
}<commit_msg>Fix tests.<commit_after>use std::prelude::v1::*;
use std::mem::{transmute};
use libc;
use rand;
use std::mem::size_of;

// The types we want to test:
use super::{ZoneAllocator, SlabPage, SlabAllocator, SlabPageProvider, BASE_PAGE_SIZE};

use test::Bencher;

/// Page allocator based on mmap/munmap system calls for backing slab memory.
struct MmapPageProvider {
    currently_allocated: usize
}

impl MmapPageProvider {
    pub fn new() -> MmapPageProvider {
        MmapPageProvider{ currently_allocated: 0 }
    }
}

impl MmapPageProvider {
    pub fn currently_allocated(&self) -> usize {
        self.currently_allocated
    }
}

impl<'a> SlabPageProvider<'a> for MmapPageProvider {

    /// Allocates a new SlabPage from the system.
    ///
    /// Uses `mmap` to map a page and casts it to a SlabPage.
    fn allocate_slabpage(&mut self) -> Option<&'a mut SlabPage<'a>> {
        let mut addr: libc::c_void = libc::c_void::__variant1;
        let len: libc::size_t = BASE_PAGE_SIZE as u64;
        let prot = libc::PROT_READ | libc::PROT_WRITE;
        let flags = libc::MAP_PRIVATE | libc::MAP_ANON;
        let fd = -1;
        let offset = 0;
        let r = unsafe { libc::mmap(&mut addr, len as libc::size_t, prot, flags, fd, offset) };
        if r == libc::MAP_FAILED {
            return None;
        }
        else {
            let mut slab_page: &'a mut SlabPage = unsafe { transmute(r as usize) };
            self.currently_allocated += 1;
            return Some(slab_page);
        }
    }

    /// Release a SlabPage back to the system.slab_page
    ///
    /// Uses `munmap` to release the page back to the OS.
    fn release_slabpage(&mut self, p: &'a mut SlabPage<'a>) {
        let addr: *mut libc::c_void = unsafe { transmute(p) };
        let len: libc::size_t = BASE_PAGE_SIZE as u64;
        let r = unsafe { libc::munmap(addr, len) };
        if r != 0 {
            panic!("munmap failed!");
        }
        self.currently_allocated -= 1;
    }

}

#[test]
fn type_size() {
    assert!(BASE_PAGE_SIZE as usize == size_of::<SlabPage>(),
               "SlabPage should be exactly the size of a single page.");
}

#[test]
fn test_mmap_allocator() {
    let mut mmap = MmapPageProvider::new();
    match mmap.allocate_slabpage() {
        Some(sp) =>  {
            assert!(!sp.is_full(), "Got empty slab");
            mmap.release_slabpage(sp)
        },
        None => panic!("failed to allocate slabpage")
    }
}

macro_rules! test_slab_allocation {
    ( $test:ident, $size:expr, $alignment:expr, $allocations:expr  ) => {
        #[test]
        fn $test() {
            let mut mmap = MmapPageProvider::new();

            {
                let mut sa: SlabAllocator = SlabAllocator::new($size, Some(&mut mmap));
                let alignment = $alignment;

                let mut objects: Vec<*mut u8> = Vec::new();
                let mut vec: Vec<(usize, &mut [usize; $size / 8])> = Vec::new();

                for _ in 0..$allocations {
                    match sa.allocate(alignment) {
                        None => panic!("OOM is unlikely."),
                        Some(obj) => {
                            unsafe { vec.push( (rand::random::<usize>(), transmute(obj)) ) };
                            objects.push(obj)
                        }
                    }
                }

                // Write the objects with a random pattern
                for item in vec.iter_mut() {
                    let (pattern, ref mut obj) = *item;
                    for i in 0..obj.len() {
                        obj[i] = pattern;
                    }
                }

                for item in vec.iter() {
                    let (pattern, ref obj) = *item;
                    for i in 0..obj.len() {
                        assert!( (obj[i]) == pattern, "No two allocations point to the same memory.");
                    }
                }

                // Make sure we can correctly deallocate:
                let pages_allocated = sa.slabs.elements;

                // Deallocate all the objects
                for item in objects.iter_mut() {
                    sa.deallocate(*item);
                }

                objects.clear();

                // then allocate everything again,
                for idx in 0..$allocations {
                    match sa.allocate(alignment) {
                        None => panic!("OOM is unlikely."),
                        Some(obj) => {
                            unsafe { vec.push( (rand::random::<usize>(), transmute(obj)) ) };
                            objects.push(obj)
                        }
                    }
                }

                // and make sure we do not request more pages than what we had previously
                // println!("{} {}", pages_allocated, sa.slabs.elements);
                assert!(pages_allocated == sa.slabs.elements,
                        "Did not use more memory for 2nd allocation run.");

                // Deallocate everything once more
                for item in objects.iter_mut() {
                    sa.deallocate(*item);
                }
            }

            // Check that we released everything to our page allocator:
            assert!(mmap.currently_allocated() == 0, "Released all pages to underlying memory manager.");
        }

    };
}

macro_rules! test_slab_allocation_panic {
    ( $test:ident, $size:expr, $alignment:expr, $allocations:expr  ) => {
        test_slab_allocation!($test, $size, $alignment, $allocations);
    };
}

test_slab_allocation!(test_slab_allocation8192_size8_alignment1, 8, 1, 512);
test_slab_allocation!(test_slab_allocation4096_size8_alignment8, 8, 8, 4096);
test_slab_allocation!(test_slab_allocation500_size8_alignment64, 8, 64, 500);
test_slab_allocation!(test_slab_allocation4096_size12_alignment1, 12, 1, 4096);
test_slab_allocation!(test_slab_allocation4096_size13_alignment1, 13, 1, 4096);
test_slab_allocation!(test_slab_allocation2000_size14_alignment1, 14, 1, 2000);
test_slab_allocation!(test_slab_allocation4096_size15_alignment1, 15, 1, 4096);
test_slab_allocation!(test_slab_allocation8000_size16_alignment1, 16, 1, 8000);
test_slab_allocation!(test_slab_allocation1024_size24_alignment1, 24, 1, 1024);
test_slab_allocation!(test_slab_allocation3090_size32_alignment1, 32, 1, 3090);
test_slab_allocation!(test_slab_allocation4096_size64_alignment1, 64, 1, 4096);
test_slab_allocation!(test_slab_allocation1000_size512_alignment1, 512, 1, 1000);
test_slab_allocation!(test_slab_allocation4096_size1024_alignment1, 1024, 1, 4096);
test_slab_allocation!(test_slab_allocation10_size2048_alignment1, 2048, 1, 10);

#[test]
#[should_panic]
fn invalid_alignment() {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(10, Some(&mut mmap));

    sa.allocate(3);
}

#[test]
fn test_readme() {
    let object_size = 12;
    let alignment = 4;
    let mut mmap = MmapPageProvider::new();
    let mut zone = ZoneAllocator::new(Some(&mut mmap));

    let allocated = zone.allocate(object_size, alignment);
    allocated.map(|ptr| { zone.deallocate(ptr, object_size, alignment) });
}

#[test]
fn test_readme2() {
    let object_size = 10;
    let alignment = 8;
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(object_size, Some(&mut mmap));
    sa.allocate(alignment);
}

#[bench]
fn bench_allocate(b: &mut Bencher) {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(8, Some(&mut mmap));

    b.iter(|| sa.allocate(4));
}

#[bench]
fn bench_allocate_big(b: &mut Bencher) {
    let mut mmap = MmapPageProvider::new();
    let mut sa: SlabAllocator = SlabAllocator::new(512, Some(&mut mmap));

    b.iter(|| sa.allocate(1));
}<|endoftext|>


<commit_before>/* Copyright (c) 2016
 * Jeff Nettleton
 *
 * Licensed under the MIT license (http://opensource.org/licenses/MIT). This
 * file may not be copied, modified, or distributed except according to those
 * terms
 */

<commit_msg>delete src/tests.rs<commit_after><|endoftext|>


<commit_before>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref().as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        self.sink.append(decoder);
        Ok(())
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing
    pub fn playing(&self) -> bool {
        !self.paused() // && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}

// TODO: global start, stop, volume?
<commit_msg>Implement From<Arc<[u8]>> for SoundData<commit_after>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref().as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        self.sink.append(decoder);
        Ok(())
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing
    pub fn playing(&self) -> bool {
        !self.paused() // && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}

// TODO: global start, stop, volume?
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use syntax::abi;

pub use self::Global::*;
pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;

static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;

#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct ModuleId(usize);
pub static ROOT_MODULE_ID: ModuleId = ModuleId(0);

impl ModuleId {
    pub fn next() -> ModuleId {
        ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1)
    }
}

pub type ModuleMap = HashMap<ModuleId, Module>;

#[derive(Clone)]
pub struct Module {
    pub name: String,
    pub globals: Vec<Global>,
    pub parent_id: Option<ModuleId>,
    // Just for convenience
    pub children_ids: Vec<ModuleId>,
    /// Types that must be substituted in this module,
    /// in the form original_name -> substituted_type
    pub translations: HashMap<String, Global>,
}

impl Module {
    pub fn new(name: String, parent_id: Option<ModuleId>) -> Self {
        Module {
            name: name,
            globals: vec![],
            parent_id: parent_id,
            children_ids: vec![],
            translations: HashMap::new(),
        }
    }

    #[allow(dead_code)]
    pub fn add_global(&mut self, g: Global) {
        self.globals.push(g)
    }
}

#[derive(Clone)]
pub enum Global {
    GType(Rc<RefCell<TypeInfo>>),
    GComp(Rc<RefCell<CompInfo>>),
    GCompDecl(Rc<RefCell<CompInfo>>),
    GEnum(Rc<RefCell<EnumInfo>>),
    GEnumDecl(Rc<RefCell<EnumInfo>>),
    GVar(Rc<RefCell<VarInfo>>),
    GFunc(Rc<RefCell<VarInfo>>),
    GOther
}

impl Global {
    // XXX prevent this dumb to_owned()... didn't want to deal with the borrowed lifetime
    pub fn name(&self) -> String {
        match *self {
            GType(ref info) => info.borrow().name.to_owned(),
            GComp(ref info)
            | GCompDecl(ref info) => info.borrow().name.to_owned(),
            GEnum(ref info)
            | GEnumDecl(ref info) => info.borrow().name.to_owned(),
            GVar(ref info)
            | GFunc(ref info) => info.borrow().name.to_owned(),
            GOther => "".to_owned(),
        }
    }

    pub fn layout(&self) -> Option<Layout> {
        Some(match *self {
            GType(ref info) => info.borrow().layout,
            GComp(ref info)
            | GCompDecl(ref info) => info.borrow().layout,
            GEnum(ref info)
            | GEnumDecl(ref info) => info.borrow().layout,
            GVar(_)
            | GFunc(_)
            | GOther => return None,
        })
    }

    pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> {
        match *self {
            GComp(ref i)
            | GCompDecl(ref i) => i.clone(),
            _ => panic!("global_compinfo")
        }
    }

    pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> {
        match *self {
            GEnum(ref i)
            | GEnumDecl(ref i) => i.clone(),
            _ => panic!("global_enuminfo")
        }
    }

    pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> {
        match *self {
            GType(ref i) => i.clone(),
            _ => panic!("global_typeinfo")
        }
    }

    pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> {
        match *self {
            GVar(ref i)
            | GFunc(ref i) => i.clone(),
            _ => panic!("global_varinfo")
        }
    }
}

impl fmt::Debug for Global {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GType(ref ti) => ti.borrow().fmt(f),
            GComp(ref ci)
            | GCompDecl(ref ci) => ci.borrow().fmt(f),
            GEnum(ref ei)
            | GEnumDecl(ref ei) => ei.borrow().fmt(f),
            GVar(ref vi)
            | GFunc(ref vi) => vi.borrow().fmt(f),
            GOther => "*".fmt(f),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct FuncSig {
    pub ret_ty: Box<Type>,
    pub args: Vec<(String, Type)>,
    pub is_variadic: bool,
    pub is_safe: bool,
    pub abi: abi::Abi,
}

#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    TVoid,
    TInt(IKind, Layout),
    TFloat(FKind, Layout),
    TPtr(Box<Type>, bool, bool, Layout),
    TArray(Box<Type>, usize, Layout),
    TFuncProto(FuncSig),
    TFuncPtr(FuncSig),
    TNamed(Rc<RefCell<TypeInfo>>),
    TComp(Rc<RefCell<CompInfo>>),
    TEnum(Rc<RefCell<EnumInfo>>)
}

impl Type {
    pub fn name(&self) -> Option<String> {
        match *self {
            TNamed(ref info) => Some(info.borrow().name.clone()),
            TComp(ref info)  => Some(info.borrow().name.clone()),
            TEnum(ref info)  => Some(info.borrow().name.clone()),
            TArray(ref t, _, _) => t.name(),
            TPtr(ref t, _, _, _) => t.name(),
            _ => None
        }
    }

    pub fn size(&self) -> usize {
        self.layout().map(|l| l.size).unwrap_or(0)
    }

    #[allow(dead_code)]
    pub fn align(&self) -> usize {
        self.layout().map(|l| l.align).unwrap_or(0)
    }

    pub fn layout(&self) -> Option<Layout> {
        Some(match *self {
            TInt(_, l) => l.clone(),
            TFloat(_, l) => l.clone(),
            TPtr(_, _, _, l) => l.clone(),
            TArray(_, _, l) => l.clone(),
            TComp(ref ci) => ci.borrow().layout.clone(),
            TEnum(ref ei) => ei.borrow().layout.clone(),
            TNamed(ref ti) => return ti.borrow().ty.layout(),
            TVoid |
            TFuncProto(..) |
            TFuncPtr(..) => return None,
        })
    }

    #[allow(dead_code)]
    pub fn can_derive_debug(&self) -> bool {
        match *self {
            TArray(_, size, _) => size <= 32,
            TComp(ref comp) => {
                comp.borrow()
                    .members
                    .iter()
                    .all(|member| match *member {
                        CompMember::Field(ref f) |
                        CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
                        _ => true,
                    })
            }
            _ => true,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Layout {
    pub size: usize,
    pub align: usize,
    pub packed: bool,
}

impl Layout {
    pub fn new(size: usize, align: usize) -> Layout {
        Layout { size: size, align: align, packed: false }
    }

    pub fn zero() -> Layout {
        Layout { size: 0, align: 0, packed: false }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IKind {
    IBool,
    ISChar,
    IUChar,
    IShort,
    IUShort,
    IInt,
    IUInt,
    ILong,
    IULong,
    ILongLong,
    IULongLong
}

impl IKind {
    #[allow(dead_code)]
    pub fn is_signed(self) -> bool {
        match self {
            IBool => false,
            ISChar => true,
            IUChar => false,
            IShort => true,
            IUShort => false,
            IInt => true,
            IUInt => false,
            ILong => true,
            IULong => false,
            ILongLong => true,
            IULongLong => false,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FKind {
    FFloat,
    FDouble
}

#[derive(Clone, PartialEq)]
pub enum CompMember {
    Field(FieldInfo),
    Comp(Rc<RefCell<CompInfo>>),
    #[allow(dead_code)]
    CompField(Rc<RefCell<CompInfo>>, FieldInfo),
    Enum(Rc<RefCell<EnumInfo>>),
}

#[derive(Copy, Clone, PartialEq)]
pub enum CompKind {
    Struct,
    Union,
}

#[derive(Clone, PartialEq)]
pub struct CompInfo {
    pub kind: CompKind,
    pub name: String,
    pub module_id: ModuleId,
    pub filename: String,
    pub comment: String,
    pub members: Vec<CompMember>,
    pub args: Vec<Type>,
    pub methods: Vec<VarInfo>,
    pub vmethods: Vec<VarInfo>,
    pub ref_template: Option<Type>,
    pub has_vtable: bool,
    pub has_destructor: bool,
    pub has_nonempty_base: bool,
    pub hide: bool,
    pub base_members: usize,
    pub layout: Layout,
    /// Typedef'd types names, that we'll resolve early to avoid name conflicts
    pub typedefs: Vec<String>,
    /// If this type has a template parameter which is not a type (e.g.: a size_t)
    pub has_non_type_template_params: bool,
    /// If this type was unnamed when parsed
    pub was_unnamed: bool,
}

static mut UNNAMED_COUNTER: u32 = 0;

fn unnamed_name(name: String, filename: &String) -> String {
    if name.is_empty() {
        let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER };
        format!("{}_unnamed_{}", filename, n)
    } else {
        name
    }
}

impl CompInfo {
    pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
        let was_unnamed = name.is_empty();
        CompInfo {
            kind: kind,
            module_id: module_id,
            name: unnamed_name(name, &filename),
            filename: filename,
            comment: comment,
            members: members,
            args: vec!(),
            methods: vec!(),
            vmethods: vec!(),
            ref_template: None,
            has_vtable: false,
            has_destructor: false,
            has_nonempty_base: false,
            hide: false,
            base_members: 0,
            layout: layout,
            typedefs: vec!(),
            has_non_type_template_params: false,
            was_unnamed: was_unnamed,
        }
    }
}

impl fmt::Debug for CompInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct FieldInfo {
    pub name: String,
    pub ty: Type,
    pub comment: String,
    pub bitfields: Option<Vec<(String, u32)>>,
}

impl FieldInfo {
    pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
        FieldInfo {
            name: name,
            ty: ty,
            comment: comment,
            bitfields: bitfields,
        }
    }
}

impl fmt::Debug for FieldInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct EnumInfo {
    pub name: String,
    pub module_id: ModuleId,
    pub comment: String,
    pub filename: String,
    pub items: Vec<EnumItem>,
    pub kind: IKind,
    pub layout: Layout,
}

impl EnumInfo {
    pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
        EnumInfo {
            name: unnamed_name(name, &filename),
            module_id: module_id,
            comment: String::new(),
            filename: filename,
            items: items,
            kind: kind,
            layout: layout,
        }
    }
}

impl fmt::Debug for EnumInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct EnumItem {
    pub name: String,
    pub comment: String,
    pub val: i64
}

impl EnumItem {
    pub fn new(name: String, comment: String, val: i64) -> EnumItem {
        EnumItem {
            name: name,
            comment: comment,
            val: val
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct TypeInfo {
    pub name: String,
    pub module_id: ModuleId,
    pub comment: String,
    pub ty: Type,
    pub layout: Layout,
}

impl TypeInfo {
    pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo {
        TypeInfo {
            name: name,
            module_id: module_id,
            comment: String::new(),
            ty: ty,
            layout: layout,
        }
    }
}

impl fmt::Debug for TypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct VarInfo {
    pub name: String,
    pub mangled: String,
    pub comment: String,
    pub ty: Type,
    //TODO: support non-integer constants
    pub val: Option<i64>,
    pub is_const: bool,
    pub is_static: bool,
}

impl VarInfo {
    pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo {
        let mangled = if name == mangled {
            String::new()
        } else {
            mangled
        };
        VarInfo {
            name: name,
            mangled: mangled,
            comment: comment,
            ty: ty,
            val: None,
            is_const: false,
            is_static: false,
        }
    }
}

impl fmt::Debug for VarInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}
<commit_msg>types: Fallback to the specifyed layout if no underlying layout was found<commit_after>use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use syntax::abi;

pub use self::Global::*;
pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;

static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;

#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct ModuleId(usize);
pub static ROOT_MODULE_ID: ModuleId = ModuleId(0);

impl ModuleId {
    pub fn next() -> ModuleId {
        ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1)
    }
}

pub type ModuleMap = HashMap<ModuleId, Module>;

#[derive(Clone)]
pub struct Module {
    pub name: String,
    pub globals: Vec<Global>,
    pub parent_id: Option<ModuleId>,
    // Just for convenience
    pub children_ids: Vec<ModuleId>,
    /// Types that must be substituted in this module,
    /// in the form original_name -> substituted_type
    pub translations: HashMap<String, Global>,
}

impl Module {
    pub fn new(name: String, parent_id: Option<ModuleId>) -> Self {
        Module {
            name: name,
            globals: vec![],
            parent_id: parent_id,
            children_ids: vec![],
            translations: HashMap::new(),
        }
    }

    #[allow(dead_code)]
    pub fn add_global(&mut self, g: Global) {
        self.globals.push(g)
    }
}

#[derive(Clone)]
pub enum Global {
    GType(Rc<RefCell<TypeInfo>>),
    GComp(Rc<RefCell<CompInfo>>),
    GCompDecl(Rc<RefCell<CompInfo>>),
    GEnum(Rc<RefCell<EnumInfo>>),
    GEnumDecl(Rc<RefCell<EnumInfo>>),
    GVar(Rc<RefCell<VarInfo>>),
    GFunc(Rc<RefCell<VarInfo>>),
    GOther
}

impl Global {
    // XXX prevent this dumb to_owned()... didn't want to deal with the borrowed lifetime
    pub fn name(&self) -> String {
        match *self {
            GType(ref info) => info.borrow().name.to_owned(),
            GComp(ref info)
            | GCompDecl(ref info) => info.borrow().name.to_owned(),
            GEnum(ref info)
            | GEnumDecl(ref info) => info.borrow().name.to_owned(),
            GVar(ref info)
            | GFunc(ref info) => info.borrow().name.to_owned(),
            GOther => "".to_owned(),
        }
    }

    pub fn layout(&self) -> Option<Layout> {
        Some(match *self {
            GType(ref info) => info.borrow().layout,
            GComp(ref info)
            | GCompDecl(ref info) => info.borrow().layout,
            GEnum(ref info)
            | GEnumDecl(ref info) => info.borrow().layout,
            GVar(_)
            | GFunc(_)
            | GOther => return None,
        })
    }

    pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> {
        match *self {
            GComp(ref i)
            | GCompDecl(ref i) => i.clone(),
            _ => panic!("global_compinfo")
        }
    }

    pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> {
        match *self {
            GEnum(ref i)
            | GEnumDecl(ref i) => i.clone(),
            _ => panic!("global_enuminfo")
        }
    }

    pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> {
        match *self {
            GType(ref i) => i.clone(),
            _ => panic!("global_typeinfo")
        }
    }

    pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> {
        match *self {
            GVar(ref i)
            | GFunc(ref i) => i.clone(),
            _ => panic!("global_varinfo")
        }
    }
}

impl fmt::Debug for Global {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GType(ref ti) => ti.borrow().fmt(f),
            GComp(ref ci)
            | GCompDecl(ref ci) => ci.borrow().fmt(f),
            GEnum(ref ei)
            | GEnumDecl(ref ei) => ei.borrow().fmt(f),
            GVar(ref vi)
            | GFunc(ref vi) => vi.borrow().fmt(f),
            GOther => "*".fmt(f),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct FuncSig {
    pub ret_ty: Box<Type>,
    pub args: Vec<(String, Type)>,
    pub is_variadic: bool,
    pub is_safe: bool,
    pub abi: abi::Abi,
}

#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    TVoid,
    TInt(IKind, Layout),
    TFloat(FKind, Layout),
    TPtr(Box<Type>, bool, bool, Layout),
    TArray(Box<Type>, usize, Layout),
    TFuncProto(FuncSig),
    TFuncPtr(FuncSig),
    TNamed(Rc<RefCell<TypeInfo>>),
    TComp(Rc<RefCell<CompInfo>>),
    TEnum(Rc<RefCell<EnumInfo>>)
}

impl Type {
    pub fn name(&self) -> Option<String> {
        match *self {
            TNamed(ref info) => Some(info.borrow().name.clone()),
            TComp(ref info)  => Some(info.borrow().name.clone()),
            TEnum(ref info)  => Some(info.borrow().name.clone()),
            TArray(ref t, _, _) => t.name(),
            TPtr(ref t, _, _, _) => t.name(),
            _ => None
        }
    }

    pub fn size(&self) -> usize {
        self.layout().map(|l| l.size).unwrap_or(0)
    }

    #[allow(dead_code)]
    pub fn align(&self) -> usize {
        self.layout().map(|l| l.align).unwrap_or(0)
    }

    pub fn layout(&self) -> Option<Layout> {
        Some(match *self {
            TInt(_, l) => l.clone(),
            TFloat(_, l) => l.clone(),
            TPtr(_, _, _, l) => l.clone(),
            TArray(_, _, l) => l.clone(),
            TComp(ref ci) => ci.borrow().layout.clone(),
            TEnum(ref ei) => ei.borrow().layout.clone(),
            // Test first with the underlying type layout, else with the reported one
            // This fixes a weird bug in SM when it can't find layout for uint32_t
            TNamed(ref ti) => ti.borrow().ty.layout().unwrap_or(ti.borrow().layout.clone()),
            TVoid |
            TFuncProto(..) |
            TFuncPtr(..) => return None,
        })
    }

    #[allow(dead_code)]
    pub fn can_derive_debug(&self) -> bool {
        match *self {
            TArray(_, size, _) => size <= 32,
            TComp(ref comp) => {
                comp.borrow()
                    .members
                    .iter()
                    .all(|member| match *member {
                        CompMember::Field(ref f) |
                        CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
                        _ => true,
                    })
            }
            _ => true,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Layout {
    pub size: usize,
    pub align: usize,
    pub packed: bool,
}

impl Layout {
    pub fn new(size: usize, align: usize) -> Layout {
        Layout { size: size, align: align, packed: false }
    }

    pub fn zero() -> Layout {
        Layout { size: 0, align: 0, packed: false }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum IKind {
    IBool,
    ISChar,
    IUChar,
    IShort,
    IUShort,
    IInt,
    IUInt,
    ILong,
    IULong,
    ILongLong,
    IULongLong
}

impl IKind {
    #[allow(dead_code)]
    pub fn is_signed(self) -> bool {
        match self {
            IBool => false,
            ISChar => true,
            IUChar => false,
            IShort => true,
            IUShort => false,
            IInt => true,
            IUInt => false,
            ILong => true,
            IULong => false,
            ILongLong => true,
            IULongLong => false,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FKind {
    FFloat,
    FDouble
}

#[derive(Clone, PartialEq)]
pub enum CompMember {
    Field(FieldInfo),
    Comp(Rc<RefCell<CompInfo>>),
    #[allow(dead_code)]
    CompField(Rc<RefCell<CompInfo>>, FieldInfo),
    Enum(Rc<RefCell<EnumInfo>>),
}

#[derive(Copy, Clone, PartialEq)]
pub enum CompKind {
    Struct,
    Union,
}

#[derive(Clone, PartialEq)]
pub struct CompInfo {
    pub kind: CompKind,
    pub name: String,
    pub module_id: ModuleId,
    pub filename: String,
    pub comment: String,
    pub members: Vec<CompMember>,
    pub args: Vec<Type>,
    pub methods: Vec<VarInfo>,
    pub vmethods: Vec<VarInfo>,
    pub ref_template: Option<Type>,
    pub has_vtable: bool,
    pub has_destructor: bool,
    pub has_nonempty_base: bool,
    pub hide: bool,
    pub base_members: usize,
    pub layout: Layout,
    /// Typedef'd types names, that we'll resolve early to avoid name conflicts
    pub typedefs: Vec<String>,
    /// If this type has a template parameter which is not a type (e.g.: a size_t)
    pub has_non_type_template_params: bool,
    /// If this type was unnamed when parsed
    pub was_unnamed: bool,
}

static mut UNNAMED_COUNTER: u32 = 0;

fn unnamed_name(name: String, filename: &String) -> String {
    if name.is_empty() {
        let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER };
        format!("{}_unnamed_{}", filename, n)
    } else {
        name
    }
}

impl CompInfo {
    pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
        let was_unnamed = name.is_empty();
        CompInfo {
            kind: kind,
            module_id: module_id,
            name: unnamed_name(name, &filename),
            filename: filename,
            comment: comment,
            members: members,
            args: vec!(),
            methods: vec!(),
            vmethods: vec!(),
            ref_template: None,
            has_vtable: false,
            has_destructor: false,
            has_nonempty_base: false,
            hide: false,
            base_members: 0,
            layout: layout,
            typedefs: vec!(),
            has_non_type_template_params: false,
            was_unnamed: was_unnamed,
        }
    }
}

impl fmt::Debug for CompInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct FieldInfo {
    pub name: String,
    pub ty: Type,
    pub comment: String,
    pub bitfields: Option<Vec<(String, u32)>>,
}

impl FieldInfo {
    pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
        FieldInfo {
            name: name,
            ty: ty,
            comment: comment,
            bitfields: bitfields,
        }
    }
}

impl fmt::Debug for FieldInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct EnumInfo {
    pub name: String,
    pub module_id: ModuleId,
    pub comment: String,
    pub filename: String,
    pub items: Vec<EnumItem>,
    pub kind: IKind,
    pub layout: Layout,
}

impl EnumInfo {
    pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
        EnumInfo {
            name: unnamed_name(name, &filename),
            module_id: module_id,
            comment: String::new(),
            filename: filename,
            items: items,
            kind: kind,
            layout: layout,
        }
    }
}

impl fmt::Debug for EnumInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct EnumItem {
    pub name: String,
    pub comment: String,
    pub val: i64
}

impl EnumItem {
    pub fn new(name: String, comment: String, val: i64) -> EnumItem {
        EnumItem {
            name: name,
            comment: comment,
            val: val
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct TypeInfo {
    pub name: String,
    pub module_id: ModuleId,
    pub comment: String,
    pub ty: Type,
    pub layout: Layout,
}

impl TypeInfo {
    pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo {
        TypeInfo {
            name: name,
            module_id: module_id,
            comment: String::new(),
            ty: ty,
            layout: layout,
        }
    }
}

impl fmt::Debug for TypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq)]
pub struct VarInfo {
    pub name: String,
    pub mangled: String,
    pub comment: String,
    pub ty: Type,
    //TODO: support non-integer constants
    pub val: Option<i64>,
    pub is_const: bool,
    pub is_static: bool,
}

impl VarInfo {
    pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo {
        let mangled = if name == mangled {
            String::new()
        } else {
            mangled
        };
        VarInfo {
            name: name,
            mangled: mangled,
            comment: comment,
            ty: ty,
            val: None,
            is_const: false,
            is_static: false,
        }
    }
}

impl fmt::Debug for VarInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}
<|endoftext|>


<commit_before>//! Types that specify what is contained in a ZIP.

use time;

#[derive(Clone, Copy, Debug)]
pub enum System
{
    Dos,
    Unix,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

pub const DEFAULT_VERSION: u8 = 20;

/// Structure representing a ZIP file.
#[derive(Debug)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: time::Tm,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}
<commit_msg>Fix types::System enum<commit_after>//! Types that specify what is contained in a ZIP.

use time;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum System
{
    Dos = 0,
    Unix = 3,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

pub const DEFAULT_VERSION: u8 = 20;

/// Structure representing a ZIP file.
#[derive(Debug)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: time::Tm,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}

#[cfg(test)]
mod test {
    #[test]
    fn system() {
        use super::System;
        assert_eq!(System::Dos as u16, 0u16);
        assert_eq!(System::Unix as u16, 3u16);
        assert_eq!(System::from_u8(0), System::Dos);
        assert_eq!(System::from_u8(3), System::Unix);
    }
}
<|endoftext|>


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

//! Runtime type information.

use translate::{FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibPtr, ToGlibContainerFromSlice, from_glib, from_glib_none};
use ffi as glib_ffi;
use gobject_ffi;

use std::fmt;
use std::mem;
use std::ptr;

/// A GLib or GLib-based library type
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
    /// An invalid `Type` used as error return value in some functions
    Invalid,
    /// The fundamental type corresponding to the unit type `()`
    Unit,
    /// The fundamental type corresponding to `i8`
    I8,
    /// The fundamental type corresponding to `u8`
    U8,
    /// The fundamental type corresponding to `bool`
    Bool,
    /// The fundamental type corresponding to `i32`
    I32,
    /// The fundamental type corresponding to `u32`
    U32,
    /// The fundamental type corresponding to C `long`
    ILong,
    /// The fundamental type corresponding to C `unsigned long`
    ULong,
    /// The fundamental type corresponding to `i64`
    I64,
    /// The fundamental type corresponding to `u64`
    U64,
    /// The fundamental type corresponding to `f32`
    F32,
    /// The fundamental type corresponding to `f64`
    F64,
    /// The fundamental type corresponding to `String`
    String,
    /// The fundamental type corresponding to a pointer
    Pointer,
    /// The fundamental type of GVariant
    Variant,
    /// The fundamental type from which all interfaces are derived
    BaseInterface,
    /// The fundamental type from which all enumeration types are derived
    BaseEnum,
    /// The fundamental type from which all flags types are derived
    BaseFlags,
    /// The fundamental type from which all boxed types are derived
    BaseBoxed,
    /// The fundamental type from which all `GParamSpec` types are derived
    BaseParamSpec,
    /// The fundamental type from which all objects are derived
    BaseObject,
    /// A non-fundamental type identified by value of type `usize`
    Other(usize),
}

impl Type {
    pub fn name(&self) -> String {
        unsafe {
            from_glib_none(gobject_ffi::g_type_name(self.to_glib()))
        }
    }

    pub fn is_a(&self, other: &Type) -> bool {
        unsafe {
            from_glib(gobject_ffi::g_type_is_a(self.to_glib(), other.to_glib()))
        }
    }

    pub fn parent(&self) -> Option<Self> {
        unsafe {
            let parent = gobject_ffi::g_type_parent(self.to_glib());
            if parent == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(parent))
            }
        }
    }

    pub fn children(&self) -> Vec<Self> {
        unsafe {
            let mut n_children = 0u32;
            let children = gobject_ffi::g_type_children(self.to_glib(), &mut n_children);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
        }
    }

    pub fn interfaces(&self) -> Vec<Self> {
        unsafe {
            let mut n_interfaces = 0u32;
            let interfaces = gobject_ffi::g_type_interfaces(self.to_glib(), &mut n_interfaces);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
        }
    }
    pub fn interface_prerequisites(&self) -> Vec<Self> {
        unsafe {
            let mut n_prereqs = 0u32;
            let prereqs = gobject_ffi::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
        }
    }

    pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
        unsafe {
            let type_ = gobject_ffi::g_type_from_name(name.into().to_glib_none().0);
            if type_ == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(type_))
            }
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

/// Types that are supported by GLib dynamic typing.
pub trait StaticType {
    /// Returns the type identifier of `Self`.
    fn static_type() -> Type;
}

impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
    fn static_type() -> Type {
        T::static_type()
    }
}

macro_rules! builtin {
    ($name:ident, $val:ident) => {
        impl StaticType for $name {
            fn static_type() -> Type {
                Type::$val
            }
        }
    }
}

builtin!(bool, Bool);
builtin!(i8, I8);
builtin!(u8, U8);
builtin!(i32, I32);
builtin!(u32, U32);
builtin!(i64, I64);
builtin!(u64, U64);
builtin!(f32, F32);
builtin!(f64, F64);
builtin!(str, String);
builtin!(String, String);

impl<'a> StaticType for [&'a str] {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl StaticType for Vec<String> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

#[inline]
pub unsafe fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
    from_glib(
        gobject_ffi::g_type_check_instance_is_a(
            ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}

impl FromGlib<glib_ffi::GType> for Type {
    #[inline]
    fn from_glib(val: glib_ffi::GType) -> Type {
        use self::Type::*;
        match val {
            gobject_ffi::G_TYPE_INVALID => Invalid,
            gobject_ffi::G_TYPE_NONE => Unit,
            gobject_ffi::G_TYPE_INTERFACE => BaseInterface,
            gobject_ffi::G_TYPE_CHAR => I8,
            gobject_ffi::G_TYPE_UCHAR => U8,
            gobject_ffi::G_TYPE_BOOLEAN => Bool,
            gobject_ffi::G_TYPE_INT => I32,
            gobject_ffi::G_TYPE_UINT => U32,
            gobject_ffi::G_TYPE_LONG => ILong,
            gobject_ffi::G_TYPE_ULONG => ULong,
            gobject_ffi::G_TYPE_INT64 => I64,
            gobject_ffi::G_TYPE_UINT64 => U64,
            gobject_ffi::G_TYPE_ENUM => BaseEnum,
            gobject_ffi::G_TYPE_FLAGS => BaseFlags,
            gobject_ffi::G_TYPE_FLOAT => F32,
            gobject_ffi::G_TYPE_DOUBLE => F64,
            gobject_ffi::G_TYPE_STRING => String,
            gobject_ffi::G_TYPE_POINTER => Pointer,
            gobject_ffi::G_TYPE_BOXED => BaseBoxed,
            gobject_ffi::G_TYPE_PARAM => BaseParamSpec,
            gobject_ffi::G_TYPE_OBJECT => BaseObject,
            gobject_ffi::G_TYPE_VARIANT => Variant,
            x => Other(x as usize),
        }
    }
}

impl ToGlib for Type {
    type GlibType = glib_ffi::GType;

    fn to_glib(&self) -> glib_ffi::GType {
        use self::Type::*;
        match *self {
            Invalid => gobject_ffi::G_TYPE_INVALID,
            Unit => gobject_ffi::G_TYPE_NONE,
            BaseInterface => gobject_ffi::G_TYPE_INTERFACE,
            I8 => gobject_ffi::G_TYPE_CHAR,
            U8 => gobject_ffi::G_TYPE_UCHAR,
            Bool => gobject_ffi::G_TYPE_BOOLEAN,
            I32 => gobject_ffi::G_TYPE_INT,
            U32 => gobject_ffi::G_TYPE_UINT,
            ILong => gobject_ffi::G_TYPE_LONG,
            ULong => gobject_ffi::G_TYPE_ULONG,
            I64 => gobject_ffi::G_TYPE_INT64,
            U64 => gobject_ffi::G_TYPE_UINT64,
            BaseEnum => gobject_ffi::G_TYPE_ENUM,
            BaseFlags => gobject_ffi::G_TYPE_FLAGS,
            F32 => gobject_ffi::G_TYPE_FLOAT,
            F64 => gobject_ffi::G_TYPE_DOUBLE,
            String => gobject_ffi::G_TYPE_STRING,
            Pointer => gobject_ffi::G_TYPE_POINTER,
            BaseBoxed => gobject_ffi::G_TYPE_BOXED,
            BaseParamSpec => gobject_ffi::G_TYPE_PARAM,
            BaseObject => gobject_ffi::G_TYPE_OBJECT,
            Variant => gobject_ffi::G_TYPE_VARIANT,
            Other(x) => x as glib_ffi::GType,
        }
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut glib_ffi::GType> for Type {
    type Storage = Option<Vec<glib_ffi::GType>>;

    fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        let mut vec = t.iter().map(|v| v.to_glib()).collect::<Vec<_>>();

        (vec.as_mut_ptr(), Some(vec))
    }

    fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        (Self::to_glib_full_from_slice(t), None)
    }

    fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_ffi::GType {
        if t.len() == 0 {
            return ptr::null_mut();
        }

        unsafe {
            let res = glib_ffi::g_malloc0(mem::size_of::<glib_ffi::GType>() * (t.len() + 1)) as *mut glib_ffi::GType;
            for (i, v) in t.iter().enumerate() {
                *res.offset(i as isize) = v.to_glib();
            }
            res
        }
    }
}

impl FromGlibContainerAsVec<Type, *const glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_ffi::GType, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib(*ptr.offset(i as isize)));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }

    unsafe fn from_glib_full_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }
}

impl FromGlibContainerAsVec<Type, *mut glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
    }
}
<commit_msg>Implement StaticType for Type<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Runtime type information.

use translate::{FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibPtr, ToGlibContainerFromSlice, from_glib, from_glib_none};
use ffi as glib_ffi;
use gobject_ffi;

use std::fmt;
use std::mem;
use std::ptr;

/// A GLib or GLib-based library type
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
    /// An invalid `Type` used as error return value in some functions
    Invalid,
    /// The fundamental type corresponding to the unit type `()`
    Unit,
    /// The fundamental type corresponding to `i8`
    I8,
    /// The fundamental type corresponding to `u8`
    U8,
    /// The fundamental type corresponding to `bool`
    Bool,
    /// The fundamental type corresponding to `i32`
    I32,
    /// The fundamental type corresponding to `u32`
    U32,
    /// The fundamental type corresponding to C `long`
    ILong,
    /// The fundamental type corresponding to C `unsigned long`
    ULong,
    /// The fundamental type corresponding to `i64`
    I64,
    /// The fundamental type corresponding to `u64`
    U64,
    /// The fundamental type corresponding to `f32`
    F32,
    /// The fundamental type corresponding to `f64`
    F64,
    /// The fundamental type corresponding to `String`
    String,
    /// The fundamental type corresponding to a pointer
    Pointer,
    /// The fundamental type of GVariant
    Variant,
    /// The fundamental type from which all interfaces are derived
    BaseInterface,
    /// The fundamental type from which all enumeration types are derived
    BaseEnum,
    /// The fundamental type from which all flags types are derived
    BaseFlags,
    /// The fundamental type from which all boxed types are derived
    BaseBoxed,
    /// The fundamental type from which all `GParamSpec` types are derived
    BaseParamSpec,
    /// The fundamental type from which all objects are derived
    BaseObject,
    /// A non-fundamental type identified by value of type `usize`
    Other(usize),
}

impl Type {
    pub fn name(&self) -> String {
        unsafe {
            from_glib_none(gobject_ffi::g_type_name(self.to_glib()))
        }
    }

    pub fn is_a(&self, other: &Type) -> bool {
        unsafe {
            from_glib(gobject_ffi::g_type_is_a(self.to_glib(), other.to_glib()))
        }
    }

    pub fn parent(&self) -> Option<Self> {
        unsafe {
            let parent = gobject_ffi::g_type_parent(self.to_glib());
            if parent == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(parent))
            }
        }
    }

    pub fn children(&self) -> Vec<Self> {
        unsafe {
            let mut n_children = 0u32;
            let children = gobject_ffi::g_type_children(self.to_glib(), &mut n_children);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
        }
    }

    pub fn interfaces(&self) -> Vec<Self> {
        unsafe {
            let mut n_interfaces = 0u32;
            let interfaces = gobject_ffi::g_type_interfaces(self.to_glib(), &mut n_interfaces);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
        }
    }
    pub fn interface_prerequisites(&self) -> Vec<Self> {
        unsafe {
            let mut n_prereqs = 0u32;
            let prereqs = gobject_ffi::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
        }
    }

    pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
        unsafe {
            let type_ = gobject_ffi::g_type_from_name(name.into().to_glib_none().0);
            if type_ == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(type_))
            }
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

/// Types that are supported by GLib dynamic typing.
pub trait StaticType {
    /// Returns the type identifier of `Self`.
    fn static_type() -> Type;
}

impl StaticType for Type {
    fn static_type() -> Type {
        unsafe {
            from_glib(gobject_ffi::g_gtype_get_type())
        }
    }
}

impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
    fn static_type() -> Type {
        T::static_type()
    }
}

macro_rules! builtin {
    ($name:ident, $val:ident) => {
        impl StaticType for $name {
            fn static_type() -> Type {
                Type::$val
            }
        }
    }
}

builtin!(bool, Bool);
builtin!(i8, I8);
builtin!(u8, U8);
builtin!(i32, I32);
builtin!(u32, U32);
builtin!(i64, I64);
builtin!(u64, U64);
builtin!(f32, F32);
builtin!(f64, F64);
builtin!(str, String);
builtin!(String, String);

impl<'a> StaticType for [&'a str] {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl StaticType for Vec<String> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

#[inline]
pub unsafe fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
    from_glib(
        gobject_ffi::g_type_check_instance_is_a(
            ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}

impl FromGlib<glib_ffi::GType> for Type {
    #[inline]
    fn from_glib(val: glib_ffi::GType) -> Type {
        use self::Type::*;
        match val {
            gobject_ffi::G_TYPE_INVALID => Invalid,
            gobject_ffi::G_TYPE_NONE => Unit,
            gobject_ffi::G_TYPE_INTERFACE => BaseInterface,
            gobject_ffi::G_TYPE_CHAR => I8,
            gobject_ffi::G_TYPE_UCHAR => U8,
            gobject_ffi::G_TYPE_BOOLEAN => Bool,
            gobject_ffi::G_TYPE_INT => I32,
            gobject_ffi::G_TYPE_UINT => U32,
            gobject_ffi::G_TYPE_LONG => ILong,
            gobject_ffi::G_TYPE_ULONG => ULong,
            gobject_ffi::G_TYPE_INT64 => I64,
            gobject_ffi::G_TYPE_UINT64 => U64,
            gobject_ffi::G_TYPE_ENUM => BaseEnum,
            gobject_ffi::G_TYPE_FLAGS => BaseFlags,
            gobject_ffi::G_TYPE_FLOAT => F32,
            gobject_ffi::G_TYPE_DOUBLE => F64,
            gobject_ffi::G_TYPE_STRING => String,
            gobject_ffi::G_TYPE_POINTER => Pointer,
            gobject_ffi::G_TYPE_BOXED => BaseBoxed,
            gobject_ffi::G_TYPE_PARAM => BaseParamSpec,
            gobject_ffi::G_TYPE_OBJECT => BaseObject,
            gobject_ffi::G_TYPE_VARIANT => Variant,
            x => Other(x as usize),
        }
    }
}

impl ToGlib for Type {
    type GlibType = glib_ffi::GType;

    fn to_glib(&self) -> glib_ffi::GType {
        use self::Type::*;
        match *self {
            Invalid => gobject_ffi::G_TYPE_INVALID,
            Unit => gobject_ffi::G_TYPE_NONE,
            BaseInterface => gobject_ffi::G_TYPE_INTERFACE,
            I8 => gobject_ffi::G_TYPE_CHAR,
            U8 => gobject_ffi::G_TYPE_UCHAR,
            Bool => gobject_ffi::G_TYPE_BOOLEAN,
            I32 => gobject_ffi::G_TYPE_INT,
            U32 => gobject_ffi::G_TYPE_UINT,
            ILong => gobject_ffi::G_TYPE_LONG,
            ULong => gobject_ffi::G_TYPE_ULONG,
            I64 => gobject_ffi::G_TYPE_INT64,
            U64 => gobject_ffi::G_TYPE_UINT64,
            BaseEnum => gobject_ffi::G_TYPE_ENUM,
            BaseFlags => gobject_ffi::G_TYPE_FLAGS,
            F32 => gobject_ffi::G_TYPE_FLOAT,
            F64 => gobject_ffi::G_TYPE_DOUBLE,
            String => gobject_ffi::G_TYPE_STRING,
            Pointer => gobject_ffi::G_TYPE_POINTER,
            BaseBoxed => gobject_ffi::G_TYPE_BOXED,
            BaseParamSpec => gobject_ffi::G_TYPE_PARAM,
            BaseObject => gobject_ffi::G_TYPE_OBJECT,
            Variant => gobject_ffi::G_TYPE_VARIANT,
            Other(x) => x as glib_ffi::GType,
        }
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut glib_ffi::GType> for Type {
    type Storage = Option<Vec<glib_ffi::GType>>;

    fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        let mut vec = t.iter().map(|v| v.to_glib()).collect::<Vec<_>>();

        (vec.as_mut_ptr(), Some(vec))
    }

    fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        (Self::to_glib_full_from_slice(t), None)
    }

    fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_ffi::GType {
        if t.len() == 0 {
            return ptr::null_mut();
        }

        unsafe {
            let res = glib_ffi::g_malloc0(mem::size_of::<glib_ffi::GType>() * (t.len() + 1)) as *mut glib_ffi::GType;
            for (i, v) in t.iter().enumerate() {
                *res.offset(i as isize) = v.to_glib();
            }
            res
        }
    }
}

impl FromGlibContainerAsVec<Type, *const glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_ffi::GType, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib(*ptr.offset(i as isize)));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }

    unsafe fn from_glib_full_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }
}

impl FromGlibContainerAsVec<Type, *mut glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::error;
use gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

#[derive(Clone, Copy)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    Message(String)
}

impl fmt::Display for GLError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLError::InvalidEnum => {
                write!(f, "Invalid enum")
            },
            GLError::InvalidValue => {
                write!(f, "Invalid value")
            },
            GLError::InvalidOperation => {
                write!(f, "Invalid operation")
            },
            GLError::InvalidFramebufferOperation => {
                write!(f, "Invalid framebuffer operation")
            },
            GLError::OutOfMemory => {
                write!(f, "Out of memory")
            },
            GLError::Message(ref s) => {
                write!(f, "{}", s)
            }
        }
    }
}

impl error::Error for GLError {
    fn description(&self) -> &str {
        match *self {
            GLError::InvalidEnum => "Invalid enum variant in OpenGL call.",
            GLError::InvalidValue => "Out-of-range value in OpenGL call.",
            GLError::InvalidOperation => "The specified OpenGL operation is not allowed in the current state.",
            GLError::InvalidFramebufferOperation => "OpenGL command tried to read or write to an incomplete framebuffer.",
            GLError::OutOfMemory => "There is not enough memory left to execute the specified OpenGL command.",
            GLError::Message(ref s) => &s
        }
    }
}

#[derive(Debug)]
pub enum GLFramebufferError {
    IncompleteAttachment,
    IncompleteDimensions,
    IncompleteMissingAttachment,
    Unsupported
}

gl_enum! {
    pub gl_enum DrawingMode {
        Points as POINTS = gl::POINTS,
        LineStrip as LINE_STRIP = gl::LINE_STRIP,
        LineLoop as LINE_LOOP = gl::LINE_LOOP,
        Lines as LINES = gl::LINES,
        TriangleStrip as TRIANGLE_STRIP = gl::TRIANGLE_STRIP,
        TriangleFan as TRIANGLE_FAN = gl::TRIANGLE_FAN,
        Triangles as TRIANGLES = gl::TRIANGLES
    }
}

gl_enum! {
    pub gl_enum DataType {
        Byte as BYTE = gl::BYTE,
        UnsignedByte as UNSIGNED_BYTE = gl::UNSIGNED_BYTE,
        Short as SHORT = gl::SHORT,
        UnsignedShort as UNSIGNED_SHORT = gl::UNSIGNED_SHORT,
        Fixed as FIXED = gl::FIXED,
        Float as FLOAT = gl::FLOAT
    }
}
<commit_msg>Add `Display` impl for `GLFramebufferError`<commit_after>use std::fmt;
use std::error;
use gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

#[derive(Clone, Copy)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    Message(String)
}

impl fmt::Display for GLError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLError::InvalidEnum => {
                write!(f, "Invalid enum")
            },
            GLError::InvalidValue => {
                write!(f, "Invalid value")
            },
            GLError::InvalidOperation => {
                write!(f, "Invalid operation")
            },
            GLError::InvalidFramebufferOperation => {
                write!(f, "Invalid framebuffer operation")
            },
            GLError::OutOfMemory => {
                write!(f, "Out of memory")
            },
            GLError::Message(ref s) => {
                write!(f, "{}", s)
            }
        }
    }
}

impl error::Error for GLError {
    fn description(&self) -> &str {
        match *self {
            GLError::InvalidEnum => "Invalid enum variant in OpenGL call.",
            GLError::InvalidValue => "Out-of-range value in OpenGL call.",
            GLError::InvalidOperation => "The specified OpenGL operation is not allowed in the current state.",
            GLError::InvalidFramebufferOperation => "OpenGL command tried to read or write to an incomplete framebuffer.",
            GLError::OutOfMemory => "There is not enough memory left to execute the specified OpenGL command.",
            GLError::Message(ref s) => &s
        }
    }
}

#[derive(Debug)]
pub enum GLFramebufferError {
    IncompleteAttachment,
    IncompleteDimensions,
    IncompleteMissingAttachment,
    Unsupported
}

impl fmt::Display for GLFramebufferError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLFramebufferError::IncompleteAttachment => {
                write!(f, "Incomplete attachment")
            },
            GLFramebufferError::IncompleteDimensions => {
                write!(f, "Incomplete dimensions")
            },
            GLFramebufferError::IncompleteMissingAttachment => {
                write!(f, "Missing attachments")
            },
            GLFramebufferError::Unsupported => {
                write!(f, "Unsupported")
            }
        }
    }
}

gl_enum! {
    pub gl_enum DrawingMode {
        Points as POINTS = gl::POINTS,
        LineStrip as LINE_STRIP = gl::LINE_STRIP,
        LineLoop as LINE_LOOP = gl::LINE_LOOP,
        Lines as LINES = gl::LINES,
        TriangleStrip as TRIANGLE_STRIP = gl::TRIANGLE_STRIP,
        TriangleFan as TRIANGLE_FAN = gl::TRIANGLE_FAN,
        Triangles as TRIANGLES = gl::TRIANGLES
    }
}

gl_enum! {
    pub gl_enum DataType {
        Byte as BYTE = gl::BYTE,
        UnsignedByte as UNSIGNED_BYTE = gl::UNSIGNED_BYTE,
        Short as SHORT = gl::SHORT,
        UnsignedShort as UNSIGNED_SHORT = gl::UNSIGNED_SHORT,
        Fixed as FIXED = gl::FIXED,
        Float as FLOAT = gl::FLOAT
    }
}
<|endoftext|>