<commit_before>//! Data structures for representing syntax definitions
//!
//! Everything here is public becaues I want this library to be useful in super integrated cases
//! like text editors and I have no idea what kind of monkeying you might want to do with the data.
//! Perhaps parsing your own syntax format into this data structure?

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use super::scope::*;
use super::regex::{Regex, Region};
use regex_syntax::escape;
use serde::{Serialize, Serializer};
use crate::parsing::syntax_set::SyntaxSet;

pub type CaptureMapping = Vec<(usize, Vec<Scope>)>;

/// An opaque ID for a [`Context`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ContextId {
    /// Index into [`SyntaxSet::syntaxes`]
    pub(crate) syntax_index: usize,

    /// Index into [`crate::parsing::SyntaxReference::contexts`] for the [`Self::syntax_index`] syntax
    pub(crate) context_index: usize,
}

/// The main data structure representing a syntax definition loaded from a
/// `.sublime-syntax` file
///
/// You'll probably only need these as references to be passed around to parsing code.
///
/// Some useful public fields are the `name` field which is a human readable name to display in
/// syntax lists, and the `hidden` field which means hide this syntax from any lists because it is
/// for internal use.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SyntaxDefinition {
    pub name: String,
    pub file_extensions: Vec<String>,
    pub scope: Scope,
    pub first_line_match: Option<String>,
    pub hidden: bool,
    #[serde(serialize_with = "ordered_map")]
    pub variables: HashMap<String, String>,
    #[serde(serialize_with = "ordered_map")]
    pub contexts: HashMap<String, Context>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Context {
    pub meta_scope: Vec<Scope>,
    pub meta_content_scope: Vec<Scope>,
    /// This being set false in the syntax file implies this field being set false,
    /// but it can also be set falso for contexts that don't include the prototype for other reasons
    pub meta_include_prototype: bool,
    pub clear_scopes: Option<ClearAmount>,
    /// This is filled in by the linker at link time
    /// for contexts that have `meta_include_prototype==true`
    /// and are not included from the prototype.
    pub prototype: Option<ContextId>,
    pub uses_backrefs: bool,

    pub patterns: Vec<Pattern>,
}

impl Context {
    pub fn new(meta_include_prototype: bool) -> Context {
        Context {
            meta_scope: Vec::new(),
            meta_content_scope: Vec::new(),
            meta_include_prototype,
            clear_scopes: None,
            uses_backrefs: false,
            patterns: Vec::new(),
            prototype: None,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Pattern {
    Match(MatchPattern),
    Include(ContextReference),
}

/// Used to iterate over all the match patterns in a context
///
/// Basically walks the tree of patterns and include directives in the correct order.
#[derive(Debug)]
pub struct MatchIter<'a> {
    syntax_set: &'a SyntaxSet,
    ctx_stack: Vec<&'a Context>,
    index_stack: Vec<usize>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct MatchPattern {
    pub has_captures: bool,
    pub regex: Regex,
    pub scope: Vec<Scope>,
    pub captures: Option<CaptureMapping>,
    pub operation: MatchOperation,
    pub with_prototype: Option<ContextReference>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ContextReference {
    Named(String),
    ByScope {
        scope: Scope,
        sub_context: Option<String>,
    },
    File {
        name: String,
        sub_context: Option<String>,
    },
    Inline(String),
    Direct(ContextId),
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum MatchOperation {
    Push(Vec<ContextReference>),
    Set(Vec<ContextReference>),
    Pop,
    None,
}

impl<'a> Iterator for MatchIter<'a> {
    type Item = (&'a Context, usize);

    fn next(&mut self) -> Option<(&'a Context, usize)> {
        loop {
            if self.ctx_stack.is_empty() {
                return None;
            }
            // uncomment for debugging infinite recursion
            // println!("{:?}", self.index_stack);
            // use std::thread::sleep_ms;
            // sleep_ms(500);
            let last_index = self.ctx_stack.len() - 1;
            let context = self.ctx_stack[last_index];
            let index = self.index_stack[last_index];
            self.index_stack[last_index] = index + 1;
            if index < context.patterns.len() {
                match context.patterns[index] {
                    Pattern::Match(_) => {
                        return Some((context, index));
                    },
                    Pattern::Include(ref ctx_ref) => {
                        let ctx_ptr = match *ctx_ref {
                            ContextReference::Direct(ref context_id) => {
                                self.syntax_set.get_context(context_id)
                            }
                            _ => return self.next(), // skip this and move onto the next one
                        };
                        self.ctx_stack.push(ctx_ptr);
                        self.index_stack.push(0);
                    }
                }
            } else {
                self.ctx_stack.pop();
                self.index_stack.pop();
            }
        }
    }
}

/// Returns an iterator over all the match patterns in this context.
///
/// It recursively follows include directives. Can only be run on contexts that have already been
/// linked up.
pub fn context_iter<'a>(syntax_set: &'a SyntaxSet, context: &'a Context) -> MatchIter<'a> {
    MatchIter {
        syntax_set,
        ctx_stack: vec![context],
        index_stack: vec![0],
    }
}

impl Context {
    /// Returns the match pattern at an index, panics if the thing isn't a match pattern
    pub fn match_at(&self, index: usize) -> &MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }
}

impl ContextReference {
    /// find the pointed to context, panics if ref is not linked
    pub fn resolve<'a>(&self, syntax_set: &'a SyntaxSet) -> &'a Context {
        match *self {
            ContextReference::Direct(ref context_id) => syntax_set.get_context(context_id),
            _ => panic!("Can only call resolve on linked references: {:?}", self),
        }
    }

    /// get the context ID this reference points to, panics if ref is not linked
    pub fn id(&self) -> ContextId {
        match *self {
            ContextReference::Direct(ref context_id) => *context_id,
            _ => panic!("Can only get ContextId of linked references: {:?}", self),
        }
    }
}

pub(crate) fn substitute_backrefs_in_regex<F>(regex_str: &str, substituter: F) -> String
    where F: Fn(usize) -> Option<String>
{
    let mut reg_str = String::with_capacity(regex_str.len());

    let mut last_was_escape = false;
    for c in regex_str.chars() {
        if last_was_escape && c.is_digit(10) {
            let val = c.to_digit(10).unwrap() as usize;
            if let Some(sub) = substituter(val) {
                reg_str.push_str(&sub);
            }
        } else if last_was_escape {
            reg_str.push('\\');
            reg_str.push(c);
        } else if c != '\\' {
            reg_str.push(c);
        }

        last_was_escape = c == '\\' && !last_was_escape;
    }
    reg_str
}

impl ContextId {
    /// Deprecated. You should never create your own context ID.
    #[deprecated]
    pub fn new(_index: usize) -> Self {
        ContextId {
            syntax_index: 666,
            context_index: 666,
        }
    }
}

impl MatchPattern {

    pub fn new(
        has_captures: bool,
        regex_str: String,
        scope: Vec<Scope>,
        captures: Option<CaptureMapping>,
        operation: MatchOperation,
        with_prototype: Option<ContextReference>,
    ) -> MatchPattern {
        MatchPattern {
            has_captures,
            regex: Regex::new(regex_str),
            scope,
            captures,
            operation,
            with_prototype,
        }
    }

    /// Used by the parser to compile a regex which needs to reference
    /// regions from another matched pattern.
    pub fn regex_with_refs(&self, region: &Region, text: &str) -> Regex {
        let new_regex = substitute_backrefs_in_regex(self.regex.regex_str(), |i| {
            region.pos(i).map(|(start, end)| escape(&text[start..end]))
        });

        Regex::new(new_regex)
    }

    pub fn regex(&self) -> &Regex {
        &self.regex
    }
}

/// Serialize the provided map in natural key order, so that it's deterministic when dumping.
pub(crate) fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize
{
    let ordered: BTreeMap<_, _> = map.iter().collect();
    ordered.serialize(serializer)
}

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

    #[test]
    fn can_compile_refs() {
        let pat = MatchPattern {
            has_captures: true,
            regex: Regex::new(r"lol \\ \2 \1 '\9' \wz".into()),
            scope: vec![],
            captures: None,
            operation: MatchOperation::None,
            with_prototype: None,
        };
        let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)".into());
        let s = r"\[]()bcde";
        let mut region = Region::new();
        let matched = r.search(s, 0, s.len(), Some(&mut region));
        assert!(matched);

        let regex_with_refs = pat.regex_with_refs(&region, s);
        assert_eq!(regex_with_refs.regex_str(), r"lol \\ b \\\[\]\(\) '' \wz");
    }
}
<commit_msg>Remove ContextId::new() rather than deprecating it<commit_after>//! Data structures for representing syntax definitions
//!
//! Everything here is public becaues I want this library to be useful in super integrated cases
//! like text editors and I have no idea what kind of monkeying you might want to do with the data.
//! Perhaps parsing your own syntax format into this data structure?

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use super::scope::*;
use super::regex::{Regex, Region};
use regex_syntax::escape;
use serde::{Serialize, Serializer};
use crate::parsing::syntax_set::SyntaxSet;

pub type CaptureMapping = Vec<(usize, Vec<Scope>)>;

/// An opaque ID for a [`Context`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ContextId {
    /// Index into [`SyntaxSet::syntaxes`]
    pub(crate) syntax_index: usize,

