<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An interface for numeric types
use cmp::Eq;
use option::{None, Option, Some};

pub trait Num {
    // FIXME: Trait composition. (#2616)
    pure fn add(&self, other: &Self) -> Self;
    pure fn sub(&self, other: &Self) -> Self;
    pure fn mul(&self, other: &Self) -> Self;
    pure fn div(&self, other: &Self) -> Self;
    pure fn modulo(&self, other: &Self) -> Self;
    pure fn neg(&self) -> Self;

    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait IntConvertible {
    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait Zero {
    static pure fn zero() -> Self;
}

pub trait One {
    static pure fn one() -> Self;
}

pub trait Round {
    pure fn round(&self, mode: RoundMode) -> self;

    pure fn floor(&self) -> self;
    pure fn ceil(&self)  -> self;
    pure fn fract(&self) -> self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

pub trait ToStrRadix {
    pub pure fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    static pub pure fn from_str_radix(str: &str, radix: uint) -> Option<self>;
}<commit_msg>Added some generic number functions to core::num<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An interface for numeric types
use cmp::Eq;
use option::{None, Option, Some};

pub trait Num {
    // FIXME: Trait composition. (#2616)
    pure fn add(&self, other: &Self) -> Self;
    pure fn sub(&self, other: &Self) -> Self;
    pure fn mul(&self, other: &Self) -> Self;
    pure fn div(&self, other: &Self) -> Self;
    pure fn modulo(&self, other: &Self) -> Self;
    pure fn neg(&self) -> Self;

    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait IntConvertible {
    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait Zero {
    static pure fn zero() -> Self;
}

pub trait One {
    static pure fn one() -> Self;
}

pub trait Round {
    pure fn round(&self, mode: RoundMode) -> self;

    pure fn floor(&self) -> self;
    pure fn ceil(&self)  -> self;
    pure fn fract(&self) -> self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

pub trait ToStrRadix {
    pub pure fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    static pub pure fn from_str_radix(str: &str, radix: uint) -> Option<self>;
}

// Generic math functions:

/// Dynamically calculates the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    _1 / _0
}

/// Dynamically calculates the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn neg_infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    - _1 / _0
}

/// Dynamically calculates the value `NaN` (`0/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn NaN<T: Num Zero>() -> T {
    let _0: T = Zero::zero();
    _0 / _0
}

/// Returns `true` if `num` has the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (infinity::<T>())
}

/// Returns `true` if `num` has the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (neg_infinity::<T>())
}

/// Returns `true` if `num` has the value `NaN` (is not equal to itself).
#[inline(always)]
pub pure fn is_NaN<T: Num Eq>(num: &T) -> bool {
    (*num) != (*num)
}

/// Returns `true` if `num` has the value `-0` (`1/num == -1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_zero<T: Num One Zero Eq>(num: &T) -> bool {
    let _1: T = One::one();
    let _0: T = Zero::zero();
    *num == _0 && is_neg_infinity(&(_1 / *num))
}

/**
 * Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 *
 * Returns `radix^pow` as `T`.
 *
 * Note:
 * Also returns `1` for `0^0`, despite that technically being an
 * undefined number. The Reason for this is twofold:
 * - If code written to use this function cares about that special case, it's
 *   probably going to catch it before making the call.
 * - If code written to use this function doesn't care about it, it's
 *   probably assuming that `x^0` always equals `1`.
 */
pub pure fn pow_with_uint<T: Num One Zero>(radix: uint, pow: uint) -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();

    if pow   == 0u { return _1; }
    if radix == 0u { return _0; }
    let mut my_pow     = pow;
    let mut total      = _1;
    let mut multiplier = Num::from_int(radix as int);
    while (my_pow > 0u) {
        if my_pow % 2u == 1u {
            total *= multiplier;
        }
        my_pow     /= 2u;
        multiplier *= multiplier;
    }
    total
}<|endoftext|>


<commit_before>use crate::clean::*;

crate fn strip_item(mut item: Item) -> Item {
    if !matches!(*item.kind, StrippedItem(..)) {
        item.kind = box StrippedItem(item.kind);
    }
    item
}

crate trait DocFolder: Sized {
    fn fold_item(&mut self, item: Item) -> Option<Item> {
        Some(self.fold_item_recur(item))
    }

    /// don't override!
    fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
        match kind {
            StrippedItem(..) => unreachable!(),
            ModuleItem(i) => ModuleItem(self.fold_mod(i)),
            StructItem(mut i) => {
                let num_fields = i.fields.len();
                i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                i.fields_stripped |=
                    num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
                StructItem(i)
            }
            UnionItem(mut i) => {
                let num_fields = i.fields.len();
                i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                i.fields_stripped |=
                    num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
                UnionItem(i)
            }
            EnumItem(mut i) => {
                let num_variants = i.variants.len();
                i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
                i.variants_stripped |=
                    num_variants != i.variants.len() || i.variants.iter().any(|f| f.is_stripped());
                EnumItem(i)
            }
            TraitItem(mut i) => {
                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                TraitItem(i)
            }
            ImplItem(mut i) => {
                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                ImplItem(i)
            }
            VariantItem(i) => match i {
                Variant::Struct(mut j) => {
                    let num_fields = j.fields.len();
                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                    j.fields_stripped |=
                        num_fields != j.fields.len() || j.fields.iter().any(|f| f.is_stripped());
                    VariantItem(Variant::Struct(j))
                }
                Variant::Tuple(fields) => {
                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                    VariantItem(Variant::Tuple(fields))
                }
                Variant::CLike => VariantItem(Variant::CLike),
            },
            ExternCrateItem { src: _ }
            | ImportItem(_)
            | FunctionItem(_)
            | TypedefItem(_, _)
            | OpaqueTyItem(_)
            | StaticItem(_)
            | ConstantItem(_)
            | TraitAliasItem(_)
            | TyMethodItem(_)
            | MethodItem(_, _)
            | StructFieldItem(_)
            | ForeignFunctionItem(_)
            | ForeignStaticItem(_)
            | ForeignTypeItem
            | MacroItem(_)
            | ProcMacroItem(_)
            | PrimitiveItem(_)
            | AssocConstItem(_, _)
            | AssocTypeItem(_, _)
            | KeywordItem(_) => kind,
        }
    }

    /// don't override!
    fn fold_item_recur(&mut self, mut item: Item) -> Item {
        item.kind = box match *item.kind {
            StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
            _ => self.fold_inner_recur(*item.kind),
        };
        item
    }

    fn fold_mod(&mut self, m: Module) -> Module {
        Module {
            span: m.span,
            items: m.items.into_iter().filter_map(|i| self.fold_item(i)).collect(),
        }
    }

    fn fold_crate(&mut self, mut c: Crate) -> Crate {
        c.module = self.fold_item(c.module).unwrap();

        let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
        for (k, mut v) in external_traits {
            v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
            c.external_traits.borrow_mut().insert(k, v);
        }

        c
    }
}
<commit_msg>rustdoc: Use conditional for _stripped fold<commit_after>use crate::clean::*;

crate fn strip_item(mut item: Item) -> Item {
    if !matches!(*item.kind, StrippedItem(..)) {
        item.kind = box StrippedItem(item.kind);
    }
    item
}

