<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::Binding;

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.roots = self.roots.union(&parent.roots).cloned().collect();
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => Ok(()),
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, gc_yield: bool) -> Option<Box<Scope>> {
        if gc_yield {
            // The interpreter says we can GC now
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

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

    use js_types::js_var::{JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let child_scope = Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.))];
            let (var, ptr) = test_utils::make_obj(kvs);
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack(false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }
}
<commit_msg>Pop root pointer from the stack when their contents get GC'd<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::Binding;
use js_types::allocator::Allocator;

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.roots = self.roots.union(&parent.roots).cloned().collect();
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => Ok(()),
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, gc_yield: bool) -> Option<Box<Scope>> {
        if gc_yield {
            // The interpreter says we can GC now
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
            // Pop all of the roots we just deleted
            for bnd in self.roots.iter() {
                if let None = self.heap.borrow().find_id(bnd) {
                    self.stack.remove(bnd);
                }
            }
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

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

    use js_types::js_var::{JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let child_scope = Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.))];
            let (var, ptr) = test_utils::make_obj(kvs);
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack(false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }
}
<|endoftext|>


<commit_before>

use super::{MetaData, duration_to_str, match_version, render_markdown};
use super::error::Nope;
use super::page::Page;
use db::connect_db;
use iron::prelude::*;
use iron::status;
use std::collections::BTreeMap;
use time;
use rustc_serialize::json::{Json, ToJson};
use router::Router;
use postgres::Connection;
use semver;

// TODO: Add target name and versions

#[derive(Debug)]
struct CrateDetails {
    name: String,
    version: String,
    description: Option<String>,
    authors: Vec<(String, String)>,
    authors_json: Option<Json>,
    dependencies: Option<Json>,
    readme: Option<String>,
    rustdoc: Option<String>, // this is description_long in database
    release_time: time::Timespec,
    build_status: bool,
    rustdoc_status: bool,
    repository_url: Option<String>,
    homepage_url: Option<String>,
    keywords: Option<Json>,
    have_examples: bool, // need to check this manually
    target_name: Option<String>,
    versions: Vec<String>,
    github: bool, // is crate hosted in github
    github_stars: Option<i32>,
    github_forks: Option<i32>,
    github_issues: Option<i32>,
    metadata: MetaData,
    is_library: bool,
}

impl ToJson for CrateDetails {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("authors".to_string(), self.authors.to_json());
        m.insert("authors_json".to_string(), self.authors_json.to_json());
        m.insert("dependencies".to_string(), self.dependencies.to_json());
        if let Some(ref readme) = self.readme {
            m.insert("readme".to_string(), render_markdown(&readme).to_json());
        }
        if let Some(ref rustdoc) = self.rustdoc {
            m.insert("rustdoc".to_string(), render_markdown(&rustdoc).to_json());
        }
        m.insert("release_time".to_string(),
                 duration_to_str(self.release_time).to_json());
        m.insert("build_status".to_string(), self.build_status.to_json());
        m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json());
        m.insert("repository_url".to_string(), self.repository_url.to_json());
        m.insert("homepage_url".to_string(), self.homepage_url.to_json());
        m.insert("keywords".to_string(), self.keywords.to_json());
        m.insert("have_examples".to_string(), self.have_examples.to_json());
        m.insert("target_name".to_string(), self.target_name.to_json());
        m.insert("versions".to_string(), self.versions.to_json());
        m.insert("github".to_string(), self.github.to_json());
        m.insert("github_stars".to_string(), self.github_stars.to_json());
        m.insert("github_forks".to_string(), self.github_forks.to_json());
        m.insert("github_issues".to_string(), self.github_issues.to_json());
        m.insert("metadata".to_string(), self.metadata.to_json());
        m.insert("is_library".to_string(), self.is_library.to_json());
        m.to_json()
    }
}