    /// Index into [`crate::parsing::SyntaxReference::contexts`] for the [`Self::syntax_index`] syntax
    pub(crate) context_index: usize,
}

/// The main data structure representing a syntax definition loaded from a
/// `.sublime-syntax` file
///
/// You'll probably only need these as references to be passed around to parsing code.
///
/// Some useful public fields are the `name` field which is a human readable name to display in
/// syntax lists, and the `hidden` field which means hide this syntax from any lists because it is
/// for internal use.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SyntaxDefinition {
    pub name: String,
    pub file_extensions: Vec<String>,
    pub scope: Scope,
    pub first_line_match: Option<String>,
    pub hidden: bool,
    #[serde(serialize_with = "ordered_map")]
    pub variables: HashMap<String, String>,
    #[serde(serialize_with = "ordered_map")]
    pub contexts: HashMap<String, Context>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Context {
    pub meta_scope: Vec<Scope>,
    pub meta_content_scope: Vec<Scope>,
    /// This being set false in the syntax file implies this field being set false,
    /// but it can also be set falso for contexts that don't include the prototype for other reasons
    pub meta_include_prototype: bool,
    pub clear_scopes: Option<ClearAmount>,
    /// This is filled in by the linker at link time
    /// for contexts that have `meta_include_prototype==true`
    /// and are not included from the prototype.
    pub prototype: Option<ContextId>,
    pub uses_backrefs: bool,

    pub patterns: Vec<Pattern>,
}

impl Context {
    pub fn new(meta_include_prototype: bool) -> Context {
        Context {
            meta_scope: Vec::new(),
            meta_content_scope: Vec::new(),
            meta_include_prototype,
            clear_scopes: None,
            uses_backrefs: false,
            patterns: Vec::new(),
            prototype: None,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Pattern {
    Match(MatchPattern),
    Include(ContextReference),
}

/// Used to iterate over all the match patterns in a context
///
/// Basically walks the tree of patterns and include directives in the correct order.
#[derive(Debug)]
pub struct MatchIter<'a> {
    syntax_set: &'a SyntaxSet,
    ctx_stack: Vec<&'a Context>,
    index_stack: Vec<usize>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct MatchPattern {
    pub has_captures: bool,
    pub regex: Regex,
    pub scope: Vec<Scope>,
    pub captures: Option<CaptureMapping>,
    pub operation: MatchOperation,
    pub with_prototype: Option<ContextReference>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ContextReference {
    Named(String),
    ByScope {
        scope: Scope,
        sub_context: Option<String>,
    },
    File {
        name: String,
        sub_context: Option<String>,
    },
    Inline(String),
    Direct(ContextId),
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum MatchOperation {
    Push(Vec<ContextReference>),
    Set(Vec<ContextReference>),
    Pop,
    None,
}

impl<'a> Iterator for MatchIter<'a> {
    type Item = (&'a Context, usize);

    fn next(&mut self) -> Option<(&'a Context, usize)> {
        loop {
            if self.ctx_stack.is_empty() {
                return None;
            }
            // uncomment for debugging infinite recursion
            // println!("{:?}", self.index_stack);
            // use std::thread::sleep_ms;
            // sleep_ms(500);
            let last_index = self.ctx_stack.len() - 1;
            let context = self.ctx_stack[last_index];
            let index = self.index_stack[last_index];
            self.index_stack[last_index] = index + 1;
            if index < context.patterns.len() {
                match context.patterns[index] {
                    Pattern::Match(_) => {
                        return Some((context, index));
                    },
                    Pattern::Include(ref ctx_ref) => {
                        let ctx_ptr = match *ctx_ref {
                            ContextReference::Direct(ref context_id) => {
                                self.syntax_set.get_context(context_id)
                            }
                            _ => return self.next(), // skip this and move onto the next one
                        };
                        self.ctx_stack.push(ctx_ptr);
                        self.index_stack.push(0);
                    }
                }
            } else {
                self.ctx_stack.pop();
                self.index_stack.pop();
            }
        }
    }
}

/// Returns an iterator over all the match patterns in this context.
///
/// It recursively follows include directives. Can only be run on contexts that have already been
/// linked up.
pub fn context_iter<'a>(syntax_set: &'a SyntaxSet, context: &'a Context) -> MatchIter<'a> {
    MatchIter {
        syntax_set,
        ctx_stack: vec![context],
        index_stack: vec![0],
    }
}

impl Context {
    /// Returns the match pattern at an index, panics if the thing isn't a match pattern
    pub fn match_at(&self, index: usize) -> &MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }
}

impl ContextReference {
    /// find the pointed to context, panics if ref is not linked
    pub fn resolve<'a>(&self, syntax_set: &'a SyntaxSet) -> &'a Context {
        match *self {
            ContextReference::Direct(ref context_id) => syntax_set.get_context(context_id),
            _ => panic!("Can only call resolve on linked references: {:?}", self),
        }
    }

    /// get the context ID this reference points to, panics if ref is not linked
    pub fn id(&self) -> ContextId {
        match *self {
            ContextReference::Direct(ref context_id) => *context_id,
            _ => panic!("Can only get ContextId of linked references: {:?}", self),
        }
    }
}

pub(crate) fn substitute_backrefs_in_regex<F>(regex_str: &str, substituter: F) -> String
    where F: Fn(usize) -> Option<String>
{
    let mut reg_str = String::with_capacity(regex_str.len());

    let mut last_was_escape = false;
    for c in regex_str.chars() {
        if last_was_escape && c.is_digit(10) {
            let val = c.to_digit(10).unwrap() as usize;
            if let Some(sub) = substituter(val) {
                reg_str.push_str(&sub);
            }
        } else if last_was_escape {
            reg_str.push('\\');
            reg_str.push(c);
        } else if c != '\\' {
            reg_str.push(c);
        }

        last_was_escape = c == '\\' && !last_was_escape;
    }
    reg_str
}

impl MatchPattern {

    pub fn new(
        has_captures: bool,
        regex_str: String,
        scope: Vec<Scope>,
        captures: Option<CaptureMapping>,
        operation: MatchOperation,
        with_prototype: Option<ContextReference>,
    ) -> MatchPattern {
        MatchPattern {
            has_captures,
            regex: Regex::new(regex_str),
            scope,
            captures,
            operation,
            with_prototype,
        }
    }

    /// Used by the parser to compile a regex which needs to reference
    /// regions from another matched pattern.
    pub fn regex_with_refs(&self, region: &Region, text: &str) -> Regex {
        let new_regex = substitute_backrefs_in_regex(self.regex.regex_str(), |i| {
            region.pos(i).map(|(start, end)| escape(&text[start..end]))
        });

        Regex::new(new_regex)
    }

    pub fn regex(&self) -> &Regex {
        &self.regex
    }
}

/// Serialize the provided map in natural key order, so that it's deterministic when dumping.
pub(crate) fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize
{
    let ordered: BTreeMap<_, _> = map.iter().collect();
    ordered.serialize(serializer)
}

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

    #[test]
    fn can_compile_refs() {
        let pat = MatchPattern {
            has_captures: true,
            regex: Regex::new(r"lol \\ \2 \1 '\9' \wz".into()),
            scope: vec![],
            captures: None,
            operation: MatchOperation::None,
            with_prototype: None,
        };
        let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)".into());
        let s = r"\[]()bcde";
        let mut region = Region::new();
        let matched = r.search(s, 0, s.len(), Some(&mut region));
        assert!(matched);

        let regex_with_refs = pat.regex_with_refs(&region, s);
        assert_eq!(regex_with_refs.regex_str(), r"lol \\ b \\\[\]\(\) '' \wz");
    }
}
<|endoftext|>


<commit_before>use nom::alpha;
use std::str;
use ast::Expression;

fn bytes_to_string(bytes: &[u8]) -> String {
    str::from_utf8(bytes).unwrap().to_string()
}

// Convert the main parser to the AST
named!(pub identifier_literal<Expression>,
    map!(
        alt!(symbol_identifier | alpha_identifier),
        Expression::Identifier
    )
);

// In Lisp, we can use symbols for identifiers so parse them as such
named!(pub symbol_identifier<String>,
    map!(
        recognize!(
            many0!(
                alt!(char!('{')
                    | char!('}')
                    | char!('(')
                    | char!(')')
                    | char!('[')
                    | char!(']')
                    | char!('.')
                    | char!(';')
                    | char!(',')
                    | char!('<')
                    | char!('>')
                    | char!('=')
                    | char!('!')
                    | char!('+')
                    | char!('-')
                    | char!('*')
                    | char!('/')
                    | char!('&')
                    | char!('|')
                    | char!('^')
                    | char!('~')
                    | char!('?')
                    | char!(':')
                )
            )
        ), bytes_to_string
    )
);

// Represents letters etc in identifiers
named!(pub alpha_identifier<String>,
    map!(
        recognize!(
            tuple!(
                alpha,
                // Somethimes a symbol might follow a letter
                opt!(symbol_identifier)
            )
        ),
        bytes_to_string
    )
);
<commit_msg>Temporarily remove complex parsing from alpa_identifiers<commit_after>use nom::alpha;
use std::str;
use ast::Expression;

fn bytes_to_string(bytes: &[u8]) -> String {
    str::from_utf8(bytes).unwrap().to_string()
}

// Convert the main parser to the AST
named!(pub identifier_literal<Expression>,
    map!(
        alt!(symbol_identifier | alpha_identifier),
        Expression::Identifier
    )
);

// In Lisp, we can use symbols for identifiers so parse them as such
named!(pub symbol_identifier<String>,
    map!(
        recognize!(
            many0!(
                alt!(char!('{')
                    | char!('}')
                    | char!('(')
                    | char!(')')
                    | char!('[')
                    | char!(']')
                    | char!('.')
                    | char!(';')
                    | char!(',')
                    | char!('<')
                    | char!('>')
                    | char!('=')
                    | char!('!')
                    | char!('+')
                    | char!('-')
                    | char!('*')
                    | char!('/')
                    | char!('&')
                    | char!('|')
                    | char!('^')
                    | char!('~')
                    | char!('?')
                    | char!(':')
                )
            )
        ), bytes_to_string
    )
);

// Represents letters etc in identifiers
named!(pub alpha_identifier<String>,
    map!(
        alpha,
        bytes_to_string
    )
);
<|endoftext|>


<commit_before>use sdl2;

use geometry;

struct Player {
	size: geometry::Size,
}

struct PlayerState {
	player: ~Player,
	position: geometry::Point,
	sprite: ~sdl2::surface::Surface,
	sprite_path: ~str,
}

impl Player {
	pub fn new(size: geometry::Size) -> Player {
		Player{size: size}
	}

