<commit_before>use std::{
    fmt,
    collections::HashMap,
};

use libsyntax2::{
    SyntaxNodeRef, SyntaxNode, SmolStr, AstNode,
    ast::{self, NameOwner},
    algo::{ancestors, generate, walk::preorder}
};

type ScopeId = usize;

#[derive(Debug)]
pub struct FnScopes {
    scopes: Vec<ScopeData>,
    scope_for: HashMap<SyntaxNode, ScopeId>,
}

impl FnScopes {
    pub fn new(fn_def: ast::FnDef) -> FnScopes {
        let mut scopes = FnScopes {
            scopes: Vec::new(),
            scope_for: HashMap::new()
        };
        let root = scopes.root_scope();
        scopes.add_params_bindings(root, fn_def.param_list());
        if let Some(body) = fn_def.body() {
            compute_block_scopes(body, &mut scopes, root)
        }
        scopes
    }
    pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
        &self.scopes[scope].entries
    }
    pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
        generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
    }
    fn root_scope(&mut self) -> ScopeId {
        let res = self.scopes.len();
        self.scopes.push(ScopeData { parent: None, entries: vec![] });
        res
    }
    fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
        let res = self.scopes.len();
        self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
        res
    }
    fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
        let entries = preorder(pat.syntax())
            .filter_map(ast::BindPat::cast)
            .filter_map(ScopeEntry::new);
        self.scopes[scope].entries.extend(entries);
    }
    fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
        params.into_iter()
            .flat_map(|it| it.params())
            .filter_map(|it| it.pat())
            .for_each(|it| self.add_bindings(scope, it));
    }
    fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
        self.scope_for.insert(node.owned(), scope);
    }
    fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
        ancestors(node)
            .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
            .next()
    }
}

pub struct ScopeEntry {
    syntax: SyntaxNode
}

impl ScopeEntry {
    fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
        if pat.name().is_some() {
            Some(ScopeEntry { syntax: pat.syntax().owned() })
        } else {
            None
        }
    }
    pub fn name(&self) -> SmolStr {
        self.ast().name()
            .unwrap()
            .text()
    }
    fn ast(&self) -> ast::BindPat {
        ast::BindPat::cast(self.syntax.borrowed())
            .unwrap()
    }
}

impl fmt::Debug for ScopeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ScopeEntry")
         .field("name", &self.name())
         .field("syntax", &self.syntax)
         .finish()
    }
}

fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
    for stmt in block.statements() {
        match stmt {
            ast::Stmt::LetStmt(stmt) => {
                if let Some(expr) = stmt.initializer() {
                    scopes.set_scope(expr.syntax(), scope);
                    compute_expr_scopes(expr, scopes, scope);
                }
                scope = scopes.new_scope(scope);
                if let Some(pat) = stmt.pat() {
                    scopes.add_bindings(scope, pat);
                }
            }
            ast::Stmt::ExprStmt(expr_stmt) => {
                if let Some(expr) = expr_stmt.expr() {
                    scopes.set_scope(expr.syntax(), scope);
                    compute_expr_scopes(expr, scopes, scope);
                }
            }
        }
    }
    if let Some(expr) = block.expr() {
        scopes.set_scope(expr.syntax(), scope);
        compute_expr_scopes(expr, scopes, scope);
    }
}

fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
    match expr {
        ast::Expr::IfExpr(e) => {
            let cond_scope = e.condition().and_then(|cond| {
                compute_cond_scopes(cond, scopes, scope)
            });
            if let Some(block) = e.then_branch() {
                compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
            }
            if let Some(block) = e.else_branch() {
                compute_block_scopes(block, scopes, scope);
            }
        },
        ast::Expr::WhileExpr(e) => {
            let cond_scope = e.condition().and_then(|cond| {
                compute_cond_scopes(cond, scopes, scope)
            });
            if let Some(block) = e.body() {
                compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
            }
        },
        ast::Expr::BlockExpr(e) => {
            if let Some(block) = e.block() {
                compute_block_scopes(block, scopes, scope);
            }
        }
        ast::Expr::ForExpr(e) => {
            if let Some(expr) = e.iterable() {
                compute_expr_scopes(expr, scopes, scope);
            }
            let mut scope = scope;
            if let Some(pat) = e.pat() {
                scope = scopes.new_scope(scope);
                scopes.add_bindings(scope, pat);
            }
            if let Some(block) = e.body() {
                compute_block_scopes(block, scopes, scope);
            }
        },
        ast::Expr::LambdaExpr(e) => {
            let mut scope = scopes.new_scope(scope);
            scopes.add_params_bindings(scope, e.param_list());
            if let Some(body) = e.body() {
                scopes.set_scope(body.syntax(), scope);
                compute_expr_scopes(body, scopes, scope);
            }
        }
        ast::Expr::CallExpr(e) => {
            e.arg_list().into_iter()
                .flat_map(|it| it.args())
                .chain(e.expr())
                .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
        }
        _ => {
            expr.syntax().children()
                .filter_map(ast::Expr::cast)
                .for_each(|expr| compute_expr_scopes(expr, scopes, scope))
        }
    };

    fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
        if let Some(expr) = cond.expr() {
            compute_expr_scopes(expr, scopes, scope);
        }
        if let Some(pat) = cond.pat() {
            let s = scopes.new_scope(scope);
            scopes.add_bindings(s, pat);
            Some(s)
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct ScopeData {
    parent: Option<ScopeId>,
    entries: Vec<ScopeEntry>
}

#[cfg(test)]
mod tests {
    use super::*;
    use libsyntax2::File;
    use {find_node_at_offset, test_utils::extract_offset};

    fn do_check(code: &str, expected: &[&str]) {
        let (off, code) = extract_offset(code);
        let code = {
            let mut buf = String::new();
            let off = u32::from(off) as usize;
            buf.push_str(&code[..off]);
            buf.push_str("marker");
            buf.push_str(&code[off..]);
            buf
        };
        let file = File::parse(&code);
        let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
        let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
        let scopes = FnScopes::new(fn_def);
        let actual = scopes.scope_chain(marker.syntax())
            .flat_map(|scope| scopes.entries(scope))
            .map(|it| it.name())
            .collect::<Vec<_>>();
        assert_eq!(expected, actual.as_slice());
    }

    #[test]
    fn test_lambda_scope() {
        do_check(r"
            fn quux(foo: i32) {
                let f = |bar| {
                    <|>
                };
            }",
            &["bar", "foo"],
        );
    }

    #[test]
    fn test_call_scope() {
        do_check(r"
            fn quux() {
                f(|x| <|> );
            }",
            &["x"],
        );
    }
}
<commit_msg>loop scope<commit_after>use std::{
    fmt,
    collections::HashMap,
};

use libsyntax2::{
    SyntaxNodeRef, SyntaxNode, SmolStr, AstNode,
    ast::{self, NameOwner},
    algo::{ancestors, generate, walk::preorder}
};

type ScopeId = usize;

#[derive(Debug)]
pub struct FnScopes {
    scopes: Vec<ScopeData>,
    scope_for: HashMap<SyntaxNode, ScopeId>,
}

impl FnScopes {
    pub fn new(fn_def: ast::FnDef) -> FnScopes {
        let mut scopes = FnScopes {
            scopes: Vec::new(),
            scope_for: HashMap::new()
        };
        let root = scopes.root_scope();
        scopes.add_params_bindings(root, fn_def.param_list());
        if let Some(body) = fn_def.body() {
            compute_block_scopes(body, &mut scopes, root)
        }
        scopes
    }
    pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
        &self.scopes[scope].entries
    }
    pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
        generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
    }
    fn root_scope(&mut self) -> ScopeId {
        let res = self.scopes.len();
        self.scopes.push(ScopeData { parent: None, entries: vec![] });
        res
    }
    fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
        let res = self.scopes.len();
        self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
        res
    }
    fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
        let entries = preorder(pat.syntax())
            .filter_map(ast::BindPat::cast)
            .filter_map(ScopeEntry::new);
        self.scopes[scope].entries.extend(entries);
    }
    fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
        params.into_iter()
            .flat_map(|it| it.params())
            .filter_map(|it| it.pat())
            .for_each(|it| self.add_bindings(scope, it));
    }
    fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
        self.scope_for.insert(node.owned(), scope);
    }
    fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
        ancestors(node)
            .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
            .next()
    }
}

