<commit_before>// Copyright 2013-2015, 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>

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use glib_ffi::{self, gboolean, gpointer};
use translate::ToGlib;

pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

struct CallbackGuard;

impl Drop for CallbackGuard {
    fn drop(&mut self) {
        if thread::panicking() {
            process::exit(101);
        }
    }
}

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    let _guard = CallbackGuard;
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    let _guard = CallbackGuard;
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            transmute(trampoline), into_raw(func), Some(destroy_closure))
    }
}
<commit_msg>Document Continue and idle/timeout_add, export CallbackGuard<commit_after>// Copyright 2013-2015, 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>

//! Basic bits of `GSource` bindings.

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use glib_ffi::{self, gboolean, gpointer};
use translate::ToGlib;

/// Continue calling the closure in the future iterations or drop it.
///
/// This is the return type of `idle_add` and `timeout_add` closures.
///
/// `Continue(true)` keeps the closure assigned, to be rerun when appropriate.
///
/// `Continue(false)` disconnects and drops it.
pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

/// Unwinding propagation guard. Aborts the process if destroyed while
/// panicking.
pub struct CallbackGuard;

impl Drop for CallbackGuard {
    fn drop(&mut self) {
        if thread::panicking() {
            process::exit(101);
        }
    }
}

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    let _guard = CallbackGuard;
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    let _guard = CallbackGuard;
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn idle_add<F>(func: F) -> u32
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add<F>(interval: u32, func: F) -> u32
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            transmute(trampoline), into_raw(func), Some(destroy_closure))
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::collections::HashMap;

use uuid::Uuid;

use graphics::{ self, Graphics, ImageSize };
use graphics::math::{ Scalar, Matrix2d, Vec2d };

/// A sprite is a texture with some properties.
pub struct Sprite<I: ImageSize> {
    id: Uuid,

    visible: bool,

    anchor: Vec2d,

    position: Vec2d,
    rotation: Scalar,
    scale: Vec2d,
    color: [f32;3],

    flip_x: bool,
    flip_y: bool,

    opacity: f32,

    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,

    texture: Rc<I>,
}

impl<I: ImageSize> Sprite<I> {
    /// Crate sprite from a texture
    pub fn from_texture(texture: Rc<I>) -> Sprite<I> {
        Sprite {
            id: Uuid::new_v4(),

            visible: true,

            anchor: [0.5, 0.5],

            position: [0.0, 0.0],
            rotation: 0.0,
            scale: [1.0, 1.0],
            color: [1.0,1.0,1.0],

            flip_x: false,
            flip_y: false,

            opacity: 1.0,

            texture: texture,

            children: Vec::new(),
            children_index: HashMap::new(),
        }
    }

    /// Get the sprite's id
    #[inline(always)]
    pub fn id(&self) -> Uuid {
        self.id.clone()
    }

    /// Whether or not the sprite is visible
    pub fn get_visible(&self) -> bool {
        self.visible
    }

    /// Set the sprite's visibility
    pub fn set_visible(&mut self, visible: bool) {
        self.visible = visible;
    }

    /// Get the sprite's anchor point
    ///
    /// The value is normalized. Default value is [0.5, 0.5] (the center of texture)
    #[inline(always)]
    pub fn get_anchor(&self) -> (Scalar, Scalar) {
        (self.anchor[0], self.anchor[1])
    }

    /// Set the sprite's anchor point
    #[inline(always)]
    pub fn set_anchor(&mut self, x: Scalar, y: Scalar) {
        self.anchor = [x, y];
    }

    /// Get the sprite's position
    #[inline(always)]
    pub fn get_position(&self) -> (Scalar, Scalar) {
        (self.position[0], self.position[1])
    }

    /// Set the sprite's position
    #[inline(always)]
    pub fn set_position(&mut self, x: Scalar, y: Scalar) {
        self.position = [x, y];
    }

    /// Set the sprite's draw color (tint)
    #[inline(always)]
    pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
        self.color = [r, g, b];
    }

    /// get the sprite's color.s
    #[inline(always)]
    pub fn get_color(&self) -> (f32, f32, f32) {
        (self.color[0], self.color[1], self.color[2])
    }

    /// Get the sprite's rotation (in degree)
    #[inline(always)]
    pub fn get_rotation(&self) -> Scalar {
        self.rotation
    }

    /// Set the sprite's rotation (in degree)
    #[inline(always)]
    pub fn set_rotation(&mut self, deg: Scalar) {
        self.rotation = deg;
    }

    /// Get the sprite's scale
    #[inline(always)]
    pub fn get_scale(&self) -> (Scalar, Scalar) {
        (self.scale[0], self.scale[1])
    }

    /// Set the sprite's scale
    #[inline(always)]
    pub fn set_scale(&mut self, sx: Scalar, sy: Scalar) {
        self.scale = [sx, sy];
    }

    /// Whether or not the sprite is flipped horizontally.
    ///
    /// It only flips the texture of the sprite,
    /// and not the texture of the sprite’s children.
    ///
    /// Also, flipping the texture doesn’t alter the `anchor`.
    ///
    /// If you want to flip the `anchor` too,
    /// and/or to flip the children too use: sprite.scale.x *= -1;
    #[inline(always)]
    pub fn get_flip_x(&self) -> bool {
        self.flip_x
    }

    /// Flip the sprite
    #[inline(always)]
    pub fn set_flip_x(&mut self, flip_x: bool) {
        self.flip_x = flip_x;
    }

    /// Whether or not the sprite is flipped vertically.
    ///
    /// It only flips the texture of the sprite,
    /// and not the texture of the sprite’s children.
    ///
    /// Also, flipping the texture doesn’t alter the `anchor`.
    ///
    /// If you want to flip the `anchor` too,
    /// and/or to flip the children too use: sprite.scale.y *= -1;
    #[inline(always)]
    pub fn get_flip_y(&self) -> bool {
        self.flip_y
    }

    /// Flip the sprite
    #[inline(always)]
    pub fn set_flip_y(&mut self, flip_y: bool) {
        self.flip_y = flip_y;
    }

    /// Get the sprite's opacity
    #[inline(always)]
    pub fn get_opacity(&self) -> f32 {
        self.opacity
    }

    /// Set the sprite's opacity
    #[inline(always)]
    pub fn set_opacity(&mut self, opacity: f32) {
        self.opacity = opacity;
    }

    /// Get the sprite's texture
    #[inline(always)]
    pub fn get_texture(&self) -> &Rc<I> {
        &self.texture
    }

    /// Set the sprite's texture
    #[inline(always)]
    pub fn set_texture(&mut self, texture: Rc<I>) {
        self.texture = texture;
    }

    /// Add a sprite as the child of this sprite, return the added sprite's id.
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    /// Remove the child by `id` from this sprite's children or grandchild
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in &mut self.children {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in &self.children {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in &mut self.children {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Get the sprite's children
    #[inline(always)]
    pub fn children(&self) -> &Vec<Sprite<I>> {
        &self.children
    }

    /// Draw this sprite and its children
    pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        use graphics::*;

        if !self.visible {
            return;
        }

        let (w, h) = self.texture.get_size();
        let w = w as f64;
        let h = h as f64;
        let anchor = [self.anchor[0] * w, self.anchor[1] * h];

        let transformed = t.trans(self.position[0], self.position[1])
                           .rot_deg(self.rotation)
                           .scale(self.scale[0], self.scale[1]);

        let mut model = transformed;

        if self.flip_x {
            model = model.trans(w - 2.0 * anchor[0], 0.0).flip_h();
        }

        if self.flip_y {
            model = model.trans(0.0, h - 2.0 * anchor[1]).flip_v();
        }

        let ref draw_state: graphics::DrawState = Default::default();

        // for debug: bounding_box
        //model.rgb(1.0, 0.0, 0.0).draw(b);

        graphics::Image::new()
            .color([self.color[0], self.color[1], self.color[2], self.opacity])
            .rect([-anchor[0], -anchor[1], w, h])
            .draw(&*self.texture, draw_state, model, b);

        // for debug: anchor point
        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);

        for child in &self.children {
            child.draw(transformed, b);
        }
    }

    /// Draw this sprite and its children with color
    pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
        use graphics::*;

        if !self.visible {
            return;
        }

        let (w, h) = self.texture.get_size();
        let w = w as f64;
        let h = h as f64;
        let anchor = [self.anchor[0] * w, self.anchor[1] * h];

        let transformed = t.trans(self.position[0], self.position[1])
                           .rot_deg(self.rotation)
                           .scale(self.scale[0], self.scale[1]);

        let mut model = transformed;

        if self.flip_x {
            model = model.trans(w - 2.0 * anchor[0], 0.0).flip_h();
        }

        if self.flip_y {
            model = model.trans(0.0, h - 2.0 * anchor[1]).flip_v();
        }

        let ref draw_state: graphics::DrawState = Default::default();

        // for debug: bounding_box
        //model.rgb(1.0, 0.0, 0.0).draw(b);

        graphics::Image::new()
            .color([c[0], c[1], c[2], self.opacity])
            .rect([-anchor[0], -anchor[1], w, h])
            .draw(&*self.texture, draw_state, model, b);

        // for debug: anchor point
        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);

        for child in &self.children {
            child.draw_tinted(transformed, b, c);
        }
    }

    /// Get the sprite's bounding box
    pub fn bounding_box(&self) -> graphics::types::Rectangle {
        let (w, h) = self.texture.get_size();
        let w = w as f64 * self.scale[0];
        let h = h as f64 * self.scale[1];

        [
            self.position[0] - self.anchor[0] * w,
            self.position[1] - self.anchor[1] * h,
            w,
            h
        ]
    }
}
<commit_msg>Added `fn from_texture_rect` to accomodate sprite creation from a SourceRectangle<commit_after>use std::rc::Rc;
use std::collections::HashMap;