	pub fn clone(&self) -> ~Player {
		~Player{size: self.size}
	}
}

impl PlayerState {
	pub fn new(player: ~Player, position: geometry::Point, sprite_path: ~str) -> PlayerState {
        let sprite = match sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")) {
        	Ok(loaded_sprite) => loaded_sprite,
        	Err(_) => fail!(format!("Failed to load player sprite at path: {}", sprite_path))
        };

		PlayerState{player: player, position: position, sprite: sprite, sprite_path: sprite_path}
	}
}

impl Clone for PlayerState {
	fn clone(&self) -> PlayerState {
        let sprite = sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")).unwrap();
		PlayerState{player: self.player.clone(), position: self.position, sprite: sprite, sprite_path: self.sprite_path.clone()}
	}
}<commit_msg>Explicitly implement Clone for Player<commit_after>use sdl2;

use geometry;

struct Player {
	size: geometry::Size,
}

struct PlayerState {
	player: ~Player,
	position: geometry::Point,
	sprite: ~sdl2::surface::Surface,
	sprite_path: ~str,
}

impl Player {
	pub fn new(size: geometry::Size) -> Player {
		Player{size: size}
	}
}

impl Clone for Player {
	fn clone(&self) -> Player {
		Player{size: self.size}
	}
}

impl PlayerState {
	pub fn new(player: ~Player, position: geometry::Point, sprite_path: ~str) -> PlayerState {
        let sprite = match sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")) {
        	Ok(loaded_sprite) => loaded_sprite,
        	Err(_) => fail!(format!("Failed to load player sprite at path: {}", sprite_path))
        };

		PlayerState{player: player, position: position, sprite: sprite, sprite_path: sprite_path}
	}
}

impl Clone for PlayerState {
	fn clone(&self) -> PlayerState {
        let sprite = sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")).unwrap();
		PlayerState{player: self.player.clone(), position: self.position, sprite: sprite, sprite_path: self.sprite_path.clone()}
	}
}<|endoftext|>


