<commit_before>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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 std::mem;
use std::fmt;
use std::vec::Vec;

// Helper struct for *u16 manipulation.
#[allow(missing_copy_implementations)]
pub struct CU16String {
    buf: *const u16,
    /// length of buffer, including null
    len: usize,
}

impl CU16String {
    /// Create a CU16String from a pointer.
    pub unsafe fn new(buf: *const u16) -> CU16String {
        CU16String {
            buf: buf,
            len: {
                let mut length_counter = 0;
                loop {
                    if *buf.offset(length_counter)==0 {
                        break;
                    }
                    length_counter += 1;
                }
                length_counter as usize
            }
        }
    }

    /// Converts the CU16String into a `&[u16]` without copying.
    /// NULL is not included.
    ///
    /// # Failure
    ///
    /// Fails if the CU16String is null.
    #[inline]
    pub fn as_u16_vec<'a>(&'a self) -> &'a [u16] {
        if self.buf.is_null() { panic!("CU16String is null!"); }
        unsafe {
            mem::transmute((self.buf, self.len - 1))
        }
    }
}

impl fmt::Show for CU16String {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = if self.buf.is_null() {
            "".to_string()
        } else {
            String::from_utf16_lossy(self.as_u16_vec())
        };
        s.fmt(f)
    }
}

/// Parses a C utf-16 "multistring".
/// See `std::c_str::from_c_multistring` for detailed explanation.
pub unsafe fn from_c_u16_multistring<F>(buf: *const u16, count: Option<usize>, f: F) -> usize
    where F: Fn(&[u16]) {
    let mut curr_ptr: usize = buf as usize;
    let mut ctr = 0;
    let (limited_count, limit) = match count {
        Some(limit) => (true, limit),
        None => (false, 0)
    };
    while ((limited_count && ctr < limit) || !limited_count)
          && *(curr_ptr as *const u16) != 0 as u16 {
        let cstr = CU16String::new(curr_ptr as *const u16);
        f(cstr.as_u16_vec());
        curr_ptr += cstr.len * 2;
        ctr += 1;
    }
    return ctr;
}

/// A generic trait for converting a value to a `CU16String`, like `ToCStr`.
pub trait ToCU16Str {
    fn to_c_u16(&self) -> Vec<u16>;
}

impl<'a> ToCU16Str for &'a str {
    fn to_c_u16(&self) -> Vec<u16> {
        let mut t : Vec<u16> = self.utf16_units().collect();
        t.push(0u16);
        t
    }
}

impl ToCU16Str for String {
    fn to_c_u16(&self) -> Vec<u16> {
        self.as_slice().to_c_u16()
    }
}

impl<S: Str> ToCU16Str for Option<S> {
    fn to_c_u16(&self) -> Vec<u16> {
        match self {
            &None => Vec::new(),
            &Some(ref s) => s.as_slice().to_c_u16(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::CU16String;
    use super::from_c_u16_multistring;
    use std::str::from_utf16;

    #[test]
    fn test_as_u16_vec() {
        let u16s: &[u16] = [
            0xac00, 0x20, 0xac00, 0x00,
        ];

        let cu = unsafe { CU16String::new(u16s.as_ptr()) };
        let v = cu.as_u16_vec();
        assert_eq!(v, u16s.slice_to(u16s.len() - 1));
    }

    #[test]
    fn test_from_c_u16_multistring() {
        let test: &[u16] = [
            0xac00, 0x00,
            0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0xac02, 0x00,
            0x00,
        ];
        let compare = [
            "가",
            "가가",
            "가가가",
            "가가가갂",
        ];
        let mut i = 0;
        let buf = test.as_ptr();
        unsafe {
            from_c_u16_multistring(buf, None, |p| {
                let b = from_utf16(p).expect("invalid utf-16 sequence");
                assert_eq!(b.char_len(), i + 1);
                assert_eq!(b, compare[i].to_owned());
                i += 1;
            });
        }
        assert_eq!(i, 4);
    }
}
<commit_msg>rename fmt::Show to fmt::Display<commit_after>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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 std::mem;
use std::fmt;
use std::fmt::Display;
use std::vec::Vec;

// Helper struct for *u16 manipulation.
#[allow(missing_copy_implementations)]
pub struct CU16String {
    buf: *const u16,
    /// length of buffer, including null
    len: usize,
}

impl CU16String {
    /// Create a CU16String from a pointer.
    pub unsafe fn new(buf: *const u16) -> CU16String {
        CU16String {
            buf: buf,
            len: {
                let mut length_counter = 0;
                loop {
                    if *buf.offset(length_counter)==0 {
                        break;
                    }
                    length_counter += 1;
                }
                length_counter as usize
            }
        }
    }

    /// Converts the CU16String into a `&[u16]` without copying.
    /// NULL is not included.
    ///
    /// # Failure
    ///
    /// Fails if the CU16String is null.
    #[inline]
    pub fn as_u16_vec<'a>(&'a self) -> &'a [u16] {
        if self.buf.is_null() { panic!("CU16String is null!"); }
        unsafe {
            mem::transmute((self.buf, self.len - 1))
        }
    }
}

impl fmt::Display for CU16String {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = if self.buf.is_null() {
            "".to_string()
        } else {
            String::from_utf16_lossy(self.as_u16_vec())
        };
        s.fmt(f)
    }
}

/// Parses a C utf-16 "multistring".
/// See `std::c_str::from_c_multistring` for detailed explanation.
pub unsafe fn from_c_u16_multistring<F>(buf: *const u16, count: Option<usize>, f: F) -> usize
    where F: Fn(&[u16]) {
    let mut curr_ptr: usize = buf as usize;
    let mut ctr = 0;
    let (limited_count, limit) = match count {
        Some(limit) => (true, limit),
        None => (false, 0)
    };
    while ((limited_count && ctr < limit) || !limited_count)
          && *(curr_ptr as *const u16) != 0 as u16 {
        let cstr = CU16String::new(curr_ptr as *const u16);
        f(cstr.as_u16_vec());
        curr_ptr += cstr.len * 2;
        ctr += 1;
    }
    return ctr;
}

/// A generic trait for converting a value to a `CU16String`, like `ToCStr`.
pub trait ToCU16Str {
    fn to_c_u16(&self) -> Vec<u16>;
}

impl<'a> ToCU16Str for &'a str {
    fn to_c_u16(&self) -> Vec<u16> {
        let mut t : Vec<u16> = self.utf16_units().collect();
        t.push(0u16);
        t
    }
}

impl ToCU16Str for String {
    fn to_c_u16(&self) -> Vec<u16> {
        self.as_slice().to_c_u16()
    }
}