impl CrateDetails {
    fn new(conn: &Connection, name: &str, version: &str) -> Option<CrateDetails> {

        // get all stuff, I love you rustfmt
        let query = "SELECT crates.name, \
                            releases.version, \
                            releases.description, \
                            releases.authors, \
                            releases.dependencies, \
                            releases.readme, \
                            releases.description_long, \
                            releases.release_time, \
                            releases.build_status, \
                            releases.rustdoc_status, \
                            releases.repository_url, \
                            releases.homepage_url, \
                            releases.keywords, \
                            releases.have_examples, \
                            releases.target_name, \
                            crates.versions, \
                            authors.name, \
                            authors.slug, \
                            crates.github_stars, \
                            crates.github_forks, \
                            crates.github_issues, \
                            releases.is_library \
                     FROM author_rels \
                     LEFT OUTER JOIN authors ON authors.id = author_rels.aid \
                     LEFT OUTER JOIN releases ON releases.id = author_rels.rid \
                     LEFT OUTER JOIN crates ON crates.id = releases.crate_id \
                     WHERE crates.name = $1 AND releases.version = $2;";

        let rows = conn.query(query, &[&name, &version]).unwrap();

        if rows.len() == 0 {
            return None;
        }

        // sort versions with semver
        let versions = {
            let mut versions: Vec<semver::Version> = Vec::new();
            let versions_from_db: Json = rows.get(0).get(15);

            versions_from_db.as_array().map(|vers| {
                for version in vers {
                    version.as_string().map(|version| {
                        if let Ok(sem_ver) = semver::Version::parse(&version) {
                            versions.push(sem_ver);
                        };
                    });
                }
            });

            versions.sort();
            versions.reverse();
            versions.iter().map(|semver| format!("{}", semver)).collect()
        };

        let metadata = MetaData {
            name: rows.get(0).get(0),
            version: rows.get(0).get(1),
            description: rows.get(0).get(2),
            rustdoc_status: rows.get(0).get(9),
            target_name: rows.get(0).get(14),
        };

        let mut crate_details = CrateDetails {
            name: rows.get(0).get(0),
            version: rows.get(0).get(1),
            description: rows.get(0).get(2),
            authors: Vec::new(),
            authors_json: rows.get(0).get(3),
            dependencies: rows.get(0).get(4),
            readme: rows.get(0).get(5),
            rustdoc: rows.get(0).get(6),
            release_time: rows.get(0).get(7),
            build_status: rows.get(0).get(8),
            rustdoc_status: rows.get(0).get(9),
            repository_url: rows.get(0).get(10),
            homepage_url: rows.get(0).get(11),
            keywords: rows.get(0).get(12),
            have_examples: rows.get(0).get(13),
            target_name: rows.get(0).get(14),
            versions: versions,
            github: false,
            github_stars: rows.get(0).get(18),
            github_forks: rows.get(0).get(19),
            github_issues: rows.get(0).get(20),
            metadata: metadata,
            is_library: rows.get(0).get(21),
        };

        if let Some(repository_url) = crate_details.repository_url.clone() {
            crate_details.github = repository_url.starts_with("http://github.com") ||
                                   repository_url.starts_with("https://github.com");
        }

        // Insert authors with name and slug
        for row in &rows {
            crate_details.authors.push((row.get(16), row.get(17)));
        }

        Some(crate_details)
    }
}

pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
    // this handler must always called with a crate name
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap();
    let req_version = req.extensions.get::<Router>().unwrap().find("version");

    let conn = connect_db().unwrap();

    match_version(&conn, &name, req_version)
        .and_then(|version| CrateDetails::new(&conn, &name, &version))
        .ok_or(IronError::new(Nope::CrateNotFound, status::NotFound))
        .and_then(|details| {
            Page::new(details)
                .set_true("show_package_navigation")
                .set_true("javascript_highlightjs")
                .set_true("package_navigation_crate_tab")
                .to_resp("crate_details")
        })
}
<commit_msg>Use connection pool in crate details handler<commit_after>

use super::pool::Pool;
use super::{MetaData, duration_to_str, match_version, render_markdown};
use super::error::Nope;
use super::page::Page;
use iron::prelude::*;
use iron::status;
use std::collections::BTreeMap;
use time;
use rustc_serialize::json::{Json, ToJson};
use router::Router;
use postgres::Connection;
use semver;

// TODO: Add target name and versions

#[derive(Debug)]
struct CrateDetails {
    name: String,
    version: String,
    description: Option<String>,
    authors: Vec<(String, String)>,
    authors_json: Option<Json>,
    dependencies: Option<Json>,
    readme: Option<String>,
    rustdoc: Option<String>, // this is description_long in database
    release_time: time::Timespec,
    build_status: bool,
    rustdoc_status: bool,
    repository_url: Option<String>,
    homepage_url: Option<String>,
    keywords: Option<Json>,
    have_examples: bool, // need to check this manually
    target_name: Option<String>,
    versions: Vec<String>,
    github: bool, // is crate hosted in github
    github_stars: Option<i32>,
    github_forks: Option<i32>,
    github_issues: Option<i32>,
    metadata: MetaData,
    is_library: bool,
}