crate trait DocFolder: Sized {
    fn fold_item(&mut self, item: Item) -> Option<Item> {
        Some(self.fold_item_recur(item))
    }

    /// don't override!
    fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
        match kind {
            StrippedItem(..) => unreachable!(),
            ModuleItem(i) => ModuleItem(self.fold_mod(i)),
            StructItem(mut i) => {
                let num_fields = i.fields.len();
                i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                if !i.fields_stripped {
                    i.fields_stripped =
                        num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
                }
                StructItem(i)
            }
            UnionItem(mut i) => {
                let num_fields = i.fields.len();
                i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                if !i.fields_stripped {
                    i.fields_stripped =
                        num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
                }
                UnionItem(i)
            }
            EnumItem(mut i) => {
                let num_variants = i.variants.len();
                i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
                if !i.variants_stripped {
                    i.variants_stripped = num_variants != i.variants.len()
                        || i.variants.iter().any(|f| f.is_stripped());
                }
                EnumItem(i)
            }
            TraitItem(mut i) => {
                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                TraitItem(i)
            }
            ImplItem(mut i) => {
                i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                ImplItem(i)
            }
            VariantItem(i) => match i {
                Variant::Struct(mut j) => {
                    let num_fields = j.fields.len();
                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                    if !j.fields_stripped {
                        j.fields_stripped = num_fields != j.fields.len()
                            || j.fields.iter().any(|f| f.is_stripped());
                    }
                    VariantItem(Variant::Struct(j))
                }
                Variant::Tuple(fields) => {
                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
                    VariantItem(Variant::Tuple(fields))
                }
                Variant::CLike => VariantItem(Variant::CLike),
            },
            ExternCrateItem { src: _ }
            | ImportItem(_)
            | FunctionItem(_)
            | TypedefItem(_, _)
            | OpaqueTyItem(_)
            | StaticItem(_)
            | ConstantItem(_)
            | TraitAliasItem(_)
            | TyMethodItem(_)
            | MethodItem(_, _)
            | StructFieldItem(_)
            | ForeignFunctionItem(_)
            | ForeignStaticItem(_)
            | ForeignTypeItem
            | MacroItem(_)
            | ProcMacroItem(_)
            | PrimitiveItem(_)
            | AssocConstItem(_, _)
            | AssocTypeItem(_, _)
            | KeywordItem(_) => kind,
        }
    }

    /// don't override!
    fn fold_item_recur(&mut self, mut item: Item) -> Item {
        item.kind = box match *item.kind {
            StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
            _ => self.fold_inner_recur(*item.kind),
        };
        item
    }

    fn fold_mod(&mut self, m: Module) -> Module {
        Module {
            span: m.span,
            items: m.items.into_iter().filter_map(|i| self.fold_item(i)).collect(),
        }
    }

    fn fold_crate(&mut self, mut c: Crate) -> Crate {
        c.module = self.fold_item(c.module).unwrap();

        let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
        for (k, mut v) in external_traits {
            v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
            c.external_traits.borrow_mut().insert(k, v);
        }

        c
    }
}
<|endoftext|>


<commit_before>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;
use std::cmp::{Eq, Ord, PartialOrd, PartialEq, Ordering};

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    translation: Vector,
    rotation: Quaternion,
    scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        assert!(f32::is_finite(time));
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a + b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
    /// Return the transformation stored for this keyframe
    pub fn transform(&self) -> Transform {
        let m = self.rotation.to_matrix() * self.scaling;
        Transform::translate(&self.translation) * Transform::from_mat(&m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

impl Ord for Keyframe {
    fn cmp(&self, other: &Keyframe) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl PartialOrd for Keyframe {
    fn partial_cmp(&self, other: &Keyframe) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl Eq for Keyframe {}

impl PartialEq for Keyframe {
    fn eq(&self, other: &Keyframe) -> bool {
        self.time == other.time
    }
}

<commit_msg>Make keyframe members public<commit_after>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;
use std::cmp::{Eq, Ord, PartialOrd, PartialEq, Ordering};

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    pub translation: Vector,
    pub rotation: Quaternion,
    pub scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        assert!(f32::is_finite(time));
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a + b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
    /// Return the transformation stored for this keyframe
    pub fn transform(&self) -> Transform {
        let m = self.rotation.to_matrix() * self.scaling;
        Transform::translate(&self.translation) * Transform::from_mat(&m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

impl Ord for Keyframe {
    fn cmp(&self, other: &Keyframe) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl PartialOrd for Keyframe {
    fn partial_cmp(&self, other: &Keyframe) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl Eq for Keyframe {}

impl PartialEq for Keyframe {
    fn eq(&self, other: &Keyframe) -> bool {
        self.time == other.time
    }
}

<|endoftext|>


<commit_before>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}

pub fn yield_cpu() -> i32 {
    sched_op(SchedOp::Yield, 0)
}
<commit_msg>sched: Add poweroff() function<commit_after>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
enum ShutdownReason {
    PowerOff = 0,
    Reboot = 1,
    Suspend = 2,
    Crash = 3,
    Watchdog = 4,
}

#[repr(C)]
struct SchedShutdown {
    reason: u32,
}

fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}

pub fn yield_cpu() -> i32 {
    sched_op(SchedOp::Yield, 0)
}

fn shutdown(reason: ShutdownReason) -> i32 {
    let r = SchedShutdown {
        reason: reason as u32,
    };

    sched_op(SchedOp::Shutdown, &r as *const SchedShutdown as Ulong)
}

fn shutdown_code(status: Ulong) -> i32 {
    sched_op(SchedOp::ShutdownCode, status)
}

pub fn poweroff(status: Ulong) -> i32 {
    let ret: i32 = shutdown_code(status);

    if ret < 0 {
        return ret
    }

    shutdown(ShutdownReason::PowerOff)
}
<|endoftext|>


<commit_before>use std::sync::Mutex;

<commit_msg>marionette_bits: remove<commit_after><|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16, be_u32, be_u64,
  le_u32,
  IResult,
  ErrorCode, Err,
  Needed,
};

use std::str::from_utf8;

use metadata::{
  Block, BlockData,
  StreamInfo, Application, VorbisComment, CueSheet, Picture,
  SeekPoint, CueSheetTrack, CueSheetTrackIndex, PictureType,
};

use utility::to_u32;

macro_rules! skip_bytes(
  ($input: expr, $length: expr) => (
    {
      match take!($input, $length) {
        IResult::Done(i, bytes)   => {
          let sum = bytes.iter().fold(0, |result, byte| result + byte);

          if sum == 0 {
            IResult::Done(i, bytes)
          } else {
            IResult::Error(Err::Position(ErrorCode::Digit as u32, $input))
          }
        }
        IResult::Error(error)     => IResult::Error(error),
        IResult::Incomplete(need) => IResult::Incomplete(need),
      }
    }
  );
);

named!(stream_info <&[u8], BlockData>,
  chain!(
    min_block_size: be_u16 ~
    max_block_size: be_u16 ~
    min_frame_size: map!(take!(3), to_u32) ~
    max_frame_size: map!(take!(3), to_u32) ~
    bytes: take!(8) ~
    md5_sum: take!(16),
    || {
      let sample_rate     = ((bytes[0] as u32) << 12) +
                            ((bytes[1] as u32) << 4)  +
                            (bytes[2] as u32) >> 4;
      let channels        = (bytes[2] >> 1) & 0b0111;
      let bits_per_sample = ((bytes[2] & 0b01) << 4) +
                            bytes[3] >> 4;
      let total_samples   = (((bytes[3] as u64) & 0x0f) << 32) +
                            ((bytes[4] as u64) << 24) +
                            ((bytes[5] as u64) << 16) +
                            ((bytes[6] as u64) << 8) +
                            (bytes[7] as u64);

      BlockData::StreamInfo(StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: min_frame_size,
        max_frame_size: max_frame_size,
        sample_rate: sample_rate,
        channels: channels + 1,
        bits_per_sample: bits_per_sample + 1,
        total_samples: total_samples,
        md5_sum: md5_sum,
      })
    }
  )
);

fn padding(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, skip_bytes!(length), |_| BlockData::Padding(0))
}

fn application(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  chain!(input,
    id: take_str!(4) ~
    data: take!(length - 4),
    || {
      BlockData::Application(Application {
        id: id,
        data: data,
      })
    }
  )
}

named!(seek_point <&[u8], SeekPoint>,
  chain!(
    sample_number: be_u64 ~
    stream_offset: be_u64 ~
    frame_samples: be_u16,
    || {
      SeekPoint {
        sample_number: sample_number,
        stream_offset: stream_offset,
        frame_samples: frame_samples,
      }
    }
  )
);

fn seek_table(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  let seek_count = (length / 18) as usize;

  map!(input, count!(seek_point, seek_count), BlockData::SeekTable)
}

named!(vorbis_comment <&[u8], BlockData>,
  chain!(
    vendor_string_length: le_u32 ~
    vendor_string: take_str!(vendor_string_length)  ~
    number_of_comments: le_u32 ~
    comments: count!(comment_field, number_of_comments as usize),
    || {
      BlockData::VorbisComment(VorbisComment {
        vendor_string: vendor_string,
        comments: comments,
      })
    }
  )
);

named!(comment_field <&[u8], &str>,
  chain!(
    comment_length: le_u32 ~
    comment: take_str!(comment_length),
    || { comment }
  )
);

named!(cue_sheet <&[u8], BlockData>,
  chain!(
    media_catalog_number: take_str!(128) ~
    lead_in: be_u64 ~
    bytes: take!(259) ~ // TODO: last (7 + 258 * 8) bits must be 0
    num_tracks: be_u8 ~
    tracks: count!(cue_sheet_track, num_tracks as usize),
    || {
      let is_cd = ((bytes[0] >> 7) & 0b01) == 1;

      BlockData::CueSheet(CueSheet {
        media_catalog_number: media_catalog_number,
        lead_in: lead_in,
        is_cd: is_cd,
        tracks: tracks,
      })
    }
  )
);

named!(cue_sheet_track <&[u8], CueSheetTrack>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    isrc: take_str!(12) ~
    bytes: take!(14) ~ // TODO: last (6 + 13 * 8) bits must be 0
    num_indices: be_u8 ~
    indices: cond!(
      num_indices != 0,
      count!(cue_sheet_track_index, num_indices as usize)
    ),
    || {
      let isnt_audio      = ((bytes[0] >> 7) & 0b01) == 1;
      let is_pre_emphasis = ((bytes[0] >> 6) & 0b01) == 1;

      CueSheetTrack {
        offset: offset,
        number: number,
        isrc: isrc,
        isnt_audio: isnt_audio,
        is_pre_emphasis: is_pre_emphasis,
        indices: indices.unwrap_or(Vec::new()),
      }
    }
  )
);

named!(cue_sheet_track_index <&[u8], CueSheetTrackIndex>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    take!(3), // TODO: these bytes must be 0
    || {
      CueSheetTrackIndex {
        offset: offset,
        number: number,
      }
    }
  )
);

named!(picture <&[u8], BlockData>,
  chain!(
    picture_type_num: be_u32 ~
    mime_type_length:  be_u32 ~
    mime_type: take_str!(mime_type_length) ~
    description_length: be_u32 ~
    description: take_str!(description_length) ~
    width: be_u32 ~
    height: be_u32 ~
    depth: be_u32 ~
    colors: be_u32 ~
    data_length: be_u32 ~
    data: take!(data_length),
    || {
      let picture_type = match picture_type_num {
        0  => PictureType::Other,
        1  => PictureType::FileIconStandard,
        2  => PictureType::FileIcon,
        3  => PictureType::FrontCover,
        4  => PictureType::BackCover,
        5  => PictureType::LeafletPage,
        6  => PictureType::Media,
        7  => PictureType::LeadArtist,
        8  => PictureType::Artist,
        9  => PictureType::Conductor,
        10 => PictureType::Band,
        11 => PictureType::Composer,
        12 => PictureType::Lyricist,
        13 => PictureType::RecordingLocation,
        14 => PictureType::DuringRecording,
        15 => PictureType::DuringPerformace,
        16 => PictureType::VideoScreenCapture,
        17 => PictureType::Fish,
        18 => PictureType::Illustration,
        19 => PictureType::BandLogoType,
        20 => PictureType::PublisherLogoType,
        _  => PictureType::Other,
      };

      BlockData::Picture(Picture {
        picture_type: picture_type,
        mime_type: mime_type,
        description: description,
        width: width,
        height: height,
        depth: depth,
        colors: colors,
        data: data,
      })
    }
  )
);

// As of FLAC v1.3.1, there is support for up to 127 different metadata
// `Block`s but actually 7 that are implemented. When the `Block` type isn't
// recognised, this block gets skipped over with this parser.
fn unknown(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), BlockData::Unknown)
}