pub struct ScopeEntry {
    syntax: SyntaxNode
}

impl ScopeEntry {
    fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
        if pat.name().is_some() {
            Some(ScopeEntry { syntax: pat.syntax().owned() })
        } else {
            None
        }
    }
    pub fn name(&self) -> SmolStr {
        self.ast().name()
            .unwrap()
            .text()
    }
    fn ast(&self) -> ast::BindPat {
        ast::BindPat::cast(self.syntax.borrowed())
            .unwrap()
    }
}

impl fmt::Debug for ScopeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ScopeEntry")
         .field("name", &self.name())
         .field("syntax", &self.syntax)
         .finish()
    }
}

fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
    for stmt in block.statements() {
        match stmt {
            ast::Stmt::LetStmt(stmt) => {
                if let Some(expr) = stmt.initializer() {
                    scopes.set_scope(expr.syntax(), scope);
                    compute_expr_scopes(expr, scopes, scope);
                }
                scope = scopes.new_scope(scope);
                if let Some(pat) = stmt.pat() {
                    scopes.add_bindings(scope, pat);
                }
            }
            ast::Stmt::ExprStmt(expr_stmt) => {
                if let Some(expr) = expr_stmt.expr() {
                    scopes.set_scope(expr.syntax(), scope);
                    compute_expr_scopes(expr, scopes, scope);
                }
            }
        }
    }
    if let Some(expr) = block.expr() {
        scopes.set_scope(expr.syntax(), scope);
        compute_expr_scopes(expr, scopes, scope);
    }
}

fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
    match expr {
        ast::Expr::IfExpr(e) => {
            let cond_scope = e.condition().and_then(|cond| {
                compute_cond_scopes(cond, scopes, scope)
            });
            if let Some(block) = e.then_branch() {
                compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
            }
            if let Some(block) = e.else_branch() {
                compute_block_scopes(block, scopes, scope);
            }
        },
        ast::Expr::WhileExpr(e) => {
            let cond_scope = e.condition().and_then(|cond| {
                compute_cond_scopes(cond, scopes, scope)
            });
            if let Some(block) = e.body() {
                compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
            }
        },
        ast::Expr::BlockExpr(e) => {
            if let Some(block) = e.block() {
                compute_block_scopes(block, scopes, scope);
            }
        }
        ast::Expr::ForExpr(e) => {
            if let Some(expr) = e.iterable() {
                compute_expr_scopes(expr, scopes, scope);
            }
            let mut scope = scope;
            if let Some(pat) = e.pat() {
                scope = scopes.new_scope(scope);
                scopes.add_bindings(scope, pat);
            }
            if let Some(block) = e.body() {
                compute_block_scopes(block, scopes, scope);
            }
        },
        ast::Expr::LambdaExpr(e) => {
            let mut scope = scopes.new_scope(scope);
            scopes.add_params_bindings(scope, e.param_list());
            if let Some(body) = e.body() {
                scopes.set_scope(body.syntax(), scope);
                compute_expr_scopes(body, scopes, scope);
            }
        }
        ast::Expr::CallExpr(e) => {
            e.arg_list().into_iter()
                .flat_map(|it| it.args())
                .chain(e.expr())
                .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
        }
        ast::Expr::LoopExpr(e) => {
            if let Some(block) = e.body() {
                compute_block_scopes(block, scopes, scope);
            }
        }
        _ => {
            expr.syntax().children()
                .filter_map(ast::Expr::cast)
                .for_each(|expr| compute_expr_scopes(expr, scopes, scope))
        }
    };

    fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
        if let Some(expr) = cond.expr() {
            compute_expr_scopes(expr, scopes, scope);
        }
        if let Some(pat) = cond.pat() {
            let s = scopes.new_scope(scope);
            scopes.add_bindings(s, pat);
            Some(s)
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct ScopeData {
    parent: Option<ScopeId>,
    entries: Vec<ScopeEntry>
}

#[cfg(test)]
mod tests {
    use super::*;
    use libsyntax2::File;
    use {find_node_at_offset, test_utils::extract_offset};

    fn do_check(code: &str, expected: &[&str]) {
        let (off, code) = extract_offset(code);
        let code = {
            let mut buf = String::new();
            let off = u32::from(off) as usize;
            buf.push_str(&code[..off]);
            buf.push_str("marker");
            buf.push_str(&code[off..]);
            buf
        };
        let file = File::parse(&code);
        let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
        let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
        let scopes = FnScopes::new(fn_def);
        let actual = scopes.scope_chain(marker.syntax())
            .flat_map(|scope| scopes.entries(scope))
            .map(|it| it.name())
            .collect::<Vec<_>>();
        assert_eq!(expected, actual.as_slice());
    }

    #[test]
    fn test_lambda_scope() {
        do_check(r"
            fn quux(foo: i32) {
                let f = |bar| {
                    <|>
                };
            }",
            &["bar", "foo"],
        );
    }

    #[test]
    fn test_call_scope() {
        do_check(r"
            fn quux() {
                f(|x| <|> );
            }",
            &["x"],
        );
    }

    #[test]
    fn test_loop_scope() {
        do_check(r"
            fn quux() {
                loop {
                    let x = ();
                    <|>
                };
            }",
            &["x"],
        );
    }
}
<|endoftext|>


<commit_before>use super::ffi::*;

use libc;
use std::ffi::CStr;
use std::mem;
use std::default;

pub fn initialize() -> Result<(), &'static str> {
    if unsafe { GLSLangInitialize() } == 0 {
        Err("Couldn't initialize GLSLang")
    } else {
        Ok(())
    }
}