impl ToJson for CrateDetails {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("authors".to_string(), self.authors.to_json());
        m.insert("authors_json".to_string(), self.authors_json.to_json());
        m.insert("dependencies".to_string(), self.dependencies.to_json());
        if let Some(ref readme) = self.readme {
            m.insert("readme".to_string(), render_markdown(&readme).to_json());
        }
        if let Some(ref rustdoc) = self.rustdoc {
            m.insert("rustdoc".to_string(), render_markdown(&rustdoc).to_json());
        }
        m.insert("release_time".to_string(),
                 duration_to_str(self.release_time).to_json());
        m.insert("build_status".to_string(), self.build_status.to_json());
        m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json());
        m.insert("repository_url".to_string(), self.repository_url.to_json());
        m.insert("homepage_url".to_string(), self.homepage_url.to_json());
        m.insert("keywords".to_string(), self.keywords.to_json());
        m.insert("have_examples".to_string(), self.have_examples.to_json());
        m.insert("target_name".to_string(), self.target_name.to_json());
        m.insert("versions".to_string(), self.versions.to_json());
        m.insert("github".to_string(), self.github.to_json());
        m.insert("github_stars".to_string(), self.github_stars.to_json());
        m.insert("github_forks".to_string(), self.github_forks.to_json());
        m.insert("github_issues".to_string(), self.github_issues.to_json());
        m.insert("metadata".to_string(), self.metadata.to_json());
        m.insert("is_library".to_string(), self.is_library.to_json());
        m.to_json()
    }
}

impl CrateDetails {
    fn new(conn: &Connection, name: &str, version: &str) -> Option<CrateDetails> {

        // get all stuff, I love you rustfmt
        let query = "SELECT crates.name, \
                            releases.version, \
                            releases.description, \
                            releases.authors, \
                            releases.dependencies, \
                            releases.readme, \
                            releases.description_long, \
                            releases.release_time, \
                            releases.build_status, \
                            releases.rustdoc_status, \
                            releases.repository_url, \
                            releases.homepage_url, \
                            releases.keywords, \
                            releases.have_examples, \
                            releases.target_name, \
                            crates.versions, \
                            authors.name, \
                            authors.slug, \
                            crates.github_stars, \
                            crates.github_forks, \
                            crates.github_issues, \
                            releases.is_library \
                     FROM author_rels \
                     LEFT OUTER JOIN authors ON authors.id = author_rels.aid \
                     LEFT OUTER JOIN releases ON releases.id = author_rels.rid \
                     LEFT OUTER JOIN crates ON crates.id = releases.crate_id \
                     WHERE crates.name = $1 AND releases.version = $2;";

        let rows = conn.query(query, &[&name, &version]).unwrap();

        if rows.len() == 0 {
            return None;
        }

        // sort versions with semver
        let versions = {
            let mut versions: Vec<semver::Version> = Vec::new();
            let versions_from_db: Json = rows.get(0).get(15);

            versions_from_db.as_array().map(|vers| {
                for version in vers {
                    version.as_string().map(|version| {
                        if let Ok(sem_ver) = semver::Version::parse(&version) {
                            versions.push(sem_ver);
                        };
                    });
                }
            });

            versions.sort();
            versions.reverse();
            versions.iter().map(|semver| format!("{}", semver)).collect()
        };

        let metadata = MetaData {
            name: rows.get(0).get(0),
            version: rows.get(0).get(1),
            description: rows.get(0).get(2),
            rustdoc_status: rows.get(0).get(9),
            target_name: rows.get(0).get(14),
        };

        let mut crate_details = CrateDetails {
            name: rows.get(0).get(0),
            version: rows.get(0).get(1),
            description: rows.get(0).get(2),
            authors: Vec::new(),
            authors_json: rows.get(0).get(3),
            dependencies: rows.get(0).get(4),
            readme: rows.get(0).get(5),
            rustdoc: rows.get(0).get(6),
            release_time: rows.get(0).get(7),
            build_status: rows.get(0).get(8),
            rustdoc_status: rows.get(0).get(9),
            repository_url: rows.get(0).get(10),
            homepage_url: rows.get(0).get(11),
            keywords: rows.get(0).get(12),
            have_examples: rows.get(0).get(13),
            target_name: rows.get(0).get(14),
            versions: versions,
            github: false,
            github_stars: rows.get(0).get(18),
            github_forks: rows.get(0).get(19),
            github_issues: rows.get(0).get(20),
            metadata: metadata,
            is_library: rows.get(0).get(21),
        };

        if let Some(repository_url) = crate_details.repository_url.clone() {
            crate_details.github = repository_url.starts_with("http://github.com") ||
                                   repository_url.starts_with("https://github.com");
        }

        // Insert authors with name and slug
        for row in &rows {
            crate_details.authors.push((row.get(16), row.get(17)));
        }

        Some(crate_details)
    }
}

pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
    // this handler must always called with a crate name
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap();
    let req_version = req.extensions.get::<Router>().unwrap().find("version");

    let conn = req.extensions.get::<Pool>().unwrap();

    match_version(&conn, &name, req_version)
        .and_then(|version| CrateDetails::new(&conn, &name, &version))
        .ok_or(IronError::new(Nope::CrateNotFound, status::NotFound))
        .and_then(|details| {
            Page::new(details)
                .set_true("show_package_navigation")
                .set_true("javascript_highlightjs")
                .set_true("package_navigation_crate_tab")
                .to_resp("crate_details")
        })
}
<|endoftext|>


<commit_before>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::{Touch, TouchPhase};