impl<S: Str> ToCU16Str for Option<S> {
    fn to_c_u16(&self) -> Vec<u16> {
        match self {
            &None => Vec::new(),
            &Some(ref s) => s.as_slice().to_c_u16(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::CU16String;
    use super::from_c_u16_multistring;
    use std::str::from_utf16;

    #[test]
    fn test_as_u16_vec() {
        let u16s: &[u16] = [
            0xac00, 0x20, 0xac00, 0x00,
        ];

        let cu = unsafe { CU16String::new(u16s.as_ptr()) };
        let v = cu.as_u16_vec();
        assert_eq!(v, u16s.slice_to(u16s.len() - 1));
    }

    #[test]
    fn test_from_c_u16_multistring() {
        let test: &[u16] = [
            0xac00, 0x00,
            0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0xac02, 0x00,
            0x00,
        ];
        let compare = [
            "가",
            "가가",
            "가가가",
            "가가가갂",
        ];
        let mut i = 0;
        let buf = test.as_ptr();
        unsafe {
            from_c_u16_multistring(buf, None, |p| {
                let b = from_utf16(p).expect("invalid utf-16 sequence");
                assert_eq!(b.char_len(), i + 1);
                assert_eq!(b, compare[i].to_owned());
                i += 1;
            });
        }
        assert_eq!(i, 4);
    }
}
<|endoftext|>


<commit_before>use anymap::AnyMap;
use std::any::Any;
use std::collections::HashMap;

use entity::Entity;
use EntityIterator;

/// Keeps track of entities and their components.
pub struct World {
    next_idx: usize,
    next_uuid: usize,
    /// Lists every entity with it's uuid.
    /// A uuid of `0` means an inactive entity.
    active: Vec<usize>,
    reusable_idxs: Vec<usize>,
    /// List of all the components.
    components: Vec<AnyMap>,

    parents: HashMap<Entity, Entity>,

    ent_added: HashMap<usize, usize>,
    ent_remove: HashMap<usize, usize>,
    ent_changed: HashMap<usize, usize>,
}

impl World {
    pub fn new() -> World {
        World {
            next_idx: 0,
            next_uuid: 1,
            active: Vec::new(),
            reusable_idxs: Vec::new(),
            components: Vec::new(),

            parents: HashMap::new(),

            ent_added: HashMap::new(),
            ent_remove: HashMap::new(),
            ent_changed: HashMap::new(),
        }
    }

    /// Adds a new entity.
    /// Will reuse an idx if available, if not it will increment the idx counter and allocate
    /// space for the components.
    /// The new entity will only show up in the iterator and list after
    /// `confirm_changes()` is called.
    pub fn add_entity(&mut self) -> Entity {
        // Get the idx.
        let idx = match self.reusable_idxs.pop() {
            None => {
                // No reusable idxs, so make a new one.
                let idx = self.next_idx;
                self.next_idx += 1;
                // And add a new entry to the components vector.
                self.components.push(AnyMap::new());
                idx
            },
            Some(idx) => idx,
        };

        // Get the uuid.
        let uuid = self.next_uuid;
        self.next_uuid += 1;

        // Register the entity as active.
        if self.active.len() <= uuid {
            self.active.resize(uuid + 1, 0);
        }
        self.active[idx] = uuid;

        // Register the entity as newly added.
        self.ent_added.insert(idx, uuid);

        Entity { idx: idx, uuid: uuid }
    }

    /// Slates an entity for removal.
    /// The removal won't actually be done until `confirm_changes()` is called.
    pub fn remove_entity(&mut self, entity: Entity) {
        self.ent_remove.insert(entity.idx, entity.uuid);
    }

    /// Removes all entities currently slated for removal.
    /// Also clears the list of removed and changed entities.
    pub fn confirm_changes(&mut self) {
        // Remove all entities in the `remove` list.
        for (&idx, &uuid) in self.ent_remove.iter() {
            if self.is_valid_entity(&Entity{ idx: idx, uuid: uuid }) {
                self.active[idx] = 0;
                self.reusable_idxs.push(idx);
                // Clear the components associated with the entity.
                self.components[idx].clear();
            }
        }

        self.ent_added.clear();
        self.ent_remove.clear();
        self.ent_changed.clear();
    }

    /// Checks if an `Entity` reference is valid.
    pub fn is_valid_entity(&self, entity: &Entity) -> bool {
        match self.active.get(entity.idx) {
            Some(&uuid) => {
                uuid != 0 && entity.uuid == uuid
            },
            None => false,
        }
    }

    /// Returns the uuid currently associated with an entity index.
    /// Returns 0 for nonexistent entities.
    pub fn get_uuid(&self, idx: usize) -> usize {
        match self.active.get(idx) {
            Some(&uuid) => uuid,
            None => 0,
        }
    }

    /// Adds a new component to an entity.
    /// If the entity already had that component, that component is returned.
    /// Otherwise, `None` is returned.
    pub fn add_component<T: Any>(&mut self, entity: &Entity, component: T) -> Option<T> {
        if self.is_valid_entity(entity) {
            self.ent_changed.insert(entity.idx, entity.uuid);
            return self.components[entity.idx].insert(component);
        }
        None
    }

    /// Returns whether an entity has a specific component or not.
    /// Does also search the parents for the component.
    pub fn has_component<T: Any>(&self, entity: &Entity) -> bool {
        if self.is_valid_entity(entity) {
            if self.components[entity.idx].contains::<T>() {
                return true;
            } else {
                // This entity doesn't have the component.
                // See if has inherited it from a parent.
                let mut cur_ent = *entity;
                println!("Start {}, {}", cur_ent.idx, cur_ent.uuid);
                loop  {
                    if self.is_valid_entity(&cur_ent) {
                        if self.components[cur_ent.idx].contains::<T>() {
                            return true;
                        }
                        if let Some(parent) = self.get_parent(&cur_ent) {
                            cur_ent = parent;
                            println!("Parent {}, {}", cur_ent.idx, cur_ent.uuid);
                        } else {
                            // No parents left.
                            break;
                        }
                    } else {
                        // No valid parents left.
                        break;
                    }
                }
            }
        }
        false
    }

    /// Returns a reference to a component.
    /// If a component does not exist, but it does in the parent,
    /// the parent's component will be returned.
    pub fn get_component<T: Any>(&self, entity: &Entity) -> Option<&T> {
        if self.is_valid_entity(entity) {
            // See if the component is there, if so: return it.
            match self.components[entity.idx].get::<T>() {
                Some(comp) => return Some(comp),
                None => {
                    // This entity doesn't have the component.
                    // See if has inherited it from a parent.
                    let mut cur_ent = *entity;
                    loop  {
                        if self.is_valid_entity(&cur_ent) {
                            if let Some(comp) = self.components[cur_ent.idx].get::<T>() {
                                return Some(comp);
                            }
                            if let Some(parent) = self.get_parent(&cur_ent) {
                                cur_ent = parent;
                            } else {
                                // No parents left.
                                break;
                            }
                        } else {
                            // No valid parents left.
                            break;
                        }
                    }
                }
            }
        }
        None
    }

    /// Returns a mutable reference to a component, if it exists.
    /// Mutable references won't be retreived from an entities parent,
    /// as this will easily lead to bugs that are very hard to debug.
    pub fn get_mut_component<T: Any>(&mut self, entity: &Entity) -> Option<&mut T> {
        if self.is_valid_entity(entity) {
            let comp = self.components[entity.idx].get_mut::<T>();

            return match comp {
                Some(val) => {
                    self.ent_changed.insert(entity.idx, entity.uuid);
                    Some(val)
                },
                None => None,
            }
        }
        None
    }

    /// Removes a component from an entity.
    /// Returning the component if it existed, or `None` if it didn't.
    pub fn remove_component<T: Any>(&mut self, entity: &Entity) -> Option<T> {
        if self.is_valid_entity(entity) {
            let res = self.components[entity.idx].remove::<T>();

            return match res {
                Some(res) => {
                    self.ent_changed.insert(entity.idx, entity.uuid);
                    Some(res)
                },
                None => None,
            }
        }
        None
    }

    /// Sets the parent of an entity.
    /// Checks if both the entity and the parent are valid.
    pub fn set_parent(&mut self, entity: &Entity, parent: &Entity) -> bool {
        if self.is_valid_entity(entity) && self.is_valid_entity(parent) {
            self.parents.insert(entity.clone(), parent.clone());
        } else {
            return false
        }
        true
    }

    /// Returns the parent of an entity, if it has one.
    pub fn get_parent(&self, entity: &Entity) -> Option<Entity> {
        if self.is_valid_entity(entity) {
            if let Some(parent) = self.parents.get(entity) {
                return Some(parent.clone());
            }
        }
        None
    }

    /// Temoves the parenting link from an Entity.
    pub fn unlink_parent(&mut self, entity: &Entity) {
        if self.is_valid_entity(entity) {
            self.parents.remove(entity);
        }
    }

    /// Returns a lazy iterator for immutable acces to the entities.
    pub fn iterator(&self) -> EntityIterator {
        EntityIterator {
            active: &self.active,
            added: &self.ent_added,
            curr: 0,
        }
    }

    /// Returns a vector listing all the currently active entities.
    /// Can be used to iterate over all active entities while making changes to the world.
    pub fn list_entities(&self) -> Vec<Entity> {
        self.active.iter().enumerate()
            .filter(|&(_, &uuid)| uuid != 0)
            .filter(|&(idx, &uuid)| {
                if let Some(&other_uuid) = self.ent_added.get(&idx) {
                    if uuid == other_uuid {
                        return false;
                    }
                }
                true
            })
            .map(|(idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }

    /// Returns a vector listing all the recently added entities.
    pub fn list_additions(&self) -> Vec<Entity> {
        self.ent_added.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }
    /// Returns a vector listing all the entities currently slated for removal.
    pub fn list_removals(&self) -> Vec<Entity> {
        self.ent_remove.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }

    /// Returns a vector listing all the entities that have changed since the last call of.
    /// `confirm_changes`.
    pub fn list_changes(&self) -> Vec<Entity> {
        self.ent_changed.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }
}
<commit_msg>`confirm_changes` now also checks for any invalid parenting links and removes them.<commit_after>use anymap::AnyMap;
use std::any::Any;
use std::collections::HashMap;

use entity::Entity;
use EntityIterator;

/// Keeps track of entities and their components.
pub struct World {
    next_idx: usize,
    next_uuid: usize,
    /// Lists every entity with it's uuid.
    /// A uuid of `0` means an inactive entity.
    active: Vec<usize>,
    reusable_idxs: Vec<usize>,
    /// List of all the components.
    components: Vec<AnyMap>,

    parents: HashMap<Entity, Entity>,

    ent_added: HashMap<usize, usize>,
    ent_remove: HashMap<usize, usize>,
    ent_changed: HashMap<usize, usize>,
}

impl World {
    pub fn new() -> World {
        World {
            next_idx: 0,
            next_uuid: 1,
            active: Vec::new(),
            reusable_idxs: Vec::new(),
            components: Vec::new(),

            parents: HashMap::new(),

            ent_added: HashMap::new(),
            ent_remove: HashMap::new(),
            ent_changed: HashMap::new(),
        }
    }

    /// Adds a new entity.
    /// Will reuse an idx if available, if not it will increment the idx counter and allocate
    /// space for the components.
    /// The new entity will only show up in the iterator and list after
    /// `confirm_changes()` is called.
    pub fn add_entity(&mut self) -> Entity {
        // Get the idx.
        let idx = match self.reusable_idxs.pop() {
            None => {
                // No reusable idxs, so make a new one.
                let idx = self.next_idx;
                self.next_idx += 1;
                // And add a new entry to the components vector.
                self.components.push(AnyMap::new());
                idx
            },
            Some(idx) => idx,
        };

        // Get the uuid.
        let uuid = self.next_uuid;
        self.next_uuid += 1;

        // Register the entity as active.
        if self.active.len() <= uuid {
            self.active.resize(uuid + 1, 0);
        }
        self.active[idx] = uuid;

        // Register the entity as newly added.
        self.ent_added.insert(idx, uuid);

        Entity { idx: idx, uuid: uuid }
    }

    /// Slates an entity for removal.
    /// The removal won't actually be done until `confirm_changes()` is called.
    pub fn remove_entity(&mut self, entity: Entity) {
        self.ent_remove.insert(entity.idx, entity.uuid);
    }

    /// Removes all entities currently slated for removal.
    /// Also clears the lists of added, removed and changed entities and
    /// checks all entries in the `parents` hashmap for validity.
    pub fn confirm_changes(&mut self) {
        // Remove all entities in the `remove` list.
        for (&idx, &uuid) in self.ent_remove.iter() {
            if self.is_valid_entity(&Entity{ idx: idx, uuid: uuid }) {
                self.active[idx] = 0;
                self.reusable_idxs.push(idx);
                // Clear the components associated with the entity.
                self.components[idx].clear();
            }
        }

        // Check if there are any invalid parent links.
        for (child, parent) in self.parents.clone().iter() {
            if !(self.is_valid_entity(child) && self.is_valid_entity(parent)) {
                self.parents.remove(child);
            }
        }

        self.ent_added.clear();
        self.ent_remove.clear();
        self.ent_changed.clear();
    }

    /// Checks if an `Entity` reference is valid.
    pub fn is_valid_entity(&self, entity: &Entity) -> bool {
        match self.active.get(entity.idx) {
            Some(&uuid) => {
                uuid != 0 && entity.uuid == uuid
            },
            None => false,
        }
    }

    /// Returns the uuid currently associated with an entity index.
    /// Returns 0 for nonexistent entities.
    pub fn get_uuid(&self, idx: usize) -> usize {
        match self.active.get(idx) {
            Some(&uuid) => uuid,
            None => 0,
        }
    }

    /// Adds a new component to an entity.
    /// If the entity already had that component, that component is returned.
    /// Otherwise, `None` is returned.
    pub fn add_component<T: Any>(&mut self, entity: &Entity, component: T) -> Option<T> {
        if self.is_valid_entity(entity) {
            self.ent_changed.insert(entity.idx, entity.uuid);
            return self.components[entity.idx].insert(component);
        }
        None
    }

    /// Returns whether an entity has a specific component or not.
    /// Does also search the parents for the component.
    pub fn has_component<T: Any>(&self, entity: &Entity) -> bool {
        if self.is_valid_entity(entity) {
            if self.components[entity.idx].contains::<T>() {
                return true;
            } else {
                // This entity doesn't have the component.
                // See if has inherited it from a parent.
                let mut cur_ent = *entity;
                println!("Start {}, {}", cur_ent.idx, cur_ent.uuid);
                loop  {
                    if self.is_valid_entity(&cur_ent) {
                        if self.components[cur_ent.idx].contains::<T>() {
                            return true;
                        }
                        if let Some(parent) = self.get_parent(&cur_ent) {
                            cur_ent = parent;
                            println!("Parent {}, {}", cur_ent.idx, cur_ent.uuid);
                        } else {
                            // No parents left.
                            break;
                        }
                    } else {
                        // No valid parents left.
                        break;
                    }
                }
            }
        }
        false
    }

    /// Returns a reference to a component.
    /// If a component does not exist, but it does in the parent,
    /// the parent's component will be returned.
    pub fn get_component<T: Any>(&self, entity: &Entity) -> Option<&T> {
        if self.is_valid_entity(entity) {
            // See if the component is there, if so: return it.
            match self.components[entity.idx].get::<T>() {
                Some(comp) => return Some(comp),
                None => {
                    // This entity doesn't have the component.
                    // See if has inherited it from a parent.
                    let mut cur_ent = *entity;
                    loop  {
                        if self.is_valid_entity(&cur_ent) {
                            if let Some(comp) = self.components[cur_ent.idx].get::<T>() {
                                return Some(comp);
                            }
                            if let Some(parent) = self.get_parent(&cur_ent) {
                                cur_ent = parent;
                            } else {
                                // No parents left.
                                break;
                            }
                        } else {
                            // No valid parents left.
                            break;
                        }
                    }
                }
            }
        }
        None
    }

    /// Returns a mutable reference to a component, if it exists.
    /// Mutable references won't be retreived from an entities parent,
    /// as this will easily lead to bugs that are very hard to debug.
    pub fn get_mut_component<T: Any>(&mut self, entity: &Entity) -> Option<&mut T> {
        if self.is_valid_entity(entity) {
            let comp = self.components[entity.idx].get_mut::<T>();

            return match comp {
                Some(val) => {
                    self.ent_changed.insert(entity.idx, entity.uuid);
                    Some(val)
                },
                None => None,
            }
        }
        None
    }

    /// Removes a component from an entity.
    /// Returning the component if it existed, or `None` if it didn't.
    pub fn remove_component<T: Any>(&mut self, entity: &Entity) -> Option<T> {
        if self.is_valid_entity(entity) {
            let res = self.components[entity.idx].remove::<T>();

            return match res {
                Some(res) => {
                    self.ent_changed.insert(entity.idx, entity.uuid);
                    Some(res)
                },
                None => None,
            }
        }
        None
    }

    /// Sets the parent of an entity.
    /// Checks if both the entity and the parent are valid.
    pub fn set_parent(&mut self, entity: &Entity, parent: &Entity) -> bool {
        if self.is_valid_entity(entity) && self.is_valid_entity(parent) {
            self.parents.insert(entity.clone(), parent.clone());
        } else {
            return false
        }
        true
    }

    /// Returns the parent of an entity, if it has one.
    pub fn get_parent(&self, entity: &Entity) -> Option<Entity> {
        if self.is_valid_entity(entity) {
            if let Some(parent) = self.parents.get(entity) {
                return Some(parent.clone());
            }
        }
        None
    }

    /// Temoves the parenting link from an Entity.
    pub fn unlink_parent(&mut self, entity: &Entity) {
        if self.is_valid_entity(entity) {
            self.parents.remove(entity);
        }
    }

    /// Returns a lazy iterator for immutable acces to the entities.
    pub fn iterator(&self) -> EntityIterator {
        EntityIterator {
            active: &self.active,
            added: &self.ent_added,
            curr: 0,
        }
    }

    /// Returns a vector listing all the currently active entities.
    /// Can be used to iterate over all active entities while making changes to the world.
    pub fn list_entities(&self) -> Vec<Entity> {
        self.active.iter().enumerate()
            .filter(|&(_, &uuid)| uuid != 0)
            .filter(|&(idx, &uuid)| {
                if let Some(&other_uuid) = self.ent_added.get(&idx) {
                    if uuid == other_uuid {
                        return false;
                    }
                }
                true
            })
            .map(|(idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }

    /// Returns a vector listing all the recently added entities.
    pub fn list_additions(&self) -> Vec<Entity> {
        self.ent_added.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }
    /// Returns a vector listing all the entities currently slated for removal.
    pub fn list_removals(&self) -> Vec<Entity> {
        self.ent_remove.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }

    /// Returns a vector listing all the entities that have changed since the last call of.
    /// `confirm_changes`.
    pub fn list_changes(&self) -> Vec<Entity> {
        self.ent_changed.iter()
            .map(|(&idx, &uuid)| Entity{ idx: idx, uuid: uuid })
            .collect::<Vec<Entity>>()
    }
}
<|endoftext|>


<commit_before>use SChunks;
use std::fs::File;
use std::io::{Error, Write};

/// This function fills the buffer of a given local file, with the content of chunks.
pub fn write_file(local_file_buf: &mut File, chunks: &SChunks) -> Result<(), Error> {

    // Get the access to the chunks
    let chunks_m = chunks.lock().unwrap();

    // For each ones, write it into the file buffer
    for chunk in chunks_m.iter() {
        match local_file_buf.write_all(chunk) {
            Ok(_) => (),
            Err(error) => return Err(error),
        }
    }

    // Return a positive result if the remote content has been saved
    Ok(())
}<commit_msg>Little modifications<commit_after>use SChunks;
use std::fs::File;
use std::io::{Error, Write};

/// This function fills the buffer of a given local file, with the content of chunks.
pub fn write_file(local_file_buf: &mut File, chunks: &SChunks) -> Result<(), Error> {

    // Get the access to the chunks
    let chunks_m = chunks.lock().unwrap();

    // For each ones, write it into the file buffer
    for chunk in chunks_m.iter() {
        match local_file_buf.write_all(chunk) {
            Ok(_) => (),
            Err(error) => return Err(error),
        }
    }

    // Return a positive result if the remote content has been saved
    Ok(())
}
<|endoftext|>


<commit_before>extern crate rustc_typeck as typeck;

use syntax::ptr::P;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, mt, MethodTraitItemId};
use rustc::middle::def::{DefTy, DefStruct, DefTrait};
use syntax::codemap::{Span, Spanned};

declare_lint!(pub LEN_ZERO, Warn,
              "Warn on usage of double-mut refs, e.g. '&mut &mut ...'");

declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn,
              "Warn on traits and impls that have .len() but not .is_empty()");

#[derive(Copy,Clone)]
pub struct LenZero;

impl LintPass for LenZero {
	fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
	}

	fn check_item(&mut self, cx: &Context, item: &Item) {
		match &item.node {
			&ItemTrait(_, _, _, ref trait_items) =>
				check_trait_items(cx, item, trait_items),
			&ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait
				check_impl_items(cx, item, impl_items),
			_ => ()
		}
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) =
				&expr.node {
			match cmp {
				BiEq => check_cmp(cx, expr.span, left, right, ""),
				BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"),
				_ => ()
			}
		}
	}
}

fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) {
	fn is_named_self(item: &TraitItem, name: &str) -> bool {
		item.ident.as_str() == name && item.attrs.len() == 0
	}

	if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
		//cx.span_lint(LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
		for i in trait_items {
			if is_named_self(i, "len") {
				cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span,
					&format!("Trait '{}' has a '.len()' method, but no \
						'.is_empty()' method. Consider adding one.",
						item.ident.as_str()));
			}
		};
	}
}

fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) {
	fn is_named_self(item: &ImplItem, name: &str) -> bool {
		item.ident.as_str() == name && item.attrs.len() == 0
	}

	if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
		for i in impl_items {
			if is_named_self(i, "len") {
				cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span,
					&format!("Item '{}' has a '.len()' method, but no \
						'.is_empty()' method. Consider adding one.",
						item.ident.as_str()));
				return;
			}
		}
	}
}

fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) {
	match (&left.node, &right.node) {
		(&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) =>
			check_len_zero(cx, span, method, args, lit, empty),
		(&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) =>
			check_len_zero(cx, span, method, args, lit, empty),
		_ => ()
	}
}

fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent,
		args: &[P<Expr>], lit: &Lit, empty: &str) {
	if let &Spanned{node: LitInt(0, _), ..} = lit {
		if method.node.as_str() == "len" && args.len() == 1 {
			cx.span_lint(LEN_ZERO, span, &format!(
				"Consider replacing the len comparison with '{}_.is_empty()' if available",
					empty))
		}
	}
}
<commit_msg>Fix copy+paste in description of LEN_ZERO<commit_after>extern crate rustc_typeck as typeck;

use syntax::ptr::P;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, mt, MethodTraitItemId};
use rustc::middle::def::{DefTy, DefStruct, DefTrait};
use syntax::codemap::{Span, Spanned};