named!(header <&[u8], (u8, bool, u32)>,
  chain!(
    block_byte: be_u8 ~
    length: map!(take!(3), to_u32),
    || {
      let is_last    = (block_byte >> 7) == 1;
      let block_type = block_byte & 0b01111111;

      (block_type, is_last, length)
    }
  )
);

fn block_data(input: &[u8], block_type: u8, length: u32)
              -> IResult<&[u8], BlockData> {
  match block_type {
    0       => stream_info(input),
    1       => padding(input, length),
    2       => application(input, length),
    3       => seek_table(input, length),
    4       => vorbis_comment(input),
    5       => cue_sheet(input),
    6       => picture(input),
    7...126 => unknown(input, length),
    _       => IResult::Error(Err::Position(ErrorCode::Alt as u32, input)),
  }
}

named!(block <&[u8], Block>,
  chain!(
    block_header: header ~
    data: apply!(block_data, block_header.0, block_header.2),
    || {
      Block {
        is_last: block_header.1,
        length: block_header.2,
        data: data
      }
    }
  )
);

/// Parses one or more metadata `Block`s
///
/// The first block should always be `StreamInfo` since that is the only
/// required `Block`. At the moment `many_blocks` doesn't check that
/// requirement.
pub fn many_blocks(input: &[u8]) -> IResult<&[u8], Vec<Block>> {
  let mut is_last   = false;
  let mut blocks    = Vec::new();
  let mut start     = 0;
  let mut remaining = input.len();

  while !is_last {
    match block(&input[start..]) {
      IResult::Done(i, block) => {
        let result_len = i.len();

        if result_len == input[start..].len() {
          break;
        }

        start    += remaining - result_len;
        remaining = result_len;
        is_last   = block.is_last;

        blocks.push(block);
      }
      _                       => break,
    }
  }

  if blocks.len() == 0 {
    IResult::Error(Err::Position(ErrorCode::Many1 as u32, input))
  } else if is_last {
    IResult::Done(&input[start..], blocks)
  } else {
    IResult::Incomplete(Needed::Unknown)
  }
}
<commit_msg>Add skip_bytes! to cue_sheet_track_index<commit_after>use nom::{
  be_u8, be_u16, be_u32, be_u64,
  le_u32,
  IResult,
  ErrorCode, Err,
  Needed,
};

use std::str::from_utf8;

use metadata::{
  Block, BlockData,
  StreamInfo, Application, VorbisComment, CueSheet, Picture,
  SeekPoint, CueSheetTrack, CueSheetTrackIndex, PictureType,
};

use utility::to_u32;

macro_rules! skip_bytes(
  ($input: expr, $length: expr) => (
    {
      match take!($input, $length) {
        IResult::Done(i, bytes)   => {
          let sum = bytes.iter().fold(0, |result, byte| result + byte);

          if sum == 0 {
            IResult::Done(i, bytes)
          } else {
            IResult::Error(Err::Position(ErrorCode::Digit as u32, $input))
          }
        }
        IResult::Error(error)     => IResult::Error(error),
        IResult::Incomplete(need) => IResult::Incomplete(need),
      }
    }
  );
);