use std::collections::VecDeque;

use Api;
use ContextError;
use CursorState;
use GlAttributes;
use GlContext;
use GlRequest;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;
use native_monitor::NativeMonitorId;

use api::egl;
use api::egl::Context as EglContext;

pub struct Window {
    context: EglContext,
    event_rx: Receiver<android_glue::Event>,
}

#[derive(Clone)]
pub struct MonitorId;

mod ffi;

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    let mut rb = VecDeque::new();
    rb.push_back(MonitorId);
    rb
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    MonitorId
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_native_identifier(&self) -> NativeMonitorId {
        NativeMonitorId::Unavailable
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self.window.event_rx.try_recv() {
            Ok(android_glue::Event::EventMotion(motion)) => {
                Some(Event::Touch(Touch {
                    phase: match motion.action {
                        android_glue::MotionAction::Down => TouchPhase::Started,
                        android_glue::MotionAction::Move => TouchPhase::Moved,
                        android_glue::MotionAction::Up => TouchPhase::Ended,
                        android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
                    },
                    location: (motion.x as f64, motion.y as f64),
                    id: motion.pointer_id as u64,
                }))
            }
            _ => {
                None
            }
        }
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        loop {
            // calling poll_events()
            if let Some(ev) = self.window.poll_events().next() {
                return Some(ev);
            }

            // TODO: Implement a proper way of sleeping on the event queue
            // timer::sleep(Duration::milliseconds(16));
        }
    }
}

impl Window {
    pub fn new(win_attribs: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>, _: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window, CreationError>
    {
        use std::{mem, ptr};

        // not implemented
        assert!(win_attribs.min_dimensions.is_none());
        assert!(win_attribs.max_dimensions.is_none());

        let opengl = opengl.clone().map_sharing(|w| &w.context);

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let context = try!(EglContext::new(egl::ffi::egl::Egl, pf_reqs, &opengl,
                                           egl::NativeDisplay::Android)
                                                .and_then(|p| p.finish(native_window as *const _)));

        let (tx, rx) = channel();
        android_glue::add_sender(tx);
        android_glue::set_multitouch(win_attribs.multitouch);

        Ok(Window {
            context: context,
            event_rx: rx,
        })
    }

    #[inline]
    pub fn is_closed(&self) -> bool {
        false
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        unimplemented!();
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        unimplemented!();
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.context.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.context.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.context.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.context.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.context.get_pixel_format()
    }
}

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

pub struct HeadlessContext(EglContext);

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(dimensions: (u32, u32), pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&HeadlessContext>,
               _: &PlatformSpecificHeadlessBuilderAttributes)
               -> Result<HeadlessContext, CreationError>
    {
        let opengl = opengl.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl, pf_reqs, &opengl,
                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl GlContext for HeadlessContext {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<commit_msg>android: Fixed Window::get_pixel_format<commit_after>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::{Touch, TouchPhase};

use std::collections::VecDeque;

use Api;
use ContextError;
use CursorState;
use GlAttributes;
use GlContext;
use GlRequest;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;
use native_monitor::NativeMonitorId;

use api::egl;
use api::egl::Context as EglContext;

pub struct Window {
    context: EglContext,
    event_rx: Receiver<android_glue::Event>,
}

#[derive(Clone)]
pub struct MonitorId;

mod ffi;

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    let mut rb = VecDeque::new();
    rb.push_back(MonitorId);
    rb
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    MonitorId
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_native_identifier(&self) -> NativeMonitorId {
        NativeMonitorId::Unavailable
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self.window.event_rx.try_recv() {
            Ok(android_glue::Event::EventMotion(motion)) => {
                Some(Event::Touch(Touch {
                    phase: match motion.action {
                        android_glue::MotionAction::Down => TouchPhase::Started,
                        android_glue::MotionAction::Move => TouchPhase::Moved,
                        android_glue::MotionAction::Up => TouchPhase::Ended,
                        android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
                    },
                    location: (motion.x as f64, motion.y as f64),
                    id: motion.pointer_id as u64,
                }))
            }
            _ => {
                None
            }
        }
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        loop {
            // calling poll_events()
            if let Some(ev) = self.window.poll_events().next() {
                return Some(ev);
            }

            // TODO: Implement a proper way of sleeping on the event queue
            // timer::sleep(Duration::milliseconds(16));
        }
    }
}

impl Window {
    pub fn new(win_attribs: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>, _: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window, CreationError>
    {
        use std::{mem, ptr};

        // not implemented
        assert!(win_attribs.min_dimensions.is_none());
        assert!(win_attribs.max_dimensions.is_none());

        let opengl = opengl.clone().map_sharing(|w| &w.context);

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let context = try!(EglContext::new(egl::ffi::egl::Egl, pf_reqs, &opengl,
                                           egl::NativeDisplay::Android)
                                                .and_then(|p| p.finish(native_window as *const _)));

        let (tx, rx) = channel();
        android_glue::add_sender(tx);
        android_glue::set_multitouch(win_attribs.multitouch);

        Ok(Window {
            context: context,
            event_rx: rx,
        })
    }

    #[inline]
    pub fn is_closed(&self) -> bool {
        false
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.context.get_pixel_format()
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        unimplemented!();
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.context.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.context.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.context.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.context.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.get_pixel_format()
    }
}

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

pub struct HeadlessContext(EglContext);

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(dimensions: (u32, u32), pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&HeadlessContext>,
               _: &PlatformSpecificHeadlessBuilderAttributes)
               -> Result<HeadlessContext, CreationError>
    {
        let opengl = opengl.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl, pf_reqs, &opengl,
                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl GlContext for HeadlessContext {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<|endoftext|>


<commit_before>

// -*- rust -*-
use std;
import std::rand;

#[test]
fn test() {
    let r1: rand::rng = rand::mk_rng();
    log r1.next();
    log r1.next();
    {
        let r2 = rand::mk_rng();
        log r1.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r2.next();
    }
    log r1.next();
    log r1.next();
}
<commit_msg>Add fs::rmdir() and tempfile/gen_str() tests.<commit_after>

// -*- rust -*-
use std;
import std::rand;
import std::str;

#[test]
fn test() {
    let r1: rand::rng = rand::mk_rng();
    log r1.next();
    log r1.next();
    {
        let r2 = rand::mk_rng();
        log r1.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r2.next();
    }
    log r1.next();
    log r1.next();
}

#[test]
fn genstr() {
    let r: rand::rng = rand::mk_rng();
    log r.gen_str(10u);
    log r.gen_str(10u);
    log r.gen_str(10u);
    assert(str::char_len(r.gen_str(10u)) == 10u);
    assert(str::char_len(r.gen_str(16u)) == 16u);
}
<|endoftext|>


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

#![no_std]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "32838")]

#![feature(allocator_api)]
#![feature(core_intrinsics)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
#![rustc_alloc_kind = "lib"]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs",
              target_arch = "wasm32")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64",
              target_arch = "mips64",
              target_arch = "s390x",
              target_arch = "sparc64")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 16;

use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
use core::ptr::NonNull;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type can be used in a `static` item
/// with the `#[global_allocator]` attribute
/// to force the global allocator to be the system’s one.
/// (The default is jemalloc for executables, on some platforms.)
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// It can also be used directly to allocate memory
/// independently of the standard library’s global allocator.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
pub struct System;

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: NonNull<u8>,
                      layout: Layout,
                      new_size: usize) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
    }
}