pub fn finalize() -> Result<(), &'static str> {
    if unsafe { GLSLangFinalize() } == 0 {
        Err("Couldn't finalize GLSLang")
    } else {
        Ok(())
    }
}

pub trait AsAngleEnum {
    fn as_angle_enum(&self) -> i32;
}

pub enum ShaderSpec {
    Gles2,
    WebGL,
    Gles3,
    WebGL2,
    Css,
}

impl AsAngleEnum for ShaderSpec {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        match *self {
            ShaderSpec::Gles2 => SH_GLES2_SPEC,
            ShaderSpec::WebGL => SH_WEBGL_SPEC,
            ShaderSpec::Gles3 => SH_GLES3_SPEC,
            ShaderSpec::WebGL2 => SH_WEBGL2_SPEC,
            ShaderSpec::Css => SH_CSS_SHADERS_SPEC,
        }
    }
}

pub enum Output {
    Essl,
    Glsl,
    GlslCompat,
    GlslCore,
    Glsl130,
    Glsl140,
    Glsl150Core,
    Glsl330Core,
    Glsl400Core,
    Glsl410Core,
    Glsl420Core,
    Glsl430Core,
    Glsl440Core,
    Glsl450Core,
}

impl AsAngleEnum for Output {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        match *self {
            Output::Essl => SH_ESSL_OUTPUT,
            Output::Glsl => SH_GLSL_OUTPUT,
            Output::GlslCompat => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCore => SH_GLSL_CORE_OUTPUT,
            Output::Glsl130 => SH_GLSL_130_OUTPUT,
            Output::Glsl140 => SH_GLSL_140_OUTPUT,
            Output::Glsl150Core => SH_GLSL_150_CORE_OUTPUT,
            Output::Glsl330Core => SH_GLSL_330_CORE_OUTPUT,
            Output::Glsl400Core => SH_GLSL_400_CORE_OUTPUT,
            Output::Glsl410Core => SH_GLSL_410_CORE_OUTPUT,
            Output::Glsl420Core => SH_GLSL_420_CORE_OUTPUT,
            Output::Glsl430Core => SH_GLSL_430_CORE_OUTPUT,
            Output::Glsl440Core => SH_GLSL_440_CORE_OUTPUT,
            Output::Glsl450Core => SH_GLSL_450_CORE_OUTPUT,
        }
    }
}

pub type BuiltInResources = ShBuiltInResources;

impl default::Default for BuiltInResources {
    fn default() -> BuiltInResources {
        unsafe {
            let mut ret: BuiltInResources = mem::uninitialized();
            GLSLangInitBuiltInResources(&mut ret);
            ret
        }
    }
}

impl BuiltInResources {
    #[inline]
    pub fn empty() -> BuiltInResources {
        unsafe { mem::zeroed() }
    }
}

pub struct ShaderValidator {
    handle: ShHandle,
}

impl ShaderValidator {
    /// Create a new ShaderValidator instance
    /// NB: To call this you should have called first
    /// initialize()
    pub fn new(shader_type: u32,
               spec: ShaderSpec,
               output: Output,
               resources: &BuiltInResources) -> Option<ShaderValidator> {
        let handle = unsafe {
            GLSLangConstructCompiler(shader_type, spec.as_angle_enum(), output.as_angle_enum(), resources)
        };

        if handle.is_null() {
            return None;
        }

        Some(ShaderValidator {
            handle: handle,
        })
    }

    #[inline]
    pub fn for_webgl(shader_type: u32,
                     output: Output,
                     resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL, output, resources)
    }

    pub fn compile(&self, strings: &[&[u8]], options: i32) -> Result<(), &'static str> {
        if unsafe { GLSLangCompile(self.handle,
                                   strings.as_ptr() as *const *const libc::c_char,
                                   strings.len() as u64,
                                   options) } == 0 {
            return Err("Couldn't compile shader")
        }
        Ok(())
    }

    pub fn object_code(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetObjectCode(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn info_log(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetInfoLog(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn compile_and_translate(&self, strings: &[&[u8]]) -> Result<String, &'static str> {
        let options = SH_VALIDATE | SH_OBJECT_CODE | SH_INTERMEDIATE_TREE |
                      SH_EMULATE_BUILT_IN_FUNCTIONS | // To workaround drivers
                      SH_TIMING_RESTRICTIONS |
                      SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
                      SH_INIT_GL_POSITION |
                      SH_ENFORCE_PACKING_RESTRICTIONS |
                      SH_LIMIT_CALL_STACK_DEPTH;
        try!(self.compile(strings, options));
        Ok(self.object_code())
    }
}

impl Drop for ShaderValidator {
    fn drop(&mut self) {
        unsafe {
            GLSLangDestructCompiler(self.handle)
        }
    }
}
<commit_msg>Don't print the intermediate tree (at least by default)<commit_after>use super::ffi::*;

use libc;
use std::ffi::CStr;
use std::mem;
use std::default;

pub fn initialize() -> Result<(), &'static str> {
    if unsafe { GLSLangInitialize() } == 0 {
        Err("Couldn't initialize GLSLang")
    } else {
        Ok(())
    }
}

pub fn finalize() -> Result<(), &'static str> {
    if unsafe { GLSLangFinalize() } == 0 {
        Err("Couldn't finalize GLSLang")
    } else {
        Ok(())
    }
}

