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

use base::ShareContext;
use context::GraphicsContextMethods;

use extra::arc::ARC;
use extra::arc;
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use io_surface::IOSurfaceMethods;
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};
use opengles::gl2;
use std::cast::transmute;
use std::ptr::{null, to_unsafe_ptr};

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

/// Mac-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    cgl_context: ARC<CGLContextObj>,
}

impl GraphicsContext {
    /// Returns a new context, possibly shared with another context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        unsafe {
            // Choose a pixel format.
            let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
            let pixel_format = null();
            let pixel_format_count = 1;
            let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                                to_unsafe_ptr(&pixel_format),
                                                to_unsafe_ptr(&pixel_format_count));
            assert!(gl_error == kCGLNoError);

            // Create the context.
            let cgl_context = null();
            let gl_error = match share_context {
                None => CGLCreateContext(pixel_format, null(), &cgl_context),
                Some(ref share_context) => {
                    let native = share_context.native();
                    CGLCreateContext(pixel_format, *native.get(), &cgl_context)
                }
            };
            assert!(gl_error == kCGLNoError);

            GraphicsContextMethods::wrap(ARC(cgl_context))
        }
    }
}

impl GraphicsContextMethods<CGLContextObj> for GraphicsContext {
    /// Wraps the given instance of the native Core OpenGL graphics context.
    fn wrap(instance: ARC<CGLContextObj>) -> GraphicsContext {
        unsafe {
            GraphicsContext {
                cgl_context: instance
            }
        }
    }

    /// Returns the underlying native 3D context without modifying its reference count.
    fn native(&self) -> ARC<CGLContextObj> {
        self.cgl_context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let gl_error = CGLSetCurrentContext(*self.cgl_context.get());
            assert!(gl_error == kCGLNoError)
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContextMethods::wrap(self.native())
    }
}

pub struct Context {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> GraphicsContext {
    let context: GraphicsContext = GraphicsContextMethods::new();
    context.make_current();
    context
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use core_foundation::boolean::CFBoolean;
    use core_foundation::number::CFNumber;
    use core_foundation::string::CFString;
    use core_foundation;
    use io_surface;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width = CFString::wrap_shared(kIOSurfaceWidth);
    let v_width = CFNumber::new(size.width as i32);

    let k_height = CFString::wrap_shared(kIOSurfaceHeight);
    let v_height = CFNumber::new(size.height as i32);

    let k_bytes_per_row = CFString::wrap_shared(kIOSurfaceBytesPerRow);
    let v_bytes_per_row = CFNumber::new(size.width as i32 * 4);

    let k_bytes_per_elem = CFString::wrap_shared(kIOSurfaceBytesPerElement);
    let v_bytes_per_elem = CFNumber::new(4i32);

    let k_is_global = CFString::wrap_shared(kIOSurfaceIsGlobal);
    let v_is_global = CFBoolean::true_value();