<commit_before>use std::ops::Deref;
use rustc::hir::*;
use rustc::hir::map::Node::{NodeImplItem, NodeItem};
use rustc::lint::*;
use syntax::ast::LitKind;
use syntax::symbol::InternedString;
use syntax_pos::Span;
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint, span_lint_and_sugg};
use utils::{opt_def_id, paths};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
declare_lint! {
    pub PRINT_LITERAL,
    Allow,
    "printing a literal with a format string"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRINT_WITH_NEWLINE, PRINTLN_EMPTY_STRING, PRINT_STDOUT, USE_DEBUG, PRINT_LITERAL)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {
            if let ExprCall(ref fun, ref args) = expr.node;
            if let ExprPath(ref qpath) = fun.node;
            if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
            then {

                // Search for `std::io::_print(..)` which is unique in a
                // `print!` expansion.
                if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) {
                    if let Some(span) = is_expn_of(expr.span, "print") {
                        // `println!` uses `print!`.
                        let (span, name) = match is_expn_of(span, "println") {
                            Some(span) => (span, "println"),
                            None => (span, "print"),
                        };

                        span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));

                        // Check for literals in the print!/println! args
                        // Also, ensure the format string is `{}` with no special options, like `{:X}`
                        check_print_args_for_literal(cx, args);

                        if_chain! {
                            // ensure we're calling Arguments::new_v1
                            if args.len() == 1;
                            if let ExprCall(ref args_fun, ref args_args) = args[0].node;
                            if let ExprPath(ref qpath) = args_fun.node;
                            if let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id));
                            if match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1);
                            if args_args.len() == 2;
                            if let ExprAddrOf(_, ref match_expr) = args_args[1].node;
                            if let ExprMatch(ref args, _, _) = match_expr.node;
                            if let ExprTup(ref args) = args.node;
                            if let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]);
                            then {
                                match name {
                                    "print" => check_print(cx, span, args, fmtstr, fmtlen),
                                    "println" => check_println(cx, span, fmtstr, fmtlen),
                                    _ => (),
                                }
                            }
                        }
                    }
                }
                // Search for something like
                // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
                else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
                    if let ExprPath(ref qpath) = args[1].node {
                        if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) {
                            if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD)
                                    && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
                                span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
                            }
                        }
                    }
                }
            }
        }
    }
}

// Check for literals in print!/println! args
// ensuring the format string for the literal is `DISPLAY_FMT_METHOD`
// e.g., `println!("... {} ...", "foo")`
//                                ^ literal in `println!`
fn check_print_args_for_literal<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    args: &HirVec<Expr>
) {
    if_chain! {
        if args.len() == 1;
        if let ExprCall(_, ref args_args) = args[0].node;
        if args_args.len() > 1;
        if let ExprAddrOf(_, ref match_expr) = args_args[1].node;
        if let ExprMatch(ref matchee, ref arms, _) = match_expr.node;
        if let ExprTup(ref tup) = matchee.node;
        if arms.len() == 1;
        if let ExprArray(ref arm_body_exprs) = arms[0].body.node;
        then {
            // it doesn't matter how many args there are in the `print!`/`println!`,
            // if there's one literal, we should warn the user
            for (idx, tup_arg) in tup.iter().enumerate() {
                if_chain! {
                    // first, make sure we're dealing with a literal (i.e., an ExprLit)
                    if let ExprAddrOf(_, ref tup_val) = tup_arg.node;
                    if let ExprLit(_) = tup_val.node;

                    // next, check the corresponding match arm body to ensure
                    // this is "{}", or DISPLAY_FMT_METHOD
                    if let ExprCall(_, ref body_args) = arm_body_exprs[idx].node;
                    if body_args.len() == 2;
                    if let ExprPath(ref body_qpath) = body_args[1].node;
                    if let Some(fun_def_id) = opt_def_id(resolve_node(cx, body_qpath, body_args[1].hir_id));
                    if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD) ||
                       match_def_path(cx.tcx, fun_def_id, &paths::DEBUG_FMT_METHOD);
                    then {
                        span_lint(cx, PRINT_LITERAL, tup_val.span, "printing a literal with an empty format string");
                    }
                }
            }
        }
    }
}

// Check for print!("... \n", ...).
fn check_print<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    span: Span,
    args: &HirVec<Expr>,
    fmtstr: InternedString,
    fmtlen: usize,
) {
    if_chain! {
        // check the final format string part
        if let Some('\n') = fmtstr.chars().last();

        // "foo{}bar" is made into two strings + one argument,
        // if the format string starts with `{}` (eg. "{}foo"),
        // the string array is prepended an empty string "".
        // We only want to check the last string after any `{}`:
        if args.len() < fmtlen;
        then {
            span_lint(cx, PRINT_WITH_NEWLINE, span,
                      "using `print!()` with a format string that ends in a \
                       newline, consider using `println!()` instead");
        }
    }
}

/// Check for println!("")
fn check_println<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, fmtstr: InternedString, fmtlen: usize) {
    if_chain! {
        // check that the string is empty
        if fmtlen == 1;
        if fmtstr.deref() == "\n";

        // check the presence of that string
        if let Ok(snippet) = cx.sess().codemap().span_to_snippet(span);
        if snippet.contains("\"\"");
        then {
            span_lint_and_sugg(
                cx,
                PRINT_WITH_NEWLINE,
                span,
                "using `println!(\"\")`",
                "replace it with",
                "println!()".to_string(),
            );
         }
    }
}

fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
    let map = &cx.tcx.hir;

    // `fmt` method
    if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
        // `Debug` impl
        if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
            if let ItemImpl(_, _, _, _, Some(ref tr), _, _) = item.node {
                return match_path(&tr.path, &["Debug"]);
            }
        }
    }

    false
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node; // &["…", "…", …]
        if let ExprArray(ref exprs) = expr.node;
        if let Some(expr) = exprs.last();
        if let ExprLit(ref lit) = expr.node;
        if let LitKind::Str(ref lit, _) = lit.node;
        then {
            return Some((lit.as_str(), exprs.len()));
        }
    }
    None
}
<commit_msg>Change declare_lint! to declare_clippy_lint!<commit_after>use std::ops::Deref;
use rustc::hir::*;
use rustc::hir::map::Node::{NodeImplItem, NodeItem};
use rustc::lint::*;
use syntax::ast::LitKind;
use syntax::symbol::InternedString;
use syntax_pos::Span;
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint, span_lint_and_sugg};
use utils::{opt_def_id, paths};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRINT_WITH_NEWLINE, PRINTLN_EMPTY_STRING, PRINT_STDOUT, USE_DEBUG, PRINT_LITERAL)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if_chain! {
            if let ExprCall(ref fun, ref args) = expr.node;
            if let ExprPath(ref qpath) = fun.node;
            if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
            then {

                // Search for `std::io::_print(..)` which is unique in a
                // `print!` expansion.
                if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) {
                    if let Some(span) = is_expn_of(expr.span, "print") {
                        // `println!` uses `print!`.
                        let (span, name) = match is_expn_of(span, "println") {
                            Some(span) => (span, "println"),
                            None => (span, "print"),
                        };

                        span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));

                        // Check for literals in the print!/println! args
                        // Also, ensure the format string is `{}` with no special options, like `{:X}`
                        check_print_args_for_literal(cx, args);

                        if_chain! {
                            // ensure we're calling Arguments::new_v1
                            if args.len() == 1;
                            if let ExprCall(ref args_fun, ref args_args) = args[0].node;
                            if let ExprPath(ref qpath) = args_fun.node;
                            if let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id));
                            if match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1);
                            if args_args.len() == 2;
                            if let ExprAddrOf(_, ref match_expr) = args_args[1].node;
                            if let ExprMatch(ref args, _, _) = match_expr.node;
                            if let ExprTup(ref args) = args.node;
                            if let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]);
                            then {
                                match name {
                                    "print" => check_print(cx, span, args, fmtstr, fmtlen),
                                    "println" => check_println(cx, span, fmtstr, fmtlen),
                                    _ => (),
                                }
                            }
                        }
                    }
                }
                // Search for something like
                // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
                else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
                    if let ExprPath(ref qpath) = args[1].node {
                        if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) {
                            if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD)
                                    && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
                                span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
                            }
                        }
                    }
                }
            }
        }
    }
}