pub trait AsAngleEnum {
    fn as_angle_enum(&self) -> i32;
}

pub enum ShaderSpec {
    Gles2,
    WebGL,
    Gles3,
    WebGL2,
    Css,
}

impl AsAngleEnum for ShaderSpec {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        match *self {
            ShaderSpec::Gles2 => SH_GLES2_SPEC,
            ShaderSpec::WebGL => SH_WEBGL_SPEC,
            ShaderSpec::Gles3 => SH_GLES3_SPEC,
            ShaderSpec::WebGL2 => SH_WEBGL2_SPEC,
            ShaderSpec::Css => SH_CSS_SHADERS_SPEC,
        }
    }
}

pub enum Output {
    Essl,
    Glsl,
    GlslCompat,
    GlslCore,
    Glsl130,
    Glsl140,
    Glsl150Core,
    Glsl330Core,
    Glsl400Core,
    Glsl410Core,
    Glsl420Core,
    Glsl430Core,
    Glsl440Core,
    Glsl450Core,
}

impl AsAngleEnum for Output {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        match *self {
            Output::Essl => SH_ESSL_OUTPUT,
            Output::Glsl => SH_GLSL_OUTPUT,
            Output::GlslCompat => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCore => SH_GLSL_CORE_OUTPUT,
            Output::Glsl130 => SH_GLSL_130_OUTPUT,
            Output::Glsl140 => SH_GLSL_140_OUTPUT,
            Output::Glsl150Core => SH_GLSL_150_CORE_OUTPUT,
            Output::Glsl330Core => SH_GLSL_330_CORE_OUTPUT,
            Output::Glsl400Core => SH_GLSL_400_CORE_OUTPUT,
            Output::Glsl410Core => SH_GLSL_410_CORE_OUTPUT,
            Output::Glsl420Core => SH_GLSL_420_CORE_OUTPUT,
            Output::Glsl430Core => SH_GLSL_430_CORE_OUTPUT,
            Output::Glsl440Core => SH_GLSL_440_CORE_OUTPUT,
            Output::Glsl450Core => SH_GLSL_450_CORE_OUTPUT,
        }
    }
}

pub type BuiltInResources = ShBuiltInResources;

impl default::Default for BuiltInResources {
    fn default() -> BuiltInResources {
        unsafe {
            let mut ret: BuiltInResources = mem::uninitialized();
            GLSLangInitBuiltInResources(&mut ret);
            ret
        }
    }
}

impl BuiltInResources {
    #[inline]
    pub fn empty() -> BuiltInResources {
        unsafe { mem::zeroed() }
    }
}

pub struct ShaderValidator {
    handle: ShHandle,
}

impl ShaderValidator {
    /// Create a new ShaderValidator instance
    /// NB: To call this you should have called first
    /// initialize()
    pub fn new(shader_type: u32,
               spec: ShaderSpec,
               output: Output,
               resources: &BuiltInResources) -> Option<ShaderValidator> {
        let handle = unsafe {
            GLSLangConstructCompiler(shader_type, spec.as_angle_enum(), output.as_angle_enum(), resources)
        };

        if handle.is_null() {
            return None;
        }

        Some(ShaderValidator {
            handle: handle,
        })
    }