    io_surface::new(&core_foundation::dictionary::CFDictionary::new([
        (*k_width.contents.borrow_ref(),          *v_width.contents.borrow_type_ref()),
        (*k_height.contents.borrow_ref(),         *v_height.contents.borrow_type_ref()),
        (*k_bytes_per_row.contents.borrow_ref(),  *v_bytes_per_row.contents.borrow_type_ref()),
        (*k_bytes_per_elem.contents.borrow_ref(), *v_bytes_per_elem.contents.borrow_type_ref()),
        (*k_is_global.contents.borrow_ref(),      *v_is_global.contents.borrow_type_ref()),
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &GraphicsContext, surface: &IOSurface, size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let native = context.native();
        let gl_error = CGLTexImageIOSurface2D(*native.get(),
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for Context {
    fn new(size: Size2D<int>) -> Context {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        Context {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

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

use base::ShareContext;
use context::GraphicsContextMethods;

use extra::arc::ARC;
use extra::arc;
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use io_surface::IOSurfaceMethods;
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};
use opengles::gl2;
use std::cast::transmute;
use std::ptr::{null, to_unsafe_ptr};

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

/// Mac-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    cgl_context: ARC<CGLContextObj>,
}

impl GraphicsContext {
    /// Returns a new context, possibly shared with another context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        unsafe {
            // Choose a pixel format.
            let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
            let pixel_format = null();
            let pixel_format_count = 1;
            let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                                to_unsafe_ptr(&pixel_format),
                                                to_unsafe_ptr(&pixel_format_count));
            assert!(gl_error == kCGLNoError);

            // Create the context.
            let cgl_context = null();
            let gl_error = match share_context {
                None => CGLCreateContext(pixel_format, null(), &cgl_context),
                Some(ref share_context) => {
                    let native = share_context.native();
                    CGLCreateContext(pixel_format, *native.get(), &cgl_context)
                }
            };
            assert!(gl_error == kCGLNoError);

            GraphicsContextMethods::wrap(ARC(cgl_context))
        }
    }
}

impl GraphicsContextMethods<CGLContextObj> for GraphicsContext {
    /// Wraps the given instance of the native Core OpenGL graphics context.
    fn wrap(instance: ARC<CGLContextObj>) -> GraphicsContext {
        unsafe {
            GraphicsContext {
                cgl_context: instance
            }
        }
    }

    /// Returns the underlying native 3D context without modifying its reference count.
    fn native(&self) -> ARC<CGLContextObj> {
        self.cgl_context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let gl_error = CGLSetCurrentContext(*self.cgl_context.get());
            assert!(gl_error == kCGLNoError)
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContextMethods::wrap(self.native())
    }
}

pub struct Context {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> GraphicsContext {
    let context: GraphicsContext = GraphicsContextMethods::new();
    context.make_current();
    context
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use core_foundation::boolean::CFBoolean;
    use core_foundation::number::CFNumber;
    use core_foundation::string::CFString;
    use core_foundation;
    use io_surface;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width = CFString::wrap_shared(kIOSurfaceWidth);
    let v_width = CFNumber::new(size.width as i32);

    let k_height = CFString::wrap_shared(kIOSurfaceHeight);
    let v_height = CFNumber::new(size.height as i32);

    let k_bytes_per_row = CFString::wrap_shared(kIOSurfaceBytesPerRow);
    let v_bytes_per_row = CFNumber::new(size.width as i32 * 4);

    let k_bytes_per_elem = CFString::wrap_shared(kIOSurfaceBytesPerElement);
    let v_bytes_per_elem = CFNumber::new(4i32);

    let k_is_global = CFString::wrap_shared(kIOSurfaceIsGlobal);
    let v_is_global = CFBoolean::true_value();

    io_surface::new(&core_foundation::dictionary::CFDictionary::new([
        (*k_width.contents.borrow_ref(),          *v_width.contents.borrow_type_ref()),
        (*k_height.contents.borrow_ref(),         *v_height.contents.borrow_type_ref()),
        (*k_bytes_per_row.contents.borrow_ref(),  *v_bytes_per_row.contents.borrow_type_ref()),
        (*k_bytes_per_elem.contents.borrow_ref(), *v_bytes_per_elem.contents.borrow_type_ref()),
        (*k_is_global.contents.borrow_ref(),      *v_is_global.contents.borrow_type_ref()),
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &GraphicsContext, surface: &IOSurface, size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let native = context.native();
        let gl_error = CGLTexImageIOSurface2D(*native.get(),
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(surface.obj.clone()),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for Context {
    fn new(size: Size2D<int>) -> Context {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(size.clone());

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        Context {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

<|endoftext|>


<commit_before>use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_context::{EvalContext, EvalResult, EvalError};

const UNIT_PRECEDENCE: u8 = 9;

pub fn setup_defaults(context: &mut EvalContext) {
    setup_fixity_constants(context);

    context.define_built_in_method_defaults(
        "operator",
        4,
        BuiltInFunction::new(operator),
    );

    context.define_built_in_method(
        "units",
        Fixity::Postfix,
        UNIT_PRECEDENCE,
        1,
        BuiltInFunction::new(remove_unit),
    );

    context.define_built_in_method_defaults(
        "defineUnit",
        1,
        BuiltInFunction::new(define_unit),
    );

    context.define_built_in_method_defaults(
        "convert",
        2,
        BuiltInFunction::new(convert),
    );

    context.define_built_in_method_defaults(
        "unitFor",
        1,
        BuiltInFunction::new(unit_for),
    );

    context.define_built_in_method_defaults(
        "valueOf",
        1,
        BuiltInFunction::new(remove_unit),
    );

    context.define_built_in_method_defaults(
        "conversion",
        3,
        BuiltInFunction::new(conversion),
    );
}

fn setup_fixity_constants(context: &mut EvalContext) {
    context.set_constant("PREFIX", Fixity::Prefix.to_string());
    context.set_constant("INFIX", Fixity::Infix.to_string());
    context.set_constant("POSTFIX", Fixity::Postfix.to_string());
}

fn operator(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 4));

    try!(expect_param_is(params[0].is_constant(),
        "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
    try!(expect_param_is(params[1].is_number(),
        "Precedence must be a numeric value"));
    try!(expect_param_is(params[2].is_constant(),
        "Name of the operator must be a string literal"));
    try!(expect_param_is(params[3].is_function(),
        "Function definition must be either an existing function or an anonymous function"));

    let fixity = {
        let fx = Fixity::from_str(&params.remove(0).unwrap_constant());
        try!(expect_param_is(fx.is_some(),
            "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
        fx.unwrap()
    };

    let precedence = {
        let p = params.remove(0).unwrap_number();
        try!(expect_param_is(p.is_dimensionless(),
            "Precedence cannot have a unit"));
        p.value as u8
    };

    let name = &params.remove(0).unwrap_constant();
    let function = params.remove(0);

    debug_assert!(params.is_empty(), "Not all parameters used");

    match function {
        ContextItem::Definition { function, .. } => {
            context.define(name, fixity, precedence, function);
        },
        ContextItem::BuiltInMethod { function, params, .. } => {
            context.define_built_in_method(name, fixity, precedence, params, function)
        },
        _ => unreachable!(),
    };

    Ok(ContextItem::Nothing)
}

fn remove_unit(_: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_number(),
        "Value to convert must be numeric"));

    let value = params.remove(0).unwrap_number();
    debug_assert!(params.is_empty(), "Not all parameters used");

    Ok(ContextItem::Number(value.without_units()))
}

fn define_unit(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_constant(),
        "Name of the unit must be a string literal"));

    let unit_name = &params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not all parameters used");

    let unit = context.create_unit(unit_name);

    context.define_built_in_method(
        unit_name,
        Fixity::Postfix,
        UNIT_PRECEDENCE,
        1,
        BuiltInFunction::new(move |context, mut params| {
            try!(expect_params(&params, 1));
            try!(expect_param_is(params[0].is_number(),
                "Value to convert must be numeric"));

            let value = params.remove(0).unwrap_number();
            debug_assert!(params.is_empty(), "Not parameters used");

            context.convert(value, Some(unit))
        }),
    );

    Ok(ContextItem::Nothing)
}

fn convert(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 2));

    try!(expect_param_is(params[0].is_number(),
        "Value to convert must be numeric"));
    try!(expect_param_is(params[1].is_constant(),
        "Unit to convert to must be a string literal"));

    let value = params.remove(0).unwrap_number();
    let target_unit_name = params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not all parameters used");

    let unit = context.lookup_unit_name(&target_unit_name).unwrap();

    context.convert(value, Some(unit))
}

fn unit_for(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    unimplemented!();
}

fn conversion(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 3));

    unimplemented!();
}

fn expect_params(params: &Vec<ContextItem>, nparams: usize) -> Result<(), EvalError> {
    if params.len() != nparams {
        Err(EvalError::ExpectedParams(nparams))
    }
    else {
        Ok(())
    }
}

fn expect_param_is(cond: bool, message: &str) -> Result<(), EvalError> {
    if cond {
        Ok(())
    }
    else {
        Err(EvalError::InvalidParam(message.to_owned()))
    }
}

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

    use ast::*;

    use math::rich_number::RichNumber;

    use eval::fixity::Fixity;
    use eval::context_item::ContextItem;
    use eval::eval_context::EvalContext;

    #[test]
    fn fixity_constants() {
        let mut context = EvalContext::new();
        setup_defaults(&mut context);

        let lookup_fixity = |name| Fixity::from_str(&context.get(name).unwrap().unwrap_constant()).unwrap();

        assert_eq!(lookup_fixity("PREFIX"), Fixity::Prefix);
        assert_eq!(lookup_fixity("INFIX"), Fixity::Infix);
        assert_eq!(lookup_fixity("POSTFIX"), Fixity::Postfix);
    }

    #[test]
    fn can_define_operators_with_different_fixities() {
        let mut context = EvalContext::new();
        setup_defaults(&mut context);

        let fixity = Fixity::Prefix;
        let precedence: u8 = 0;
        let name = "foo".to_owned();

        let params = vec!["x".to_owned()];
        let function_body: Expr = vec![
            ExprItem::SingleTerm(Term::Symbol("x".to_owned())),
        ];

        assert_eq!(context.call("operator", vec![
            ContextItem::Constant(fixity.to_string()),
            ContextItem::Number(RichNumber::from(precedence as f64)),
            ContextItem::Constant(name.clone()),
            ContextItem::new_definition(
                // must be different from the other values for these
                Fixity::Postfix,
                precedence + 1,
                Function {
                    params: params.clone(),
                    body: function_body.clone(),
                },
            ),
        ]).unwrap().unwrap(), ContextItem::Nothing);

        let defined = context.get(&name).unwrap();

        match defined {
            ContextItem::Definition {
                precedence: dprecedence,
                fixity: dfixity,
                function,
            } => {
                assert_eq!(dprecedence, precedence);
                assert_eq!(dfixity, fixity);
                assert_eq!(function.params, params);
                assert_eq!(function.body, function_body);
            },
            _ => panic!("operator did not define a function"),
        }
    }
}

<commit_msg>Implemented unitFor<commit_after>use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_context::{EvalContext, EvalResult, EvalError};

const UNIT_PRECEDENCE: u8 = 9;

pub fn setup_defaults(context: &mut EvalContext) {
    setup_fixity_constants(context);

    context.define_built_in_method_defaults(
        "operator",
        4,
        BuiltInFunction::new(operator),
    );

    context.define_built_in_method(
        "units",
        Fixity::Postfix,
        UNIT_PRECEDENCE,
        1,
        BuiltInFunction::new(remove_unit),
    );

    context.define_built_in_method_defaults(
        "defineUnit",
        1,
        BuiltInFunction::new(define_unit),
    );

    context.define_built_in_method_defaults(
        "convert",
        2,
        BuiltInFunction::new(convert),
    );

    context.define_built_in_method_defaults(
        "unitFor",
        1,
        BuiltInFunction::new(unit_for),
    );

    context.define_built_in_method_defaults(
        "valueOf",
        1,
        BuiltInFunction::new(remove_unit),
    );

    context.define_built_in_method_defaults(
        "conversion",
        3,
        BuiltInFunction::new(conversion),
    );
}

fn setup_fixity_constants(context: &mut EvalContext) {
    context.set_constant("PREFIX", Fixity::Prefix.to_string());
    context.set_constant("INFIX", Fixity::Infix.to_string());
    context.set_constant("POSTFIX", Fixity::Postfix.to_string());
}

fn operator(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 4));

    try!(expect_param_is(params[0].is_constant(),
        "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
    try!(expect_param_is(params[1].is_number(),
        "Precedence must be a numeric value"));
    try!(expect_param_is(params[2].is_constant(),
        "Name of the operator must be a string literal"));
    try!(expect_param_is(params[3].is_function(),
        "Function definition must be either an existing function or an anonymous function"));

    let fixity = {
        let fx = Fixity::from_str(&params.remove(0).unwrap_constant());
        try!(expect_param_is(fx.is_some(),
            "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
        fx.unwrap()
    };

    let precedence = {
        let p = params.remove(0).unwrap_number();
        try!(expect_param_is(p.is_dimensionless(),
            "Precedence cannot have a unit"));
        p.value as u8
    };

    let name = &params.remove(0).unwrap_constant();
    let function = params.remove(0);

    debug_assert!(params.is_empty(), "Not all parameters used");

    match function {
        ContextItem::Definition { function, .. } => {
            context.define(name, fixity, precedence, function);
        },
        ContextItem::BuiltInMethod { function, params, .. } => {
            context.define_built_in_method(name, fixity, precedence, params, function)
        },
        _ => unreachable!(),
    };

    Ok(ContextItem::Nothing)
}

fn remove_unit(_: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_number(),
        "Value to convert must be numeric"));

    let value = params.remove(0).unwrap_number();
    debug_assert!(params.is_empty(), "Not all parameters used");

    Ok(ContextItem::Number(value.without_units()))
}

fn define_unit(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_constant(),
        "Name of the unit must be a string literal"));

    let unit_name = &params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not all parameters used");

    let unit = context.create_unit(unit_name);

    context.define_built_in_method(
        unit_name,
        Fixity::Postfix,
        UNIT_PRECEDENCE,
        1,
        BuiltInFunction::new(move |context, mut params| {
            try!(expect_params(&params, 1));
            try!(expect_param_is(params[0].is_number(),
                "Value to convert must be numeric"));

            let value = params.remove(0).unwrap_number();
            debug_assert!(params.is_empty(), "Not parameters used");

            context.convert(value, Some(unit))
        }),
    );

    Ok(ContextItem::Nothing)
}

fn convert(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 2));

    try!(expect_param_is(params[0].is_number(),
        "Value to convert must be numeric"));
    try!(expect_param_is(params[1].is_constant(),
        "Unit to convert to must be a string literal"));

    let value = params.remove(0).unwrap_number();
    let target_unit_name = params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not all parameters used");

    let unit = context.lookup_unit_name(&target_unit_name).unwrap();

    context.convert(value, Some(unit))
}

fn unit_for(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_number(),
        "Value to convert must be numeric"));