named!(stream_info <&[u8], BlockData>,
  chain!(
    min_block_size: be_u16 ~
    max_block_size: be_u16 ~
    min_frame_size: map!(take!(3), to_u32) ~
    max_frame_size: map!(take!(3), to_u32) ~
    bytes: take!(8) ~
    md5_sum: take!(16),
    || {
      let sample_rate     = ((bytes[0] as u32) << 12) +
                            ((bytes[1] as u32) << 4)  +
                            (bytes[2] as u32) >> 4;
      let channels        = (bytes[2] >> 1) & 0b0111;
      let bits_per_sample = ((bytes[2] & 0b01) << 4) +
                            bytes[3] >> 4;
      let total_samples   = (((bytes[3] as u64) & 0x0f) << 32) +
                            ((bytes[4] as u64) << 24) +
                            ((bytes[5] as u64) << 16) +
                            ((bytes[6] as u64) << 8) +
                            (bytes[7] as u64);

      BlockData::StreamInfo(StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: min_frame_size,
        max_frame_size: max_frame_size,
        sample_rate: sample_rate,
        channels: channels + 1,
        bits_per_sample: bits_per_sample + 1,
        total_samples: total_samples,
        md5_sum: md5_sum,
      })
    }
  )
);

fn padding(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, skip_bytes!(length), |_| BlockData::Padding(0))
}

fn application(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  chain!(input,
    id: take_str!(4) ~
    data: take!(length - 4),
    || {
      BlockData::Application(Application {
        id: id,
        data: data,
      })
    }
  )
}

named!(seek_point <&[u8], SeekPoint>,
  chain!(
    sample_number: be_u64 ~
    stream_offset: be_u64 ~
    frame_samples: be_u16,
    || {
      SeekPoint {
        sample_number: sample_number,
        stream_offset: stream_offset,
        frame_samples: frame_samples,
      }
    }
  )
);

fn seek_table(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  let seek_count = (length / 18) as usize;

  map!(input, count!(seek_point, seek_count), BlockData::SeekTable)
}

named!(vorbis_comment <&[u8], BlockData>,
  chain!(
    vendor_string_length: le_u32 ~
    vendor_string: take_str!(vendor_string_length)  ~
    number_of_comments: le_u32 ~
    comments: count!(comment_field, number_of_comments as usize),
    || {
      BlockData::VorbisComment(VorbisComment {
        vendor_string: vendor_string,
        comments: comments,
      })
    }
  )
);

named!(comment_field <&[u8], &str>,
  chain!(
    comment_length: le_u32 ~
    comment: take_str!(comment_length),
    || { comment }
  )
);

named!(cue_sheet <&[u8], BlockData>,
  chain!(
    media_catalog_number: take_str!(128) ~
    lead_in: be_u64 ~
    bytes: take!(259) ~ // TODO: last (7 + 258 * 8) bits must be 0
    num_tracks: be_u8 ~
    tracks: count!(cue_sheet_track, num_tracks as usize),
    || {
      let is_cd = ((bytes[0] >> 7) & 0b01) == 1;

      BlockData::CueSheet(CueSheet {
        media_catalog_number: media_catalog_number,
        lead_in: lead_in,
        is_cd: is_cd,
        tracks: tracks,
      })
    }
  )
);

named!(cue_sheet_track <&[u8], CueSheetTrack>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    isrc: take_str!(12) ~
    bytes: take!(14) ~ // TODO: last (6 + 13 * 8) bits must be 0
    num_indices: be_u8 ~
    indices: cond!(
      num_indices != 0,
      count!(cue_sheet_track_index, num_indices as usize)
    ),
    || {
      let isnt_audio      = ((bytes[0] >> 7) & 0b01) == 1;
      let is_pre_emphasis = ((bytes[0] >> 6) & 0b01) == 1;

      CueSheetTrack {
        offset: offset,
        number: number,
        isrc: isrc,
        isnt_audio: isnt_audio,
        is_pre_emphasis: is_pre_emphasis,
        indices: indices.unwrap_or(Vec::new()),
      }
    }
  )
);

named!(cue_sheet_track_index <&[u8], CueSheetTrackIndex>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    skip_bytes!(3),
    || {
      CueSheetTrackIndex {
        offset: offset,
        number: number,
      }
    }
  )
);

named!(picture <&[u8], BlockData>,
  chain!(
    picture_type_num: be_u32 ~
    mime_type_length:  be_u32 ~
    mime_type: take_str!(mime_type_length) ~
    description_length: be_u32 ~
    description: take_str!(description_length) ~
    width: be_u32 ~
    height: be_u32 ~
    depth: be_u32 ~
    colors: be_u32 ~
    data_length: be_u32 ~
    data: take!(data_length),
    || {
      let picture_type = match picture_type_num {
        0  => PictureType::Other,
        1  => PictureType::FileIconStandard,
        2  => PictureType::FileIcon,
        3  => PictureType::FrontCover,
        4  => PictureType::BackCover,
        5  => PictureType::LeafletPage,
        6  => PictureType::Media,
        7  => PictureType::LeadArtist,
        8  => PictureType::Artist,
        9  => PictureType::Conductor,
        10 => PictureType::Band,
        11 => PictureType::Composer,
        12 => PictureType::Lyricist,
        13 => PictureType::RecordingLocation,
        14 => PictureType::DuringRecording,
        15 => PictureType::DuringPerformace,
        16 => PictureType::VideoScreenCapture,
        17 => PictureType::Fish,
        18 => PictureType::Illustration,
        19 => PictureType::BandLogoType,
        20 => PictureType::PublisherLogoType,
        _  => PictureType::Other,
      };

      BlockData::Picture(Picture {
        picture_type: picture_type,
        mime_type: mime_type,
        description: description,
        width: width,
        height: height,
        depth: depth,
        colors: colors,
        data: data,
      })
    }
  )
);

// As of FLAC v1.3.1, there is support for up to 127 different metadata
// `Block`s but actually 7 that are implemented. When the `Block` type isn't
// recognised, this block gets skipped over with this parser.
fn unknown(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), BlockData::Unknown)
}

named!(header <&[u8], (u8, bool, u32)>,
  chain!(
    block_byte: be_u8 ~
    length: map!(take!(3), to_u32),
    || {
      let is_last    = (block_byte >> 7) == 1;
      let block_type = block_byte & 0b01111111;

      (block_type, is_last, length)
    }
  )
);

fn block_data(input: &[u8], block_type: u8, length: u32)
              -> IResult<&[u8], BlockData> {
  match block_type {
    0       => stream_info(input),
    1       => padding(input, length),
    2       => application(input, length),
    3       => seek_table(input, length),
    4       => vorbis_comment(input),
    5       => cue_sheet(input),
    6       => picture(input),
    7...126 => unknown(input, length),
    _       => IResult::Error(Err::Position(ErrorCode::Alt as u32, input)),
  }
}

named!(block <&[u8], Block>,
  chain!(
    block_header: header ~
    data: apply!(block_data, block_header.0, block_header.2),
    || {
      Block {
        is_last: block_header.1,
        length: block_header.2,
        data: data
      }
    }
  )
);

/// Parses one or more metadata `Block`s
///
/// The first block should always be `StreamInfo` since that is the only
/// required `Block`. At the moment `many_blocks` doesn't check that
/// requirement.
pub fn many_blocks(input: &[u8]) -> IResult<&[u8], Vec<Block>> {
  let mut is_last   = false;
  let mut blocks    = Vec::new();
  let mut start     = 0;
  let mut remaining = input.len();

  while !is_last {
    match block(&input[start..]) {
      IResult::Done(i, block) => {
        let result_len = i.len();

        if result_len == input[start..].len() {
          break;
        }

        start    += remaining - result_len;
        remaining = result_len;
        is_last   = block.is_last;

        blocks.push(block);
      }
      _                       => break,
    }
  }

  if blocks.len() == 0 {
    IResult::Error(Err::Position(ErrorCode::Many1 as u32, input))
  } else if is_last {
    IResult::Done(&input[start..], blocks)
  } else {
    IResult::Incomplete(Needed::Unknown)
  }
}
<|endoftext|>