declare_lint!(pub LEN_ZERO, Warn,
              "Warn when .is_empty() could be used instead of checking .len()");

declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn,
              "Warn on traits and impls that have .len() but not .is_empty()");

#[derive(Copy,Clone)]
pub struct LenZero;

impl LintPass for LenZero {
	fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
	}

	fn check_item(&mut self, cx: &Context, item: &Item) {
		match &item.node {
			&ItemTrait(_, _, _, ref trait_items) =>
				check_trait_items(cx, item, trait_items),
			&ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait
				check_impl_items(cx, item, impl_items),
			_ => ()
		}
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) =
				&expr.node {
			match cmp {
				BiEq => check_cmp(cx, expr.span, left, right, ""),
				BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"),
				_ => ()
			}
		}
	}
}

fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) {
	fn is_named_self(item: &TraitItem, name: &str) -> bool {
		item.ident.as_str() == name && item.attrs.len() == 0
	}

	if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
		//cx.span_lint(LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
		for i in trait_items {
			if is_named_self(i, "len") {
				cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span,
					&format!("Trait '{}' has a '.len()' method, but no \
						'.is_empty()' method. Consider adding one.",
						item.ident.as_str()));
			}
		};
	}
}

fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) {
	fn is_named_self(item: &ImplItem, name: &str) -> bool {
		item.ident.as_str() == name && item.attrs.len() == 0
	}

	if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
		for i in impl_items {
			if is_named_self(i, "len") {
				cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span,
					&format!("Item '{}' has a '.len()' method, but no \
						'.is_empty()' method. Consider adding one.",
						item.ident.as_str()));
				return;
			}
		}
	}
}

fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) {
	match (&left.node, &right.node) {
		(&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) =>
			check_len_zero(cx, span, method, args, lit, empty),
		(&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) =>
			check_len_zero(cx, span, method, args, lit, empty),
		_ => ()
	}
}

fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent,
		args: &[P<Expr>], lit: &Lit, empty: &str) {
	if let &Spanned{node: LitInt(0, _), ..} = lit {
		if method.node.as_str() == "len" && args.len() == 1 {
			cx.span_lint(LEN_ZERO, span, &format!(
				"Consider replacing the len comparison with '{}_.is_empty()' if available",
					empty))
		}
	}
}
<|endoftext|>


<commit_before>
use std::iter;
use std::num::{Float, NumCast};

/// An iterator of `n` evenly spaced floats.
///
/// Iterator element type is `F`.
pub type Linspace<F> = iter::Take<iter::Counter<F>>;

/// Return an iterator with `n` elements, where the first
/// element is `a` and the last element is `b`.
///
/// Iterator element type is `F`.
///
/// ```
/// use itertools as it;
/// let mut xs = it::linspace::<f32>(0., 1., 5);
/// assert_eq!(xs.collect::<Vec<_>>(),
///            vec![0., 0.25, 0.5, 0.75, 1.0]);
/// ```
#[inline]
pub fn linspace<F>(a: F, b: F, n: usize) -> Linspace<F> where
    F: Float,
{
    let nf: F = NumCast::from(n).unwrap();
    let step = (b - a)/(nf - Float::one());
    iter::count(a, step).take(n)
}
<commit_msg>Use .step_by instead of iter::counter<commit_after>
use std::ops::RangeFrom;
use std::iter;
use std::num::{Float, NumCast};

/// An iterator of `n` evenly spaced floats.
///
/// Iterator element type is `F`.
pub type Linspace<F> = iter::Take<iter::StepBy<F, RangeFrom<F>>>;