    let value = params.remove(0).unwrap_number();
    debug_assert!(params.is_empty(), "Not all parameters used");

    Ok(ContextItem::Constant(
        value.unit.map_or_else(
            || "units".to_owned(),
            // since all units are defined by the eval context itself,
            // we can trust unit constants to exist and use unwrap here
            |v| context.lookup_unit(v).unwrap()
        )
    ))
}

fn conversion(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 3));

    unimplemented!();
}

fn expect_params(params: &Vec<ContextItem>, nparams: usize) -> Result<(), EvalError> {
    if params.len() != nparams {
        Err(EvalError::ExpectedParams(nparams))
    }
    else {
        Ok(())
    }
}

fn expect_param_is(cond: bool, message: &str) -> Result<(), EvalError> {
    if cond {
        Ok(())
    }
    else {
        Err(EvalError::InvalidParam(message.to_owned()))
    }
}

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

    use ast::*;

    use math::rich_number::RichNumber;

    use eval::fixity::Fixity;
    use eval::context_item::ContextItem;
    use eval::eval_context::EvalContext;

    #[test]
    fn fixity_constants() {
        let context = context_with_defaults();

        let lookup_fixity = |name| Fixity::from_str(&context.get(name).unwrap().unwrap_constant()).unwrap();

        assert_eq!(lookup_fixity("PREFIX"), Fixity::Prefix);
        assert_eq!(lookup_fixity("INFIX"), Fixity::Infix);
        assert_eq!(lookup_fixity("POSTFIX"), Fixity::Postfix);
    }

    #[test]
    fn can_define_operators_with_different_fixities() {
        let mut context = context_with_defaults();

        let fixity = Fixity::Prefix;
        let precedence: u8 = 0;
        let name = "foo".to_owned();

        let params = vec!["x".to_owned()];
        let function_body: Expr = vec![
            ExprItem::SingleTerm(Term::Symbol("x".to_owned())),
        ];

        assert_eq!(context.call("operator", vec![
            ContextItem::Constant(fixity.to_string()),
            ContextItem::Number(RichNumber::from(precedence as f64)),
            ContextItem::Constant(name.clone()),
            ContextItem::new_definition(
                // must be different from the other values for these
                Fixity::Postfix,
                precedence + 1,
                Function {
                    params: params.clone(),
                    body: function_body.clone(),
                },
            ),
        ]).unwrap().unwrap(), ContextItem::Nothing);

        let defined = context.get(&name).unwrap();

        match defined {
            ContextItem::Definition {
                precedence: dprecedence,
                fixity: dfixity,
                function,
            } => {
                assert_eq!(dprecedence, precedence);
                assert_eq!(dfixity, fixity);
                assert_eq!(function.params, params);
                assert_eq!(function.body, function_body);
            },
            _ => panic!("operator did not define a function"),
        }
    }

    #[test]
    fn can_get_units() {
        let mut context = context_with_defaults();

        let unit_name = "foo";
        let unit = context.create_unit(unit_name);

        assert_eq!(context.call("unitFor", vec![
            ContextItem::Number(RichNumber::from_unit(23f64, unit)),
        ]).unwrap().unwrap().unwrap_constant(), unit_name);

        assert_eq!(context.call("unitFor", vec![
            ContextItem::Number(RichNumber::from(23f64)),
        ]).unwrap().unwrap().unwrap_constant(), "units");
    }

    fn context_with_defaults() -> EvalContext {
        let mut context = EvalContext::new();
        setup_defaults(&mut context);
        context
    }
}