#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
mod realloc_fallback {
    use core::alloc::{GlobalAlloc, Layout};
    use core::cmp;
    use core::ptr;

    impl super::System {
        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
                                              new_size: usize) -> *mut u8 {
            // Docs for GlobalAlloc::realloc require this to be valid:
            let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());

            let new_ptr = GlobalAlloc::alloc(self, new_layout);
            if !new_ptr.is_null() {
                let size = cmp::min(old_layout.size(), new_size);
                ptr::copy_nonoverlapping(ptr, new_ptr, size);
                GlobalAlloc::dealloc(self, ptr, old_layout);
            }
            new_ptr
        }
    }
}

#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))]
mod platform {
    extern crate libc;

    use core::ptr;

    use MIN_ALIGN;
    use System;
    use core::alloc::{GlobalAlloc, Layout};

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
                libc::malloc(layout.size()) as *mut u8
            } else {
                #[cfg(target_os = "macos")]
                {
                    if layout.align() > (1 << 31) {
                        return ptr::null_mut()
                    }
                }
                aligned_malloc(&layout)
            }
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
                libc::calloc(layout.size(), 1) as *mut u8
            } else {
                let ptr = self.alloc(layout.clone());
                if !ptr.is_null() {
                    ptr::write_bytes(ptr, 0, layout.size());
                }
                ptr
            }
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
            libc::free(ptr as *mut libc::c_void)
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
            } else {
                self.realloc_fallback(ptr, layout, new_size)
            }
        }
    }

    #[cfg(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris"))]
    #[inline]
    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
        // On android we currently target API level 9 which unfortunately
        // doesn't have the `posix_memalign` API used below. Instead we use
        // `memalign`, but this unfortunately has the property on some systems
        // where the memory returned cannot be deallocated by `free`!
        //
        // Upon closer inspection, however, this appears to work just fine with
        // Android, so for this platform we should be fine to call `memalign`
        // (which is present in API level 9). Some helpful references could
        // possibly be chromium using memalign [1], attempts at documenting that
        // memalign + free is ok [2] [3], or the current source of chromium
        // which still uses memalign on android [4].
        //
        // [1]: https://codereview.chromium.org/10796020/
        // [2]: https://code.google.com/p/android/issues/detail?id=35391
        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
        //                                       /memory/aligned_memory.cc
        libc::memalign(layout.align(), layout.size()) as *mut u8
    }

    #[cfg(not(any(target_os = "android",
                  target_os = "hermit",
                  target_os = "redox",
                  target_os = "solaris")))]
    #[inline]
    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
        let mut out = ptr::null_mut();
        let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
        if ret != 0 {
            ptr::null_mut()
        } else {
            out as *mut u8
        }
    }
}