use uuid::Uuid;

use graphics::{ self, Graphics, ImageSize };
use graphics::math::{ Scalar, Matrix2d, Vec2d };
use graphics::types::SourceRectangle;

/// A sprite is a texture with some properties.
pub struct Sprite<I: ImageSize> {
    id: Uuid,

    visible: bool,

    anchor: Vec2d,

    position: Vec2d,
    rotation: Scalar,
    scale: Vec2d,
    color: [f32;3],

    flip_x: bool,
    flip_y: bool,

    opacity: f32,

    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,

    src_rect: Option<SourceRectangle>,
    texture: Rc<I>,
}

impl<I: ImageSize> Sprite<I> {
    /// Crate sprite from a texture
    pub fn from_texture(texture: Rc<I>) -> Sprite<I> {
        Sprite {
            id: Uuid::new_v4(),

            visible: true,

            anchor: [0.5, 0.5],

            position: [0.0, 0.0],
            rotation: 0.0,
            scale: [1.0, 1.0],
            color: [1.0,1.0,1.0],

            flip_x: false,
            flip_y: false,

            opacity: 1.0,

            texture: texture,
            src_rect: None,

            children: Vec::new(),
            children_index: HashMap::new(),
        }
    }

    /// Create sprite from a rectangle selection of a texture
    pub fn from_texture_rect(texture: Rc<I>, src_rect: SourceRectangle) -> Sprite<I> {
        Sprite {
            id: Uuid::new_v4(),

            visible: true,

            anchor: [0.5, 0.5],

            position: [0.0, 0.0],
            rotation: 0.0,
            scale: [1.0, 1.0],
            color: [1.0,1.0,1.0],

            flip_x: false,
            flip_y: false,

            opacity: 1.0,

            texture: texture,
            src_rect: From::from(src_rect),

            children: Vec::new(),
            children_index: HashMap::new(),
        }
    }

    /// Get the sprite's id
    #[inline(always)]
    pub fn id(&self) -> Uuid {
        self.id.clone()
    }

    /// Whether or not the sprite is visible
    pub fn get_visible(&self) -> bool {
        self.visible
    }

    /// Set the sprite's visibility
    pub fn set_visible(&mut self, visible: bool) {
        self.visible = visible;
    }

    /// Get the sprite's anchor point
    ///
    /// The value is normalized. Default value is [0.5, 0.5] (the center of texture)
    #[inline(always)]
    pub fn get_anchor(&self) -> (Scalar, Scalar) {
        (self.anchor[0], self.anchor[1])
    }

    /// Set the sprite's anchor point
    #[inline(always)]
    pub fn set_anchor(&mut self, x: Scalar, y: Scalar) {
        self.anchor = [x, y];
    }

    /// Get the sprite's position
    #[inline(always)]
    pub fn get_position(&self) -> (Scalar, Scalar) {
        (self.position[0], self.position[1])
    }

    /// Set the sprite's position
    #[inline(always)]
    pub fn set_position(&mut self, x: Scalar, y: Scalar) {
        self.position = [x, y];
    }

    /// Set the sprite's draw color (tint)
    #[inline(always)]
    pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
        self.color = [r, g, b];
    }

    /// get the sprite's color.s
    #[inline(always)]
    pub fn get_color(&self) -> (f32, f32, f32) {
        (self.color[0], self.color[1], self.color[2])
    }

    /// Get the sprite's rotation (in degree)
    #[inline(always)]
    pub fn get_rotation(&self) -> Scalar {
        self.rotation
    }

    /// Set the sprite's rotation (in degree)
    #[inline(always)]
    pub fn set_rotation(&mut self, deg: Scalar) {
        self.rotation = deg;
    }

    /// Get the sprite's scale
    #[inline(always)]
    pub fn get_scale(&self) -> (Scalar, Scalar) {
        (self.scale[0], self.scale[1])
    }

    /// Set the sprite's scale
    #[inline(always)]
    pub fn set_scale(&mut self, sx: Scalar, sy: Scalar) {
        self.scale = [sx, sy];
    }

    /// Whether or not the sprite is flipped horizontally.
    ///
    /// It only flips the texture of the sprite,
    /// and not the texture of the sprite’s children.
    ///
    /// Also, flipping the texture doesn’t alter the `anchor`.
    ///
    /// If you want to flip the `anchor` too,
    /// and/or to flip the children too use: sprite.scale.x *= -1;
    #[inline(always)]
    pub fn get_flip_x(&self) -> bool {
        self.flip_x
    }

    /// Flip the sprite
    #[inline(always)]
    pub fn set_flip_x(&mut self, flip_x: bool) {
        self.flip_x = flip_x;
    }

    /// Whether or not the sprite is flipped vertically.
    ///
    /// It only flips the texture of the sprite,
    /// and not the texture of the sprite’s children.
    ///
    /// Also, flipping the texture doesn’t alter the `anchor`.
    ///
    /// If you want to flip the `anchor` too,
    /// and/or to flip the children too use: sprite.scale.y *= -1;
    #[inline(always)]
    pub fn get_flip_y(&self) -> bool {
        self.flip_y
    }

    /// Flip the sprite
    #[inline(always)]
    pub fn set_flip_y(&mut self, flip_y: bool) {
        self.flip_y = flip_y;
    }

    /// Get the sprite's opacity
    #[inline(always)]
    pub fn get_opacity(&self) -> f32 {
        self.opacity
    }

    /// Set the sprite's opacity
    #[inline(always)]
    pub fn set_opacity(&mut self, opacity: f32) {
        self.opacity = opacity;
    }

    /// Get the sprite's source rectangle
    #[inline(always)]
    pub fn get_src_rect(&self) -> Option<SourceRectangle> {
        self.src_rect
    }

    /// Set the sprite's source rectangle
    #[inline(always)]
    pub fn set_src_rect(&mut self, src_rect: SourceRectangle) {
        self.src_rect = From::from(src_rect);
    }

    /// Get the sprite's texture
    #[inline(always)]
    pub fn get_texture(&self) -> &Rc<I> {
        &self.texture
    }

    /// Set the sprite's texture
    #[inline(always)]
    pub fn set_texture(&mut self, texture: Rc<I>) {
        self.texture = texture;
    }

    /// Add a sprite as the child of this sprite, return the added sprite's id.
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    /// Remove the child by `id` from this sprite's children or grandchild
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in &mut self.children {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in &self.children {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in &mut self.children {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Get the sprite's children
    #[inline(always)]
    pub fn children(&self) -> &Vec<Sprite<I>> {
        &self.children
    }

    /// Draw this sprite and its children
    pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        use graphics::*;

        if !self.visible {
            return;
        }

        let (tex_w, tex_h) = self.texture.get_size();
        let tex_w = tex_w as f64;
        let tex_h = tex_h as f64;
        let source_rectangle = self.src_rect.unwrap_or({
            let (w, h) = (tex_w, tex_h);
            [0.0, 0.0, w as f64, h as f64]
        });
        let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];

        let transformed = t.trans(self.position[0], self.position[1])
                           .rot_deg(self.rotation)
                           .scale(self.scale[0], self.scale[1]);

        let mut model = transformed;

        if self.flip_x {
            model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
        }

        if self.flip_y {
            model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
        }

        let ref draw_state: graphics::DrawState = Default::default();

        // for debug: bounding_box
        //model.rgb(1.0, 0.0, 0.0).draw(b);

        graphics::Image::new()
            .color([self.color[0], self.color[1], self.color[2], self.opacity])
            .rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
            .maybe_src_rect(self.src_rect)
            .draw(&*self.texture, draw_state, model, b);

        // for debug: anchor point
        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);

        for child in &self.children {
            child.draw(transformed, b);
        }
    }

    /// Draw this sprite and its children with color
    pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
        use graphics::*;

        if !self.visible {
            return;
        }

        let (tex_w, tex_h) = self.texture.get_size();
        let tex_w = tex_w as f64;
        let tex_h = tex_h as f64;
        let source_rectangle = self.src_rect.unwrap_or({
            let (w, h) = (tex_w, tex_h);
            [0.0, 0.0, w as f64, h as f64]
        });
        let anchor = [self.anchor[0] * source_rectangle[2], self.anchor[1] * source_rectangle[3]];

        let transformed = t.trans(self.position[0], self.position[1])
                           .rot_deg(self.rotation)
                           .scale(self.scale[0], self.scale[1]);

        let mut model = transformed;

        if self.flip_x {
            model = model.trans(source_rectangle[2] - 2.0 * anchor[0], 0.0).flip_h();
        }

        if self.flip_y {
            model = model.trans(0.0, source_rectangle[3] - 2.0 * anchor[1]).flip_v();
        }

        let ref draw_state: graphics::DrawState = Default::default();

        // for debug: bounding_box
        //model.rgb(1.0, 0.0, 0.0).draw(b);

        graphics::Image::new()
            .color([c[0], c[1], c[2], self.opacity])
            .rect([-anchor[0], -anchor[1], source_rectangle[2], source_rectangle[3]])
            .maybe_src_rect(self.src_rect)
            .draw(&*self.texture, draw_state, model, b);

        // for debug: anchor point
        //c.trans(self.position[0], self.position[1]).rect(-5.0, -5.0, 10.0, 10.0).rgb(0.0, 0.0, 1.0).draw(b);

        for child in &self.children {
            child.draw_tinted(transformed, b, c);
        }
    }

    /// Get the sprite's bounding box
    pub fn bounding_box(&self) -> graphics::types::Rectangle {
        let (w, h) = self.texture.get_size();
        let source_rectangle = self.src_rect.unwrap_or({
            let (sprite_w, sprite_h) = (w, h);
            [0.0, 0.0, sprite_w as f64, sprite_h as f64]
        });
        let sprite_w = source_rectangle[2] * self.scale[0];
        let sprite_h = source_rectangle[3] * self.scale[1];

        [
            self.position[0] - self.anchor[0] * sprite_w,
            self.position[1] - self.anchor[1] * sprite_h,
            sprite_w,
            sprite_h
        ]
    }
}
<|endoftext|>