<|endoftext|>


<commit_before>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }
}
<commit_msg>Add test for `decode_middle_side`<commit_after>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

pub fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_middle_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_middle_side(&mut channels);

    assert_eq!(&channels, &results);
  }
}
<|endoftext|>


<commit_before>#[cfg(feature = "with-serde")]
use serde;

use std::default::Default;
use std::hash::Hash;
use std::option;

use crate::clear::Clear;
use crate::Message;

/// Wrapper around `Option<Box<T>>`, convenient newtype.
///
/// # Examples
///
/// ```no_run
/// # use protobuf::MessageField;
/// # use std::ops::Add;
/// # struct Address {
/// # }
/// # struct Customer {
/// #     address: MessageField<Address>,
/// # }
/// # impl Customer {
/// #     fn new() -> Customer { unimplemented!() }
/// # }
/// #
/// #
/// # fn make_address() -> Address { unimplemented!() }
/// let mut customer = Customer::new();
///
/// // field of type `SingularPtrField` can be initialized like this
/// customer.address = MessageField::some(make_address());
/// // or using `Option` and `Into`
/// customer.address = Some(make_address()).into();
/// ```
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct MessageField<T>(pub Option<Box<T>>);

impl<T> MessageField<T> {
    /// Construct `SingularPtrField` from given object.
    #[inline]
    pub fn some(value: T) -> MessageField<T> {
        MessageField(Some(Box::new(value)))
    }

    /// Construct an empty `SingularPtrField`.
    #[inline]
    pub const fn none() -> MessageField<T> {
        MessageField(None)
    }

    /// Construct `SingularPtrField` from optional.
    #[inline]
    pub fn from_option(option: Option<T>) -> MessageField<T> {
        match option {
            Some(x) => MessageField::some(x),
            None => MessageField::none(),
        }
    }

    /// True iff this object contains data.
    #[inline]
    pub fn is_some(&self) -> bool {
        self.0.is_some()
    }

    /// True iff this object contains no data.
    #[inline]
    pub fn is_none(&self) -> bool {
        self.0.is_none()
    }

    /// Convert into `Option<T>`.
    #[inline]
    pub fn into_option(self) -> Option<T> {
        self.0.map(|v| *v)
    }

    /// View data as reference option.
    #[inline]
    pub fn as_ref(&self) -> Option<&T> {
        self.0.as_ref().map(|v| &**v)
    }

    /// View data as mutable reference option.
    #[inline]
    pub fn as_mut(&mut self) -> Option<&mut T> {
        self.0.as_mut().map(|v| &mut **v)
    }

    /// Get data as reference.
    /// Panics if empty.
    #[inline]
    pub fn get_ref(&self) -> &T {
        self.as_ref().unwrap()
    }

    /// Get data as mutable reference.
    /// Panics if empty.
    #[inline]
    pub fn get_mut_ref(&mut self) -> &mut T {
        self.as_mut().unwrap()
    }

    /// Take the data.
    /// Panics if empty
    #[inline]
    pub fn unwrap(self) -> T {
        *self.0.unwrap()
    }

    /// Take the data or return supplied default element if empty.
    #[inline]
    pub fn unwrap_or(self, def: T) -> T {
        self.0.map(|v| *v).unwrap_or(def)
    }

    /// Take the data or return supplied default element if empty.
    #[inline]
    pub fn unwrap_or_else<F>(self, f: F) -> T
    where
        F: FnOnce() -> T,
    {
        self.0.map(|v| *v).unwrap_or_else(f)
    }

    /// Apply given function to contained data to construct another `SingularPtrField`.
    /// Returns empty `SingularPtrField` if this object is empty.
    #[inline]
    pub fn map<U, F>(self, f: F) -> MessageField<U>
    where
        F: FnOnce(T) -> U,
    {
        MessageField::from_option(self.into_option().map(f))
    }

    /// View data as iterator.
    #[inline]
    pub fn iter(&self) -> option::IntoIter<&T> {
        self.as_ref().into_iter()
    }

    /// View data as mutable iterator.
    #[inline]
    pub fn mut_iter(&mut self) -> option::IntoIter<&mut T> {
        self.as_mut().into_iter()
    }

    /// Take data as option, leaving this object empty.
    #[inline]
    pub fn take(&mut self) -> Option<T> {
        self.0.take().map(|v| *v)
    }

    /// Clear this object, but do not call destructor of underlying data.
    #[inline]
    pub fn clear(&mut self) {
        self.0 = None;
    }
}

impl<T: Default + Clear> MessageField<T> {
    /// Get contained data, consume self. Return default value for type if this is empty.
    #[inline]
    pub fn unwrap_or_default(self) -> T {
        *self.0.unwrap_or_default()
    }

    /// Set object to `Some(T::default())`.
    // TODO: inline
    #[inline]
    pub fn set_default(&mut self) -> &mut T {
        *self = MessageField::some(Default::default());
        self.as_mut().unwrap()
    }
}