<commit_before>use super::{Error};
use std::io::Write;
use std::io::Read;
use super::super::parse::ast::DataSrc;
use super::super::parse::ast::CompType;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

/// General enums in SQL
#[derive(Debug, Clone, Copy, RustcDecodable, RustcEncodable, PartialEq)]
pub enum SqlType {
    Int,
    Bool,
    Char(u8),
}

/// Defines the size of Sql data types
/// and returns them
impl SqlType {
    pub fn size(&self) -> u32 {
        match self {
            &SqlType::Int => 4 as u32,
            &SqlType::Bool => 1 as u32,
            &SqlType::Char(len) => (len + 1) as u32,
        }
    }

    /// Decodes the data in buf according to SqlType into a DataSrc enum.
    pub fn decode_from<R: Read>(&self, mut buf: &mut R) -> Result<DataSrc, Error> {
        match self {
            &SqlType::Int => {
                let i = try!(buf.read_i32::<BigEndian>());
                Ok(DataSrc::Int(i as i64))
            },
            &SqlType::Bool => {
                let b = try!(buf.read_u8());
                Ok(DataSrc::Bool(b))
            },
            &SqlType::Char(_) => {
                let mut s = String::new();
                try!(buf.read_to_string(&mut s));
                Ok(DataSrc::String(s))
            },
        }
    }

    /// Writes data to buf
    /// Returns the bytes written.
    /// Returns Error::InvalidType if type of DataSrc does not match expected
    /// type.
    /// Returns byteorder::Error, if data could not be written to buf.
    /// DataSrc: contains data to write to buf
    /// buf: target of write operation.
    pub fn encode_into<W: Write>(&self, mut buf: &mut W, data: &DataSrc)
    -> Result<u32, Error>
    {
        match self {
            &SqlType::Int => {
                match data {
                    &DataSrc::Int(a) => {
                        if a > i32::max_value() as i64 {
                            Err(Error::InvalidType)
                        }
                        else {
                            try!(buf.write_i32::<BigEndian>(a as i32));
                            Ok(self.size())
                        }
                    },
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
            &SqlType::Bool => {
                match data {
                    &DataSrc::Bool(a) => {
                        try!(buf.write_u8(a as u8));
                        Ok(self.size())
                    }
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
            &SqlType::Char(len) => {
                match data {
                    &DataSrc::String(ref a) => {
                        let str_as_bytes = Self::to_nul_terminated_bytes(&a, (len + 1) as u32);
                        try!(buf.write_all(&str_as_bytes));
                        Ok(self.size())
                    }
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
        }
    }
    /// Writes the vector vec to buf.
    /// Returns the bytes written.
    /// Returns byteorder::Error if vec could not be written to buf
    fn write_to_buf<W: Write>(mut buf: W, vec: &Vec<u8>) -> Result<u32, Error> {
        let mut it = vec.into_iter();
        let mut bytes_written = 0;

        loop {
            match it.next() {
                Some(v) => {
                    try!(buf.write_u8(*v));
                    bytes_written += 1;
                },
                None => break,
            }
        }
        Ok(bytes_written)
    }

    /// Convert s to a vector with l bytes.
    /// If length of s is > l, the returning vector will only contain the first
    /// l bytes.
    /// Otherwise the returned vector will be filled with \0
    /// until it contains l bytes.
    fn to_nul_terminated_bytes(s : &str, l: u32) -> Vec<u8> {
        let mut v = s.to_string().into_bytes();

        v.truncate((l - 1) as usize);

        while v.len() < l as usize {
            v.push(0x00);
        }
        v
    }

    pub fn cmp(&self, val: &[u8], val2: &[u8], comp: CompType)
    -> Result<bool, Error>
    {
        match self {
            &SqlType::Int => {
                match comp {
                    CompType::Equ => { self.compare_byte_for_equal(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },

            &SqlType::Bool => {
                match comp {
                    CompType::Equ => { self.compare_as_bool(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },

            &SqlType::Char(x) => {
                match comp {
                    CompType::Equ => { self.compare_byte_for_equal(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },
        }
    }

    fn compare_byte_for_equal(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] != val2[i] {
                return Ok(false)
            }
        }
        Ok(true)
    }

    fn compare_byte_greater_than(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] > val2[i] {
                return Ok(true)
            }
        }
        Ok(false)
    }

    fn compare_byte_lesser_than(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] < val2[i] {
                return Ok(true)
            }
        }
        Ok(false)
    }

    fn compare_as_bool(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        let mut sov: bool = false;
        let mut sov2: bool = false;
        for i in 0 .. val.len() {
            if val[i] != 0 {
                sov = true;
                break;
            }
        }

        for i in 0 .. val2.len() {
            if val2[i] != 0 {
                sov = true;
                break;
            }
        }

        if sov == sov2 {
            return Ok(true)
        }

        Ok(false)
    }
}

//---------------------------------------------------------------
// Column
//---------------------------------------------------------------

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, // name of column
    pub sql_type: SqlType, // name of the data type that is contained in this column
    pub is_primary_key: bool, // defines if column is PK
    pub allow_null: bool, // defines if cloumn allows null
    pub description: String //Displays text describing this column.
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn new(
        name: &str,
        sql_type: SqlType,
        allow_null: bool,
        description: &str,
        is_primary_key: bool
        ) -> Column {

        Column {
            name: name.to_string(),
            sql_type: sql_type.clone(),
            allow_null: allow_null,
            description: description.to_string(),
            is_primary_key: is_primary_key
        }
    }

    pub fn get_sql_type(&self) -> &SqlType {
        &self.sql_type
    }

    pub fn get_coulmn_name(&self) -> &str {
        &self.name
    }

    pub fn get_size(&self) -> u32 {
        self.sql_type.size() as u32
    }
}

//---------------------------------------------------------------
// FromSql
//---------------------------------------------------------------

pub trait FromSql {
    fn from_sql(data: &[u8]) -> Result<Self, Error>;
}

impl FromSql for i32 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let i = try!(data.read_i32::<BigEndian>());
        Ok(i)
    }
}

impl FromSql for u16 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let u = try!(data.read_u16::<BigEndian>());
        Ok(u)
    }
}

impl FromSql for u8 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        Err(Error::NoImplementation)
    }
}
impl FromSql for String {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {

        let mut s = String::new();

        try!(data.read_to_string(&mut s));
        //s.trim_matches('\0');
        Ok(s)
    }
}

impl FromSql for bool {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let b = try!(data.read_u8());
        if b == 0 {
            return Ok(false)
        }
        Ok(true)
    }
}
<commit_msg>Add Documentation<commit_after>use super::{Error};
use std::io::Write;
use std::io::Read;
use super::super::parse::ast::DataSrc;
use super::super::parse::ast::CompType;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

/// General enums in SQL
#[derive(Debug, Clone, Copy, RustcDecodable, RustcEncodable, PartialEq)]
pub enum SqlType {
    Int,
    Bool,
    Char(u8),
}

/// Defines the size of Sql data types
/// and returns them
impl SqlType {
    pub fn size(&self) -> u32 {
        match self {
            &SqlType::Int => 4 as u32,
            &SqlType::Bool => 1 as u32,
            &SqlType::Char(len) => (len + 1) as u32,
        }
    }