// Check for literals in print!/println! args
// ensuring the format string for the literal is `DISPLAY_FMT_METHOD`
// e.g., `println!("... {} ...", "foo")`
//                                ^ literal in `println!`
fn check_print_args_for_literal<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    args: &HirVec<Expr>
) {
    if_chain! {
        if args.len() == 1;
        if let ExprCall(_, ref args_args) = args[0].node;
        if args_args.len() > 1;
        if let ExprAddrOf(_, ref match_expr) = args_args[1].node;
        if let ExprMatch(ref matchee, ref arms, _) = match_expr.node;
        if let ExprTup(ref tup) = matchee.node;
        if arms.len() == 1;
        if let ExprArray(ref arm_body_exprs) = arms[0].body.node;
        then {
            // it doesn't matter how many args there are in the `print!`/`println!`,
            // if there's one literal, we should warn the user
            for (idx, tup_arg) in tup.iter().enumerate() {
                if_chain! {
                    // first, make sure we're dealing with a literal (i.e., an ExprLit)
                    if let ExprAddrOf(_, ref tup_val) = tup_arg.node;
                    if let ExprLit(_) = tup_val.node;

                    // next, check the corresponding match arm body to ensure
                    // this is "{}", or DISPLAY_FMT_METHOD
                    if let ExprCall(_, ref body_args) = arm_body_exprs[idx].node;
                    if body_args.len() == 2;
                    if let ExprPath(ref body_qpath) = body_args[1].node;
                    if let Some(fun_def_id) = opt_def_id(resolve_node(cx, body_qpath, body_args[1].hir_id));
                    if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD) ||
                       match_def_path(cx.tcx, fun_def_id, &paths::DEBUG_FMT_METHOD);
                    then {
                        span_lint(cx, PRINT_LITERAL, tup_val.span, "printing a literal with an empty format string");
                    }
                }
            }
        }
    }
}

// Check for print!("... \n", ...).
fn check_print<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    span: Span,
    args: &HirVec<Expr>,
    fmtstr: InternedString,
    fmtlen: usize,
) {
    if_chain! {
        // check the final format string part
        if let Some('\n') = fmtstr.chars().last();

        // "foo{}bar" is made into two strings + one argument,
        // if the format string starts with `{}` (eg. "{}foo"),
        // the string array is prepended an empty string "".
        // We only want to check the last string after any `{}`:
        if args.len() < fmtlen;
        then {
            span_lint(cx, PRINT_WITH_NEWLINE, span,
                      "using `print!()` with a format string that ends in a \
                       newline, consider using `println!()` instead");
        }
    }
}

/// Check for println!("")
fn check_println<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, fmtstr: InternedString, fmtlen: usize) {
    if_chain! {
        // check that the string is empty
        if fmtlen == 1;
        if fmtstr.deref() == "\n";

        // check the presence of that string
        if let Ok(snippet) = cx.sess().codemap().span_to_snippet(span);
        if snippet.contains("\"\"");
        then {
            span_lint_and_sugg(
                cx,
                PRINT_WITH_NEWLINE,
                span,
                "using `println!(\"\")`",
                "replace it with",
                "println!()".to_string(),
            );
         }
    }
}

fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
    let map = &cx.tcx.hir;

    // `fmt` method
    if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
        // `Debug` impl
        if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
            if let ItemImpl(_, _, _, _, Some(ref tr), _, _) = item.node {
                return match_path(&tr.path, &["Debug"]);
            }
        }
    }

    false
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node; // &["…", "…", …]
        if let ExprArray(ref exprs) = expr.node;
        if let Some(expr) = exprs.last();
        if let ExprLit(ref lit) = expr.node;
        if let LitKind::Str(ref lit, _) = lit.node;
        then {
            return Some((lit.as_str(), exprs.len()));
        }
    }
    None
}
<|endoftext|>


<commit_before>use client::Client;
use common::block_position::BlockPosition;
use common::color::Color3;
use common::communicate::ServerToClient;
use common::process_events::process_channel;
use common::surroundings_loader::radius_between;
use light::Light;
use nalgebra::Vec3;
use std::cmp::partial_max;
use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::f32::consts::PI;
use std::num::Float;
use std::old_io::timer;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::Mutex;
use std::time::duration::Duration;
use surroundings_thread::lod_index;
use view_update::ClientToView;

#[allow(missing_docs)]
pub fn server_thread(
  client: &Client,
  ups_from_server: &Receiver<ServerToClient>,
  ups_to_view: &Mutex<Sender<ClientToView>>,
) {
  loop {
    process_channel(
      ups_from_server,
      |update| {
        match update {
          ServerToClient::UpdatePlayer(position) => {
            *client.player_position.lock().unwrap() = position;
            ups_to_view.lock().unwrap().send(ClientToView::MoveCamera(position)).unwrap();
          },
          ServerToClient::AddMob(id, v) => {
            ups_to_view.lock().unwrap().send(ClientToView::AddMob(id, v)).unwrap();
          },
          ServerToClient::UpdateMob(id, v) => {
            ups_to_view.lock().unwrap().send(ClientToView::UpdateMob(id, v)).unwrap();
          },
          ServerToClient::UpdateSun(fraction) => {
            // Convert to radians.
            let angle = fraction * 2.0 * PI;
            let (s, c) = angle.sin_cos();

            let sun_color =
              Color3::of_rgb(
                c.abs(),
                (s + 1.0) / 2.0,
                (s * 0.75 + 0.25).abs(),
              );

            let radius = 1024.0;
            let rel_position = Vec3::new(c, s, 0.0) * radius;

            ups_to_view.lock().unwrap().send(ClientToView::SetPointLight(
              Light {
                position: *client.player_position.lock().unwrap() + rel_position,
                intensity: sun_color,
              }
            )).unwrap();

            let ambient_light = partial_max(0.4, s / 2.0).unwrap();

            ups_to_view.lock().unwrap().send(ClientToView::SetAmbientLight(
              Color3::of_rgb(
                sun_color.r * ambient_light,
                sun_color.g * ambient_light,
                sun_color.b * ambient_light,
              ),
            )).unwrap();

            ups_to_view.lock().unwrap().send(ClientToView::SetClearColor(sun_color)).unwrap();
          },
          // TODO: Is there a race where this block is stale by the time it gets to the client?
          ServerToClient::AddBlock(position, block, lod) => {
            let player_position =
              BlockPosition::from_world_position(&client.player_position.lock().unwrap().clone());
            let distance = radius_between(&player_position, &position);
            if distance <= client.max_load_distance && lod_index(distance) == lod {
              match client.loaded_blocks.lock().unwrap().entry(position) {
                Vacant(entry) => {
                  entry.insert((block.clone(), lod));
                },
                Occupied(mut entry) => {
                  {
                    // The block removal code is duplicated elsewhere.

                    let &(ref prev_block, prev_lod) = entry.get();
                    for &id in prev_block.ids.iter() {
                      ups_to_view.lock().unwrap().send(ClientToView::RemoveTerrain(id)).unwrap();
                    }
                    ups_to_view.lock().unwrap().send(
                      ClientToView::RemoveBlockData(position, prev_lod)
                    ).unwrap();
                  }
                  entry.insert((block.clone(), lod));
                },
              };

              if !block.ids.is_empty() {
                ups_to_view.lock().unwrap().send(ClientToView::AddBlock(position, block, lod)).unwrap();
              }
            }
          },
        };
        true
      },
    );

    // TODO: Is sleep(1) much better than sleep(0)?
    timer::sleep(Duration::milliseconds(1));
  }
}
<commit_msg>Simplify client::server_thread.<commit_after>use client::Client;
use common::block_position::BlockPosition;
use common::color::Color3;
use common::communicate::ServerToClient;
use common::surroundings_loader::radius_between;
use light::Light;
use nalgebra::Vec3;
use std::cmp::partial_max;
use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::f32::consts::PI;
use std::num::Float;
use std::old_io::timer;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::Mutex;
use std::time::duration::Duration;
use surroundings_thread::lod_index;
use view_update::ClientToView;