impl<M: Message + Default> MessageField<M> {
    /// Get a reference to contained value or a default instance.
    pub fn get_or_default(&self) -> &M {
        self.as_ref().unwrap_or_else(|| M::default_instance())
    }

    /// Get a mutable reference to contained value, initialize if not initialized yet.
    pub fn mut_or_default(&mut self) -> &mut M {
        if self.is_none() {
            *self = MessageField::some(Default::default());
        }
        self.get_mut_ref()
    }
}

impl<T> Default for MessageField<T> {
    #[inline]
    fn default() -> MessageField<T> {
        MessageField::none()
    }
}

impl<T> From<Option<T>> for MessageField<T> {
    fn from(o: Option<T>) -> Self {
        MessageField::from_option(o)
    }
}

impl<'a, T> IntoIterator for &'a MessageField<T> {
    type Item = &'a T;
    type IntoIter = option::IntoIter<&'a T>;

    fn into_iter(self) -> option::IntoIter<&'a T> {
        self.iter()
    }
}

#[cfg(feature = "with-serde")]
impl<T: serde::Serialize> serde::Serialize for MessageField<T> {
    fn serialize<S>(
        &self,
        serializer: S,
    ) -> Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
    where
        S: serde::Serializer,
    {
        self.as_ref().serialize(serializer)
    }
}

#[cfg(feature = "with-serde")]
impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for MessageField<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as serde::Deserializer<'de>>::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Option::deserialize(deserializer).map(MessageField::from)
    }
}
<commit_msg>Unnecessary Clear constraints in MessageField<commit_after>#[cfg(feature = "with-serde")]
use serde;

use std::default::Default;
use std::hash::Hash;
use std::option;

use crate::Message;

/// Wrapper around `Option<Box<T>>`, convenient newtype.
///
/// # Examples
///
/// ```no_run
/// # use protobuf::MessageField;
/// # use std::ops::Add;
/// # struct Address {
/// # }
/// # struct Customer {
/// #     address: MessageField<Address>,
/// # }
/// # impl Customer {
/// #     fn new() -> Customer { unimplemented!() }
/// # }
/// #
/// #
/// # fn make_address() -> Address { unimplemented!() }
/// let mut customer = Customer::new();
///
/// // field of type `SingularPtrField` can be initialized like this
/// customer.address = MessageField::some(make_address());
/// // or using `Option` and `Into`
/// customer.address = Some(make_address()).into();
/// ```
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct MessageField<T>(pub Option<Box<T>>);

impl<T> MessageField<T> {
    /// Construct `SingularPtrField` from given object.
    #[inline]
    pub fn some(value: T) -> MessageField<T> {
        MessageField(Some(Box::new(value)))
    }

    /// Construct an empty `SingularPtrField`.
    #[inline]
    pub const fn none() -> MessageField<T> {
        MessageField(None)
    }

    /// Construct `SingularPtrField` from optional.
    #[inline]
    pub fn from_option(option: Option<T>) -> MessageField<T> {
        match option {
            Some(x) => MessageField::some(x),
            None => MessageField::none(),
        }
    }

    /// True iff this object contains data.
    #[inline]
    pub fn is_some(&self) -> bool {
        self.0.is_some()
    }

    /// True iff this object contains no data.
    #[inline]
    pub fn is_none(&self) -> bool {
        self.0.is_none()
    }

    /// Convert into `Option<T>`.
    #[inline]
    pub fn into_option(self) -> Option<T> {
        self.0.map(|v| *v)
    }

    /// View data as reference option.
    #[inline]
    pub fn as_ref(&self) -> Option<&T> {
        self.0.as_ref().map(|v| &**v)
    }

    /// View data as mutable reference option.
    #[inline]
    pub fn as_mut(&mut self) -> Option<&mut T> {
        self.0.as_mut().map(|v| &mut **v)
    }

    /// Get data as reference.
    /// Panics if empty.
    #[inline]
    pub fn get_ref(&self) -> &T {
        self.as_ref().unwrap()
    }

    /// Get data as mutable reference.
    /// Panics if empty.
    #[inline]
    pub fn get_mut_ref(&mut self) -> &mut T {
        self.as_mut().unwrap()
    }

    /// Take the data.
    /// Panics if empty
    #[inline]
    pub fn unwrap(self) -> T {
        *self.0.unwrap()
    }

    /// Take the data or return supplied default element if empty.
    #[inline]
    pub fn unwrap_or(self, def: T) -> T {
        self.0.map(|v| *v).unwrap_or(def)
    }

    /// Take the data or return supplied default element if empty.
    #[inline]
    pub fn unwrap_or_else<F>(self, f: F) -> T
    where
        F: FnOnce() -> T,
    {
        self.0.map(|v| *v).unwrap_or_else(f)
    }

    /// Apply given function to contained data to construct another `SingularPtrField`.
    /// Returns empty `SingularPtrField` if this object is empty.
    #[inline]
    pub fn map<U, F>(self, f: F) -> MessageField<U>
    where
        F: FnOnce(T) -> U,
    {
        MessageField::from_option(self.into_option().map(f))
    }

    /// View data as iterator.
    #[inline]
    pub fn iter(&self) -> option::IntoIter<&T> {
        self.as_ref().into_iter()
    }

    /// View data as mutable iterator.
    #[inline]
    pub fn mut_iter(&mut self) -> option::IntoIter<&mut T> {
        self.as_mut().into_iter()
    }

    /// Take data as option, leaving this object empty.
    #[inline]
    pub fn take(&mut self) -> Option<T> {
        self.0.take().map(|v| *v)
    }

    /// Clear this object, but do not call destructor of underlying data.
    #[inline]
    pub fn clear(&mut self) {
        self.0 = None;
    }
}

impl<T: Default> MessageField<T> {
    /// Get contained data, consume self. Return default value for type if this is empty.
    #[inline]
    pub fn unwrap_or_default(self) -> T {
        *self.0.unwrap_or_default()
    }

    /// Set object to `Some(T::default())`.
    // TODO: inline
    #[inline]
    pub fn set_default(&mut self) -> &mut T {
        *self = MessageField::some(Default::default());
        self.as_mut().unwrap()
    }
}

impl<M: Message + Default> MessageField<M> {
    /// Get a reference to contained value or a default instance.
    pub fn get_or_default(&self) -> &M {
        self.as_ref().unwrap_or_else(|| M::default_instance())
    }

    /// Get a mutable reference to contained value, initialize if not initialized yet.
    pub fn mut_or_default(&mut self) -> &mut M {
        if self.is_none() {
            *self = MessageField::some(Default::default());
        }
        self.get_mut_ref()
    }
}