    /// Decodes the data in buf according to SqlType into a DataSrc enum.
    pub fn decode_from<R: Read>(&self, mut buf: &mut R) -> Result<DataSrc, Error> {
        match self {
            &SqlType::Int => {
                let i = try!(buf.read_i32::<BigEndian>());
                Ok(DataSrc::Int(i as i64))
            },
            &SqlType::Bool => {
                let b = try!(buf.read_u8());
                Ok(DataSrc::Bool(b))
            },
            &SqlType::Char(_) => {
                let mut s = String::new();
                try!(buf.read_to_string(&mut s));
                Ok(DataSrc::String(s))
            },
        }
    }

    /// Writes data to buf
    /// Returns the bytes written.
    /// Returns Error::InvalidType if type of DataSrc does not match expected
    /// type.
    /// Returns byteorder::Error, if data could not be written to buf.
    /// DataSrc: contains data to write to buf
    /// buf: target of write operation.
    pub fn encode_into<W: Write>(&self, mut buf: &mut W, data: &DataSrc)
    -> Result<u32, Error>
    {
        match self {
            &SqlType::Int => {
                match data {
                    &DataSrc::Int(a) => {
                        if a > i32::max_value() as i64 {
                            Err(Error::InvalidType)
                        }
                        else {
                            try!(buf.write_i32::<BigEndian>(a as i32));
                            Ok(self.size())
                        }
                    },
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
            &SqlType::Bool => {
                match data {
                    &DataSrc::Bool(a) => {
                        try!(buf.write_u8(a as u8));
                        Ok(self.size())
                    }
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
            &SqlType::Char(len) => {
                match data {
                    &DataSrc::String(ref a) => {
                        let str_as_bytes = Self::to_nul_terminated_bytes(&a, (len + 1) as u32);
                        try!(buf.write_all(&str_as_bytes));
                        Ok(self.size())
                    }
                    _=> {
                        Err(Error::InvalidType)
                    }
                }
            },
        }
    }
    /// Writes the vector vec to buf.
    /// Returns the bytes written.
    /// Returns byteorder::Error if vec could not be written to buf
    fn write_to_buf<W: Write>(mut buf: W, vec: &Vec<u8>) -> Result<u32, Error> {
        let mut it = vec.into_iter();
        let mut bytes_written = 0;

        loop {
            match it.next() {
                Some(v) => {
                    try!(buf.write_u8(*v));
                    bytes_written += 1;
                },
                None => break,
            }
        }
        Ok(bytes_written)
    }

    /// Convert s to a vector with l bytes.
    /// If length of s is > l, the returning vector will only contain the first
    /// l bytes.
    /// Otherwise the returned vector will be filled with \0
    /// until it contains l bytes.
    fn to_nul_terminated_bytes(s : &str, l: u32) -> Vec<u8> {
        let mut v = s.to_string().into_bytes();

        v.truncate((l - 1) as usize);

        while v.len() < l as usize {
            v.push(0x00);
        }
        v
    }
    /// compare function that lets you logical compare slices of u8
    /// returns a boolean on success and Error on fail
    /// uses other compare fn for the actual compare
    pub fn cmp(&self, val: &[u8], val2: &[u8], comp: CompType)
    -> Result<bool, Error>
    {
        match self {
            &SqlType::Int => {
                match comp {
                    CompType::Equ => { self.compare_byte_for_equal(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },

            &SqlType::Bool => {
                match comp {
                    CompType::Equ => { self.compare_as_bool(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },

            &SqlType::Char(x) => {
                match comp {
                    CompType::Equ => { self.compare_byte_for_equal(val, val2) },
                    CompType::NEqu => { self.compare_byte_for_equal(val, val2).map(|x| !x) },
                    CompType::GThan => { self.compare_byte_greater_than(val, val2) },
                    CompType::SThan => { self.compare_byte_lesser_than(val, val2) },
                    CompType::GEThan => { self.compare_byte_lesser_than(val, val2).map(|x| !x) },
                    CompType::SEThan => { self.compare_byte_greater_than(val, val2).map(|x| !x) },
                }
            },
        }
    }
    /// fn compares slices of u8 byte for byte and returns if both values are equal
    /// returns boolean on success and Error when given values do not have the same size
    fn compare_byte_for_equal(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] != val2[i] {
                return Ok(false)
            }
        }
        Ok(true)
    }
    /// fn compares slices of u8 byte for byte and returns
    /// if first given value is greater than the second one
    /// returns boolean on success and Error when given values do not have the same size
    fn compare_byte_greater_than(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] > val2[i] {
                return Ok(true)
            }
        }
        Ok(false)
    }

    /// fn compares slices of u8 byte for byte and returns
    /// if first given value is lesser than the second one
    /// returns boolean on success and Error when given values do not have the same size
    fn compare_byte_lesser_than(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        if val.len() != val2.len() {
            return Err(Error::WrongLength)
        }
        for i in 0 .. val.len() {
            if val[i] < val2[i] {
                return Ok(true)
            }
        }
        Ok(false)
    }

    /// fn compares slices of u8 as booleans and returns
    /// if both both booleans are true
    /// returns boolean on success and Error when given values do not have the same size
    fn compare_as_bool(&self, val: &[u8], val2: &[u8])
    -> Result<bool, Error>
    {
        let mut sov: bool = false;
        let mut sov2: bool = false;
        for i in 0 .. val.len() {
            if val[i] != 0 {
                sov = true;
                break;
            }
        }

        for i in 0 .. val2.len() {
            if val2[i] != 0 {
                sov = true;
                break;
            }
        }

        if sov == sov2 {
            return Ok(true)
        }

        Ok(false)
    }
}

//---------------------------------------------------------------
// Column
//---------------------------------------------------------------

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, // name of column
    pub sql_type: SqlType, // name of the data type that is contained in this column
    pub is_primary_key: bool, // defines if column is PK
    pub allow_null: bool, // defines if cloumn allows null
    pub description: String //Displays text describing this column.
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn new(
        name: &str,
        sql_type: SqlType,
        allow_null: bool,
        description: &str,
        is_primary_key: bool
        ) -> Column {

        Column {
            name: name.to_string(),
            sql_type: sql_type.clone(),
            allow_null: allow_null,
            description: description.to_string(),
            is_primary_key: is_primary_key
        }
    }

    pub fn get_sql_type(&self) -> &SqlType {
        &self.sql_type
    }

    pub fn get_coulmn_name(&self) -> &str {
        &self.name
    }

    pub fn get_size(&self) -> u32 {
        self.sql_type.size() as u32
    }
}

//---------------------------------------------------------------
// FromSql
//---------------------------------------------------------------

pub trait FromSql {
    fn from_sql(data: &[u8]) -> Result<Self, Error>;
}

impl FromSql for i32 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let i = try!(data.read_i32::<BigEndian>());
        Ok(i)
    }
}

impl FromSql for u16 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let u = try!(data.read_u16::<BigEndian>());
        Ok(u)
    }
}

impl FromSql for u8 {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        Err(Error::NoImplementation)
    }
}
impl FromSql for String {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {

        let mut s = String::new();