/// Return an iterator with `n` elements, where the first
/// element is `a` and the last element is `b`.
///
/// Iterator element type is `F`.
///
/// ```
/// use itertools as it;
/// let mut xs = it::linspace::<f32>(0., 1., 5);
/// assert_eq!(xs.collect::<Vec<_>>(),
///            vec![0., 0.25, 0.5, 0.75, 1.0]);
/// ```
#[inline]
pub fn linspace<F>(a: F, b: F, n: usize) -> Linspace<F> where
    F: Float,
{
    let nf: F = NumCast::from(n).unwrap();
    let step = (b - a)/(nf - Float::one());
    (a..).step_by(step).take(n)
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, JoinHandle};

use regex::Regex;
use threadpool::ThreadPool;

use config::Config;
use dir_pool::DirPool;
use git::Git;
use github;
use github::api::Session;
use messenger;
use slack::SlackAttachmentBuilder;

pub fn merge_pull_request(session: &Session, dir_pool: &DirPool, owner: &str, repo: &str,
                          pull_request: &github::PullRequest, target_branch: &str)
                          -> Result<github::PullRequest, String> {
    Merger::new(session, dir_pool).merge_pull_request(owner, repo, pull_request, target_branch)
}

struct Merger<'a> {
    git: Git,
    session: &'a Session,
    dir_pool: &'a DirPool,
}

impl<'a> Merger<'a> {
    pub fn new(session: &'a Session, dir_pool: &'a DirPool) -> Merger<'a> {
        Merger {
            git: Git::new(session.github_host(), session.github_token()),
            session: session,
            dir_pool: dir_pool,
        }
    }

    pub fn merge_pull_request(&self, owner: &str, repo: &str, pull_request: &github::PullRequest,
                              target_branch: &str)
                              -> Result<github::PullRequest, String> {
        if !pull_request.is_merged() {
            return Err(format!("Pull Request #{} is not yet merged.", pull_request.number));
        }

        let merge_commit_sha;
        if let Some(ref sha) = pull_request.merge_commit_sha {
            merge_commit_sha = sha;
        } else {
            return Err(format!("Pull Request #{} has no merge commit.", pull_request.number));
        }

        // strip everything before last slash
        let regex = Regex::new(r".*/").unwrap();
        let pr_branch_name = format!("{}-{}",
                                     regex.replace(&pull_request.head.ref_name, ""),
                                     regex.replace(&target_branch, ""));

        let held_clone_dir = self.dir_pool.take_directory(self.session.github_host(), owner, repo);
        let clone_dir = held_clone_dir.dir();
        try!(self.clone_repo(owner, repo, &clone_dir));

        // make sure there isn't already such a branch
        let current_remotes = try!(self.git.run(&["ls-remote", "--heads"], &clone_dir));
        if current_remotes.contains(&format!("refs/heads/{}", pr_branch_name)) {
            return Err(format!("PR branch already exists on origin: '{}'", pr_branch_name));
        }

        let (title, body) = try!(self.cherry_pick(&clone_dir,
                                                  &merge_commit_sha,
                                                  &pr_branch_name,
                                                  pull_request.number,
                                                  &target_branch,
                                                  &pull_request.base.ref_name));

        try!(self.git
            .run(&["push", "origin", &format!("{}:{}", pr_branch_name, pr_branch_name)],
                 &clone_dir));

        let new_pr = try!(self.session
            .create_pull_request(owner, repo, &title, &body, &pr_branch_name, &target_branch));

        let assignees: Vec<String> =
            pull_request.assignees.iter().map(|a| a.login().to_string()).collect();
        try!(self.session.assign_pull_request(owner, repo, new_pr.number, assignees));

        Ok(new_pr)
    }

    fn clone_repo(&self, owner: &str, repo: &str, clone_dir: &PathBuf) -> Result<(), String> {
        let url = format!("https://{}@{}/{}/{}",
                          self.session.user().login(),
                          self.session.github_host(),
                          owner,
                          repo);

        if clone_dir.join(".git").exists() {
            try!(self.git.run(&["fetch"], clone_dir));
        } else {
            if let Err(e) = fs::create_dir_all(&clone_dir) {
                return Err(format!("Error creating clone directory '{:?}': {}", clone_dir, e));
            }
            try!(self.git.run(&["clone", &url, "."], clone_dir));
        }

        Ok(())
    }

    fn cherry_pick(&self, clone_dir: &PathBuf, commit_hash: &str, pr_branch_name: &str,
                   pr_number: u32, target_branch: &str, orig_base_branch: &str)
                   -> Result<(String, String), String> {
        let real_target_branch = format!("origin/{}", target_branch);

        // clean up state
        try!(self.git.run(&["reset", "--hard"], clone_dir));
        try!(self.git.run(&["clean", "-fdx"], clone_dir));

        // setup branch
        let current_branch = try!(self.git.run(&["rev-parse", "--abbrev-ref", "HEAD"], clone_dir));
        if current_branch == pr_branch_name {
            try!(self.git.run(&["reset", "--hard", &real_target_branch], clone_dir));
        } else {
            // delete if it exists
            let has_branch = try!(self.git.has_branch(pr_branch_name, clone_dir));
            if has_branch {
                try!(self.git.run(&["branch", "-D", pr_branch_name], clone_dir));
            }
            // recreate branch
            try!(self.git.run(&["checkout", "-b", pr_branch_name, &real_target_branch],
                              clone_dir));
        }

        // cherry-pick!
        try!(self.git.run(&["cherry-pick", "-X", "ignore-all-space", commit_hash],
                          clone_dir));

        let desc = try!(self.get_commit_desc(clone_dir, commit_hash));

        // grab original title and strip out the PR number at the end
        let pr_regex = Regex::new(r"(\s*\(#\d+\))+$").unwrap();
        let orig_title = pr_regex.replace(&desc.0, "");
        // strip out 'release' from the prefix to keep titles shorter
        let release_branch_regex = Regex::new(r"^release/").unwrap();
        let title = format!("{}->{}: {}",
                            orig_base_branch,
                            release_branch_regex.replace(target_branch, ""),
                            orig_title);
        let mut body = desc.1;

        if body.len() != 0 {
            body += "\n\n";
        }
        body += format!("(cherry-picked from {}, PR #{})",
                        &commit_hash[0..7],
                        pr_number)
            .as_str();

        // change commit message
        try!(self.git.run_with_stdin(&["commit", "--amend", "-F", "-"],
                                     clone_dir,
                                     &format!("{}\n\n{}", title, body)));

        Ok((title, body))
    }

    // returns (title, body)
    fn get_commit_desc(&self, clone_dir: &PathBuf, commit_hash: &str)
                       -> Result<(String, String), String> {
        let lines: Vec<String> = try!(self.git
                .run(&["log", "-1", "--pretty=%B", commit_hash], clone_dir))
            .split("\n")
            .map(|l| l.trim().to_string())
            .collect();

        if lines.len() == 0 {
            return Err(format!("Empty commit message found!"));
        }

        let title = lines[0].clone();

        let mut body = String::new();
        // skip the blank line
        if lines.len() > 2 {
            body = lines[2..].join("\n");
            body += "\n";
        }

        Ok((title, body))
    }
}

pub enum PRMergeMessage {
    Stop,
    Merge {
        repo: github::Repo,
        pull_request: github::PullRequest,
        target_branch: String,
    },
}

pub struct Worker {
    sender: Mutex<Sender<PRMergeMessage>>,
    handle: Option<JoinHandle<()>>,
}

impl PRMergeMessage {
    pub fn merge(repo: &github::Repo, pull_request: &github::PullRequest, target_branch: &str)
                 -> PRMergeMessage {
        PRMergeMessage::Merge {
            repo: repo.clone(),
            pull_request: pull_request.clone(),
            target_branch: target_branch.to_string(),
        }
    }
}

impl Drop for Worker {
    fn drop(&mut self) {
        let sender = self.new_sender();
        match sender.send(PRMergeMessage::Stop) {
            Ok(_) => {
                match self.handle.take().unwrap().join() {
                    Ok(_) => (),
                    Err(e) => error!("Error shutting down worker: {:?}", e),
                }
            }
            Err(e) => error!("Error sending stop message: {}", e),
        }
    }
}