    #[inline]
    pub fn for_webgl(shader_type: u32,
                     output: Output,
                     resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL, output, resources)
    }

    pub fn compile(&self, strings: &[&[u8]], options: i32) -> Result<(), &'static str> {
        if unsafe { GLSLangCompile(self.handle,
                                   strings.as_ptr() as *const *const libc::c_char,
                                   strings.len() as u64,
                                   options) } == 0 {
            return Err("Couldn't compile shader")
        }
        Ok(())
    }

    pub fn object_code(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetObjectCode(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn info_log(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetInfoLog(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn compile_and_translate(&self, strings: &[&[u8]]) -> Result<String, &'static str> {
        let options = SH_VALIDATE | SH_OBJECT_CODE |
                      SH_EMULATE_BUILT_IN_FUNCTIONS | // To workaround drivers
                      SH_TIMING_RESTRICTIONS |
                      SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
                      SH_INIT_GL_POSITION |
                      SH_ENFORCE_PACKING_RESTRICTIONS |
                      SH_LIMIT_CALL_STACK_DEPTH;

        try!(self.compile(strings, options));
        Ok(self.object_code())
    }
}

impl Drop for ShaderValidator {
    fn drop(&mut self) {
        unsafe {
            GLSLangDestructCompiler(self.handle)
        }
    }
}
<|endoftext|>


<commit_before>use quote::quote;
use syn::{Item, Pat, Stmt};

#[test]
fn test_pat_ident() {
    match syn::parse2(quote!(self)).unwrap() {
        Pat::Ident(_) => (),
        value => panic!("expected PatIdent, got {:?}", value),
    }
}

#[test]
fn test_pat_path() {
    match syn::parse2(quote!(self::CONST)).unwrap() {
        Pat::Path(_) => (),
        value => panic!("expected PatPath, got {:?}", value),
    }
}

#[test]
fn test_leading_vert() {
    // https://github.com/rust-lang/rust/blob/1.43.0/src/test/ui/or-patterns/remove-leading-vert.rs

    syn::parse_str::<Item>("fn f() {}").unwrap();
    syn::parse_str::<Item>("fn fun1(| A: E) {}").unwrap_err();
    syn::parse_str::<Item>("fn fun2(|| A: E) {}").unwrap_err();

    syn::parse_str::<Stmt>("let | () = ();").unwrap();
    syn::parse_str::<Stmt>("let (| A): E;").unwrap_err();
    syn::parse_str::<Stmt>("let (|| A): (E);").unwrap_err();
    syn::parse_str::<Stmt>("let (| A,): (E,);").unwrap_err();
    syn::parse_str::<Stmt>("let [| A]: [E; 1];").unwrap_err();
    syn::parse_str::<Stmt>("let [|| A]: [E; 1];").unwrap_err();
    syn::parse_str::<Stmt>("let TS(| A): TS;").unwrap_err();
    syn::parse_str::<Stmt>("let TS(|| A): TS;").unwrap_err();
    syn::parse_str::<Stmt>("let NS { f: | A }: NS;").unwrap_err();
    syn::parse_str::<Stmt>("let NS { f: || A }: NS;").unwrap_err();
}
<commit_msg>Add regression test of pattern inside None group<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Item, Pat, Stmt};

#[test]
fn test_pat_ident() {
    match syn::parse2(quote!(self)).unwrap() {
        Pat::Ident(_) => (),
        value => panic!("expected PatIdent, got {:?}", value),
    }
}

#[test]
fn test_pat_path() {
    match syn::parse2(quote!(self::CONST)).unwrap() {
        Pat::Path(_) => (),
        value => panic!("expected PatPath, got {:?}", value),
    }
}

#[test]
fn test_leading_vert() {
    // https://github.com/rust-lang/rust/blob/1.43.0/src/test/ui/or-patterns/remove-leading-vert.rs

    syn::parse_str::<Item>("fn f() {}").unwrap();
    syn::parse_str::<Item>("fn fun1(| A: E) {}").unwrap_err();
    syn::parse_str::<Item>("fn fun2(|| A: E) {}").unwrap_err();

    syn::parse_str::<Stmt>("let | () = ();").unwrap();
    syn::parse_str::<Stmt>("let (| A): E;").unwrap_err();
    syn::parse_str::<Stmt>("let (|| A): (E);").unwrap_err();
    syn::parse_str::<Stmt>("let (| A,): (E,);").unwrap_err();
    syn::parse_str::<Stmt>("let [| A]: [E; 1];").unwrap_err();
    syn::parse_str::<Stmt>("let [|| A]: [E; 1];").unwrap_err();
    syn::parse_str::<Stmt>("let TS(| A): TS;").unwrap_err();
    syn::parse_str::<Stmt>("let TS(|| A): TS;").unwrap_err();
    syn::parse_str::<Stmt>("let NS { f: | A }: NS;").unwrap_err();
    syn::parse_str::<Stmt>("let NS { f: || A }: NS;").unwrap_err();
}

#[test]
fn test_group() {
    let group = Group::new(Delimiter::None, quote!(Some(_)));
    let tokens = TokenStream::from_iter(vec![TokenTree::Group(group)]);

    snapshot!(tokens as Pat, @r###"
    Pat::TupleStruct {
        path: Path {
            segments: [
                PathSegment {
                    ident: "Some",
                    arguments: None,
                },
            ],
        },
        pat: PatTuple {
            elems: [
                Pat::Wild,
            ],
        },
    }
    "###);
}
<|endoftext|>


<commit_before>extern crate rz80;
extern crate time;

#[cfg(test)]
mod test_zex {
    use time::PreciseTime;
    use rz80;
    use rz80::RegT;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");
    static ZEXALL: &'static [u8] = include_bytes!("zexall.com");

    // emulates a CP/M BDOS call, only what's needed by ZEX
    fn cpm_bdos<I,O>(cpu: &mut rz80::CPU<I,O>)
        where I: FnMut(RegT)->RegT,
              O: FnMut(RegT, RegT) {

        match cpu.reg.c() {
            2 => {
                // output a character
                print!("{}", cpu.reg.e() as u8 as char);
            },
            9 => {
                // output a string
                let mut addr = cpu.reg.de();
                loop {
                    let c = cpu.mem.r8(addr) as u8 as char;
                    addr = (addr + 1) & 0xFFFF;
                    if c != '$' {
                        print!("{}", c);
                    }
                    else {
                        break;
                    }
                }
            },
            _ => {
                panic!("Unknown CP/M call {}!", cpu.reg.c());
            }
        }
        // emulate a RET
        let sp = cpu.reg.sp();
        cpu.reg.set_pc(cpu.mem.r16(sp));
        cpu.reg.set_sp(sp + 2);
    }

    fn dummy_in(_: RegT) -> RegT { 0 }
    fn dummy_out(_: RegT, _: RegT) { }

    fn run_test(prog: &[u8]) -> (i64, i64) {
        let mut num_ops = 0;
        let mut num_cycles = 0;
        let mut cpu = rz80::CPU::new(dummy_in, dummy_out);
        cpu.mem.write(0x0100, prog);
        cpu.reg.set_sp(0xF000);
        cpu.reg.set_pc(0x0100);
        loop {
            num_ops += 1;
            num_cycles += cpu.step();
            match cpu.reg.pc() {
                0x0005 => { cpm_bdos(&mut cpu); },  // emulated CP/M BDOS call
                0x0000 => { break; },
                _ => { },
            }
        }
        (num_ops, num_cycles)
    }

    fn test_zexdoc() {
        println!(">>> RUNNING ZEXDOC");

        let start = PreciseTime::now();
        let (num_ops, num_cycles) = run_test(&ZEXDOC);
        let end = PreciseTime::now();
        let ms = start.to(end).num_milliseconds();
        let mips = (num_ops / ms)/1000;
        let mhz  = num_cycles / ms;

        println!("\n\nops: {}, cycles: {}, duration: {}ms", num_ops, num_cycles, ms);
        println!("mips: {}, MHz: {}\n\n", mips, mhz);
    }

    fn test_zexall() {
        println!(">>> RUNNING ZEXALL");

        let start = PreciseTime::now();
        let (num_ops, num_cycles) = run_test(&ZEXALL);
        let end = PreciseTime::now();
        let ms = start.to(end).num_milliseconds();
        let mips = (num_ops / ms)/1000;
        let mhz  = (num_cycles / ms)/1000;

        println!("\n\nops: {}, cycles: {}, duration: {}ms", num_ops, num_cycles, ms);
        println!("mips: {}, MHz: {}", mips, mhz);
    }

    #[test]
    #[ignore]
    fn test_zex() {
        // have 1 test function run both sub-tests, we don't want to
        // run them in parallel
        test_zexdoc();
        test_zexall();
    }
}

<commit_msg>Worked in some feedback from the rust mailing list<commit_after>extern crate rz80;
extern crate time;

#[cfg(test)]
mod test_zex {
    use time::PreciseTime;
    use rz80;
    use rz80::RegT;

    static ZEXDOC: &'static [u8] = include_bytes!("zexdoc.com");
    static ZEXALL: &'static [u8] = include_bytes!("zexall.com");

    // emulates a CP/M BDOS call, only what's needed by ZEX
    fn cpm_bdos<I,O>(cpu: &mut rz80::CPU<I,O>)
        where I: FnMut(RegT)->RegT,
              O: FnMut(RegT, RegT) {

        match cpu.reg.c() {
            2 => {
                // output a character
                print!("{}", cpu.reg.e() as u8 as char);
            },
            9 => {
                // output a string
                let mut addr = cpu.reg.de();
                loop {
                    let c = cpu.mem.r8(addr) as u8;
                    addr = (addr + 1) & 0xFFFF;
                    if c != b'$' {
                        print!("{}", c as char);
                    }
                    else {
                        break;
                    }
                }
            },
            _ => {
                panic!("Unknown CP/M call {}!", cpu.reg.c());
            }
        }
        // emulate a RET
        let sp = cpu.reg.sp();
        cpu.reg.set_pc(cpu.mem.r16(sp));
        cpu.reg.set_sp(sp + 2);
    }

    fn dummy_in(_: RegT) -> RegT { 0 }
    fn dummy_out(_: RegT, _: RegT) { }

    fn run_test(prog: &[u8]) -> (i64, i64) {
        let mut num_ops = 0;
        let mut num_cycles = 0;
        let mut cpu = rz80::CPU::new(dummy_in, dummy_out);
        cpu.mem.write(0x0100, prog);
        cpu.reg.set_sp(0xF000);
        cpu.reg.set_pc(0x0100);
        loop {
            num_ops += 1;
            num_cycles += cpu.step();
            match cpu.reg.pc() {
                0x0005 => { cpm_bdos(&mut cpu); },  // emulated CP/M BDOS call
                0x0000 => { break; },
                _ => { },
            }
        }
        (num_ops, num_cycles)
    }

    fn test_zexdoc() {
        println!(">>> RUNNING ZEXDOC");

        let start = PreciseTime::now();
        let (num_ops, num_cycles) = run_test(&ZEXDOC);
        let end = PreciseTime::now();
        let ms = start.to(end).num_milliseconds();
        let mips = (num_ops / ms)/1000;
        let mhz  = num_cycles / ms;

        println!("\n\nops: {}, cycles: {}, duration: {}ms", num_ops, num_cycles, ms);
        println!("mips: {}, MHz: {}\n\n", mips, mhz);
    }

    fn test_zexall() {
        println!(">>> RUNNING ZEXALL");

        let start = PreciseTime::now();
        let (num_ops, num_cycles) = run_test(&ZEXALL);
        let end = PreciseTime::now();
        let ms = start.to(end).num_milliseconds();
        let mips = (num_ops / ms)/1000;
        let mhz  = (num_cycles / ms)/1000;

        println!("\n\nops: {}, cycles: {}, duration: {}ms", num_ops, num_cycles, ms);
        println!("mips: {}, MHz: {}", mips, mhz);
    }

    #[test]
    #[ignore]
    fn test_zex() {
        // have 1 test function run both sub-tests, we don't want to
        // run them in parallel
        test_zexdoc();
        test_zexall();
    }
}

<|endoftext|>


<commit_before>use na::{self, Real};

use crate::math::Isometry;
use crate::query::algorithms::{gjk, CSOPoint, VoronoiSimplex};
use crate::query::{Ray, RayCast, RayIntersection};
#[cfg(feature = "dim2")]
use crate::query;
#[cfg(feature = "dim2")]
use crate::shape::ConvexPolygon;
use crate::shape::{Capsule, Segment, SupportMap, FeatureId};
#[cfg(feature = "dim3")]
use crate::shape::{Cone, ConvexHull, Cylinder};

/// Cast a ray on a shape using the GJK algorithm.
pub fn implicit_toi_and_normal_with_ray<N, G: ?Sized>(
    m: &Isometry<N>,
    shape: &G,
    simplex: &mut VoronoiSimplex<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
where
    N: Real,
    G: SupportMap<N>,
{
    let supp = shape.support_point(m, &-ray.dir);
    simplex.reset(CSOPoint::single_point(supp - ray.origin.coords));

    let inter = gjk::cast_ray(m, shape, simplex, ray);

    if !solid {
        match inter {
            None => None,
            Some((toi, normal)) => {
                if toi.is_zero() {
                    // the ray is inside of the shape.
                    let ndir = ray.dir.normalize();
                    let supp = shape.support_point(m, &ndir);
                    let shift = (supp - ray.origin).dot(&ndir) + na::convert(0.001f64);
                    let new_ray = Ray::new(ray.origin + ndir * shift, -ray.dir);

                    // FIXME: replace by? : simplex.translate_by(&(ray.origin - new_ray.origin));
                    simplex.reset(CSOPoint::single_point(supp - new_ray.origin.coords));

                    gjk::cast_ray(m, shape, simplex, &new_ray)
                        .map(|(toi, normal)| RayIntersection::new(shift - toi, normal, FeatureId::Unknown))
                } else {
                    Some(RayIntersection::new(toi, normal, FeatureId::Unknown))
                }
            }
        }
    } else {
        inter.map(|(toi, normal)| RayIntersection::new(toi, normal, FeatureId::Unknown))
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cylinder<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cone<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Capsule<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for ConvexHull<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for ConvexPolygon<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[allow(unused_variables)]
impl<N: Real> RayCast<N> for Segment<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        #[cfg(feature = "dim2")]
        {
            let seg_dir = self.scaled_direction();
            let (s, t) = query::closest_points_internal::line_against_line_parameters(
                &ray.origin, &ray.dir, self.a(), &seg_dir);

            if s >= N::zero() && t >= N::zero() && t <= N::one() {
                let normal = self.scaled_normal();

                if normal.dot(&ray.dir) > N::zero() {
                    Some(RayIntersection::new(
                        s,
                        -normal,
                        FeatureId::Face(1)
                    ))
                } else {
                    Some(RayIntersection::new(
                        s,
                        normal,
                        FeatureId::Face(0)
                    ))
                }
            } else {
                None
            }
        }
        #[cfg(feature = "dim3")]
        {
            // XXX: implement an analytic solution for 3D too.
            let ls_ray = ray.inverse_transform_by(m);

            implicit_toi_and_normal_with_ray(
                &Isometry::identity(),
                self,
                &mut VoronoiSimplex::new(),
                &ls_ray,
                solid,
            )
                .map(|mut res| {
                    res.normal = m * res.normal;
                    res
                })
        }
    }
}
<commit_msg>Fix parallel ray-cast on 2D segment.<commit_after>use na::{self, Real};

use crate::math::Isometry;
use crate::query::algorithms::{gjk, CSOPoint, VoronoiSimplex};
use crate::query::{Ray, RayCast, RayIntersection};
#[cfg(feature = "dim2")]
use crate::query;
#[cfg(feature = "dim2")]
use crate::shape::ConvexPolygon;
use crate::shape::{Capsule, Segment, SupportMap, FeatureId};
#[cfg(feature = "dim3")]
use crate::shape::{Cone, ConvexHull, Cylinder};

/// Cast a ray on a shape using the GJK algorithm.
pub fn implicit_toi_and_normal_with_ray<N, G: ?Sized>(
    m: &Isometry<N>,
    shape: &G,
    simplex: &mut VoronoiSimplex<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
where
    N: Real,
    G: SupportMap<N>,
{
    let supp = shape.support_point(m, &-ray.dir);
    simplex.reset(CSOPoint::single_point(supp - ray.origin.coords));

    let inter = gjk::cast_ray(m, shape, simplex, ray);

    if !solid {
        match inter {
            None => None,
            Some((toi, normal)) => {
                if toi.is_zero() {
                    // the ray is inside of the shape.
                    let ndir = ray.dir.normalize();
                    let supp = shape.support_point(m, &ndir);
                    let shift = (supp - ray.origin).dot(&ndir) + na::convert(0.001f64);
                    let new_ray = Ray::new(ray.origin + ndir * shift, -ray.dir);

                    // FIXME: replace by? : simplex.translate_by(&(ray.origin - new_ray.origin));
                    simplex.reset(CSOPoint::single_point(supp - new_ray.origin.coords));

                    gjk::cast_ray(m, shape, simplex, &new_ray)
                        .map(|(toi, normal)| RayIntersection::new(shift - toi, normal, FeatureId::Unknown))
                } else {
                    Some(RayIntersection::new(toi, normal, FeatureId::Unknown))
                }
            }
        }
    } else {
        inter.map(|(toi, normal)| RayIntersection::new(toi, normal, FeatureId::Unknown))
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cylinder<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for Cone<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

impl<N: Real> RayCast<N> for Capsule<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> RayCast<N> for ConvexHull<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[cfg(feature = "dim2")]
impl<N: Real> RayCast<N> for ConvexPolygon<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        implicit_toi_and_normal_with_ray(
            &Isometry::identity(),
            self,
            &mut VoronoiSimplex::new(),
            &ls_ray,
            solid,
        )
        .map(|mut res| {
            res.normal = m * res.normal;
            res
        })
    }
}

#[allow(unused_variables)]
impl<N: Real> RayCast<N> for Segment<N> {
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        #[cfg(feature = "dim2")]
        {
            let seg = self.transformed(m);
            let seg_dir = seg.scaled_direction();
            let (s, t, parallel) = query::closest_points_internal::line_against_line_parameters_eps(
                &ray.origin, &ray.dir, seg.a(), &seg_dir, N::default_epsilon());

            if parallel {
                // The lines are parallel, we have to distinguish
                // the case where there is no intersection at all
                // from the case where the line are collinear.
                let dpos = seg.a() - ray.origin;
                let normal = seg.scaled_normal();

                if dpos.dot(&normal).abs() < N::default_epsilon() {
                    // The rays and the segment are collinear.
                    let dist1 = dpos.dot(&ray.dir);
                    let dist2 = dist1 + seg_dir.dot(&ray.dir);

                    match (dist1 >= N::zero(), dist2 >= N::zero()) {
                        (true, true) => {
                            if dist1 <= dist2 {
                                Some(RayIntersection::new(
                                    dist1 / ray.dir.norm_squared(),
                                    normal,
                                    FeatureId::Vertex(0)
                                ))
                            } else {
                                Some(RayIntersection::new(
                                    dist2 / ray.dir.norm_squared(),
                                    normal,
                                    FeatureId::Vertex(1)
                                ))
                            }
                        }
                        (true, false) | (false, true) => {
                            // The ray origin lies on the segment.
                            Some(RayIntersection::new(
                                N::zero(),
                                normal,
                                FeatureId::Face(0)
                            ))
                        }
                        (false, false) => {
                            // The segment is behind the ray.
                            None
                        },
                    }
                } else {
                    // The rays never intersect.
                    None
                }
            } else if s >= N::zero() && t >= N::zero() && t <= N::one() {
                let normal = seg.scaled_normal();

                if normal.dot(&ray.dir) > N::zero() {
                    Some(RayIntersection::new(
                        s,
                        -normal,
                        FeatureId::Face(1)
                    ))
                } else {
                    Some(RayIntersection::new(
                        s,
                        normal,
                        FeatureId::Face(0)
                    ))
                }
            } else {
                // The closest points are outside of
                // the ray or segment bounds.
                None
            }
        }
        #[cfg(feature = "dim3")]
        {
            let ls_ray = ray.inverse_transform_by(m);

            // XXX: implement an analytic solution for 3D too.
            implicit_toi_and_normal_with_ray(
                &Isometry::identity(),
                self,
                &mut VoronoiSimplex::new(),
                &ls_ray,
                solid,
            )
                .map(|mut res| {
                    res.normal = m * res.normal;
                    res
                })
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use handlebars::Handlebars;
use serde_json::Value;

use manifest::Manifest;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");

/// Represents the [`Manifest`] in JSON format. This is an intermediate type that can be converted
/// to the final manifest YAML file content, ready for consumption by a Kubernetes cluster.
///
/// The reason for the existence of this intermediate type is to allow users of this crate to be
/// able to modify the JSON before converting it to the final manifest string.
///
/// [`Manifest`]: ../manifest/struct.Manifest.html
pub struct ManifestJson {
    /// JSON object, holding values for the YAML content.
    pub value: Value,
}

impl ManifestJson {
    /// Create a `ManifestJson` from `manifest`.
    pub fn new(manifest: &Manifest) -> Self {
        let mut binds = Vec::new();
        for bind in &manifest.binds {
            binds.push(bind.to_json());
        }

        ManifestJson {
            value: json!({
                "metadata_name": manifest.metadata_name,
                "service_name": manifest.pkg_ident.name,
                "image": manifest.image,
                "count": manifest.count,
                "service_topology": manifest.service_topology.to_string(),
                "service_group": manifest.service_group,
                "config": manifest.config,
                "ring_secret_name": manifest.ring_secret_name,
                "binds": binds,
            }),
        }
    }
}

impl Into<String> for ManifestJson {
    /// Convert into a string. The returned string is the final manifest YAML file content, ready
    /// for consumption by a Kubernetes cluster.
    fn into(self) -> String {
        // The Result::expect() usage in this function is justified by the fact that errors can
        // only come from the crate programmer (e.g they messed-up the manifest template or didn't
        // check the user input).
        Handlebars::new()
            .template_render(MANIFESTFILE, &self.value)
            .expect("Rendering of manifest from template failed")
    }
}
<commit_msg>pkg-export-k8s: Generate bind json values a bit differently<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use handlebars::Handlebars;
use serde_json::Value;

use manifest::Manifest;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");

/// Represents the [`Manifest`] in JSON format. This is an intermediate type that can be converted
/// to the final manifest YAML file content, ready for consumption by a Kubernetes cluster.
///
/// The reason for the existence of this intermediate type is to allow users of this crate to be
/// able to modify the JSON before converting it to the final manifest string.
///
/// [`Manifest`]: ../manifest/struct.Manifest.html
pub struct ManifestJson {
    /// JSON object, holding values for the YAML content.
    pub value: Value,
}

impl ManifestJson {
    /// Create a `ManifestJson` from `manifest`.
    pub fn new(manifest: &Manifest) -> Self {
        let binds = manifest
            .binds
            .iter()
            .map(|bind| bind.to_json())
            .collect::<Vec<_>>();

        ManifestJson {
            value: json!({
                "metadata_name": manifest.metadata_name,
                "service_name": manifest.pkg_ident.name,
                "image": manifest.image,
                "count": manifest.count,
                "service_topology": manifest.service_topology.to_string(),
                "service_group": manifest.service_group,
                "config": manifest.config,
                "ring_secret_name": manifest.ring_secret_name,
                "binds": binds,
            }),
        }
    }
}

impl Into<String> for ManifestJson {
    /// Convert into a string. The returned string is the final manifest YAML file content, ready
    /// for consumption by a Kubernetes cluster.
    fn into(self) -> String {
        // The Result::expect() usage in this function is justified by the fact that errors can
        // only come from the crate programmer (e.g they messed-up the manifest template or didn't
        // check the user input).
        Handlebars::new()
            .template_render(MANIFESTFILE, &self.value)
            .expect("Rendering of manifest from template failed")
    }
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-color")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-style")}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}"
    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: ${side},
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = self.border_${side}_width.clone();
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(specified::CSSColor,
                            specified::BorderStyle,
                            specified::BorderWidth), ()> {
    use values::specified::{CSSColor, BorderStyle, BorderWidth};
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any {
        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
            style.unwrap_or(BorderStyle::none),
            width.unwrap_or(BorderWidth::Medium)))
    } else {
        Err(())
    }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand
        name="border-${side}"
        sub_properties="${' '.join(
            'border-%s-%s' % (side, prop)
            for prop in ['color', 'style', 'width']
        )}"
        alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}"
        spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width.clone(),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let all_equal = {
                % for side in PHYSICAL_SIDES:
                  let border_${side}_width = self.border_${side}_width;
                  let border_${side}_style = self.border_${side}_style;
                  let border_${side}_color = self.border_${side}_color;
                % endfor

                border_top_width == border_right_width &&
                border_right_width == border_bottom_width &&
                border_bottom_width == border_left_width &&

                border_top_style == border_right_style &&
                border_right_style == border_bottom_style &&
                border_bottom_style == border_left_style &&

                border_top_color == border_right_color &&
                border_right_color == border_bottom_color &&
                border_bottom_color == border_left_color
            };

            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            if all_equal {
                super::serialize_directional_border(
                    dest,
                    self.border_${side}_width,
                    self.border_${side}_style,
                    self.border_${side}_color
                )
            } else {
                Ok(())
            }
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: radii.top_left,
            border_top_right_radius: radii.top_right,
            border_bottom_right_radius: radii.bottom_right,
            border_bottom_left_radius: radii.bottom_left,
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            Ok((w, o))
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: border_image_${name},
            % endfor
         })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.border_image_source.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_slice.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_width.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_outset.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_repeat.to_css(dest)
        }
    }