#[cfg(windows)]
#[allow(nonstandard_style)]
mod platform {
    use MIN_ALIGN;
    use System;
    use core::alloc::{GlobalAlloc, Layout};

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
        fn GetLastError() -> DWORD;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.add(align - (ptr as usize & (align - 1)));
        *get_header(aligned) = Header(ptr);
        aligned
    }

    #[inline]
    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
        let ptr = if layout.align() <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), flags, layout.size())
        } else {
            let size = layout.size() + layout.align();
            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
            if ptr.is_null() {
                ptr
            } else {
                align_ptr(ptr, layout.align())
            }
        };
        ptr as *mut u8
    }

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            allocate_with_flags(layout, 0)
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
            if layout.align() <= MIN_ALIGN {
                let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
                debug_assert!(err != 0, "Failed to free heap memory: {}",
                              GetLastError());
            } else {
                let header = get_header(ptr);
                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
                debug_assert!(err != 0, "Failed to free heap memory: {}",
                              GetLastError());
            }
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            if layout.align() <= MIN_ALIGN {
                HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
            } else {
                self.realloc_fallback(ptr, layout, new_size)
            }
        }
    }
}

// This is an implementation of a global allocator on the wasm32 platform when
// emscripten is not in use. In that situation there's no actual runtime for us
// to lean on for allocation, so instead we provide our own!
//
// The wasm32 instruction set has two instructions for getting the current
// amount of memory and growing the amount of memory. These instructions are the
// foundation on which we're able to build an allocator, so we do so! Note that
// the instructions are also pretty "global" and this is the "global" allocator
// after all!
//
// The current allocator here is the `dlmalloc` crate which we've got included
// in the rust-lang/rust repository as a submodule. The crate is a port of
// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
// for now which is currently technically required (can't link with C yet).
//
// The crate itself provides a global allocator which on wasm has no
// synchronization as there are no threads!
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod platform {
    extern crate dlmalloc;

    use core::alloc::{GlobalAlloc, Layout};
    use System;

    // No need for synchronization here as wasm is currently single-threaded
    static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            DLMALLOC.malloc(layout.size(), layout.align())
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            DLMALLOC.calloc(layout.size(), layout.align())
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
            DLMALLOC.free(ptr, layout.size(), layout.align())
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
        }
    }
}
<commit_msg>std: Synchronize global allocator on wasm32<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![no_std]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_system",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "32838")]

#![feature(allocator_api)]
#![feature(core_intrinsics)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![cfg_attr(
    all(target_arch = "wasm32", not(target_os = "emscripten")),
    feature(integer_atomics, stdsimd)
)]
#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
#![rustc_alloc_kind = "lib"]

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "powerpc",
              target_arch = "powerpc64",
              target_arch = "asmjs",
              target_arch = "wasm32")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
              target_arch = "aarch64",
              target_arch = "mips64",
              target_arch = "s390x",
              target_arch = "sparc64")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 16;

use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
use core::ptr::NonNull;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type can be used in a `static` item
/// with the `#[global_allocator]` attribute
/// to force the global allocator to be the system’s one.
/// (The default is jemalloc for executables, on some platforms.)
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// It can also be used directly to allocate memory
/// independently of the standard library’s global allocator.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
pub struct System;

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: NonNull<u8>,
                      layout: Layout,
                      new_size: usize) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
    }
}

#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
mod realloc_fallback {
    use core::alloc::{GlobalAlloc, Layout};
    use core::cmp;
    use core::ptr;

    impl super::System {
        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
                                              new_size: usize) -> *mut u8 {
            // Docs for GlobalAlloc::realloc require this to be valid:
            let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());

            let new_ptr = GlobalAlloc::alloc(self, new_layout);
            if !new_ptr.is_null() {
                let size = cmp::min(old_layout.size(), new_size);
                ptr::copy_nonoverlapping(ptr, new_ptr, size);
                GlobalAlloc::dealloc(self, ptr, old_layout);
            }
            new_ptr
        }
    }
}

#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))]
mod platform {
    extern crate libc;

    use core::ptr;