impl Worker {
    pub fn new(max_concurrency: usize, config: Arc<Config>, github_session: Arc<Session>)
               -> Worker {

        let (tx, rx) = channel();

        let clone_root_dir = config.clone_root_dir.to_string();

        let handle = thread::spawn(move || {
            let dir_pool = Arc::new(DirPool::new(&clone_root_dir));
            let thread_pool = ThreadPool::new(max_concurrency);

            loop {
                match rx.recv() {
                    Ok(msg) => {
                        match msg {
                            PRMergeMessage::Stop => break,
                            PRMergeMessage::Merge { repo, pull_request, target_branch } => {

                                let github_session = github_session.clone();
                                let dir_pool = dir_pool.clone();
                                let config = config.clone();
                                // launch another thread to do the merge
                                thread_pool.execute(move || {
                                    if let Err(e) = merge_pull_request(&github_session,
                                                                       &dir_pool,
                                                                       &repo.owner.login(),
                                                                       &repo.name,
                                                                       &pull_request,
                                                                       &target_branch) {

                                        let attach = SlackAttachmentBuilder::new(&e)
                                            .title(format!("Source PR: #{}: \"{}\"",
                                                           pull_request.number,
                                                           pull_request.title)
                                                .as_str())
                                            .title_link(pull_request.html_url.clone())
                                            .color("danger")
                                            .build();

                                        let messenger = messenger::from_config(config);
                                        messenger.send_to_owner("Error creating merge Pull Request",
                                                           &vec![attach],
                                                           &pull_request.user,
                                                           &repo);
                                    }
                                });
                            }
                        }
                    }
                    Err(e) => error!("Error receiving message: {}", e),
                };
            }
        });

        Worker {
            sender: Mutex::new(tx),
            handle: Some(handle),
        }
    }

    pub fn new_sender(&self) -> Sender<PRMergeMessage> {
        let sender = self.sender.lock().unwrap();
        sender.clone()
    }
}
<commit_msg>Separate out worker runner struct (#17)<commit_after>use std::fs;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{self, JoinHandle};

use regex::Regex;
use threadpool::ThreadPool;

use config::Config;
use dir_pool::DirPool;
use git::Git;
use github;
use github::api::Session;
use messenger;
use slack::SlackAttachmentBuilder;

pub fn merge_pull_request(session: &Session, dir_pool: &DirPool, owner: &str, repo: &str,
                          pull_request: &github::PullRequest, target_branch: &str)
                          -> Result<github::PullRequest, String> {
    Merger::new(session, dir_pool).merge_pull_request(owner, repo, pull_request, target_branch)
}

struct Merger<'a> {
    git: Git,
    session: &'a Session,
    dir_pool: &'a DirPool,
}

impl<'a> Merger<'a> {
    pub fn new(session: &'a Session, dir_pool: &'a DirPool) -> Merger<'a> {
        Merger {
            git: Git::new(session.github_host(), session.github_token()),
            session: session,
            dir_pool: dir_pool,
        }
    }

    pub fn merge_pull_request(&self, owner: &str, repo: &str, pull_request: &github::PullRequest,
                              target_branch: &str)
                              -> Result<github::PullRequest, String> {
        if !pull_request.is_merged() {
            return Err(format!("Pull Request #{} is not yet merged.", pull_request.number));
        }

        let merge_commit_sha;
        if let Some(ref sha) = pull_request.merge_commit_sha {
            merge_commit_sha = sha;
        } else {
            return Err(format!("Pull Request #{} has no merge commit.", pull_request.number));
        }

        // strip everything before last slash
        let regex = Regex::new(r".*/").unwrap();
        let pr_branch_name = format!("{}-{}",
                                     regex.replace(&pull_request.head.ref_name, ""),
                                     regex.replace(&target_branch, ""));

        let held_clone_dir = self.dir_pool.take_directory(self.session.github_host(), owner, repo);
        let clone_dir = held_clone_dir.dir();
        try!(self.clone_repo(owner, repo, &clone_dir));

        // make sure there isn't already such a branch
        let current_remotes = try!(self.git.run(&["ls-remote", "--heads"], &clone_dir));
        if current_remotes.contains(&format!("refs/heads/{}", pr_branch_name)) {
            return Err(format!("PR branch already exists on origin: '{}'", pr_branch_name));
        }

        let (title, body) = try!(self.cherry_pick(&clone_dir,
                                                  &merge_commit_sha,
                                                  &pr_branch_name,
                                                  pull_request.number,
                                                  &target_branch,
                                                  &pull_request.base.ref_name));

        try!(self.git
            .run(&["push", "origin", &format!("{}:{}", pr_branch_name, pr_branch_name)],
                 &clone_dir));

        let new_pr = try!(self.session
            .create_pull_request(owner, repo, &title, &body, &pr_branch_name, &target_branch));

        let assignees: Vec<String> =
            pull_request.assignees.iter().map(|a| a.login().to_string()).collect();
        try!(self.session.assign_pull_request(owner, repo, new_pr.number, assignees));

        Ok(new_pr)
    }

    fn clone_repo(&self, owner: &str, repo: &str, clone_dir: &PathBuf) -> Result<(), String> {
        let url = format!("https://{}@{}/{}/{}",
                          self.session.user().login(),
                          self.session.github_host(),
                          owner,
                          repo);

        if clone_dir.join(".git").exists() {
            try!(self.git.run(&["fetch"], clone_dir));
        } else {
            if let Err(e) = fs::create_dir_all(&clone_dir) {
                return Err(format!("Error creating clone directory '{:?}': {}", clone_dir, e));
            }
            try!(self.git.run(&["clone", &url, "."], clone_dir));
        }

        Ok(())
    }

    fn cherry_pick(&self, clone_dir: &PathBuf, commit_hash: &str, pr_branch_name: &str,
                   pr_number: u32, target_branch: &str, orig_base_branch: &str)
                   -> Result<(String, String), String> {
        let real_target_branch = format!("origin/{}", target_branch);

        // clean up state
        try!(self.git.run(&["reset", "--hard"], clone_dir));
        try!(self.git.run(&["clean", "-fdx"], clone_dir));

        // setup branch
        let current_branch = try!(self.git.run(&["rev-parse", "--abbrev-ref", "HEAD"], clone_dir));
        if current_branch == pr_branch_name {
            try!(self.git.run(&["reset", "--hard", &real_target_branch], clone_dir));
        } else {
            // delete if it exists
            let has_branch = try!(self.git.has_branch(pr_branch_name, clone_dir));
            if has_branch {
                try!(self.git.run(&["branch", "-D", pr_branch_name], clone_dir));
            }
            // recreate branch
            try!(self.git.run(&["checkout", "-b", pr_branch_name, &real_target_branch],
                              clone_dir));
        }

        // cherry-pick!
        try!(self.git.run(&["cherry-pick", "-X", "ignore-all-space", commit_hash],
                          clone_dir));

        let desc = try!(self.get_commit_desc(clone_dir, commit_hash));

        // grab original title and strip out the PR number at the end
        let pr_regex = Regex::new(r"(\s*\(#\d+\))+$").unwrap();
        let orig_title = pr_regex.replace(&desc.0, "");
        // strip out 'release' from the prefix to keep titles shorter
        let release_branch_regex = Regex::new(r"^release/").unwrap();
        let title = format!("{}->{}: {}",
                            orig_base_branch,
                            release_branch_regex.replace(target_branch, ""),
                            orig_title);
        let mut body = desc.1;

        if body.len() != 0 {
            body += "\n\n";
        }
        body += format!("(cherry-picked from {}, PR #{})",
                        &commit_hash[0..7],
                        pr_number)
            .as_str();

        // change commit message
        try!(self.git.run_with_stdin(&["commit", "--amend", "-F", "-"],
                                     clone_dir,
                                     &format!("{}\n\n{}", title, body)));

        Ok((title, body))
    }

    // returns (title, body)
    fn get_commit_desc(&self, clone_dir: &PathBuf, commit_hash: &str)
                       -> Result<(String, String), String> {
        let lines: Vec<String> = try!(self.git
                .run(&["log", "-1", "--pretty=%B", commit_hash], clone_dir))
            .split("\n")
            .map(|l| l.trim().to_string())
            .collect();

        if lines.len() == 0 {
            return Err(format!("Empty commit message found!"));
        }

        let title = lines[0].clone();

        let mut body = String::new();
        // skip the blank line
        if lines.len() > 2 {
            body = lines[2..].join("\n");
            body += "\n";
        }

        Ok((title, body))
    }
}

pub enum PRMergeMessage {
    Stop,
    Merge(PRMergeRequest),
}

pub struct PRMergeRequest {
    repo: github::Repo,
    pull_request: github::PullRequest,
    target_branch: String,
}

pub struct Worker {
    sender: Mutex<Sender<PRMergeMessage>>,
    handle: Option<JoinHandle<()>>,
}

impl PRMergeMessage {
    pub fn merge(repo: &github::Repo, pull_request: &github::PullRequest, target_branch: &str)
                 -> PRMergeMessage {
        PRMergeMessage::Merge(PRMergeRequest {
            repo: repo.clone(),
            pull_request: pull_request.clone(),
            target_branch: target_branch.to_string(),
        })
    }
}