<commit_before>use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::{fmt,ptr,mem};
use std::marker::PhantomData;
use libc::{c_char, size_t};

use jsonnet_sys;
use super::JsonnetVm;

/// Rust wrapper for libjsonnet string values.
///
/// This string is allocated against a particular JsonnetVm, and may
/// not outlive the JsonentVm.  It is UTF-8, and may not contain
/// embedded nul characters (ie: it is javascript and C -safe).
pub struct JsonnetString<'a> {
    vm: &'a JsonnetVm,
    data: *mut c_char,
}

impl<'a> JsonnetString<'a> {
    /// Allocate a new JsonnetString and copy `v` into it.
    ///
    /// # Panics
    ///
    /// Panics if `v` contains an embedded nul character.
    pub fn new(vm: &'a JsonnetVm, v: &str) -> Self {
        // TODO: remove this additional copy, and just copy the bytes
        // and add the trailing nul myself (remember to check for
        // embedded nuls).

        let data = CString::new(v).unwrap().into_bytes_with_nul();
        unsafe {
            let p = jsonnet_sys::jsonnet_realloc(vm.as_ptr(), ptr::null(), data.len());
            ptr::copy_nonoverlapping(data.as_ptr(), p as *mut u8, data.len());
            Self::from_ptr(vm, p)
        }
    }

    /// Construct a `JsonnetString` from a pointer returned from a
    /// low-level jsonnet C function.
    ///
    /// # Safety
    ///
    /// It is assumed that `p` points to a UTF-8 C string (ie: nul
    /// terminated).  It is up to the caller to ensure that `p` was
    /// indeed allocated by `vm`.
    pub unsafe fn from_ptr(vm: &'a JsonnetVm, p: *mut c_char) -> Self {
        JsonnetString{vm: vm, data: p}
    }

    fn realloc(&mut self, size: size_t) {
        unsafe {
            self.data = jsonnet_sys::jsonnet_realloc(self.vm.as_ptr(), self.data, size);
        }
    }

    /// Returns the contents as a `&str`.
    pub fn as_str(&self) -> &'a str {
        self.as_cstr().to_str().unwrap()
    }

    /// Returns the contents as a `&CStr`.
    pub fn as_cstr(&self) -> &'a CStr {
        unsafe { CStr::from_ptr(self.data) }
    }

    /// Returns the inner pointer to this jsonnet string.
    ///
    /// The returned pointer will be valid for as long as `self` is.
    pub fn as_ptr(&self) -> *const c_char { self.data }

    /// Transfer ownership to a C caller (presumably a jsonnet
    /// function).
    ///
    /// If you call this, it is up to you to ensure that the string is
    /// freed correctly (using the appropriate jsonnet function), or
    /// the memory will leak.
    pub fn into_raw(self) -> *mut c_char {
        let result = self.data;
        mem::forget(self);
        result
    }
}

impl<'a> Deref for JsonnetString<'a> {
    type Target = str;
    fn deref(&self) -> &str { self.as_str() }
}

impl<'a> fmt::Debug for JsonnetString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl<'a> fmt::Display for JsonnetString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl<'a> Drop for JsonnetString<'a> {
    fn drop(&mut self) {
        self.realloc(0);
    }
}

impl<'a> PartialEq for JsonnetString<'a> {
    fn eq<'b>(&self, other: &JsonnetString<'b>) -> bool {
        self.as_str() == other.as_str()
    }
}

impl<'a> Eq for JsonnetString<'a> {}

#[test]
fn simple() {
    let vm = JsonnetVm::new();
    let s = JsonnetString::new(&vm, "1234");
    assert_eq!(s.as_str(), "1234");
    assert_eq!(s.as_cstr().to_bytes_with_nul(), b"1234\0");
}

/// An iterator over nul-separated multi-valued jsonnet string.
#[derive(Debug)]
pub struct JsonnetStringIter<'a,'b:'a> {
    cursor: *const c_char,
    marker: PhantomData<&'a JsonnetString<'b>>,
}

impl<'a,'b> JsonnetStringIter<'a,'b> {
    /// Caller takes responsibility for ensuring this actually is a
    /// multi-valued string.
    pub unsafe fn new(inner: &'a JsonnetString<'b>) -> Self {
        let cursor = inner.as_ptr();
        JsonnetStringIter{cursor: cursor, marker: PhantomData}
    }

    fn end(&self) -> bool {
        let c = unsafe { *self.cursor };
        c == 0
    }

    // Caller checks that cursor is actually pointing at another string.
    unsafe fn take_next(&mut self) -> &'a CStr {
        let ret = CStr::from_ptr(self.cursor);
        let len = ret.to_bytes_with_nul().len();
        self.cursor = self.cursor.offset(len as isize);
        ret
    }
}

impl<'a,'b> Iterator for JsonnetStringIter<'a,'b> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        if self.end() {
            None
        } else {
            let v = unsafe { self.take_next() };
            Some(v.to_str().unwrap())
        }
    }
}
<commit_msg>Remove a copy from JsonnetString::new()<commit_after>use std::ffi::CStr;
use std::ops::Deref;
use std::{fmt,ptr,mem};
use std::marker::PhantomData;
use libc::{c_char, size_t};

use jsonnet_sys;
use super::JsonnetVm;

/// Rust wrapper for libjsonnet string values.
///
/// This string is allocated against a particular JsonnetVm, and may
/// not outlive the JsonentVm.  It is UTF-8, and may not contain
/// embedded nul characters (ie: it is javascript and C -safe).
pub struct JsonnetString<'a> {
    vm: &'a JsonnetVm,
    data: *mut c_char,
}

impl<'a> JsonnetString<'a> {
    /// Allocate a new JsonnetString and copy `v` into it.
    ///
    /// # Panics
    ///
    /// Panics if `v` contains an embedded nul character.
    pub fn new(vm: &'a JsonnetVm, v: &str) -> Self {
        JsonnetString::from_bytes(vm, v.as_bytes())
    }

    /// Allocate a new JsonnetString and copy `v` into it.
    ///
    /// # Panics
    ///
    /// Panics if `v` contains an embedded nul character.  In most
    /// cases, jsonnet requires strings to be utf8, so prefer
    /// `JsonnetString::new` over this function.
    pub fn from_bytes(vm: &'a JsonnetVm, v: &[u8]) -> Self {
        unsafe {
            let p = jsonnet_sys::jsonnet_realloc(vm.as_ptr(), ptr::null(), v.len() + 1);
            ptr::copy_nonoverlapping(v.as_ptr(), p as *mut u8, v.len());
            *(p.offset(v.len() as isize)) = 0;  // trailing nul for C string
            Self::from_ptr(vm, p)
        }
    }

    /// Construct a `JsonnetString` from a pointer returned from a
    /// low-level jsonnet C function.
    ///
    /// # Safety
    ///
    /// It is assumed that `p` points to a UTF-8 C string (ie: nul
    /// terminated).  It is up to the caller to ensure that `p` was
    /// indeed allocated by `vm`.
    pub unsafe fn from_ptr(vm: &'a JsonnetVm, p: *mut c_char) -> Self {
        JsonnetString{vm: vm, data: p}
    }

    fn realloc(&mut self, size: size_t) {
        unsafe {
            self.data = jsonnet_sys::jsonnet_realloc(self.vm.as_ptr(), self.data, size);
        }
    }