</%helpers:shorthand>
<commit_msg>Auto merge of #15820 - snehasi:master, r=KiChjang<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-color")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-style")}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}"
    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: ${side},
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = self.border_${side}_width.clone();
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(specified::CSSColor,
                            specified::BorderStyle,
                            specified::BorderWidth), ()> {
    use values::specified::{CSSColor, BorderStyle, BorderWidth};
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any {
        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
            style.unwrap_or(BorderStyle::none),
            width.unwrap_or(BorderWidth::Medium)))
    } else {
        Err(())
    }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand
        name="border-${side}"
        sub_properties="${' '.join(
            'border-%s-%s' % (side, prop)
            for prop in ['color', 'style', 'width']
        )}"
        alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}"
        spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width.clone(),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let all_equal = {
                % for side in PHYSICAL_SIDES:
                  let border_${side}_width = self.border_${side}_width;
                  let border_${side}_style = self.border_${side}_style;
                  let border_${side}_color = self.border_${side}_color;
                % endfor

                border_top_width == border_right_width &&
                border_right_width == border_bottom_width &&
                border_bottom_width == border_left_width &&

                border_top_style == border_right_style &&
                border_right_style == border_bottom_style &&
                border_bottom_style == border_left_style &&

                border_top_color == border_right_color &&
                border_right_color == border_bottom_color &&
                border_bottom_color == border_left_color
            };

            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            if all_equal {
                super::serialize_directional_border(
                    dest,
                    self.border_${side}_width,
                    self.border_${side}_style,
                    self.border_${side}_color
                )
            } else {
                Ok(())
            }
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: radii.top_left,
            border_top_right_radius: radii.top_right,
            border_bottom_right_radius: radii.bottom_right,
            border_bottom_left_radius: radii.bottom_left,
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            if w.is_none() && o.is_none() {
                               Err(())
                            }
                            else {
                               Ok((w, o))
                            }
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: border_image_${name},
            % endfor
         })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.border_image_source.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_slice.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_width.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_outset.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_repeat.to_css(dest)
        }
    }
</%helpers:shorthand>
<|endoftext|>