#[allow(missing_docs)]
pub fn server_thread(
  client: &Client,
  ups_from_server: &Receiver<ServerToClient>,
  ups_to_view: &Mutex<Sender<ClientToView>>,
) {
  loop {
    let update = ups_from_server.recv().unwrap();
    match update {
      ServerToClient::UpdatePlayer(position) => {
        *client.player_position.lock().unwrap() = position;
        ups_to_view.lock().unwrap().send(ClientToView::MoveCamera(position)).unwrap();
      },
      ServerToClient::AddMob(id, v) => {
        ups_to_view.lock().unwrap().send(ClientToView::AddMob(id, v)).unwrap();
      },
      ServerToClient::UpdateMob(id, v) => {
        ups_to_view.lock().unwrap().send(ClientToView::UpdateMob(id, v)).unwrap();
      },
      ServerToClient::UpdateSun(fraction) => {
        // Convert to radians.
        let angle = fraction * 2.0 * PI;
        let (s, c) = angle.sin_cos();

        let sun_color =
          Color3::of_rgb(
            c.abs(),
            (s + 1.0) / 2.0,
            (s * 0.75 + 0.25).abs(),
          );

        let radius = 1024.0;
        let rel_position = Vec3::new(c, s, 0.0) * radius;

        ups_to_view.lock().unwrap().send(ClientToView::SetPointLight(
          Light {
            position: *client.player_position.lock().unwrap() + rel_position,
            intensity: sun_color,
          }
        )).unwrap();

        let ambient_light = partial_max(0.4, s / 2.0).unwrap();

        ups_to_view.lock().unwrap().send(ClientToView::SetAmbientLight(
          Color3::of_rgb(
            sun_color.r * ambient_light,
            sun_color.g * ambient_light,
            sun_color.b * ambient_light,
          ),
        )).unwrap();

        ups_to_view.lock().unwrap().send(ClientToView::SetClearColor(sun_color)).unwrap();
      },
      // TODO: Is there a race where this block is stale by the time it gets to the client?
      ServerToClient::AddBlock(position, block, lod) => {
        let player_position =
          BlockPosition::from_world_position(&client.player_position.lock().unwrap().clone());
        let distance = radius_between(&player_position, &position);
        if distance <= client.max_load_distance && lod_index(distance) == lod {
          match client.loaded_blocks.lock().unwrap().entry(position) {
            Vacant(entry) => {
              entry.insert((block.clone(), lod));
            },
            Occupied(mut entry) => {
              {
                // The block removal code is duplicated elsewhere.

                let &(ref prev_block, prev_lod) = entry.get();
                for &id in prev_block.ids.iter() {
                  ups_to_view.lock().unwrap().send(ClientToView::RemoveTerrain(id)).unwrap();
                }
                ups_to_view.lock().unwrap().send(
                  ClientToView::RemoveBlockData(position, prev_lod)
                ).unwrap();
              }
              entry.insert((block.clone(), lod));
            },
          };

          if !block.ids.is_empty() {
            ups_to_view.lock().unwrap().send(ClientToView::AddBlock(position, block, lod)).unwrap();
          }
        }
      },
    };

    timer::sleep(Duration::milliseconds(0));
  }
}
<|endoftext|>


<commit_before>use {Pattern, PatternNode, PatternOperand};
use machine::avr::registers;

use machine;
use select;

use mir;

macro_rules! pattern {
    ($node:expr) => { Pattern { root: $node } }
}

macro_rules! node {
    ($opcode:ident, $operands:expr) => {
        PatternNode {
            opcode: mir::OpCode::$opcode,
            operands: $operands,
        }
    };

    ($opcode:ident) => {
        node!($opcode, vec![])
    }

}

macro_rules! operands {
    ($($operand:expr),*) => {
        vec![$( $operand ),+]
    }
}

macro_rules! inst_rdrr {
    ($opcode:ident) => {
        pattern! {
            node!($opcode,
                  operands!(
                      select::PatternOperand::Value(PatternOperand::Register(&registers::GPR8)),
                      select::PatternOperand::Value(PatternOperand::Register(&registers::GPR8))
                  )
            )
        }
    }
}

pub fn selector() -> machine::Selector {
    machine::Selector::new(self::patterns())
}

pub fn patterns() -> Vec<Pattern> {
    vec![
        inst_rdrr!(Add),
        inst_rdrr!(Sub),
        pattern! { node!(Ret) },
    ]
}

<commit_msg>Add pattern for the AVR add with immediate instruction<commit_after>use {Pattern, PatternNode, PatternOperand};
use machine::avr::registers;

use machine;
use select;

use mir;

macro_rules! pattern {
    ($node:expr) => { Pattern { root: $node } }
}

macro_rules! node {
    ($opcode:ident, $operands:expr) => {
        PatternNode {
            opcode: mir::OpCode::$opcode,
            operands: $operands,
        }
    };

    ($opcode:ident) => {
        node!($opcode, vec![])
    }

}

macro_rules! operands {
    ($($operand:expr),*) => {
        vec![$( $operand ),+]
    }
}

/// An instruction which takes a destination and source GPR8.
macro_rules! inst_rdrr {
    ($opcode:ident) => {
        pattern! {
            node!($opcode,
                  operands!(
                      select::PatternOperand::Value(PatternOperand::Register(&registers::GPR8)),
                      select::PatternOperand::Value(PatternOperand::Register(&registers::GPR8))
                  )
            )
        }
    }
}

/// An instruction which takes a GPR8 and an 8-bit immediate.
macro_rules! inst_rdi {
    ($opcode:ident) => {
        pattern! {
            node!($opcode,
                  operands!(
                      select::PatternOperand::Value(PatternOperand::Register(&registers::GPR8)),
                      select::PatternOperand::Value(PatternOperand::Immediate { width: 8 })
                  )
            )
        }
    }
}

pub fn selector() -> machine::Selector {
    machine::Selector::new(self::patterns())
}

pub fn patterns() -> Vec<Pattern> {
    vec![
        inst_rdi!(Add),  // ADDRdK

        inst_rdrr!(Add), // ADDRdRr
        inst_rdrr!(Sub), // SUBRdRr
        pattern! { node!(Ret) },
    ]
}

<|endoftext|>


<commit_before>#[doc = "
A graphics sink that renders to PNG format buffers

Each time the renderer renders a frame the bufsink will output a
`[u8]` containing the frame in PNG format.
"];

export msg, pngsink;

import azure::cairo;
import azure_bg = azure::bindgen;
import azure::AzDrawTargetRef;
import cairo_bg = cairo::bindgen;

enum msg {
    begin_drawing(chan<AzDrawTargetRef>),
    draw(chan<AzDrawTargetRef>, AzDrawTargetRef),
    exit
}

impl pngsink of renderer::sink for chan<msg> {
    fn begin_drawing(next_dt: chan<AzDrawTargetRef>) {
        self.send(begin_drawing(next_dt))
    }
    fn draw(next_dt: chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef) {
        self.send(draw(next_dt, draw_me))
    }
}

fn pngsink(output: chan<[u8]>) -> chan<msg> {
    task::spawn_listener::<msg> { |po|

        let cairo_surf = cairo_bg::cairo_image_surface_create(
            cairo::CAIRO_FORMAT_ARGB32, 800 as libc::c_int, 600 as libc::c_int
            );
        assert cairo_surf.is_not_null();

        let draw_target = azure_bg::AzCreateDrawTargetForCairoSurface(cairo_surf);
        assert draw_target.is_not_null();

        loop {
            alt po.recv() {
              begin_drawing(sender) {
                #debug("pngsink: begin_drawing");
                sender.send(draw_target);
              }
              draw(sender, dt) {
                #debug("pngsink: draw");
                do_draw(sender, dt, output, cairo_surf);
              }
              exit { break }
            }
        }

        azure_bg::AzReleaseDrawTarget(draw_target);
        cairo_bg::cairo_surface_destroy(cairo_surf);
    }
}