impl<T> Default for MessageField<T> {
    #[inline]
    fn default() -> MessageField<T> {
        MessageField::none()
    }
}

impl<T> From<Option<T>> for MessageField<T> {
    fn from(o: Option<T>) -> Self {
        MessageField::from_option(o)
    }
}

impl<'a, T> IntoIterator for &'a MessageField<T> {
    type Item = &'a T;
    type IntoIter = option::IntoIter<&'a T>;

    fn into_iter(self) -> option::IntoIter<&'a T> {
        self.iter()
    }
}

#[cfg(feature = "with-serde")]
impl<T: serde::Serialize> serde::Serialize for MessageField<T> {
    fn serialize<S>(
        &self,
        serializer: S,
    ) -> Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
    where
        S: serde::Serializer,
    {
        self.as_ref().serialize(serializer)
    }
}

#[cfg(feature = "with-serde")]
impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for MessageField<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as serde::Deserializer<'de>>::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Option::deserialize(deserializer).map(MessageField::from)
    }
}
<|endoftext|>


<commit_before>//! Special type node attribute.

use std::io;
use std::io::Read;

use parser::binary::{BinaryParser, CountReader};

/// Attribute type of special value.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpecialAttributeType {
    /// Binary value.
    Binary,
    /// String value.
    ///
    /// Note that the encoding is not specified.
    /// The attribute string may be UTF-8, UTF-16, or any other encodings.
    String,
}

/// Special type attribute.
#[derive(Debug)]
pub struct SpecialAttribute<'a, R: 'a> {
    /// Parser.
    parser: &'a mut BinaryParser<R>,
    /// Value type.
    value_type: SpecialAttributeType,
    /// Length of the value in bytes.
    byte_length: u32,
    /// End offset of the attribute value.
    end_offset: u64,
}

impl<'a, R: 'a + Read> SpecialAttribute<'a, R> {
    /// Returns reader of the raw attribute value.
    pub fn reader(&mut self) -> io::Take<&mut CountReader<R>> {
        let limit = self.rest_len();
        self.parser.source.by_ref().take(limit)
    }

    /// Returns attribute value type.
    pub fn value_type(&self) -> SpecialAttributeType {
        self.value_type
    }

    /// Returns length of the whole value.
    pub fn total_len(&self) -> u64 {
        self.byte_length as u64
    }

    /// Returns rest data size.
    pub fn rest_len(&self) -> u64 {
        self.end_offset - self.parser.source.count()
    }

    /// Read the attribute to the vector.
    pub fn into_vec(mut self) -> io::Result<Vec<u8>> {
        let mut buf = Vec::with_capacity(self.rest_len() as usize);
        try!(self.reader().read_to_end(&mut buf));
        Ok(buf)
    }

    /// Read the attribute to the string.
    pub fn into_string(mut self) -> io::Result<String> {
        let mut buf = String::with_capacity(self.rest_len() as usize);
        try!(self.reader().read_to_string(&mut buf));
        Ok(buf)
    }
}

/// Read special type attribute from the given parser.
pub fn read_special_attribute<R: Read>(parser: &mut BinaryParser<R>, type_code: u8) -> io::Result<(SpecialAttribute<R>, u64)> {
    let byte_length = try!(parser.source.read_u32());
    let value_type = match type_code {
        b'R' => SpecialAttributeType::Binary,
        b'S' => SpecialAttributeType::String,
        _ => unreachable!(),
    };
    let current_pos = parser.source.count();
    let end_offset = current_pos + byte_length as u64;

    Ok((SpecialAttribute {
        parser: parser,
        value_type: value_type,
        byte_length: byte_length,
        end_offset: end_offset,
    }, end_offset))
}
<commit_msg>`RustFmt` sources<commit_after>//! Special type node attribute.

use std::io;
use std::io::Read;

use parser::binary::{BinaryParser, CountReader};

/// Attribute type of special value.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpecialAttributeType {
    /// Binary value.
    Binary,
    /// String value.
    ///
    /// Note that the encoding is not specified.
    /// The attribute string may be UTF-8, UTF-16, or any other encodings.
    String,
}

/// Special type attribute.
#[derive(Debug)]
pub struct SpecialAttribute<'a, R: 'a> {
    /// Parser.
    parser: &'a mut BinaryParser<R>,
    /// Value type.
    value_type: SpecialAttributeType,
    /// Length of the value in bytes.
    byte_length: u32,
    /// End offset of the attribute value.
    end_offset: u64,
}

impl<'a, R: 'a + Read> SpecialAttribute<'a, R> {
    /// Returns reader of the raw attribute value.
    pub fn reader(&mut self) -> io::Take<&mut CountReader<R>> {
        let limit = self.rest_len();
        self.parser.source.by_ref().take(limit)
    }

    /// Returns attribute value type.
    pub fn value_type(&self) -> SpecialAttributeType {
        self.value_type
    }

    /// Returns length of the whole value.
    pub fn total_len(&self) -> u64 {
        self.byte_length as u64
    }

    /// Returns rest data size.
    pub fn rest_len(&self) -> u64 {
        self.end_offset - self.parser.source.count()
    }

    /// Read the attribute to the vector.
    pub fn into_vec(mut self) -> io::Result<Vec<u8>> {
        let mut buf = Vec::with_capacity(self.rest_len() as usize);
        try!(self.reader().read_to_end(&mut buf));
        Ok(buf)
    }

    /// Read the attribute to the string.
    pub fn into_string(mut self) -> io::Result<String> {
        let mut buf = String::with_capacity(self.rest_len() as usize);
        try!(self.reader().read_to_string(&mut buf));
        Ok(buf)
    }
}

/// Read special type attribute from the given parser.
pub fn read_special_attribute<R: Read>(
    parser: &mut BinaryParser<R>,
    type_code: u8
) -> io::Result<(SpecialAttribute<R>, u64)> {
    let byte_length = try!(parser.source.read_u32());
    let value_type = match type_code {
        b'R' => SpecialAttributeType::Binary,
        b'S' => SpecialAttributeType::String,
        _ => unreachable!(),
    };
    let current_pos = parser.source.count();
    let end_offset = current_pos + byte_length as u64;

    Ok((SpecialAttribute {
        parser: parser,
        value_type: value_type,
        byte_length: byte_length,
        end_offset: end_offset,
    },
        end_offset))
}
<|endoftext|>


<commit_before>#![feature(path, core, io, os, rustc_private)]

extern crate serialize;