        try!(data.read_to_string(&mut s));
        //s.trim_matches('\0');
        Ok(s)
    }
}

impl FromSql for bool {
    fn from_sql(mut data: &[u8]) -> Result<Self, Error> {
        let b = try!(data.read_u8());
        if b == 0 {
            return Ok(false)
        }
        Ok(true)
    }
}
<|endoftext|>


<commit_before>use Display;

use gl;
use GlObject;
use context::GlVersion;

use libc;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::mpsc::channel;

pub struct TextureImplementation {
    display: Display,
    id: gl::types::GLuint,
    bind_point: gl::types::GLenum,
    width: u32,
    height: Option<u32>,
    depth: Option<u32>,
    array_size: Option<u32>,
}

impl TextureImplementation {
    /// Builds a new texture.
    pub fn new<P>(display: &Display, format: gl::types::GLenum, data: Option<Vec<P>>,
        client_format: gl::types::GLenum, client_type: gl::types::GLenum, width: u32,
        height: Option<u32>, depth: Option<u32>, array_size: Option<u32>) -> TextureImplementation
        where P: Send
    {
        use std::num::Float;

        if let Some(ref data) = data {
            if width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 2 != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 3 != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 4 != data.len()
            {
                panic!("Texture data size mismatch");
            }
        }

        let texture_type = if height.is_none() && depth.is_none() {
            if array_size.is_none() { gl::TEXTURE_1D } else { gl::TEXTURE_1D_ARRAY }
        } else if depth.is_none() {
            if array_size.is_none() { gl::TEXTURE_2D } else { gl::TEXTURE_2D_ARRAY }
        } else {
            gl::TEXTURE_3D
        };

        let texture_levels = 1 + (::std::cmp::max(width, ::std::cmp::max(height.unwrap_or(1),
                                 depth.unwrap_or(1))) as f32).log2() as gl::types::GLsizei;

        let (tx, rx) = channel();
        display.context.context.exec(move |: ctxt| {
            unsafe {
                let data = data;
                let data_raw = if let Some(ref data) = data {
                    data.as_ptr() as *const libc::c_void
                } else {
                    ptr::null()
                };

                ctxt.gl.PixelStorei(gl::UNPACK_ALIGNMENT, 1);

                if ctxt.state.pixel_unpack_buffer_binding != 0 {
                    ctxt.state.pixel_unpack_buffer_binding = 0;
                    ctxt.gl.BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
                }

                let id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenTextures(1, mem::transmute(&id));

                ctxt.gl.BindTexture(texture_type, id);

                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
                if height.is_some() || depth.is_some() || array_size.is_some() {
                    ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
                }
                if depth.is_some() || array_size.is_some() {
                    ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_R, gl::REPEAT as i32);
                }
                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_MIN_FILTER,
                    gl::LINEAR_MIPMAP_LINEAR as i32);

                if texture_type == gl::TEXTURE_3D || texture_type == gl::TEXTURE_2D_ARRAY {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage3D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei,
                                             height.unwrap() as gl::types::GLsizei,
                                             depth.unwrap() as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage3D(texture_type, 0, 0, 0, 0,
                                                  width as gl::types::GLsizei,
                                                  height.unwrap() as gl::types::GLsizei,
                                                  depth.unwrap() as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage3D(texture_type, 0, format as i32, width as i32,
                                           height.unwrap() as i32,
                                           if let Some(d) = depth { d } else {
                                               array_size.unwrap_or(1)
                                           } as i32, 0,
                                           client_format as u32, client_type, data_raw);
                    }

                } else if texture_type == gl::TEXTURE_2D || texture_type == gl::TEXTURE_1D_ARRAY {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage2D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei,
                                             height.unwrap() as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage2D(texture_type, 0, 0, 0, width as gl::types::GLsizei,
                                                  height.unwrap() as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage2D(texture_type, 0, format as i32, width as i32,
                                           height.unwrap() as i32, 0, client_format as u32,
                                           client_type, data_raw);
                    }

                } else {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage1D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage1D(texture_type, 0, 0, width as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage1D(texture_type, 0, format as i32, width as i32, 0,
                                           client_format as u32, client_type, data_raw);
                    }
                }

                if ctxt.version >= &GlVersion(3, 0) {
                    ctxt.gl.GenerateMipmap(texture_type);
                } else {
                    ctxt.gl.GenerateMipmapEXT(texture_type);
                }

                tx.send(id).unwrap();
            }
        });