    use MIN_ALIGN;
    use System;
    use core::alloc::{GlobalAlloc, Layout};

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
                libc::malloc(layout.size()) as *mut u8
            } else {
                #[cfg(target_os = "macos")]
                {
                    if layout.align() > (1 << 31) {
                        return ptr::null_mut()
                    }
                }
                aligned_malloc(&layout)
            }
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
                libc::calloc(layout.size(), 1) as *mut u8
            } else {
                let ptr = self.alloc(layout.clone());
                if !ptr.is_null() {
                    ptr::write_bytes(ptr, 0, layout.size());
                }
                ptr
            }
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
            libc::free(ptr as *mut libc::c_void)
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
            } else {
                self.realloc_fallback(ptr, layout, new_size)
            }
        }
    }

    #[cfg(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris"))]
    #[inline]
    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
        // On android we currently target API level 9 which unfortunately
        // doesn't have the `posix_memalign` API used below. Instead we use
        // `memalign`, but this unfortunately has the property on some systems
        // where the memory returned cannot be deallocated by `free`!
        //
        // Upon closer inspection, however, this appears to work just fine with
        // Android, so for this platform we should be fine to call `memalign`
        // (which is present in API level 9). Some helpful references could
        // possibly be chromium using memalign [1], attempts at documenting that
        // memalign + free is ok [2] [3], or the current source of chromium
        // which still uses memalign on android [4].
        //
        // [1]: https://codereview.chromium.org/10796020/
        // [2]: https://code.google.com/p/android/issues/detail?id=35391
        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
        //                                       /memory/aligned_memory.cc
        libc::memalign(layout.align(), layout.size()) as *mut u8
    }

    #[cfg(not(any(target_os = "android",
                  target_os = "hermit",
                  target_os = "redox",
                  target_os = "solaris")))]
    #[inline]
    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
        let mut out = ptr::null_mut();
        let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
        if ret != 0 {
            ptr::null_mut()
        } else {
            out as *mut u8
        }
    }
}

#[cfg(windows)]
#[allow(nonstandard_style)]
mod platform {
    use MIN_ALIGN;
    use System;
    use core::alloc::{GlobalAlloc, Layout};

    type LPVOID = *mut u8;
    type HANDLE = LPVOID;
    type SIZE_T = usize;
    type DWORD = u32;
    type BOOL = i32;

    extern "system" {
        fn GetProcessHeap() -> HANDLE;
        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
        fn GetLastError() -> DWORD;
    }

    #[repr(C)]
    struct Header(*mut u8);

    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;

    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
        &mut *(ptr as *mut Header).offset(-1)
    }

    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
        let aligned = ptr.add(align - (ptr as usize & (align - 1)));
        *get_header(aligned) = Header(ptr);
        aligned
    }

    #[inline]
    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
        let ptr = if layout.align() <= MIN_ALIGN {
            HeapAlloc(GetProcessHeap(), flags, layout.size())
        } else {
            let size = layout.size() + layout.align();
            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
            if ptr.is_null() {
                ptr
            } else {
                align_ptr(ptr, layout.align())
            }
        };
        ptr as *mut u8
    }

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            allocate_with_flags(layout, 0)
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
            if layout.align() <= MIN_ALIGN {
                let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
                debug_assert!(err != 0, "Failed to free heap memory: {}",
                              GetLastError());
            } else {
                let header = get_header(ptr);
                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
                debug_assert!(err != 0, "Failed to free heap memory: {}",
                              GetLastError());
            }
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            if layout.align() <= MIN_ALIGN {
                HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
            } else {
                self.realloc_fallback(ptr, layout, new_size)
            }
        }
    }
}

// This is an implementation of a global allocator on the wasm32 platform when
// emscripten is not in use. In that situation there's no actual runtime for us
// to lean on for allocation, so instead we provide our own!
//
// The wasm32 instruction set has two instructions for getting the current
// amount of memory and growing the amount of memory. These instructions are the
// foundation on which we're able to build an allocator, so we do so! Note that
// the instructions are also pretty "global" and this is the "global" allocator
// after all!
//
// The current allocator here is the `dlmalloc` crate which we've got included
// in the rust-lang/rust repository as a submodule. The crate is a port of
// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
// for now which is currently technically required (can't link with C yet).
//
// The crate itself provides a global allocator which on wasm has no
// synchronization as there are no threads!
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod platform {
    extern crate dlmalloc;

    use core::alloc::{GlobalAlloc, Layout};
    use System;

    static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;

    #[stable(feature = "alloc_system_type", since = "1.28.0")]
    unsafe impl GlobalAlloc for System {
        #[inline]
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            let _lock = lock::lock();
            DLMALLOC.malloc(layout.size(), layout.align())
        }

        #[inline]
        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
            let _lock = lock::lock();
            DLMALLOC.calloc(layout.size(), layout.align())
        }

        #[inline]
        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
            let _lock = lock::lock();
            DLMALLOC.free(ptr, layout.size(), layout.align())
        }

        #[inline]
        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
            let _lock = lock::lock();
            DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
        }
    }

    #[cfg(target_feature = "atomics")]
    mod lock {
        use core::arch::wasm32;
        use core::sync::atomic::{AtomicI32, Ordering::SeqCst};

        static LOCKED: AtomicI32 = AtomicI32::new(0);

        pub struct DropLock;

        pub fn lock() -> DropLock {
            loop {
                if LOCKED.swap(1, SeqCst) == 0 {
                    return DropLock
                }
                unsafe {
                    let r = wasm32::atomic::wait_i32(
                        &LOCKED as *const AtomicI32 as *mut i32,
                        1,  // expected value
                        -1, // timeout
                    );
                    debug_assert!(r == 0 || r == 1);
                }
            }
        }

        impl Drop for DropLock {
            fn drop(&mut self) {
                let r = LOCKED.swap(0, SeqCst);
                debug_assert_eq!(r, 1);
                unsafe {
                    wasm32::atomic::wake(
                        &LOCKED as *const AtomicI32 as *mut i32,
                        1, // only one thread
                    );
                }
            }
        }
    }

    #[cfg(not(target_feature = "atomics"))]
    mod lock {
        pub fn lock() {} // no atomics, no threads, that's easy!
    }
}
<|endoftext|>


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