fn do_draw(sender: chan<AzDrawTargetRef>,
           dt: AzDrawTargetRef,
           output: comm::chan<[u8]>,
           cairo_surf: *cairo::cairo_surface_t) {

    import libc::*;

    listen {|data_ch|

        crust fn write_fn(closure: *c_void,
                          data: *c_uchar,
                          len: c_uint)

            -> cairo::cairo_status_t unsafe {

            let p: *chan<[u8]> = unsafe::reinterpret_cast(closure);
            let data_ch = *p;

            // Convert from *c_uchar to *u8
            let data = unsafe::reinterpret_cast(data);
            let len = len as uint;
            // Copy to a vector
            let data = vec::unsafe::from_buf(data, len);
            data_ch.send(data);

            ret cairo::CAIRO_STATUS_SUCCESS;
        }

        let closure = ptr::addr_of(data_ch);

        unsafe {
            cairo_bg::cairo_surface_write_to_png_stream(
                cairo_surf, write_fn, unsafe::reinterpret_cast(closure));
        }

        // Collect the entire image into a single vector
        let mut result = [];
        while data_ch.peek() {
            result += data_ch.recv();
        }

        // Send the PNG image away
        output.send(result);
    }
    // Send the next draw target to the renderer
    sender.send(dt);
}

#[test]
fn sanity_check() {
    listen {|ch|
        let sink = pngsink(ch);
        let renderer = renderer::renderer(sink);

        let dlist = [];
        renderer.send(renderer::RenderMsg(dlist));
        listen {
            |from_renderer|
            renderer.send(renderer::ExitMsg(from_renderer));
            from_renderer.recv();
        }

        sink.send(exit)
    }
}
<commit_msg>"ch" -> "self_channel"<commit_after>#[doc = "
A graphics sink that renders to PNG format buffers

Each time the renderer renders a frame the bufsink will output a
`[u8]` containing the frame in PNG format.
"];

export msg, pngsink;

import azure::cairo;
import azure_bg = azure::bindgen;
import azure::AzDrawTargetRef;
import cairo_bg = cairo::bindgen;

enum msg {
    begin_drawing(chan<AzDrawTargetRef>),
    draw(chan<AzDrawTargetRef>, AzDrawTargetRef),
    exit
}

impl pngsink of renderer::sink for chan<msg> {
    fn begin_drawing(next_dt: chan<AzDrawTargetRef>) {
        self.send(begin_drawing(next_dt))
    }
    fn draw(next_dt: chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef) {
        self.send(draw(next_dt, draw_me))
    }
}

fn pngsink(output: chan<[u8]>) -> chan<msg> {
    task::spawn_listener::<msg> { |po|

        let cairo_surf = cairo_bg::cairo_image_surface_create(
            cairo::CAIRO_FORMAT_ARGB32, 800 as libc::c_int, 600 as libc::c_int
            );
        assert cairo_surf.is_not_null();

        let draw_target = azure_bg::AzCreateDrawTargetForCairoSurface(cairo_surf);
        assert draw_target.is_not_null();

        loop {
            alt po.recv() {
              begin_drawing(sender) {
                #debug("pngsink: begin_drawing");
                sender.send(draw_target);
              }
              draw(sender, dt) {
                #debug("pngsink: draw");
                do_draw(sender, dt, output, cairo_surf);
              }
              exit { break }
            }
        }

        azure_bg::AzReleaseDrawTarget(draw_target);
        cairo_bg::cairo_surface_destroy(cairo_surf);
    }
}

fn do_draw(sender: chan<AzDrawTargetRef>,
           dt: AzDrawTargetRef,
           output: comm::chan<[u8]>,
           cairo_surf: *cairo::cairo_surface_t) {

    import libc::*;

    listen {|data_ch|

        crust fn write_fn(closure: *c_void,
                          data: *c_uchar,
                          len: c_uint)

            -> cairo::cairo_status_t unsafe {

            let p: *chan<[u8]> = unsafe::reinterpret_cast(closure);
            let data_ch = *p;

            // Convert from *c_uchar to *u8
            let data = unsafe::reinterpret_cast(data);
            let len = len as uint;
            // Copy to a vector
            let data = vec::unsafe::from_buf(data, len);
            data_ch.send(data);

            ret cairo::CAIRO_STATUS_SUCCESS;
        }

        let closure = ptr::addr_of(data_ch);

        unsafe {
            cairo_bg::cairo_surface_write_to_png_stream(
                cairo_surf, write_fn, unsafe::reinterpret_cast(closure));
        }

        // Collect the entire image into a single vector
        let mut result = [];
        while data_ch.peek() {
            result += data_ch.recv();
        }

        // Send the PNG image away
        output.send(result);
    }
    // Send the next draw target to the renderer
    sender.send(dt);
}

#[test]
fn sanity_check() {
    listen {
        |self_channel|

        let sink = pngsink(self_channel);
        let renderer = renderer::renderer(sink);

        let dlist = [];
        renderer.send(renderer::RenderMsg(dlist));
        listen {
            |from_renderer|
            renderer.send(renderer::ExitMsg(from_renderer));
            from_renderer.recv();
        }

        sink.send(exit)
    }
}
<|endoftext|>


<commit_before>extern mod harfbuzz;

export shape_text;

use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void};
use font::Font;
use glyph::{Glyph, GlyphPos};
use ptr::{null, addr_of, offset};
use gfx::geometry::{au, px_to_au};
use geom::point::Point2D;
use font_library::FontLibrary;

use unsafe::reinterpret_cast;
use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

#[doc = "
Calculate the layout metrics associated with a some given text
when rendered in a specific font.
"]
fn shape_text(font: &Font, text: ~str) -> ~[Glyph] unsafe {
    #debug("shaping text '%s'", text);

    let face_blob = vec::as_imm_buf(*(*font).buf(), |buf, len| {
        hb_blob_create(reinterpret_cast(&buf),
                       len as c_uint,
                       HB_MEMORY_MODE_READONLY,
                       null(),
                       null())
    });

    let hbface = hb_face_create(face_blob, 0 as c_uint);
    let hbfont = hb_font_create(hbface);

    hb_font_set_ppem(hbfont, 10 as c_uint, 10 as c_uint);
    hb_font_set_scale(hbfont, 10 as c_int, 10 as c_int);

    let funcs = hb_font_funcs_create();
    hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
    hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());
    hb_font_set_funcs(hbfont, funcs, reinterpret_cast(&addr_of(*font)), null());

    let buffer = hb_buffer_create();

    hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);

    str::as_c_str(text, |ctext| {
        hb_buffer_add_utf8(buffer, ctext,
                           text.len() as c_int,
                           0 as c_uint,
                           text.len() as c_int);
    });

    hb_shape(hbfont, buffer, null(), 0 as c_uint);

    let info_len = 0 as c_uint;
    let info_ = hb_buffer_get_glyph_infos(buffer, addr_of(info_len));
    assert info_.is_not_null();
    let pos_len = 0 as c_uint;
    let pos = hb_buffer_get_glyph_positions(buffer, addr_of(pos_len));
    assert pos.is_not_null();

    assert info_len == pos_len;

    let mut glyphs = ~[];

    for uint::range(0u, info_len as uint) |i| {
        let info_ = offset(info_, i);
        let pos = offset(pos, i);
        let codepoint = (*info_).codepoint as uint;
        let pos = hb_glyph_pos_to_servo_glyph_pos(&*pos);
        #debug("glyph %?: codep %?, x_adv %?, y_adv %?, x_off %?, y_of %?",
               i, codepoint, pos.advance.x, pos.advance.y, pos.offset.x, pos.offset.y);

        glyphs += ~[Glyph(codepoint, pos)];
    }

    hb_buffer_destroy(buffer);
    hb_font_funcs_destroy(funcs);
    hb_font_destroy(hbfont);
    hb_face_destroy(hbface);
    hb_blob_destroy(face_blob);

    return glyphs;
}