        TextureImplementation {
            display: display.clone(),
            id: rx.recv().unwrap(),
            bind_point: texture_type,
            width: width,
            height: height,
            depth: depth,
            array_size: array_size,
        }
    }

    /// Reads the content of a mipmap level of the texture.
    // TODO: this function only works for level 0 right now
    //       width/height need adjustements
    #[cfg(feature = "gl_extensions")]
    pub fn read<P>(&self, level: u32) -> Vec<P> where P: PixelValue {
        assert_eq!(level, 0);   // TODO:

        let pixels_count = (self.width * self.height.unwrap_or(1) * self.depth.unwrap_or(1))
                            as uint;

        // FIXME: WRONG
        let (format, gltype) = PixelValue::get_format(None::<P>).to_gl_enum();
        let my_id = self.id;

        let (tx, rx) = channel();
        self.display.context.context.exec(move |: ctxt| {
            unsafe {
                let mut data: Vec<P> = Vec::with_capacity(pixels_count);

                ctxt.gl.PixelStorei(gl::PACK_ALIGNMENT, 1);

                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.GetTextureImage(my_id, level as gl::types::GLint, format, gltype,
                        (pixels_count * mem::size_of::<P>()) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else if ctxt.extensions.gl_ext_direct_state_access {
                    ctxt.gl.GetTextureImageEXT(my_id, gl::TEXTURE_2D, level as gl::types::GLint,
                        format, gltype, data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    ctxt.gl.BindTexture(gl::TEXTURE_2D, my_id);
                    ctxt.gl.GetTexImage(gl::TEXTURE_2D, level as gl::types::GLint, format, gltype,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                data.set_len(pixels_count);
                tx.send(data);
            }
        });

        rx.recv().unwrap()
    }

    /// Returns the `Display` associated to this texture.
    pub fn get_display(&self) -> &Display {
        &self.display
    }

    /// Returns the width of the texture.
    pub fn get_width(&self) -> u32 {
        self.width
    }

    /// Returns the height of the texture.
    pub fn get_height(&self) -> Option<u32> {
        self.height.clone()
    }

    /// Returns the depth of the texture.
    pub fn get_depth(&self) -> Option<u32> {
        self.depth.clone()
    }

    /// Returns the size of array of the texture.
    pub fn get_array_size(&self) -> Option<u32> {
        self.array_size.clone()
    }
}

impl GlObject for TextureImplementation {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

impl fmt::Show for TextureImplementation {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Texture #{} (dimensions: {}x{}x{})", self.id,
            self.width, self.height, self.depth)).fmt(formatter)
    }
}

impl Drop for TextureImplementation {
    fn drop(&mut self) {
        use fbo;

        // removing FBOs which contain this texture
        {
            let mut fbos = self.display.context.framebuffer_objects.lock().unwrap();

            let to_delete = fbos.keys().filter(|b| {
                b.colors.iter().find(|&&(_, id)| id == fbo::Attachment::Texture(self.id)).is_some() ||
                b.depth == Some(fbo::Attachment::Texture(self.id)) || b.stencil == Some(fbo::Attachment::Texture(self.id))
            }).map(|k| k.clone()).collect::<Vec<_>>();

            for k in to_delete.into_iter() {
                fbos.remove(&k);
            }
        }

        let id = self.id.clone();
        self.display.context.context.exec(move |: ctxt| {
            unsafe { ctxt.gl.DeleteTextures(1, [ id ].as_ptr()); }
        });
    }
}
<commit_msg>Fix compilation with all features enabled<commit_after>use Display;

use gl;
use GlObject;
use context::GlVersion;

use texture::PixelValue;

use libc;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::mpsc::channel;

pub struct TextureImplementation {
    display: Display,
    id: gl::types::GLuint,
    bind_point: gl::types::GLenum,
    width: u32,
    height: Option<u32>,
    depth: Option<u32>,
    array_size: Option<u32>,
}

impl TextureImplementation {
    /// Builds a new texture.
    pub fn new<P>(display: &Display, format: gl::types::GLenum, data: Option<Vec<P>>,
        client_format: gl::types::GLenum, client_type: gl::types::GLenum, width: u32,
        height: Option<u32>, depth: Option<u32>, array_size: Option<u32>) -> TextureImplementation
        where P: Send
    {
        use std::num::Float;

        if let Some(ref data) = data {
            if width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 2 != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 3 != data.len() &&
               width as uint * height.unwrap_or(1) as uint * depth.unwrap_or(1) as uint *
                array_size.unwrap_or(1) as uint * 4 != data.len()
            {
                panic!("Texture data size mismatch");
            }
        }

        let texture_type = if height.is_none() && depth.is_none() {
            if array_size.is_none() { gl::TEXTURE_1D } else { gl::TEXTURE_1D_ARRAY }
        } else if depth.is_none() {
            if array_size.is_none() { gl::TEXTURE_2D } else { gl::TEXTURE_2D_ARRAY }
        } else {
            gl::TEXTURE_3D
        };

        let texture_levels = 1 + (::std::cmp::max(width, ::std::cmp::max(height.unwrap_or(1),
                                 depth.unwrap_or(1))) as f32).log2() as gl::types::GLsizei;

        let (tx, rx) = channel();
        display.context.context.exec(move |: ctxt| {
            unsafe {
                let data = data;
                let data_raw = if let Some(ref data) = data {
                    data.as_ptr() as *const libc::c_void
                } else {
                    ptr::null()
                };

                ctxt.gl.PixelStorei(gl::UNPACK_ALIGNMENT, 1);

                if ctxt.state.pixel_unpack_buffer_binding != 0 {
                    ctxt.state.pixel_unpack_buffer_binding = 0;
                    ctxt.gl.BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
                }

                let id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenTextures(1, mem::transmute(&id));

                ctxt.gl.BindTexture(texture_type, id);

                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
                if height.is_some() || depth.is_some() || array_size.is_some() {
                    ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
                }
                if depth.is_some() || array_size.is_some() {
                    ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_WRAP_R, gl::REPEAT as i32);
                }
                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
                ctxt.gl.TexParameteri(texture_type, gl::TEXTURE_MIN_FILTER,
                    gl::LINEAR_MIPMAP_LINEAR as i32);

                if texture_type == gl::TEXTURE_3D || texture_type == gl::TEXTURE_2D_ARRAY {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage3D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei,
                                             height.unwrap() as gl::types::GLsizei,
                                             depth.unwrap() as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage3D(texture_type, 0, 0, 0, 0,
                                                  width as gl::types::GLsizei,
                                                  height.unwrap() as gl::types::GLsizei,
                                                  depth.unwrap() as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage3D(texture_type, 0, format as i32, width as i32,
                                           height.unwrap() as i32,
                                           if let Some(d) = depth { d } else {
                                               array_size.unwrap_or(1)
                                           } as i32, 0,
                                           client_format as u32, client_type, data_raw);
                    }

                } else if texture_type == gl::TEXTURE_2D || texture_type == gl::TEXTURE_1D_ARRAY {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage2D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei,
                                             height.unwrap() as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage2D(texture_type, 0, 0, 0, width as gl::types::GLsizei,
                                                  height.unwrap() as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage2D(texture_type, 0, format as i32, width as i32,
                                           height.unwrap() as i32, 0, client_format as u32,
                                           client_type, data_raw);
                    }

                } else {
                    if ctxt.version >= &GlVersion(4, 2) || ctxt.extensions.gl_arb_texture_storage {
                        ctxt.gl.TexStorage1D(texture_type, texture_levels,
                                             format as gl::types::GLenum,
                                             width as gl::types::GLsizei);

                        if !data_raw.is_null() {
                            ctxt.gl.TexSubImage1D(texture_type, 0, 0, width as gl::types::GLsizei,
                                                  client_format, client_type, data_raw);
                        }

                    } else {
                        ctxt.gl.TexImage1D(texture_type, 0, format as i32, width as i32, 0,
                                           client_format as u32, client_type, data_raw);
                    }
                }

                if ctxt.version >= &GlVersion(3, 0) {
                    ctxt.gl.GenerateMipmap(texture_type);
                } else {
                    ctxt.gl.GenerateMipmapEXT(texture_type);
                }

                tx.send(id).unwrap();
            }
        });

        TextureImplementation {
            display: display.clone(),
            id: rx.recv().unwrap(),
            bind_point: texture_type,
            width: width,
            height: height,
            depth: depth,
            array_size: array_size,
        }
    }

    /// Reads the content of a mipmap level of the texture.
    // TODO: this function only works for level 0 right now
    //       width/height need adjustements
    #[cfg(feature = "gl_extensions")]
    pub fn read<P>(&self, level: u32) -> Vec<P> where P: PixelValue {
        assert_eq!(level, 0);   // TODO:

        let pixels_count = (self.width * self.height.unwrap_or(1) * self.depth.unwrap_or(1))
                            as uint;

        // FIXME: WRONG
        let (format, gltype) = PixelValue::get_format(None::<P>).to_gl_enum();
        let my_id = self.id;

        let (tx, rx) = channel();
        self.display.context.context.exec(move |: ctxt| {
            unsafe {
                let mut data: Vec<P> = Vec::with_capacity(pixels_count);

                ctxt.gl.PixelStorei(gl::PACK_ALIGNMENT, 1);

                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.GetTextureImage(my_id, level as gl::types::GLint, format, gltype,
                        (pixels_count * mem::size_of::<P>()) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else if ctxt.extensions.gl_ext_direct_state_access {
                    ctxt.gl.GetTextureImageEXT(my_id, gl::TEXTURE_2D, level as gl::types::GLint,
                        format, gltype, data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    ctxt.gl.BindTexture(gl::TEXTURE_2D, my_id);
                    ctxt.gl.GetTexImage(gl::TEXTURE_2D, level as gl::types::GLint, format, gltype,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                data.set_len(pixels_count);
                tx.send(data).unwrap();
            }
        });

        rx.recv().unwrap()
    }

    /// Returns the `Display` associated to this texture.
    pub fn get_display(&self) -> &Display {
        &self.display
    }

    /// Returns the width of the texture.
    pub fn get_width(&self) -> u32 {
        self.width
    }

    /// Returns the height of the texture.
    pub fn get_height(&self) -> Option<u32> {
        self.height.clone()
    }

    /// Returns the depth of the texture.
    pub fn get_depth(&self) -> Option<u32> {
        self.depth.clone()
    }

    /// Returns the size of array of the texture.
    pub fn get_array_size(&self) -> Option<u32> {
        self.array_size.clone()
    }
}

impl GlObject for TextureImplementation {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

impl fmt::Show for TextureImplementation {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Texture #{} (dimensions: {}x{}x{})", self.id,
            self.width, self.height, self.depth)).fmt(formatter)
    }
}

impl Drop for TextureImplementation {
    fn drop(&mut self) {
        use fbo;

        // removing FBOs which contain this texture
        {
            let mut fbos = self.display.context.framebuffer_objects.lock().unwrap();

            let to_delete = fbos.keys().filter(|b| {
                b.colors.iter().find(|&&(_, id)| id == fbo::Attachment::Texture(self.id)).is_some() ||
                b.depth == Some(fbo::Attachment::Texture(self.id)) || b.stencil == Some(fbo::Attachment::Texture(self.id))
            }).map(|k| k.clone()).collect::<Vec<_>>();

            for k in to_delete.into_iter() {
                fbos.remove(&k);
            }
        }

        let id = self.id.clone();
        self.display.context.context.exec(move |: ctxt| {
            unsafe { ctxt.gl.DeleteTextures(1, [ id ].as_ptr()); }
        });
    }
}
<|endoftext|>