impl Drop for Worker {
    fn drop(&mut self) {
        let sender = self.new_sender();
        match sender.send(PRMergeMessage::Stop) {
            Ok(_) => {
                match self.handle.take().unwrap().join() {
                    Ok(_) => (),
                    Err(e) => error!("Error shutting down worker: {:?}", e),
                }
            }
            Err(e) => error!("Error sending stop message: {}", e),
        }
    }
}

impl Worker {
    pub fn new(max_concurrency: usize, config: Arc<Config>, github_session: Arc<Session>)
               -> Worker {

        let (tx, rx) = channel();

        let clone_root_dir = config.clone_root_dir.to_string();

        Worker {
            sender: Mutex::new(tx),
            handle: Some(thread::spawn(move || {
                let runner = WorkerRunner {
                    rx: rx,
                    config: config,
                    github_session: github_session,
                    dir_pool: Arc::new(DirPool::new(&clone_root_dir)),
                    thread_pool: ThreadPool::new(max_concurrency),
                };
                runner.run();
            })),
        }
    }

    pub fn new_sender(&self) -> Sender<PRMergeMessage> {
        let sender = self.sender.lock().unwrap();
        sender.clone()
    }
}

struct WorkerRunner {
    rx: Receiver<PRMergeMessage>,
    config: Arc<Config>,
    github_session: Arc<Session>,
    dir_pool: Arc<DirPool>,
    thread_pool: ThreadPool,
}

impl WorkerRunner {
    fn run(&self) {
        loop {
            match self.rx.recv() {
                Ok(PRMergeMessage::Stop) => break,
                Ok(PRMergeMessage::Merge(req)) => self.handle_merge(req),
                Err(e) => error!("Error receiving message: {}", e),
            };
        }
    }