extern fn glyph_func(_font: *hb_font_t,
                     font_data: *c_void,
                     unicode: hb_codepoint_t,
                     _variant_selector: hb_codepoint_t,
                     glyph: *mut hb_codepoint_t,
                     _user_data: *c_void) -> hb_bool_t unsafe {

    let font: *Font = reinterpret_cast(&font_data);
    assert font.is_not_null();

    return match (*font).glyph_index(unicode as char) {
      Some(g) => {
        *glyph = g as hb_codepoint_t;
        true
      }
      None => {
        false
      }
    } as hb_bool_t;
}

extern fn glyph_h_advance_func(_font: *hb_font_t,
                               font_data: *c_void,
                               glyph: hb_codepoint_t,
                               _user_data: *c_void) -> hb_position_t unsafe {
    let font: *Font = reinterpret_cast(&font_data);
    assert font.is_not_null();

    let h_advance = (*font).glyph_h_advance(glyph as uint);
    #debug("h_advance for codepoint %? is %?", glyph, h_advance);
    return h_advance as hb_position_t;
}

fn hb_glyph_pos_to_servo_glyph_pos(hb_pos: &hb_glyph_position_t) -> GlyphPos {
    GlyphPos(Point2D(px_to_au(hb_pos.x_advance as int),
                     px_to_au(hb_pos.y_advance as int)),
             Point2D(px_to_au(hb_pos.x_offset as int),
                     px_to_au(hb_pos.y_offset as int)))
}

fn should_get_glyph_indexes() {
    #[test];
    #[ignore(cfg(target_os = "macos"), reason = "bad metrics")];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyphs = shape_text(font, ~"firecracker");
    let idxs = glyphs.map(|glyph| glyph.index);
    assert idxs == ~[32u, 8u, 13u, 14u, 10u, 13u, 201u, 10u, 37u, 14u, 13u];
}

fn should_get_glyph_h_advance() {
    #[test];
    #[ignore(cfg(target_os = "macos"), reason = "bad metrics")];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyphs = shape_text(font, ~"firecracker");
    let actual = glyphs.map(|g| g.pos.advance.x);
    let expected = (~[6, 4, 7, 9, 8, 7, 10, 8, 9, 9, 7]).map(|a| px_to_au(a));
    assert expected == actual;
}
<commit_msg>Make shape_text take &str instead of ~str<commit_after>extern mod harfbuzz;

export shape_text;

use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void, c_char};
use font::Font;
use glyph::{Glyph, GlyphPos};
use ptr::{null, addr_of, offset};
use gfx::geometry::{au, px_to_au};
use geom::point::Point2D;
use font_library::FontLibrary;

use unsafe::reinterpret_cast;
use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

#[doc = "
Calculate the layout metrics associated with a some given text
when rendered in a specific font.
"]
fn shape_text(font: &Font, text: &str) -> ~[Glyph] unsafe {
    #debug("shaping text '%s'", text);

    let face_blob = vec::as_imm_buf(*(*font).buf(), |buf, len| {
        hb_blob_create(reinterpret_cast(&buf),
                       len as c_uint,
                       HB_MEMORY_MODE_READONLY,
                       null(),
                       null())
    });

    let hbface = hb_face_create(face_blob, 0 as c_uint);
    let hbfont = hb_font_create(hbface);

    hb_font_set_ppem(hbfont, 10 as c_uint, 10 as c_uint);
    hb_font_set_scale(hbfont, 10 as c_int, 10 as c_int);

    let funcs = hb_font_funcs_create();
    hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
    hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());
    hb_font_set_funcs(hbfont, funcs, reinterpret_cast(&addr_of(*font)), null());

    let buffer = hb_buffer_create();

    hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);

    // Using as_buf because it never does a copy - we don't need the trailing null
    str::as_buf(text, |ctext, _l| {
        hb_buffer_add_utf8(buffer, ctext as *c_char,
                           text.len() as c_int,
                           0 as c_uint,
                           text.len() as c_int);
    });

    hb_shape(hbfont, buffer, null(), 0 as c_uint);

    let info_len = 0 as c_uint;
    let info_ = hb_buffer_get_glyph_infos(buffer, addr_of(info_len));
    assert info_.is_not_null();
    let pos_len = 0 as c_uint;
    let pos = hb_buffer_get_glyph_positions(buffer, addr_of(pos_len));
    assert pos.is_not_null();

    assert info_len == pos_len;

    let mut glyphs = ~[];

    for uint::range(0u, info_len as uint) |i| {
        let info_ = offset(info_, i);
        let pos = offset(pos, i);
        let codepoint = (*info_).codepoint as uint;
        let pos = hb_glyph_pos_to_servo_glyph_pos(&*pos);
        #debug("glyph %?: codep %?, x_adv %?, y_adv %?, x_off %?, y_of %?",
               i, codepoint, pos.advance.x, pos.advance.y, pos.offset.x, pos.offset.y);

        glyphs += ~[Glyph(codepoint, pos)];
    }

    hb_buffer_destroy(buffer);
    hb_font_funcs_destroy(funcs);
    hb_font_destroy(hbfont);
    hb_face_destroy(hbface);
    hb_blob_destroy(face_blob);

    return glyphs;
}

extern fn glyph_func(_font: *hb_font_t,
                     font_data: *c_void,
                     unicode: hb_codepoint_t,
                     _variant_selector: hb_codepoint_t,
                     glyph: *mut hb_codepoint_t,
                     _user_data: *c_void) -> hb_bool_t unsafe {

    let font: *Font = reinterpret_cast(&font_data);
    assert font.is_not_null();

    return match (*font).glyph_index(unicode as char) {
      Some(g) => {
        *glyph = g as hb_codepoint_t;
        true
      }
      None => {
        false
      }
    } as hb_bool_t;
}

extern fn glyph_h_advance_func(_font: *hb_font_t,
                               font_data: *c_void,
                               glyph: hb_codepoint_t,
                               _user_data: *c_void) -> hb_position_t unsafe {
    let font: *Font = reinterpret_cast(&font_data);
    assert font.is_not_null();

    let h_advance = (*font).glyph_h_advance(glyph as uint);
    #debug("h_advance for codepoint %? is %?", glyph, h_advance);
    return h_advance as hb_position_t;
}

fn hb_glyph_pos_to_servo_glyph_pos(hb_pos: &hb_glyph_position_t) -> GlyphPos {
    GlyphPos(Point2D(px_to_au(hb_pos.x_advance as int),
                     px_to_au(hb_pos.y_advance as int)),
             Point2D(px_to_au(hb_pos.x_offset as int),
                     px_to_au(hb_pos.y_offset as int)))
}

fn should_get_glyph_indexes() {
    #[test];
    #[ignore(cfg(target_os = "macos"), reason = "bad metrics")];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyphs = shape_text(font, ~"firecracker");
    let idxs = glyphs.map(|glyph| glyph.index);
    assert idxs == ~[32u, 8u, 13u, 14u, 10u, 13u, 201u, 10u, 37u, 14u, 13u];
}

fn should_get_glyph_h_advance() {
    #[test];
    #[ignore(cfg(target_os = "macos"), reason = "bad metrics")];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyphs = shape_text(font, ~"firecracker");
    let actual = glyphs.map(|g| g.pos.advance.x);
    let expected = (~[6, 4, 7, 9, 8, 7, 10, 8, 9, 9, 7]).map(|a| px_to_au(a));
    assert expected == actual;
}
<|endoftext|>