    /// Returns the contents as a `&str`.
    pub fn as_str(&self) -> &'a str {
        self.as_cstr().to_str().unwrap()
    }

    /// Returns the contents as a `&CStr`.
    pub fn as_cstr(&self) -> &'a CStr {
        unsafe { CStr::from_ptr(self.data) }
    }

    /// Returns the inner pointer to this jsonnet string.
    ///
    /// The returned pointer will be valid for as long as `self` is.
    pub fn as_ptr(&self) -> *const c_char { self.data }

    /// Transfer ownership to a C caller (presumably a jsonnet
    /// function).
    ///
    /// If you call this, it is up to you to ensure that the string is
    /// freed correctly (using the appropriate jsonnet function), or
    /// the memory will leak.
    pub fn into_raw(self) -> *mut c_char {
        let result = self.data;
        mem::forget(self);
        result
    }
}

impl<'a> Deref for JsonnetString<'a> {
    type Target = str;
    fn deref(&self) -> &str { self.as_str() }
}

impl<'a> fmt::Debug for JsonnetString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl<'a> fmt::Display for JsonnetString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl<'a> Drop for JsonnetString<'a> {
    fn drop(&mut self) {
        self.realloc(0);
    }
}

impl<'a> PartialEq for JsonnetString<'a> {
    fn eq<'b>(&self, other: &JsonnetString<'b>) -> bool {
        self.as_str() == other.as_str()
    }
}

impl<'a> Eq for JsonnetString<'a> {}

#[test]
fn simple() {
    let vm = JsonnetVm::new();
    let s = JsonnetString::new(&vm, "1234");
    assert_eq!(s.as_str(), "1234");
    assert_eq!(s.as_cstr().to_bytes_with_nul(), b"1234\0");
}

/// An iterator over nul-separated multi-valued jsonnet string.
#[derive(Debug)]
pub struct JsonnetStringIter<'a,'b:'a> {
    cursor: *const c_char,
    marker: PhantomData<&'a JsonnetString<'b>>,
}

impl<'a,'b> JsonnetStringIter<'a,'b> {
    /// Caller takes responsibility for ensuring this actually is a
    /// multi-valued string.
    pub unsafe fn new(inner: &'a JsonnetString<'b>) -> Self {
        let cursor = inner.as_ptr();
        JsonnetStringIter{cursor: cursor, marker: PhantomData}
    }

    fn end(&self) -> bool {
        let c = unsafe { *self.cursor };
        c == 0
    }

    // Caller checks that cursor is actually pointing at another string.
    unsafe fn take_next(&mut self) -> &'a CStr {
        let ret = CStr::from_ptr(self.cursor);
        let len = ret.to_bytes_with_nul().len();
        self.cursor = self.cursor.offset(len as isize);
        ret
    }
}