mod num;
<commit_msg>coretest: Ensure that pointer formatting flags are cleaned up<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod num;

#[test]
fn test_format_flags() {
    // No residual flags left by pointer formatting
    let p = "".as_ptr();
    assert_eq!(format!("{:p} {:x}", p, 16u), format!("{:p} 10", p));
}
<|endoftext|>


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

//! This example shows how managed objects can be accessed from callbacks

extern mod glfw;

use std::local_data;

static tls_key: local_data::Key<@mut TitleUpdater> = &local_data::Key;

struct TitleUpdater {
    window: @mut glfw::Window,
}

impl TitleUpdater {
    pub fn update(&self, title: &str) {
        self.window.set_title(title);
    }

    /* TLS management. */
    pub fn set(tu: @mut TitleUpdater) {
        local_data::set(tls_key, tu);
    }

    pub fn get() -> @mut TitleUpdater {
        do local_data::get(tls_key) |opt| {
            match opt {
                Some(x) => *x,
                None => fail!("Invalid TitleUpdater"),
            }
        }
    }
}

#[start]
fn start(argc: int, argv: **u8, crate_map: *u8) -> int {
    std::rt::start_on_main_thread(argc, argv, crate_map, main)
}

fn main() {
    do glfw::set_error_callback |_, msg| {
        printfln!("GLFW Error: %s", msg);
    }

    do glfw::start {
        let window = @mut glfw::Window::create(300, 300, "Move cursor in window", glfw::Windowed).unwrap();
        let title_updater = @mut TitleUpdater { window: window };
        TitleUpdater::set(title_updater); // Store in TLS.

        // Title updater must be in TLS and cannot be captured in the callback.
        do window.set_cursor_pos_callback |_, x, y| {
            TitleUpdater::get().update(fmt!("(%f %f)", x, y));
        }

        do window.set_key_callback |win, key, _, action, _mods| {
            if action == glfw::PRESS && key == glfw::KEY_ESCAPE {
                win.set_should_close(true);
            }
        }
        window.make_context_current();

        while !window.should_close() {
            glfw::poll_events();
        }
    }
}

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

//! This example shows how managed objects can be accessed from callbacks

extern mod glfw;

use std::local_data;

static tls_key: local_data::Key<@mut State> = &local_data::Key;

struct State {
    priv pos: (float, float),
}

impl State {
    pub fn init(x: float, y: float) {
        local_data::set(tls_key, @mut State { pos: (x, y) });
    }

    pub fn update(x: float, y: float) {
        do local_data::get(tls_key) |opt| {
            opt.expect("Task-local state not initialized.").pos = (x, y);
        }
    }

    pub fn get_pos() -> (float, float) {
        do local_data::get(tls_key) |opt| {
            opt.expect("Task-local state not initialized.").pos
        }
    }
}

#[start]
fn start(argc: int, argv: **u8, crate_map: *u8) -> int {
    std::rt::start_on_main_thread(argc, argv, crate_map, main)
}

fn main() {
    do glfw::set_error_callback |_, msg| {
        printfln!("GLFW Error: %s", msg);
    }

    do glfw::start {
        let window = glfw::Window::create(300, 300, "Move cursor in window", glfw::Windowed).unwrap();
        State::init(0f, 0f);

        do window.set_cursor_pos_callback |_, x, y| {
            State::update(x, y);
        }

        do window.set_key_callback |win, key, _, action, _mods| {
            if action == glfw::PRESS && key == glfw::KEY_ESCAPE {
                win.set_should_close(true);
            }
        }
        window.make_context_current();

        while !window.should_close() {
            glfw::poll_events();
            window.set_title(format!("{:?}", State::get_pos()));
        }
    }
}

<|endoftext|>