use std::collections::HashMap;
use std::old_io::process::Command;
use std::old_io::{File, TempDir};
use std::old_io::fs;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::old_io::process::InheritFd(1)).stderr(std::old_io::process::InheritFd(2))
        .status().unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-shared")
        .arg("-Wl,-E")
        .stdout(std::old_io::process::InheritFd(1))
        .stderr(std::old_io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::old_io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::old_io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::old_io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    copy_assets(&directory.path());

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::old_io::process::InheritFd(1))
        .stderr(std::old_io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

#[cfg(feature = "assets_hack")]
fn copy_assets(build_path: &Path) {
    use std::old_io::fs::{PathExtensions};

    let cwd = std::os::getcwd().ok()
        .expect("Can not get current working directory!");
    let assets_path = cwd.join("assets");
    if assets_path.exists() {
        fs::symlink(&assets_path, &build_path.join("assets"))
            .ok().expect("Can not create symlink to assets");
    }
}

#[cfg(not(feature = "assets_hack"))]
fn copy_assets(_: &Path) {}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, Path> {
    let base_path = args.output.dir_path().join("native");
    let mut native_shared_libs: HashMap<String, Path> = HashMap::new();

    fs::walk_dir(&base_path).and_then(|dirs| {
        for dir in dirs {
            fs::readdir(&dir).and_then(|paths| {
                for path in paths.iter() {
                    match (path.filename_str(), path.extension_str()) {
                        (Some(filename), Some(ext)) => {
                            if filename.starts_with("lib") && ext == "so" {
                                native_shared_libs.insert(filename.to_string(), path.clone());
                            }
                        }
                        _ => {}
                    }
                }
                Ok(())
            }).ok();
        }
        Ok(())
    }).ok();

    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, Path>) -> TempDir {
    use std::old_io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::mkdir_recursive(&src_path, std::old_io::USER_RWX).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_str(java_src(libs).as_slice())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name, activity_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::old_io::USER_RWX).unwrap();
    }

    {
        // Make sure that 'src' directory is creates
        let src_path = build_directory.path().join("src");
        fs::mkdir_recursive(&src_path, std::old_io::USER_RWX).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, Path>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).unwrap().display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<commit_msg>added more verbage to help user determine that tool executable is missing or not accessible by the program<commit_after>#![feature(path, core, io, os, rustc_private)]

extern crate serialize;

use std::collections::HashMap;
use std::old_io::process::Command;
use std::old_io::{File, TempDir};
use std::old_io::fs;
use std::old_io::fs::PathExtensions;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create the apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // Set the paths for the tools used in one central place. Then we also use this to not
    // only invoke the tool when needed, but also to check before first invocation in order
    // to display a nice error message to the user if the tool is missing from the path.
    let toolgccpath = standalone_path.join("bin").join("arm-linux-androideabi-gcc");
    let toolantpath = Path::new("ant");

    if !toolgccpath.exists() {
        println!("Missing Tool `{}`!", toolgccpath.display());
        std::os::set_exit_status(1);
    }
    // compiling android_native_app_glue.c
    if Command::new(toolgccpath.clone())
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::old_io::process::InheritFd(1)).stderr(std::old_io::process::InheritFd(2))
        .status().unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to a shared object
    if Command::new(toolgccpath.clone())
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-shared")
        .arg("-Wl,-E")
        .stdout(std::old_io::process::InheritFd(1))
        .stderr(std::old_io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::old_io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::old_io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::old_io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    copy_assets(&directory.path());

    // executing ant
    let antcmd = Command::new(toolantpath).arg("debug").stdout(std::old_io::process::InheritFd(1))
        .stderr(std::old_io::process::InheritFd(2)).cwd(directory.path())
        .status();
    if antcmd.is_err() || antcmd.unwrap() != std::old_io::process::ExitStatus(0)
    {
        println!("Error while executing program `ant` debug, or missing program.");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

#[cfg(feature = "assets_hack")]
fn copy_assets(build_path: &Path) {
    use std::old_io::fs::{PathExtensions};

    let cwd = std::os::getcwd().ok()
        .expect("Can not get current working directory!");
    let assets_path = cwd.join("assets");
    if assets_path.exists() {
        fs::symlink(&assets_path, &build_path.join("assets"))
            .ok().expect("Can not create symlink to assets");
    }
}

#[cfg(not(feature = "assets_hack"))]
fn copy_assets(_: &Path) {}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, Path> {
    let base_path = args.output.dir_path().join("native");
    let mut native_shared_libs: HashMap<String, Path> = HashMap::new();

    fs::walk_dir(&base_path).and_then(|dirs| {
        for dir in dirs {
            fs::readdir(&dir).and_then(|paths| {
                for path in paths.iter() {
                    match (path.filename_str(), path.extension_str()) {
                        (Some(filename), Some(ext)) => {
                            if filename.starts_with("lib") && ext == "so" {
                                native_shared_libs.insert(filename.to_string(), path.clone());
                            }
                        }
                        _ => {}
                    }
                }
                Ok(())
            }).ok();
        }
        Ok(())
    }).ok();

    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, Path>) -> TempDir {
    use std::old_io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::mkdir_recursive(&src_path, std::old_io::USER_RWX).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_str(java_src(libs).as_slice())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name, activity_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::old_io::USER_RWX).unwrap();
    }

    {
        // Make sure that 'src' directory is creates
        let src_path = build_directory.path().join("src");
        fs::mkdir_recursive(&src_path, std::old_io::USER_RWX).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, Path>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).unwrap().display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<|endoftext|>


<commit_before>use std::arch::asm;

use dora_asm::arm64::Cond;
use lazy_static::lazy_static;

use crate::masm::CondCode;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            asm!("dc civac, {}", in(reg) ptr);
        }

        ptr += dcacheline_size;
    }

    unsafe {
        asm!("dsb ish");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            asm!("ic ivau, {}", in(reg) ptr);
        }

        ptr += icacheline_size;
    }

    unsafe {
        asm!("dsb ish", "isb");
    }
}

pub fn has_lse_atomics() -> bool {
    *HAS_LSE_ATOMICS
}

lazy_static! {
    static ref HAS_LSE_ATOMICS: bool = check_support_for_lse_atomics();
}

#[cfg(target_os = "macos")]
fn check_support_for_lse_atomics() -> bool {
    use std::ffi::CString;

    unsafe {
        let mut oldbuffer: usize = 0;
        let mut oldlenp: libc::size_t = 4;
        let name = CString::new("hw.optional.armv8_1_atomics").unwrap();
        let result = libc::sysctlbyname(
            name.as_ptr(),
            &mut oldbuffer as *mut usize as *mut libc::c_void,
            &mut oldlenp,
            std::ptr::null_mut(),
            0,
        );
        assert_eq!(result, 0);
        oldbuffer != 0
    }
}