impl<'a,'b> Iterator for JsonnetStringIter<'a,'b> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        if self.end() {
            None
        } else {
            let v = unsafe { self.take_next() };
            Some(v.to_str().unwrap())
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// Non-standard properties that Gecko uses for XUL elements.
<% data.new_style_struct("XUL", inherited=False) %>

${helpers.single_keyword("-moz-box-align", "stretch start center baseline end",
                         products="gecko", gecko_ffi_name="mBoxAlign",
                         gecko_enum_prefix="StyleBoxAlign",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         alias="-webkit-box-align",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)")}

${helpers.single_keyword("-moz-box-direction", "normal reverse",
                         products="gecko", gecko_ffi_name="mBoxDirection",
                         gecko_enum_prefix="StyleBoxDirection",
                         animation_type="none",
                         alias="-webkit-box-direction",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")}

${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative",
                          products="gecko", gecko_ffi_name="mBoxFlex",
                          animation_type="none",
                          alias="-webkit-box-flex",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}

${helpers.single_keyword("-moz-box-orient", "horizontal vertical",
                         products="gecko", gecko_ffi_name="mBoxOrient",
                         gecko_enum_prefix="StyleBoxOrient",
                         animation_type="none",
                         alias="-webkit-box-orient",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)")}

${helpers.single_keyword("-moz-box-pack", "start center end justify",
                         products="gecko", gecko_ffi_name="mBoxPack",
                         gecko_enum_prefix="StyleBoxPack",
                         animation_type="none",
                         alias="-webkit-box-pack",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)")}

${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore",
                         products="gecko", gecko_ffi_name="mStretchStack",
                         gecko_constant_prefix="NS_STYLE_STACK_SIZING",
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")}

${helpers.predefined_type("-moz-box-ordinal-group", "Integer", "0",
                          parse_method="parse_non_negative",
                          products="gecko",
                          alias="-webkit-box-ordinal-group",
                          gecko_ffi_name="mBoxOrdinal",
                          animation_type="none",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)")}
<commit_msg>Add `inline-axis` and `block-axis` aliases for `-moz-box-orient`.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// Non-standard properties that Gecko uses for XUL elements.
<% data.new_style_struct("XUL", inherited=False) %>

${helpers.single_keyword("-moz-box-align", "stretch start center baseline end",
                         products="gecko", gecko_ffi_name="mBoxAlign",
                         gecko_enum_prefix="StyleBoxAlign",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         alias="-webkit-box-align",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)")}

${helpers.single_keyword("-moz-box-direction", "normal reverse",
                         products="gecko", gecko_ffi_name="mBoxDirection",
                         gecko_enum_prefix="StyleBoxDirection",
                         animation_type="none",
                         alias="-webkit-box-direction",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")}

${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative",
                          products="gecko", gecko_ffi_name="mBoxFlex",
                          animation_type="none",
                          alias="-webkit-box-flex",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}

${helpers.single_keyword("-moz-box-orient", "horizontal vertical",
                         products="gecko", gecko_ffi_name="mBoxOrient",
                         extra_gecko_aliases="inline-axis=horizontal block-axis=vertical",
                         gecko_enum_prefix="StyleBoxOrient",
                         animation_type="none",
                         alias="-webkit-box-orient",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)")}

${helpers.single_keyword("-moz-box-pack", "start center end justify",
                         products="gecko", gecko_ffi_name="mBoxPack",
                         gecko_enum_prefix="StyleBoxPack",
                         animation_type="none",
                         alias="-webkit-box-pack",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)")}

${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore",
                         products="gecko", gecko_ffi_name="mStretchStack",
                         gecko_constant_prefix="NS_STYLE_STACK_SIZING",
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")}

${helpers.predefined_type("-moz-box-ordinal-group", "Integer", "0",
                          parse_method="parse_non_negative",
                          products="gecko",
                          alias="-webkit-box-ordinal-group",
                          gecko_ffi_name="mBoxOrdinal",
                          animation_type="none",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)")}
<|endoftext|>


<commit_before>// 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.

use super::error::SBError;
use super::event::SBEvent;
use super::frame::SBFrame;
use super::process::SBProcess;
use super::queue::SBQueue;
use super::stream::SBStream;
use super::value::SBValue;
use super::{lldb_tid_t, StopReason};
use std::ffi::CStr;
use std::fmt;
use sys;

/// A thread of execution.
///
/// `SBThread`s can be referred to by their ID, which maps to the system
/// specific thread identifier, or by `IndexID`.  The ID may or may not
/// be unique depending on whether the system reuses its thread identifiers.
/// The `IndexID` is a monotonically increasing identifier that will always
/// uniquely reference a particular thread, and when that thread goes
/// away it will not be reused.
///
/// # Thread State
///
/// ...
///
/// # Execution Control
///
/// ...
///
/// # Frames
///
/// The thread contains [stack frames]. These can be iterated
/// over with [`frames`]:
///
/// ```no_run
/// # use lldb::{SBFrame, SBThread};
/// # fn look_at_frames(thread: SBThread) {
/// // Iterate over the frames...
/// for frame in thread.frames() {
///     println!("Hello {:?}!", frame);
/// }
/// // Or collect them into a vector!
/// let frames = thread.frames().collect::<Vec<SBFrame>>();
/// # }
/// ```
///
/// Some functions operate on the 'currently selected frame'. This can
/// retrieved via [`selected_frame`] and set via [`set_selected_frame`].
///
///
/// # Events
///
/// ...
///
/// [stack frames]: struct.SBFrame.html
/// [`frames`]: #method.frames
/// [`selected_frame`]: #method.selected_frame
/// [`set_selected_frame`]: #method.set_selected_frame
pub struct SBThread {
    /// The underlying raw `SBThreadRef`.
    pub raw: sys::SBThreadRef,
}

impl SBThread {
    /// Construct a new `Some(SBThread)` or `None`.
    pub fn maybe_wrap(raw: sys::SBThreadRef) -> Option<SBThread> {
        if unsafe { sys::SBThreadIsValid(raw) } {
            Some(SBThread { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBThread` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBThreadIsValid(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn broadcaster_class_name() -> &'static str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetBroadcasterClassName()).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Get the stop reason for this thread.
    pub fn stop_reason(&self) -> StopReason {
        unsafe { sys::SBThreadGetStopReason(self.raw) }
    }

    /// The return value from the last stop if we just stopped due
    /// to stepping out of a function
    pub fn stop_return_value(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBThreadGetStopReturnValue(self.raw) })
    }

    /// Returns a unique thread identifier for the current `SBThread`
    /// that will remain constant throughout the thread's lifetime in
    /// this process and will not be reused by another thread during this
    /// process lifetime.  On Mac OS X systems, this is a system-wide
    /// unique thread identifier; this identifier is also used by
    /// other tools like sample which helps to associate data from
    /// those tools with lldb.  See related [`SBThread::index_id`].
    pub fn thread_id(&self) -> lldb_tid_t {
        unsafe { sys::SBThreadGetThreadID(self.raw) }
    }

    /// Return the index number for this `SBThread`.  The index
    /// number is the same thing that a user gives as an argument
    /// to `thread select` in the command line lldb.
    ///
    /// These numbers start at `1` (for the first thread lldb sees
    /// in a debug session) and increments up throughout the process
    /// lifetime.  An index number will not be reused for a different
    /// thread later in a process - thread 1 will always be associated
    /// with the same thread.  See related [`SBThread::thread_id`].
    pub fn index_id(&self) -> u32 {
        unsafe { sys::SBThreadGetIndexID(self.raw) }
    }

    /// The name associated with the thread, if any.
    pub fn name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Return the queue associated with this thread, if any.
    ///
    /// If this `SBThread` is actually a history thread, then there may be
    /// a queue ID and name available, but not a full [`SBQueue`] as the
    /// individual attributes may have been saved, but without enough
    /// information to reconstitute the entire `SBQueue` at that time.
    pub fn queue(&self) -> Option<SBQueue> {
        SBQueue::maybe_wrap(unsafe { sys::SBThreadGetQueue(self.raw) })
    }

    /// Return the queue name associated with this thread, if any.
    ///
    /// For example, this would report a `libdispatch` (Grand Central Dispatch)
    /// queue name.
    pub fn queue_name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetQueueName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Return the `dispatch_queue_id` for this thread, if any.
    ///
    /// For example, this would report a `libdispatch` (Grand Central Dispatch)
    /// queue ID.
    pub fn queue_id(&self) -> u64 {
        unsafe { sys::SBThreadGetQueueID(self.raw) }
    }

    /// Set the user resume state for this thread to suspend.
    ///
    /// LLDB currently supports process centric debugging which means when any
    /// thread in a process stops, all other threads are stopped. The `suspend`
    /// call here tells our process to suspend a thread and not let it run when
    /// the other threads in a process are allowed to run. So when
    /// [`SBProcess::continue_execution()`] is called, any threads that
    /// aren't suspended will be allowed to run. If any of the `SBThread`
    /// functions for stepping are called (`step_over`, `step_into`,
    /// `step_out`, `step_instruction`, `run_to_address`), the thread will
    /// not be allowed to run and these functions will simply return.
    pub fn suspend(&self) -> bool {
        let error: SBError = SBError::default();
        unsafe { sys::SBThreadSuspend(self.raw, error.raw) }
    }

    /// Set the user resume state for this to allow it to run again.
    ///
    /// See the discussion on [`SBThread::suspend()`] for further details.
    pub fn resume(&self) -> bool {
        let error: SBError = SBError::default();
        unsafe { sys::SBThreadResume(self.raw, error.raw) }
    }

    /// Is this thread set to the suspended user resume state?
    ///
    /// See the discussion on [`SBThread::suspend()`] for further details.
    pub fn is_suspended(&self) -> bool {
        unsafe { sys::SBThreadIsSuspended(self.raw) }
    }

    /// Is this thread stopped?
    pub fn is_stopped(&self) -> bool {
        unsafe { sys::SBThreadIsStopped(self.raw) }
    }

    /// Get an iterator over the [frames] known to this thread instance.
    ///
    /// [frames]: struct.SBFrame.html
    pub fn frames(&self) -> SBThreadFrameIter {
        SBThreadFrameIter {
            thread: self,
            idx: 0,
        }
    }

    /// Get the currently selected frame for this thread.
    pub fn selected_frame(&self) -> SBFrame {
        SBFrame::from(unsafe { sys::SBThreadGetSelectedFrame(self.raw) })
    }

    /// Set the currently selected frame for this thread. This takes a frame index.
    pub fn set_selected_frame(&self, frame_index: u32) -> Option<SBFrame> {
        SBFrame::maybe_wrap(unsafe { sys::SBThreadSetSelectedFrame(self.raw, frame_index) })
    }

    /// Get the process in which this thread is running.
    pub fn process(&self) -> SBProcess {
        SBProcess::from(unsafe { sys::SBThreadGetProcess(self.raw) })
    }

    /// If the given event is a thread event, return it as an
    /// `SBThreadEvent`. Otherwise, return `None`.
    pub fn event_as_thread_event(event: &SBEvent) -> Option<SBThreadEvent> {
        if unsafe { sys::SBThreadEventIsThreadEvent(event.raw) } {
            Some(SBThreadEvent::new(event))
        } else {
            None
        }
    }
}

/// Iterate over the [frames] in a [thread].
///
/// [frames]: struct.SBFrame.html
/// [thread]: struct.SBThread.html
pub struct SBThreadFrameIter<'d> {
    thread: &'d SBThread,
    idx: usize,
}

impl<'d> Iterator for SBThreadFrameIter<'d> {
    type Item = SBFrame;

    fn next(&mut self) -> Option<SBFrame> {
        if self.idx < unsafe { sys::SBThreadGetNumFrames(self.thread.raw) as usize } {
            let r = Some(SBFrame::from(unsafe {
                sys::SBThreadGetFrameAtIndex(self.thread.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBThreadGetNumFrames(self.thread.raw) } as usize;
        (sz - self.idx, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBThreadFrameIter<'d> {}

impl Clone for SBThread {
    fn clone(&self) -> SBThread {
        SBThread {
            raw: unsafe { sys::CloneSBThread(self.raw) },
        }
    }
}

impl fmt::Debug for SBThread {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBThreadGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBThread {{ {} }}", stream.data())
    }
}

impl Drop for SBThread {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBThread(self.raw) };
    }
}

impl From<sys::SBThreadRef> for SBThread {
    fn from(raw: sys::SBThreadRef) -> SBThread {
        SBThread { raw }
    }
}

unsafe impl Send for SBThread {}
unsafe impl Sync for SBThread {}

/// A thread event.
pub struct SBThreadEvent<'e> {
    event: &'e SBEvent,
}

impl<'e> SBThreadEvent<'e> {
    /// Construct a new `SBThreadEvent`.
    pub fn new(event: &'e SBEvent) -> Self {
        SBThreadEvent { event }
    }

    /// Get the thread from this thread event.
    pub fn thread(&self) -> SBThread {
        SBThread::from(unsafe { sys::SBThreadGetThreadFromEvent(self.event.raw) })
    }

    /// Get the frame from this thread event.
    pub fn frame(&self) -> Option<SBFrame> {
        SBFrame::maybe_wrap(unsafe { sys::SBThreadGetStackFrameFromEvent(self.event.raw) })
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBThread: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm): This should be u64
    field thread_id() -> i32 {
        self.thread_id() as i32
    }

    // TODO(bm) This should be u32
    field index_id() -> i32 {
        self.index_id() as i32
    }

    field frames() -> Vec<SBFrame> {
        self.frames().collect()
    }

    field selected_frame() -> SBFrame {
        self.selected_frame()
    }

    field process() -> SBProcess {
        self.process()
    }
});
<commit_msg>SBThread: suspend/resume return `Result<(), SBError>` now.<commit_after>// 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.

use super::error::SBError;
use super::event::SBEvent;
use super::frame::SBFrame;
use super::process::SBProcess;
use super::queue::SBQueue;
use super::stream::SBStream;
use super::value::SBValue;
use super::{lldb_tid_t, StopReason};
use std::ffi::CStr;
use std::fmt;
use sys;

/// A thread of execution.
///
/// `SBThread`s can be referred to by their ID, which maps to the system
/// specific thread identifier, or by `IndexID`.  The ID may or may not
/// be unique depending on whether the system reuses its thread identifiers.
/// The `IndexID` is a monotonically increasing identifier that will always
/// uniquely reference a particular thread, and when that thread goes
/// away it will not be reused.
///
/// # Thread State
///
/// ...
///
/// # Execution Control
///
/// ...
///
/// # Frames
///
/// The thread contains [stack frames]. These can be iterated
/// over with [`frames`]:
///
/// ```no_run
/// # use lldb::{SBFrame, SBThread};
/// # fn look_at_frames(thread: SBThread) {
/// // Iterate over the frames...
/// for frame in thread.frames() {
///     println!("Hello {:?}!", frame);
/// }
/// // Or collect them into a vector!
/// let frames = thread.frames().collect::<Vec<SBFrame>>();
/// # }
/// ```
///
/// Some functions operate on the 'currently selected frame'. This can
/// retrieved via [`selected_frame`] and set via [`set_selected_frame`].
///
///
/// # Events
///
/// ...
///
/// [stack frames]: struct.SBFrame.html
/// [`frames`]: #method.frames
/// [`selected_frame`]: #method.selected_frame
/// [`set_selected_frame`]: #method.set_selected_frame
pub struct SBThread {
    /// The underlying raw `SBThreadRef`.
    pub raw: sys::SBThreadRef,
}

impl SBThread {
    /// Construct a new `Some(SBThread)` or `None`.
    pub fn maybe_wrap(raw: sys::SBThreadRef) -> Option<SBThread> {
        if unsafe { sys::SBThreadIsValid(raw) } {
            Some(SBThread { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBThread` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBThreadIsValid(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn broadcaster_class_name() -> &'static str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetBroadcasterClassName()).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Get the stop reason for this thread.
    pub fn stop_reason(&self) -> StopReason {
        unsafe { sys::SBThreadGetStopReason(self.raw) }
    }

    /// The return value from the last stop if we just stopped due
    /// to stepping out of a function
    pub fn stop_return_value(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBThreadGetStopReturnValue(self.raw) })
    }

    /// Returns a unique thread identifier for the current `SBThread`
    /// that will remain constant throughout the thread's lifetime in
    /// this process and will not be reused by another thread during this
    /// process lifetime.  On Mac OS X systems, this is a system-wide
    /// unique thread identifier; this identifier is also used by
    /// other tools like sample which helps to associate data from
    /// those tools with lldb.  See related [`SBThread::index_id`].
    pub fn thread_id(&self) -> lldb_tid_t {
        unsafe { sys::SBThreadGetThreadID(self.raw) }
    }

    /// Return the index number for this `SBThread`.  The index
    /// number is the same thing that a user gives as an argument
    /// to `thread select` in the command line lldb.
    ///
    /// These numbers start at `1` (for the first thread lldb sees
    /// in a debug session) and increments up throughout the process
    /// lifetime.  An index number will not be reused for a different
    /// thread later in a process - thread 1 will always be associated
    /// with the same thread.  See related [`SBThread::thread_id`].
    pub fn index_id(&self) -> u32 {
        unsafe { sys::SBThreadGetIndexID(self.raw) }
    }

    /// The name associated with the thread, if any.
    pub fn name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Return the queue associated with this thread, if any.
    ///
    /// If this `SBThread` is actually a history thread, then there may be
    /// a queue ID and name available, but not a full [`SBQueue`] as the
    /// individual attributes may have been saved, but without enough
    /// information to reconstitute the entire `SBQueue` at that time.
    pub fn queue(&self) -> Option<SBQueue> {
        SBQueue::maybe_wrap(unsafe { sys::SBThreadGetQueue(self.raw) })
    }

    /// Return the queue name associated with this thread, if any.
    ///
    /// For example, this would report a `libdispatch` (Grand Central Dispatch)
    /// queue name.
    pub fn queue_name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBThreadGetQueueName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Return the `dispatch_queue_id` for this thread, if any.
    ///
    /// For example, this would report a `libdispatch` (Grand Central Dispatch)
    /// queue ID.
    pub fn queue_id(&self) -> u64 {
        unsafe { sys::SBThreadGetQueueID(self.raw) }
    }

    /// Set the user resume state for this thread to suspend.
    ///
    /// LLDB currently supports process centric debugging which means when any
    /// thread in a process stops, all other threads are stopped. The `suspend`
    /// call here tells our process to suspend a thread and not let it run when
    /// the other threads in a process are allowed to run. So when
    /// [`SBProcess::continue_execution()`] is called, any threads that
    /// aren't suspended will be allowed to run. If any of the `SBThread`
    /// functions for stepping are called (`step_over`, `step_into`,
    /// `step_out`, `step_instruction`, `run_to_address`), the thread will
    /// not be allowed to run and these functions will simply return.
    pub fn suspend(&self) -> Result<(), SBError> {
        let error: SBError = SBError::default();
        unsafe { sys::SBThreadSuspend(self.raw, error.raw) };
        error.into_result()
    }

    /// Set the user resume state for this to allow it to run again.
    ///
    /// See the discussion on [`SBThread::suspend()`] for further details.
    pub fn resume(&self) -> Result<(), SBError> {
        let error: SBError = SBError::default();
        unsafe { sys::SBThreadResume(self.raw, error.raw) };
        error.into_result()
    }

    /// Is this thread set to the suspended user resume state?
    ///
    /// See the discussion on [`SBThread::suspend()`] for further details.
    pub fn is_suspended(&self) -> bool {
        unsafe { sys::SBThreadIsSuspended(self.raw) }
    }

    /// Is this thread stopped?
    pub fn is_stopped(&self) -> bool {
        unsafe { sys::SBThreadIsStopped(self.raw) }
    }

    /// Get an iterator over the [frames] known to this thread instance.
    ///
    /// [frames]: struct.SBFrame.html
    pub fn frames(&self) -> SBThreadFrameIter {
        SBThreadFrameIter {
            thread: self,
            idx: 0,
        }
    }

    /// Get the currently selected frame for this thread.
    pub fn selected_frame(&self) -> SBFrame {
        SBFrame::from(unsafe { sys::SBThreadGetSelectedFrame(self.raw) })
    }

    /// Set the currently selected frame for this thread. This takes a frame index.
    pub fn set_selected_frame(&self, frame_index: u32) -> Option<SBFrame> {
        SBFrame::maybe_wrap(unsafe { sys::SBThreadSetSelectedFrame(self.raw, frame_index) })
    }

    /// Get the process in which this thread is running.
    pub fn process(&self) -> SBProcess {
        SBProcess::from(unsafe { sys::SBThreadGetProcess(self.raw) })
    }

    /// If the given event is a thread event, return it as an
    /// `SBThreadEvent`. Otherwise, return `None`.
    pub fn event_as_thread_event(event: &SBEvent) -> Option<SBThreadEvent> {
        if unsafe { sys::SBThreadEventIsThreadEvent(event.raw) } {
            Some(SBThreadEvent::new(event))
        } else {
            None
        }
    }
}

/// Iterate over the [frames] in a [thread].
///
/// [frames]: struct.SBFrame.html
/// [thread]: struct.SBThread.html
pub struct SBThreadFrameIter<'d> {
    thread: &'d SBThread,
    idx: usize,
}

impl<'d> Iterator for SBThreadFrameIter<'d> {
    type Item = SBFrame;

    fn next(&mut self) -> Option<SBFrame> {
        if self.idx < unsafe { sys::SBThreadGetNumFrames(self.thread.raw) as usize } {
            let r = Some(SBFrame::from(unsafe {
                sys::SBThreadGetFrameAtIndex(self.thread.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBThreadGetNumFrames(self.thread.raw) } as usize;
        (sz - self.idx, Some(sz))
    }
}

impl<'d> ExactSizeIterator for SBThreadFrameIter<'d> {}

impl Clone for SBThread {
    fn clone(&self) -> SBThread {
        SBThread {
            raw: unsafe { sys::CloneSBThread(self.raw) },
        }
    }
}

impl fmt::Debug for SBThread {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBThreadGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBThread {{ {} }}", stream.data())
    }
}

impl Drop for SBThread {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBThread(self.raw) };
    }
}

impl From<sys::SBThreadRef> for SBThread {
    fn from(raw: sys::SBThreadRef) -> SBThread {
        SBThread { raw }
    }
}

unsafe impl Send for SBThread {}
unsafe impl Sync for SBThread {}

/// A thread event.
pub struct SBThreadEvent<'e> {
    event: &'e SBEvent,
}

impl<'e> SBThreadEvent<'e> {
    /// Construct a new `SBThreadEvent`.
    pub fn new(event: &'e SBEvent) -> Self {
        SBThreadEvent { event }
    }

    /// Get the thread from this thread event.
    pub fn thread(&self) -> SBThread {
        SBThread::from(unsafe { sys::SBThreadGetThreadFromEvent(self.event.raw) })
    }

    /// Get the frame from this thread event.
    pub fn frame(&self) -> Option<SBFrame> {
        SBFrame::maybe_wrap(unsafe { sys::SBThreadGetStackFrameFromEvent(self.event.raw) })
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBThread: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm): This should be u64
    field thread_id() -> i32 {
        self.thread_id() as i32
    }

    // TODO(bm) This should be u32
    field index_id() -> i32 {
        self.index_id() as i32
    }

    field frames() -> Vec<SBFrame> {
        self.frames().collect()
    }

    field selected_frame() -> SBFrame {
        self.selected_frame()
    }

    field process() -> SBProcess {
        self.process()
    }
});
<|endoftext|>


<commit_before>extern crate rand;

pub struct Repeatedly<F> {
    pub f: F,
}

impl<T, F: FnMut() -> T> Iterator for Repeatedly<F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut f = &mut self.f;
        Some(f())
    }
}

/// takes a function `f` of no args, presumably with side effects, and
/// returns an iterator that endlessly calls `f` and yields what it returns
pub fn repeatedly<T, F: FnMut() -> T>(f: F) -> Repeatedly<F> {
    Repeatedly { f: f }
}

#[test]
fn test_repeatedly() {
    use self::rand::{StdRng, SeedableRng};
    use helpers::random01;

    assert_eq!(vec![3, 3, 3, 3],
               repeatedly(|| 3).take(4).collect::<Vec<usize>>());

    let mut i = 0;
    assert_eq!(vec![1, 2, 3, 4],
               repeatedly(|| {
                   i += 1;
                   i
               })
                   .take(4)
                   .collect::<Vec<usize>>());
    assert_eq!(i, 4);

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    assert_eq!(vec![0.5162139860908154, 0.13628294371987984, 0.21635575241586105, 0.10006169673911681],
               repeatedly(|| random01(&mut rng))
                   .take(4)
                   .collect::<Vec<f64>>());
}
<commit_msg>move extern crates to crate root<commit_after>pub struct Repeatedly<F> {
    pub f: F,
}

impl<T, F: FnMut() -> T> Iterator for Repeatedly<F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut f = &mut self.f;
        Some(f())
    }
}

/// takes a function `f` of no args, presumably with side effects, and
/// returns an iterator that endlessly calls `f` and yields what it returns
pub fn repeatedly<T, F: FnMut() -> T>(f: F) -> Repeatedly<F> {
    Repeatedly { f: f }
}

#[test]
fn test_repeatedly() {
    use rand::{StdRng, SeedableRng};
    use helpers::random01;

    assert_eq!(vec![3, 3, 3, 3],
               repeatedly(|| 3).take(4).collect::<Vec<usize>>());

    let mut i = 0;
    assert_eq!(vec![1, 2, 3, 4],
               repeatedly(|| {
                   i += 1;
                   i
               })
                   .take(4)
                   .collect::<Vec<usize>>());
    assert_eq!(i, 4);

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    assert_eq!(vec![0.5162139860908154, 0.13628294371987984, 0.21635575241586105, 0.10006169673911681],
               repeatedly(|| random01(&mut rng))
                   .take(4)
                   .collect::<Vec<f64>>());
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "gecko")]
extern crate bindgen;
#[cfg(feature = "gecko")]
extern crate log;
#[cfg(feature = "gecko")]
extern crate regex;
#[cfg(feature = "gecko")]
extern crate toml;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{exit, Command};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe")
        .arg("--version")
        .output()
        .is_ok()
    {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe")
        .arg("--version")
        .output()
        .is_ok()
    {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!(
        "Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
        "Try fixing PATH or setting the PYTHON env var"
    ));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7")
        .arg("--version")
        .output()
        .unwrap()
        .status
        .success()
    {
        "python2.7"
    } else {
        "python"
    }
    .to_owned()
}

lazy_static! {
    pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(find_python);
}

fn generate_properties() {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            },
            _ => {},
        }
    }

    let script = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
        .join("properties")
        .join("build.py");

    #[cfg(feature = "gecko")]
    let engine = "gecko";

    #[cfg(feature = "servo-layout-2013")]
    let engine = "servo-2013";

    #[cfg(feature = "servo-layout-2020")]
    let engine = "servo-2020";

    let status = Command::new(&*PYTHON)
        .arg(&script)
        .arg(engine)
        .arg("style-crate")
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    let gecko = cfg!(feature = "gecko");
    let servo = cfg!(feature = "servo");
    if !(gecko || servo) {
        panic!("The style crate requires enabling one of its 'servo' or 'gecko' feature flags");
    }
    if gecko && servo {
        panic!(
            "The style crate does not support enabling both its 'servo' or 'gecko' \
             feature flags at the same time."
        );
    }
    if gecko && (cfg!(feature = "servo-layout-2013") || cfg!(feature = "servo-layout-2020")) {
        panic!("The 'servo-layout-*' features can only be enabled together with 'servo'.");
    }
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
    generate_properties();
    build_gecko::generate();
}
<commit_msg>Auto merge of #24294 - servo:missing-feature, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "gecko")]
extern crate bindgen;
#[cfg(feature = "gecko")]
extern crate log;
#[cfg(feature = "gecko")]
extern crate regex;
#[cfg(feature = "gecko")]
extern crate toml;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{exit, Command};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe")
        .arg("--version")
        .output()
        .is_ok()
    {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe")
        .arg("--version")
        .output()
        .is_ok()
    {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!(
        "Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
        "Try fixing PATH or setting the PYTHON env var"
    ));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7")
        .arg("--version")
        .output()
        .unwrap()
        .status
        .success()
    {
        "python2.7"
    } else {
        "python"
    }
    .to_owned()
}

lazy_static! {
    pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(find_python);
}

fn generate_properties(engine: &str) {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            },
            _ => {},
        }
    }

    let script = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
        .join("properties")
        .join("build.py");

    let status = Command::new(&*PYTHON)
        .arg(&script)
        .arg(engine)
        .arg("style-crate")
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    let gecko = cfg!(feature = "gecko");
    let servo = cfg!(feature = "servo");
    let l2013 = cfg!(feature = "servo-layout-2013");
    let l2020 = cfg!(feature = "servo-layout-2020");
    let engine = match (gecko, servo, l2013, l2020) {
        (true, false, false, false) => "gecko",
        (false, true, true, false) => "servo-2013",
        (false, true, false, true) => "servo-2020",
        _ => panic!(
            "\n\n\
             The style crate requires enabling one of its 'servo' or 'gecko' feature flags \
             and, in the 'servo' case, one of 'servo-layout-2013' or 'servo-layout-2020'.\
             \n\n"
        ),
    };
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
    generate_properties(engine);
    build_gecko::generate();
}
<|endoftext|>


<commit_before>//! Standard symbolic constants and types
//!
use {Errno, Error, Result, NixPath};
use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};
use libc::{self, c_char, c_void, c_int, size_t, pid_t, off_t, uid_t, gid_t};
use std::mem;
use std::ffi::CString;
use std::os::unix::io::RawFd;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::linux::*;

#[derive(Clone, Copy)]
pub enum ForkResult {
    Parent {
        child: pid_t
    },
    Child
}

impl ForkResult {
    #[inline]
    pub fn is_child(&self) -> bool {
        match *self {
            ForkResult::Child => true,
            _ => false
        }
    }

    #[inline]
    pub fn is_parent(&self) -> bool {
        !self.is_child()
    }
}

#[inline]
pub fn fork() -> Result<ForkResult> {
    use self::ForkResult::*;
    let res = unsafe { libc::fork() };

    Errno::result(res).map(|res| match res {
        0 => Child,
        res => Parent { child: res }
    })
}

#[inline]
pub fn getpid() -> pid_t {
    unsafe { libc::getpid() } // no error handling, according to man page: "These functions are always successful."
}
#[inline]
pub fn getppid() -> pid_t {
    unsafe { libc::getppid() } // no error handling, according to man page: "These functions are always successful."
}
#[inline]
pub fn setpgid(pid: pid_t, pgid: pid_t) -> Result<()> {
    let res = unsafe { libc::setpgid(pid, pgid) };
    Errno::result(res).map(drop)
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
pub fn gettid() -> pid_t {
    unsafe { libc::syscall(libc::SYS_gettid) as pid_t }    // no error handling, according to man page: "These functions are always successful."
}

#[inline]
pub fn dup(oldfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup(oldfd) };

    Errno::result(res)
}

#[inline]
pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup2(oldfd, newfd) };

    Errno::result(res)
}

pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
    if oldfd == newfd {
        return Err(Error::Sys(Errno::EINVAL));
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[inline]
pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe { libc::chdir(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<uid_t>, group: Option<gid_t>) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        // We use `0 - 1` to get `-1 : {u,g}id_t` which is specified as the no-op value for chown(3).
        unsafe { libc::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) }
    }));

    Errno::result(res).map(drop)
}

fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
    use std::ptr;
    use libc::c_char;

    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());
    args_p
}

#[inline]
pub fn execv(path: &CString, argv: &[CString]) -> Result<()> {
    let args_p = to_exec_array(argv);

    unsafe {
        libc::execv(path.as_ptr(), args_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

#[inline]
pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<()> {
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe {
        libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

#[inline]
pub fn execvp(filename: &CString, args: &[CString]) -> Result<()> {
    let args_p = to_exec_array(args);

    unsafe {
        libc::execvp(filename.as_ptr(), args_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
    Errno::result(res).map(drop)
}

pub fn sethostname(name: &[u8]) -> Result<()> {
    // Handle some differences in type of the len arg across platforms.
    cfg_if! {
        if #[cfg(any(target_os = "macos", target_os = "ios"))] {
            type sethostname_len_t = c_int;
        } else {
            type sethostname_len_t = size_t;
        }
    }
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as sethostname_len_t;

    let res = unsafe { libc::sethostname(ptr, len) };
    Errno::result(res).map(drop)
}

pub fn gethostname(name: &mut [u8]) -> Result<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as size_t;

    let res = unsafe { libc::gethostname(ptr, len) };
    Errno::result(res).map(drop)
}

pub fn close(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::close(fd) };
    Errno::result(res).map(drop)
}

pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
    let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    Errno::result(res).map(|r| r as usize)
}

pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
    let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    Errno::result(res).map(|r| r as usize)
}

pub fn pipe() -> Result<(RawFd, RawFd)> {
    unsafe {
        let mut fds: [c_int; 2] = mem::uninitialized();

        let res = libc::pipe(fds.as_mut_ptr());

        try!(Errno::result(res));

        Ok((fds[0], fds[1]))
    }
}

pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
    unsafe {
        let mut fds: [c_int; 2] = mem::uninitialized();

        let res = libc::pipe(fds.as_mut_ptr());

        try!(Errno::result(res));

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
    let mut res = Ok(0);

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
    Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
}

pub fn isatty(fd: RawFd) -> Result<bool> {
    use libc;

    unsafe {
        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
        // we return `Ok(false)`
        if libc::isatty(fd) == 1 {
            Ok(true)
        } else {
            match Errno::last() {
                Errno::ENOTTY => Ok(false),
                err => Err(Error::Sys(err)),
            }
        }
    }
}

pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            libc::unlink(cstr.as_ptr())
        }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe { libc::chroot(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn fsync(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::fsync(fd) };

    Errno::result(res).map(drop)
}

// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`.
// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211
#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "emscripten"))]
#[inline]
pub fn fdatasync(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::fdatasync(fd) };

    Errno::result(res).map(drop)
}

// POSIX requires that getuid, geteuid, getgid, getegid are always successful,
// so no need to check return value or errno. See:
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html
#[inline]
pub fn getuid() -> uid_t {
    unsafe { libc::getuid() }
}

#[inline]
pub fn geteuid() -> uid_t {
    unsafe { libc::geteuid() }
}

#[inline]
pub fn getgid() -> gid_t {
    unsafe { libc::getgid() }
}

#[inline]
pub fn getegid() -> gid_t {
    unsafe { libc::getegid() }
}

#[inline]
pub fn setuid(uid: uid_t) -> Result<()> {
    let res = unsafe { libc::setuid(uid) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn setgid(gid: gid_t) -> Result<()> {
    let res = unsafe { libc::setgid(gid) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn pause() -> Result<()> {
    let res = unsafe { libc::pause() };

    Errno::result(res).map(drop)
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux {
    use sys::syscall::{syscall, SYSPIVOTROOT};
    use {Errno, Result, NixPath};

    #[cfg(feature = "execvpe")]
    use std::ffi::CString;

    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
            new_root: &P1, put_old: &P2) -> Result<()> {
        let res = try!(try!(new_root.with_nix_path(|new_root| {
            put_old.with_nix_path(|put_old| {
                unsafe {
                    syscall(SYSPIVOTROOT, new_root.as_ptr(), put_old.as_ptr())
                }
            })
        })));

        Errno::result(res).map(drop)
    }

    #[inline]
    #[cfg(feature = "execvpe")]
    pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<()> {
        use std::ptr;
        use libc::c_char;

        let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
        args_p.push(ptr::null());

        let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
        env_p.push(ptr::null());

        unsafe {
            super::ffi::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
        };

        Err(Error::Sys(Errno::last()))
    }
}
<commit_msg>Auto merge of #351 - kamalmarhubi:sleep, r=posborne<commit_after>//! Standard symbolic constants and types
//!
use {Errno, Error, Result, NixPath};
use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};
use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t};
use std::mem;
use std::ffi::CString;
use std::os::unix::io::RawFd;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::linux::*;

#[derive(Clone, Copy)]
pub enum ForkResult {
    Parent {
        child: pid_t
    },
    Child
}

impl ForkResult {
    #[inline]
    pub fn is_child(&self) -> bool {
        match *self {
            ForkResult::Child => true,
            _ => false
        }
    }

    #[inline]
    pub fn is_parent(&self) -> bool {
        !self.is_child()
    }
}

#[inline]
pub fn fork() -> Result<ForkResult> {
    use self::ForkResult::*;
    let res = unsafe { libc::fork() };

    Errno::result(res).map(|res| match res {
        0 => Child,
        res => Parent { child: res }
    })
}

#[inline]
pub fn getpid() -> pid_t {
    unsafe { libc::getpid() } // no error handling, according to man page: "These functions are always successful."
}
#[inline]
pub fn getppid() -> pid_t {
    unsafe { libc::getppid() } // no error handling, according to man page: "These functions are always successful."
}
#[inline]
pub fn setpgid(pid: pid_t, pgid: pid_t) -> Result<()> {
    let res = unsafe { libc::setpgid(pid, pgid) };
    Errno::result(res).map(drop)
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
pub fn gettid() -> pid_t {
    unsafe { libc::syscall(libc::SYS_gettid) as pid_t }    // no error handling, according to man page: "These functions are always successful."
}

#[inline]
pub fn dup(oldfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup(oldfd) };

    Errno::result(res)
}

#[inline]
pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup2(oldfd, newfd) };

    Errno::result(res)
}

pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
    if oldfd == newfd {
        return Err(Error::Sys(Errno::EINVAL));
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[inline]
pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe { libc::chdir(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<uid_t>, group: Option<gid_t>) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        // We use `0 - 1` to get `-1 : {u,g}id_t` which is specified as the no-op value for chown(3).
        unsafe { libc::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) }
    }));

    Errno::result(res).map(drop)
}

fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
    use std::ptr;
    use libc::c_char;

    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());
    args_p
}

#[inline]
pub fn execv(path: &CString, argv: &[CString]) -> Result<()> {
    let args_p = to_exec_array(argv);

    unsafe {
        libc::execv(path.as_ptr(), args_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

#[inline]
pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<()> {
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe {
        libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

#[inline]
pub fn execvp(filename: &CString, args: &[CString]) -> Result<()> {
    let args_p = to_exec_array(args);

    unsafe {
        libc::execvp(filename.as_ptr(), args_p.as_ptr())
    };

    Err(Error::Sys(Errno::last()))
}

pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
    Errno::result(res).map(drop)
}

pub fn sethostname(name: &[u8]) -> Result<()> {
    // Handle some differences in type of the len arg across platforms.
    cfg_if! {
        if #[cfg(any(target_os = "macos", target_os = "ios"))] {
            type sethostname_len_t = c_int;
        } else {
            type sethostname_len_t = size_t;
        }
    }
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as sethostname_len_t;

    let res = unsafe { libc::sethostname(ptr, len) };
    Errno::result(res).map(drop)
}

pub fn gethostname(name: &mut [u8]) -> Result<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as size_t;

    let res = unsafe { libc::gethostname(ptr, len) };
    Errno::result(res).map(drop)
}

pub fn close(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::close(fd) };
    Errno::result(res).map(drop)
}

pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
    let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    Errno::result(res).map(|r| r as usize)
}

pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
    let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    Errno::result(res).map(|r| r as usize)
}

pub fn pipe() -> Result<(RawFd, RawFd)> {
    unsafe {
        let mut fds: [c_int; 2] = mem::uninitialized();

        let res = libc::pipe(fds.as_mut_ptr());

        try!(Errno::result(res));

        Ok((fds[0], fds[1]))
    }
}

pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
    unsafe {
        let mut fds: [c_int; 2] = mem::uninitialized();

        let res = libc::pipe(fds.as_mut_ptr());

        try!(Errno::result(res));

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
    let mut res = Ok(0);

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
    Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
}

pub fn isatty(fd: RawFd) -> Result<bool> {
    use libc;

    unsafe {
        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
        // we return `Ok(false)`
        if libc::isatty(fd) == 1 {
            Ok(true)
        } else {
            match Errno::last() {
                Errno::ENOTTY => Ok(false),
                err => Err(Error::Sys(err)),
            }
        }
    }
}

pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe {
            libc::unlink(cstr.as_ptr())
        }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res = try!(path.with_nix_path(|cstr| {
        unsafe { libc::chroot(cstr.as_ptr()) }
    }));

    Errno::result(res).map(drop)
}

#[inline]
pub fn fsync(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::fsync(fd) };

    Errno::result(res).map(drop)
}

// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`.
// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211
#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "emscripten"))]
#[inline]
pub fn fdatasync(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::fdatasync(fd) };

    Errno::result(res).map(drop)
}

// POSIX requires that getuid, geteuid, getgid, getegid are always successful,
// so no need to check return value or errno. See:
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html
//   - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html
#[inline]
pub fn getuid() -> uid_t {
    unsafe { libc::getuid() }
}

#[inline]
pub fn geteuid() -> uid_t {
    unsafe { libc::geteuid() }
}

#[inline]
pub fn getgid() -> gid_t {
    unsafe { libc::getgid() }
}

#[inline]
pub fn getegid() -> gid_t {
    unsafe { libc::getegid() }
}

#[inline]
pub fn setuid(uid: uid_t) -> Result<()> {
    let res = unsafe { libc::setuid(uid) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn setgid(gid: gid_t) -> Result<()> {
    let res = unsafe { libc::setgid(gid) };

    Errno::result(res).map(drop)
}

#[inline]
pub fn pause() -> Result<()> {
    let res = unsafe { libc::pause() };

    Errno::result(res).map(drop)
}

#[inline]
// Per POSIX, does not fail:
//   http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05
pub fn sleep(seconds: libc::c_uint) -> c_uint {
    unsafe { libc::sleep(seconds) }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux {
    use sys::syscall::{syscall, SYSPIVOTROOT};
    use {Errno, Result, NixPath};

    #[cfg(feature = "execvpe")]
    use std::ffi::CString;

    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
            new_root: &P1, put_old: &P2) -> Result<()> {
        let res = try!(try!(new_root.with_nix_path(|new_root| {
            put_old.with_nix_path(|put_old| {
                unsafe {
                    syscall(SYSPIVOTROOT, new_root.as_ptr(), put_old.as_ptr())
                }
            })
        })));

        Errno::result(res).map(drop)
    }

    #[inline]
    #[cfg(feature = "execvpe")]
    pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<()> {
        use std::ptr;
        use libc::c_char;

        let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
        args_p.push(ptr::null());

        let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
        env_p.push(ptr::null());

        unsafe {
            super::ffi::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
        };

        Err(Error::Sys(Errno::last()))
    }
}
<|endoftext|>