    fn handle_merge(&self, req: PRMergeRequest) {
        let github_session = self.github_session.clone();
        let dir_pool = self.dir_pool.clone();
        let config = self.config.clone();

        // launch another thread to do the merge
        self.thread_pool.execute(move || {
            if let Err(e) = merge_pull_request(&github_session,
                                               &dir_pool,
                                               &req.repo.owner.login(),
                                               &req.repo.name,
                                               &req.pull_request,
                                               &req.target_branch) {

                let attach = SlackAttachmentBuilder::new(&e)
                    .title(format!("Source PR: #{}: \"{}\"",
                                   req.pull_request.number,
                                   req.pull_request.title)
                        .as_str())
                    .title_link(req.pull_request.html_url.clone())
                    .color("danger")
                    .build();

                let messenger = messenger::from_config(config);
                messenger.send_to_owner("Error creating merge Pull Request",
                                        &vec![attach],
                                        &req.pull_request.user,
                                        &req.repo);
            }
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

/* automatically generated by rust-bindgen */

use core::libc::*;

type stbi_uc = c_uchar;

struct stbi_io_callbacks {
    read: *u8,
    skip: *u8,
    eof: *u8,
}

type enum_unnamed1 = c_uint;
static STBI_default: u32 = 0_u32;
static STBI_grey: u32 = 1_u32;
static STBI_grey_alpha: u32 = 2_u32;
static STBI_rgb: u32 = 3_u32;
static STBI_rgb_alpha: u32 = 4_u32;

#[link_args="-L. -lstb-image"]
#[nolink]
extern mod m {
}

#[nolink]
pub extern mod bindgen {

fn stbi_load_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_loadf_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_hdr_to_ldr_gamma(gamma: c_float);

fn stbi_hdr_to_ldr_scale(scale: c_float);

fn stbi_ldr_to_hdr_gamma(gamma: c_float);

fn stbi_ldr_to_hdr_scale(scale: c_float);

fn stbi_is_hdr_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void) -> c_int;

fn stbi_is_hdr_from_memory(buffer: *stbi_uc, len: c_int) -> c_int;

fn stbi_is_hdr(filename: *c_char) -> c_int;

fn stbi_is_hdr_from_file(f: *FILE) -> c_int;

fn stbi_failure_reason() -> *c_char;

fn stbi_image_free(retval_from_stbi_load: *c_void);

fn stbi_info_from_memory(buffer: *stbi_uc, len: c_int, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info(filename: *c_char, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info_from_file(f: *FILE, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_set_unpremultiply_on_load(flag_true_if_should_unpremultiply: c_int);

fn stbi_convert_iphone_png_to_rgb(flag_true_if_should_convert: c_int);

fn stbi_zlib_decode_malloc_guesssize(buffer: *c_char, len: c_int, initial_size: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

fn stbi_zlib_decode_noheader_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_noheader_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

}
<commit_msg>Language changes with extern modules<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

/* automatically generated by rust-bindgen */

use core::libc::*;

type enum_unnamed1 = c_uint;
static STBI_default: u32 = 0_u32;
static STBI_grey: u32 = 1_u32;
static STBI_grey_alpha: u32 = 2_u32;
static STBI_rgb: u32 = 3_u32;
static STBI_rgb_alpha: u32 = 4_u32;

#[link_args="-L. -lstb-image"]
#[nolink]
mod m {
  extern {
  }
}

#[nolink]
pub mod bindgen {
  use core::libc::*;

  type stbi_uc = c_uchar;
  struct stbi_io_callbacks {
    read: *u8,
    skip: *u8,
    eof: *u8,
  }

  pub extern {

fn stbi_load_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_load_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

fn stbi_loadf_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_loadf_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

fn stbi_hdr_to_ldr_gamma(gamma: c_float);

fn stbi_hdr_to_ldr_scale(scale: c_float);

fn stbi_ldr_to_hdr_gamma(gamma: c_float);

fn stbi_ldr_to_hdr_scale(scale: c_float);

fn stbi_is_hdr_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void) -> c_int;

fn stbi_is_hdr_from_memory(buffer: *stbi_uc, len: c_int) -> c_int;

fn stbi_is_hdr(filename: *c_char) -> c_int;

fn stbi_is_hdr_from_file(f: *FILE) -> c_int;

fn stbi_failure_reason() -> *c_char;

fn stbi_image_free(retval_from_stbi_load: *c_void);

fn stbi_info_from_memory(buffer: *stbi_uc, len: c_int, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info(filename: *c_char, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_info_from_file(f: *FILE, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

fn stbi_set_unpremultiply_on_load(flag_true_if_should_unpremultiply: c_int);

fn stbi_convert_iphone_png_to_rgb(flag_true_if_should_convert: c_int);

fn stbi_zlib_decode_malloc_guesssize(buffer: *c_char, len: c_int, initial_size: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

fn stbi_zlib_decode_noheader_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

fn stbi_zlib_decode_noheader_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

  }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub struct ErrorStack(Vec<(ErrorLevel, &'static str)>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "[{:?}] {}\n", error.0, error.1).unwrap();
        }

        write!(f, "")
    }
}
<commit_msg>Make struct member public<commit_after>use std::fmt;

#[derive(Debug)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

// Use a hashmap which contains an error level and a string
pub struct ErrorStack(pub Vec<(ErrorLevel, &'static str)>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "[{:?}] {}\n", error.0, error.1).unwrap();
        }

        write!(f, "")
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Factorial

fn factorial_recursive (n: uint) -> uint {
	match n {
		0 => 1,
		_ => n * factorial_recursive(n-1)
	}
}

fn factorial_iterative(n: uint) -> uint {
	range(1u, n+1).fold(1, |p, t| p * t)
}

fn main () {
	for i in range(1u, 10u) {
		println!("{}", factorial_recursive(i))
	}
	for i in range(1u, 10u) {
		println!("{}", factorial_iterative(i))
	}
}<commit_msg>Added tests and benchmarks to factorial<commit_after>// Implements http://rosettacode.org/wiki/Factorial

use std::iter::range_inclusive;

// Calculate the factorial using recursion
fn factorial_recursive (n: uint) -> uint {
	match n {
		0 => 1,
		_ => n * factorial_recursive(n-1)
	}
}

// Calculate the factorial using a fold
fn factorial_iterative(n: uint) -> uint {
	range_inclusive(1, n).fold(1, |p, t| p * t)
}

// Calculate the factorial using a for loop
fn factorial_loop(n: uint) -> uint {
    let mut fac = 1;
    for x in range_inclusive(1, n) {
        fac *= x;
    }
    fac
}

#[cfg(not(test))]
fn main () {
	for i in range(1u, 10) {
		println!("{}", factorial_recursive(i))
	}
	for i in range(1u, 10) {
		println!("{}", factorial_iterative(i))
	}
    for i in range(1u, 10) {
        println!("{}", factorial_loop(i));
    }
}

// Some tests and benchmarks
#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use super::{factorial_recursive, factorial_iterative, factorial_loop};

    // Tests
    #[test]
    fn test_fac_recursive() {
        assert!(factorial_recursive(0) == 1);
        assert!(factorial_recursive(10) == 3628800);
    }

    #[test]
    fn test_fac_iterative() {
        assert!(factorial_iterative(0) == 1);
        assert!(factorial_iterative(10) == 3628800);
    }

    #[test]
    fn test_fac_loop() {
        assert!(factorial_loop(0) == 1);
        assert!(factorial_loop(10) == 3628800);
    }

    // Benchmarks
    #[bench]
    fn bench_fac_recursive(b: &mut Bencher) {
        b.iter(|| {
            factorial_recursive(10);
        });
    }

    #[bench]
    fn bench_fac_iterative(b: &mut Bencher) {
        b.iter(|| {
            factorial_iterative(10);
        });
    }

    #[bench]
    fn bench_fac_loop(b: &mut Bencher) {
        b.iter(|| {
            factorial_loop(10);
        });
    }
}
<|endoftext|>


<commit_before>use std::old_io::{Writer, IoResult};
use util::{Rgb, V2, color};
use canvas::{Canvas, FONT_W, FONT_H};
use canvas_util::{CanvasUtil};

/// Writing text to a graphical context.
pub trait Fonter<'a, W: Writer> {
    fn text_writer(&'a mut self, origin: V2<i32>, z: f32, color: Rgb) -> W;
}

impl<'a> Fonter<'a, CanvasWriter<'a>> for Canvas {
    fn text_writer(&'a mut self, origin: V2<i32>, z: f32, color: Rgb) -> CanvasWriter<'a> {
        let origin = origin.map(|x| x as f32);
        CanvasWriter {
            canvas: self,
            origin: origin,
            cursor_pos: origin,
            color: color,
            z: z,
            border: None,
        }
    }
}

pub struct CanvasWriter<'a> {
    canvas: &'a mut Canvas,
    origin: V2<f32>,
    cursor_pos: V2<f32>,
    /// Text color
    pub color: Rgb,
    /// Z drawing depth
    pub z: f32,
    /// Border color (if any)
    pub border: Option<Rgb>,
}

impl<'a> CanvasWriter<'a> {
    pub fn set_border(mut self, c: Rgb) -> CanvasWriter<'a> {
        self.border = Some(c);
        self
    }

    /// Set cursor X pixel position relative to the cursor origin.
    pub fn set_x(&mut self, x: f32) {
        self.cursor_pos.0 = self.origin.0 + x;
    }

    /// Calculate rendered width of the given string.
    pub fn width(&self, string: &str) -> f32 {
        string.chars().fold(0.0, |a, c| a + self.char_width(c))
    }

    fn draw_char(&mut self, c: char) {
        static BORDER: [V2<f32>; 8] =
            [V2(-1.0, -1.0), V2( 0.0, -1.0), V2( 1.0, -1.0),
             V2(-1.0,  0.0),                 V2( 1.0,  0.0),
             V2(-1.0,  1.0), V2( 0.0,  1.0), V2( 1.0,  1.0)];
        if let Some(img) = self.canvas.font_image(c) {
            if let Some(b) = self.border {
                // Put the border a tiny bit further in the z-buffer so it
                // won't clobber the text on the same layer.
                let border_z = self.z + 0.00001;
                for &d in BORDER.iter() {
                    self.canvas.draw_image(img, self.cursor_pos + d, border_z, &b, &color::BLACK);
                }
            }
            self.canvas.draw_image(img, self.cursor_pos, self.z, &self.color, &color::BLACK);
        }
    }

    fn char_width(&self, c: char) -> f32 {
        // Special case for space, the atlas image won't have a width.
        if c == ' ' { return (FONT_W / 2) as f32; }

        // Infer letter width from the cropped atlas image. (Use mx instead of
        // dim on the pos rectangle so that the left-side space will be
        // preserved and the letters are kept slightly apart.)
        if let Some(img) = self.canvas.font_image(c) {
            let width = self.canvas.image_data(img).pos.mx().0;
            return width;
        }

        // Not a valid letter.
        FONT_W as f32
    }
}

impl<'a> Writer for CanvasWriter<'a> {
    fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
        // TODO: Support multibyte stuff.
        for &b in buf.iter() {
            let c = b as char;
            if c == '\n' {
                self.cursor_pos = V2(self.origin.0, self.cursor_pos.1 + FONT_H as f32);
            } else {
                self.draw_char(c);
                self.cursor_pos.0 += self.char_width(c);
            }
        }
        Ok(())
    }
}
<commit_msg>Expose char_width in fonter<commit_after>use std::old_io::{Writer, IoResult};
use util::{Rgb, V2, color};
use canvas::{Canvas, FONT_W, FONT_H};
use canvas_util::{CanvasUtil};

/// Writing text to a graphical context.
pub trait Fonter<'a, W: Writer> {
    fn text_writer(&'a mut self, origin: V2<i32>, z: f32, color: Rgb) -> W;
    fn char_width(&self, c: char) -> f32;
}

impl<'a> Fonter<'a, CanvasWriter<'a>> for Canvas {
    fn text_writer(&'a mut self, origin: V2<i32>, z: f32, color: Rgb) -> CanvasWriter<'a> {
        let origin = origin.map(|x| x as f32);
        CanvasWriter {
            canvas: self,
            origin: origin,
            cursor_pos: origin,
            color: color,
            z: z,
            border: None,
        }
    }

    fn char_width(&self, c: char) -> f32 {
        // Special case for space, the atlas image won't have a width.
        if c == ' ' { return (FONT_W / 2) as f32; }

        // Infer letter width from the cropped atlas image. (Use mx instead of
        // dim on the pos rectangle so that the left-side space will be
        // preserved and the letters are kept slightly apart.)
        if let Some(img) = self.font_image(c) {
            let width = self.image_data(img).pos.mx().0;
            return width;
        }

        // Not a valid letter.
        FONT_W as f32
    }
}

pub struct CanvasWriter<'a> {
    canvas: &'a mut Canvas,
    origin: V2<f32>,
    cursor_pos: V2<f32>,
    /// Text color
    pub color: Rgb,
    /// Z drawing depth
    pub z: f32,
    /// Border color (if any)
    pub border: Option<Rgb>,
}

impl<'a> CanvasWriter<'a> {
    pub fn set_border(mut self, c: Rgb) -> CanvasWriter<'a> {
        self.border = Some(c);
        self
    }

    /// Set cursor X pixel position relative to the cursor origin.
    pub fn set_x(&mut self, x: f32) {
        self.cursor_pos.0 = self.origin.0 + x;
    }

    /// Calculate rendered width of the given string.
    pub fn width(&self, string: &str) -> f32 {
        string.chars().fold(0.0, |a, c| a + self.canvas.char_width(c))
    }

    fn draw_char(&mut self, c: char) {
        static BORDER: [V2<f32>; 8] =
            [V2(-1.0, -1.0), V2( 0.0, -1.0), V2( 1.0, -1.0),
             V2(-1.0,  0.0),                 V2( 1.0,  0.0),
             V2(-1.0,  1.0), V2( 0.0,  1.0), V2( 1.0,  1.0)];
        if let Some(img) = self.canvas.font_image(c) {
            if let Some(b) = self.border {
                // Put the border a tiny bit further in the z-buffer so it
                // won't clobber the text on the same layer.
                let border_z = self.z + 0.00001;
                for &d in BORDER.iter() {
                    self.canvas.draw_image(img, self.cursor_pos + d, border_z, &b, &color::BLACK);
                }
            }
            self.canvas.draw_image(img, self.cursor_pos, self.z, &self.color, &color::BLACK);
        }
    }
}

impl<'a> Writer for CanvasWriter<'a> {
    fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
        // TODO: Support multibyte stuff.
        for &b in buf.iter() {
            let c = b as char;
            if c == '\n' {
                self.cursor_pos = V2(self.origin.0, self.cursor_pos.1 + FONT_H as f32);
            } else {
                self.draw_char(c);
                self.cursor_pos.0 += self.canvas.char_width(c);
            }
        }
        Ok(())
    }
}
<|endoftext|>