#[cfg(not(target_os = "macos"))]
fn check_support_for_lse_atomics() -> bool {
    let value: usize;
    unsafe {
        asm!("mrs {}, ID_AA64DFR1_EL1", out(reg) value);
    }
    (value >> 20) & 0xF == 0b0010
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        asm!("mrs {}, ctr_el0", out(reg) value);
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::language::ty::SourceType;
use dora_asm::arm64 as arm64_asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            arm64_asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            arm64_asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<commit_msg>fix warning on arm64/macos<commit_after>#[cfg(not(target_os = "macos"))]
use std::arch::asm;

use dora_asm::arm64::Cond;
use lazy_static::lazy_static;

use crate::masm::CondCode;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            asm!("dc civac, {}", in(reg) ptr);
        }

        ptr += dcacheline_size;
    }

    unsafe {
        asm!("dsb ish");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            asm!("ic ivau, {}", in(reg) ptr);
        }

        ptr += icacheline_size;
    }

    unsafe {
        asm!("dsb ish", "isb");
    }
}

pub fn has_lse_atomics() -> bool {
    *HAS_LSE_ATOMICS
}

lazy_static! {
    static ref HAS_LSE_ATOMICS: bool = check_support_for_lse_atomics();
}

#[cfg(target_os = "macos")]
fn check_support_for_lse_atomics() -> bool {
    use std::ffi::CString;

    unsafe {
        let mut oldbuffer: usize = 0;
        let mut oldlenp: libc::size_t = 4;
        let name = CString::new("hw.optional.armv8_1_atomics").unwrap();
        let result = libc::sysctlbyname(
            name.as_ptr(),
            &mut oldbuffer as *mut usize as *mut libc::c_void,
            &mut oldlenp,
            std::ptr::null_mut(),
            0,
        );
        assert_eq!(result, 0);
        oldbuffer != 0
    }
}

#[cfg(not(target_os = "macos"))]
fn check_support_for_lse_atomics() -> bool {
    let value: usize;
    unsafe {
        asm!("mrs {}, ID_AA64DFR1_EL1", out(reg) value);
    }
    (value >> 20) & 0xF == 0b0010
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        asm!("mrs {}, ctr_el0", out(reg) value);
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::language::ty::SourceType;
use dora_asm::arm64 as arm64_asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            arm64_asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            arm64_asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<|endoftext|>


<commit_before>//! Contains methods for initializing the lua config

use std::fs::{OpenOptions, File};
use std::env;
use std::path::Path;

use std::io::Result as IOResult;

pub const INIT_FILE: &'static str = "init.lua";
pub const INIT_FILE_FALLBACK_PATH: &'static str = "/etc/way-cooler/";

#[inline]
fn read_file<P: AsRef<Path>>(path: P) -> IOResult<File> {
    OpenOptions::new().read(true).open(path)
}

#[cfg(test)]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (false, Err("Loading config should be ignored during tests for now"))
}

#[cfg(not(test))]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (true, get_config_file())
}

/// Parses environment variables
fn get_config_file() -> Result<File, &'static str> {
    if let Ok(path_env) = env::var("WAY_COOLER_CONFIG") {
        if let Ok(file) = read_file(Path::new(&path_env).join(INIT_FILE)) {
            info!("Reading init file from $WAY_COOLER_INIT_FILE: {}", path_env);
            return Ok(file)
        }
        warn!("Error reading from $WAY_COOLER_INIT_FILE, defaulting...");
    }

    if let Ok(xdg) = env::var("XDG_CONFIG_HOME") {
        if let Ok(file) = read_file(Path::new(&xdg).join(INIT_FILE)) {
            info!("Reading init file from $XDG_CONFIG_HOME: {}", xdg);
            return Ok(file)
        }
        warn!("Error reading from $XDG_CONFIG_HOME, defaulting...");
    }
    let dot_config = Path::new(&env::var("HOME")
                               .expect("HOME environment variable not defined!"))
        .join(".config").join("way-cooler").join(INIT_FILE);
    trace!("Looking at {:?}", dot_config);
    if let Ok(file) = read_file(&dot_config) {
        info!("Reading init file from {:?}", &dot_config);
        return Ok(file)
    }

    let etc_config = Path::new(INIT_FILE_FALLBACK_PATH).join(INIT_FILE);

    if let Ok(file) = read_file(&etc_config) {
        info!("Reading init file from fallback {:?}", &etc_config);
        return Ok(file)
    }

    return Err("Could not find an init file in any path!")
}
<commit_msg>Fixed $WAY_COOLER_CONFIG path issue, improved log<commit_after>//! Contains methods for initializing the lua config

use std::fs::{OpenOptions, File};
use std::env;
use std::path::Path;

use std::io::Result as IOResult;

pub const INIT_FILE: &'static str = "init.lua";
pub const INIT_FILE_FALLBACK_PATH: &'static str = "/etc/way-cooler/";

#[inline]
fn read_file<P: AsRef<Path>>(path: P) -> IOResult<File> {
    OpenOptions::new().read(true).open(path)
}

#[cfg(test)]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (false, Err("Loading config should be ignored during tests for now"))
}

#[cfg(not(test))]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (true, get_config_file())
}

/// Parses environment variables
fn get_config_file() -> Result<File, &'static str> {
    if let Ok(path_env) = env::var("WAY_COOLER_CONFIG") {
        if let Ok(file) = read_file(Path::new(&path_env)) {
            info!("Reading init file from $WAY_COOLER_INIT_FILE: {}", path_env);
            return Ok(file)
        }
        warn!("$WAY_COOLER_INIT_FILE={}, was not a valid path to a config file. Defaulting ...", path_env);
    }

    if let Ok(xdg) = env::var("XDG_CONFIG_HOME") {
        if let Ok(file) = read_file(Path::new(&xdg).join(INIT_FILE)) {
            info!("Reading init file from $XDG_CONFIG_HOME: {}", xdg);
            return Ok(file)
        }
        warn!("$XDG_CONFIG_HOME={}, was not a valid path to a config file. Defaulting ...", xdg);
    }
    let dot_config = Path::new(&env::var("HOME")
                               .expect("HOME environment variable not defined!"))
        .join(".config").join("way-cooler").join(INIT_FILE);
    trace!("Looking at {:?}", dot_config);
    if let Ok(file) = read_file(&dot_config) {
        info!("Reading init file from {:?}", &dot_config);
        return Ok(file)
    }

    let etc_config = Path::new(INIT_FILE_FALLBACK_PATH).join(INIT_FILE);

    if let Ok(file) = read_file(&etc_config) {
        info!("Reading init file from fallback {:?}", &etc_config);
        return Ok(file)
    }

    return Err("Could not find an init file in any path!")
}
<|endoftext|>