<commit_before>extern crate env_logger;
extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_pipeline;
extern crate gfx_device_gl;
extern crate gfx_debug_draw;
extern crate claymore_load;
extern crate claymore_scene; //temp

type MousePos = (i32, i32);

struct Control {
    rotate_speed: f32,
    zoom_speed: f32,
    base: Option<(MousePos, claymore_scene::Transform<f32>)>,
    last_pos: MousePos,
    space: claymore_scene::Transform<f32>,
}

impl Control {
    pub fn new(rot_speed: f32, zoom_speed: f32,
               space: claymore_scene::Transform<f32>) -> Control {
        Control {
            rotate_speed: rot_speed,
            zoom_speed: zoom_speed,
            base: None,
            last_pos: (0, 0),
            space: space,
        }
    }

    pub fn capture(&mut self, transform: &claymore_scene::Transform<f32>) {
        self.base = Some((self.last_pos, transform.clone()));
    }

    pub fn release(&mut self) {
        self.base = None;
    }

    pub fn position(&mut self, coords: MousePos,
                    transform: &mut claymore_scene::Transform<f32>) {
        self.last_pos = coords;
        match self.base {
            Some((ref base_pos, ref base_transform)) => {
                use cgmath::Transform;
                // p' = Mp * Tc^ * (Tr * Rz * Tr^) * p
                // Tx = (Tr * Rz^ * Tr^) * Tc
                let path = (coords.0 - base_pos.0) as f32 * -self.rotate_speed;
                let rotation = cgmath::Decomposed {
                    scale: 1.0,
                    rot: cgmath::Rotation3::from_axis_angle(
                        &cgmath::vec3(0.0, 0.0, 1.0), cgmath::rad(path)),
                    disp: cgmath::zero(),
                };
                let space_inv = self.space.invert().unwrap();
                let relative = self.space.concat(&rotation.concat(&space_inv));
                *transform = relative.concat(base_transform);
            },
            None => (),
        }
    }

    pub fn wheel(&mut self, shift: i32, transform: &mut claymore_scene::Transform<f32>) {
        use cgmath::{Vector, Transform};
        if self.base.is_some() {
            return
        }
        let vector = transform.transform_vector(&cgmath::vec3(0.0, 0.0, 1.0));
        transform.disp.add_self_v(&vector.mul_s(shift as f32 * -self.zoom_speed));
    }
}

fn main() {
    use std::env;
    use cgmath::{vec3, FixedArray, Matrix, ToMatrix4, Transform};
    use gfx::traits::*;
    use gfx_pipeline::Pipeline;

    let path = match env::args().nth(1) {
        Some(p) => p,
        None => {
            println!("Call as 'viewer <path_to_scene>`");
            return
        }
    };

    env_logger::init().unwrap();
    println!("Initializing the window...");

    let window = glutin::WindowBuilder::new()
        .with_title("Scene viewer".to_string())
        .with_vsync()
        .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
        .build().unwrap();
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let mut graphics = gfx_device_gl::create(|s| window.get_proc_address(s))
                                    .into_graphics();

    let mut debug_renderer = gfx_debug_draw::DebugRenderer::new(
        &mut graphics, [w, h], 64, None, None).ok().unwrap();

    println!("Loading scene: {}", path);
    let (mut scene, texture) = {
        let mut context = claymore_load::Context::new(&mut graphics.factory,
            env::var("CARGO_MANIFEST_DIR").unwrap_or(".".to_string())
            ).unwrap();
        let scene = context.load_scene(&path).unwrap();
        (scene, (context.texture_black.clone(), None))
    };

    let mut pipeline = gfx_pipeline::forward::Pipeline::<gfx_device_gl::Device>::new(
        &mut graphics.factory, texture).unwrap();
    pipeline.background = Some([0.2, 0.3, 0.4, 1.0]);
    let mut frame = gfx::Frame::new(w as u16, h as u16);

    let mut camera = scene.cameras[0].clone();
    camera.projection.aspect = w as f32 / h as f32;
    let mut control = {
        use claymore_scene::base::World;
        let target_node = scene.entities[0].node;
        Control::new(0.005, 0.5, scene.world.get_transform(&target_node))
    };

    println!("Rendering...");
    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::Resized(w, h) => {
                    frame.width = w as u16;
                    frame.height = h as u16;
                    debug_renderer.resize(w, h);
                },
                glutin::Event::KeyboardInput(_, _,
                    Some(glutin::VirtualKeyCode::Escape)) =>
                    break 'main,
                glutin::Event::Closed => break 'main,
                glutin::Event::MouseInput(glutin::ElementState::Pressed, glutin::MouseButton::Left) =>
                    control.capture(&scene.world.get_node(camera.node).local),
                glutin::Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) =>
                    control.release(),
                glutin::Event::MouseMoved(coords) =>
                    control.position(coords, &mut scene.world.mut_node(camera.node).local),
                glutin::Event::MouseWheel(shift) =>
                    control.wheel(shift, &mut scene.world.mut_node(camera.node).local),
                _ => {},
            }
        }

        scene.world.update();
        let len = 1f32;

        for node in scene.world.iter_nodes() {
            let r = node.world.transform_vector(&vec3(0.0, 0.0, 0.0)).into_fixed();
            let x = node.world.transform_vector(&vec3(len, 0.0, 0.0)).into_fixed();
            let y = node.world.transform_vector(&vec3(0.0, len, 0.0)).into_fixed();
            let z = node.world.transform_vector(&vec3(0.0, 0.0, len)).into_fixed();
            debug_renderer.draw_line(r, x, [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, y, [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, z, [0.0, 0.0, 1.0, 1.0]);
        }

        let buf = pipeline.render(&scene, &camera, &frame).unwrap();
        graphics.device.submit(buf);

        //debug_renderer.render(&mut graphics, &frame,
        //    camera.get_view_projection(&scene.world));
        if true {
            use cgmath::FixedArray;
            use claymore_scene::base::World;
            let cam_inv = scene.world.get_transform(&camera.node).invert().unwrap();
            let proj_mx = camera.projection.to_matrix4().mul_m(&cam_inv.to_matrix4()).into_fixed();
            debug_renderer.render(&mut graphics, &frame, proj_mx);
        }

        graphics.end_frame();
        window.swap_buffers();
        graphics.device.after_frame();
    }
    println!("Done.");
}
<commit_msg>Multiple scenes loading for the viewer<commit_after>extern crate env_logger;
extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_pipeline;
extern crate gfx_device_gl;
extern crate gfx_debug_draw;
extern crate claymore_load;
extern crate claymore_scene; //temp

type MousePos = (i32, i32);

struct Control {
    rotate_speed: f32,
    zoom_speed: f32,
    base: Option<(MousePos, claymore_scene::Transform<f32>)>,
    last_pos: MousePos,
    space: claymore_scene::Transform<f32>,
}

impl Control {
    pub fn new(rot_speed: f32, zoom_speed: f32,
               space: claymore_scene::Transform<f32>) -> Control {
        Control {
            rotate_speed: rot_speed,
            zoom_speed: zoom_speed,
            base: None,
            last_pos: (0, 0),
            space: space,
        }
    }

    pub fn capture(&mut self, transform: &claymore_scene::Transform<f32>) {
        self.base = Some((self.last_pos, transform.clone()));
    }

    pub fn release(&mut self) {
        self.base = None;
    }

    pub fn position(&mut self, coords: MousePos,
                    transform: &mut claymore_scene::Transform<f32>) {
        self.last_pos = coords;
        match self.base {
            Some((ref base_pos, ref base_transform)) => {
                use cgmath::Transform;
                // p' = Mp * Tc^ * (Tr * Rz * Tr^) * p
                // Tx = (Tr * Rz^ * Tr^) * Tc
                let path = (coords.0 - base_pos.0) as f32 * -self.rotate_speed;
                let rotation = cgmath::Decomposed {
                    scale: 1.0,
                    rot: cgmath::Rotation3::from_axis_angle(
                        &cgmath::vec3(0.0, 0.0, 1.0), cgmath::rad(path)),
                    disp: cgmath::zero(),
                };
                let space_inv = self.space.invert().unwrap();
                let relative = self.space.concat(&rotation.concat(&space_inv));
                *transform = relative.concat(base_transform);
            },
            None => (),
        }
    }

    pub fn wheel(&mut self, shift: i32, transform: &mut claymore_scene::Transform<f32>) {
        use cgmath::{Vector, Transform};
        if self.base.is_some() {
            return
        }
        let vector = transform.transform_vector(&cgmath::vec3(0.0, 0.0, 1.0));
        transform.disp.add_self_v(&vector.mul_s(shift as f32 * -self.zoom_speed));
    }
}

fn main() {
    use std::env;
    use cgmath::{vec3, FixedArray, Matrix, ToMatrix4, Transform};
    use gfx::traits::*;
    use gfx_pipeline::Pipeline;

    env_logger::init().unwrap();
    println!("Creating the window...");

    let window = glutin::WindowBuilder::new()
        .with_title("Scene viewer".to_string())
        .with_vsync()
        .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
        .build().unwrap();
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let mut graphics = gfx_device_gl::create(|s| window.get_proc_address(s))
                                    .into_graphics();

    let mut debug_renderer = gfx_debug_draw::DebugRenderer::new(
        &mut graphics, [w, h], 64, None, None).ok().unwrap();

    let (mut scene, texture) = {
        let mut context = claymore_load::Context::new(&mut graphics.factory,
            env::var("CARGO_MANIFEST_DIR").unwrap_or(".".to_string())
            ).unwrap();
        let mut scene = context.create_scene();
        for path in env::args().skip(1) {
            println!("Loading scene: {}", path);
            context.extend_scene(&mut scene, &path).unwrap();
        }
        (scene, (context.texture_black.clone(), None))
    };

    println!("Initializing the graphics...");
    let mut pipeline = gfx_pipeline::forward::Pipeline::<gfx_device_gl::Device>::new(
        &mut graphics.factory, texture).unwrap();
    pipeline.background = Some([0.2, 0.3, 0.4, 1.0]);
    let mut frame = gfx::Frame::new(w as u16, h as u16);

    let mut camera = scene.cameras[0].clone();
    camera.projection.aspect = w as f32 / h as f32;
    let mut control = {
        use claymore_scene::base::World;
        let target_node = scene.entities[0].node;
        Control::new(0.005, 0.5, scene.world.get_transform(&target_node))
    };

    println!("Rendering...");
    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::Resized(w, h) => {
                    frame.width = w as u16;
                    frame.height = h as u16;
                    debug_renderer.resize(w, h);
                },
                glutin::Event::KeyboardInput(_, _,
                    Some(glutin::VirtualKeyCode::Escape)) =>
                    break 'main,
                glutin::Event::Closed => break 'main,
                glutin::Event::MouseInput(glutin::ElementState::Pressed, glutin::MouseButton::Left) =>
                    control.capture(&scene.world.get_node(camera.node).local),
                glutin::Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) =>
                    control.release(),
                glutin::Event::MouseMoved(coords) =>
                    control.position(coords, &mut scene.world.mut_node(camera.node).local),
                glutin::Event::MouseWheel(shift) =>
                    control.wheel(shift, &mut scene.world.mut_node(camera.node).local),
                _ => {},
            }
        }

        scene.world.update();
        let len = 1f32;

        for node in scene.world.iter_nodes() {
            let r = node.world.transform_vector(&vec3(0.0, 0.0, 0.0)).into_fixed();
            let x = node.world.transform_vector(&vec3(len, 0.0, 0.0)).into_fixed();
            let y = node.world.transform_vector(&vec3(0.0, len, 0.0)).into_fixed();
            let z = node.world.transform_vector(&vec3(0.0, 0.0, len)).into_fixed();
            debug_renderer.draw_line(r, x, [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, y, [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, z, [0.0, 0.0, 1.0, 1.0]);
        }

        let buf = pipeline.render(&scene, &camera, &frame).unwrap();
        graphics.device.submit(buf);

        // this causes an ICE: https://github.com/rust-lang/rust/issues/24152
        //debug_renderer.render(&mut graphics, &frame,
        //    camera.get_view_projection(&scene.world));
        if true {
            use cgmath::FixedArray;
            use claymore_scene::base::World;
            let cam_inv = scene.world.get_transform(&camera.node).invert().unwrap();
            let proj_mx = camera.projection.to_matrix4().mul_m(&cam_inv.to_matrix4()).into_fixed();
            debug_renderer.render(&mut graphics, &frame, proj_mx);
        }

        graphics.end_frame();
        window.swap_buffers();
        graphics.device.after_frame();
    }
    println!("Done.");
}
<|endoftext|>


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

// ignore-windows
// ignore-android
// min-lldb-version: 310

// aux-build:macro-stepping.rs

#![allow(unused)]

#[macro_use]
extern crate macro_stepping; // exports new_scope!()

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc1[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc2[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc4[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc5[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc6[...]

// === LLDB TESTS ==================================================================================

// lldb-command:set set stop-line-count-before 0
// lldb-command:set set stop-line-count-after 1
// Can't set both to zero or lldb will stop printing source at all.  So it will output the current
// line and the next.  We deal with this by having at least 2 lines between the #loc's

// lldb-command:run
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc1[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc2[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc3[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc4[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc5[...]

macro_rules! foo {
    () => {
        let a = 1;
        let b = 2;
        let c = 3;
    }
}

macro_rules! foo2 {
    () => {
        foo!();
        let x = 1;
        foo!();
    }
}

fn main() {
    zzz(); // #break

    foo!(); // #loc1

    foo2!(); // #loc2

    let x = vec![42]; // #loc3

    new_scope!(); // #loc4

    println!("Hello {}", // #loc5
             "world");

    zzz(); // #loc6
}

fn zzz() {()}
<commit_msg>debuginfo: Ignore macro-stepping test on aarch64<commit_after>// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows
// ignore-android
// ignore-aarch64
// min-lldb-version: 310

// aux-build:macro-stepping.rs

#![allow(unused)]

#[macro_use]
extern crate macro_stepping; // exports new_scope!()

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc1[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc2[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc3[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc4[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc5[...]
// gdb-command:next
// gdb-command:frame
// gdb-check:[...]#loc6[...]

// === LLDB TESTS ==================================================================================

// lldb-command:set set stop-line-count-before 0
// lldb-command:set set stop-line-count-after 1
// Can't set both to zero or lldb will stop printing source at all.  So it will output the current
// line and the next.  We deal with this by having at least 2 lines between the #loc's

// lldb-command:run
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc1[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc2[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc3[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc4[...]
// lldb-command:next
// lldb-command:frame select
// lldb-check:[...]#loc5[...]

macro_rules! foo {
    () => {
        let a = 1;
        let b = 2;
        let c = 3;
    }
}

macro_rules! foo2 {
    () => {
        foo!();
        let x = 1;
        foo!();
    }
}

fn main() {
    zzz(); // #break

    foo!(); // #loc1

    foo2!(); // #loc2

    let x = vec![42]; // #loc3

    new_scope!(); // #loc4

    println!("Hello {}", // #loc5
             "world");

    zzz(); // #loc6
}

fn zzz() {()}
<|endoftext|>


<commit_before>use parser::{Expr, Node};
use std::str;

struct Generator {
    buf: String,
    indent: u8,
    start: bool,
}

impl Generator {

    fn new() -> Generator {
        Generator { buf: String::new(), indent: 0, start: true }
    }

    fn init(&mut self, name: &str) {
        self.write("impl askama::Template for ");
        self.write(name);
        self.writeln(" {");
        self.indent();
        self.writeln("fn render(&self) -> String {");
        self.indent();
        self.writeln("let mut buf = String::new();");
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_lit(&mut self, s: &[u8]) {
        self.write("buf.push_str(");
        self.write(&format!("{:#?}", str::from_utf8(s).unwrap()));
        self.writeln(");");
    }

    fn visit_var(&mut self, s: &[u8]) {
        let var_name = str::from_utf8(s).unwrap();
        let code = format!("std::fmt::Write::write_fmt(\
            &mut buf, format_args!(\"{{}}\", self.{})).unwrap();", var_name);
        self.writeln(&code);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match expr {
            &Expr::Var(s) => self.visit_var(s),
        }
    }

    fn handle(&mut self, tokens: &Vec<Node>) {
        for n in tokens {
            match n {
                &Node::Lit(val) => { self.visit_lit(val); },
                &Node::Expr(ref val) => { self.visit_expr(&val); },
            }
        }
    }

    fn finalize(&mut self) {
        self.writeln("buf");
        self.dedent();
        self.writeln("}");
        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ctx_name: &str, tokens: &Vec<Node>) -> String {
    let mut gen = Generator::new();
    gen.init(ctx_name);
    gen.handle(tokens);
    gen.finalize();
    gen.result()
}
<commit_msg>Separate writing to buffer and node visitation in generator<commit_after>use parser::{Expr, Node};
use std::str;

struct Generator {
    buf: String,
    indent: u8,
    start: bool,
}

impl Generator {

    fn new() -> Generator {
        Generator { buf: String::new(), indent: 0, start: true }
    }

    fn init(&mut self, name: &str) {
        self.write("impl askama::Template for ");
        self.write(name);
        self.writeln(" {");
        self.indent();
        self.writeln("fn render(&self) -> String {");
        self.indent();
        self.writeln("let mut buf = String::new();");
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_var(&mut self, s: &[u8]) {
        self.write(&format!("self.{}", str::from_utf8(s).unwrap()));
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match expr {
            &Expr::Var(s) => self.visit_var(s),
        }
    }

    fn write_lit(&mut self, s: &[u8]) {
        self.write("buf.push_str(");
        self.write(&format!("{:#?}", str::from_utf8(s).unwrap()));
        self.writeln(");");
    }

    fn write_expr(&mut self, s: &Expr) {
        self.write("std::fmt::Write::write_fmt(&mut buf, format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn handle(&mut self, tokens: &Vec<Node>) {
        for n in tokens {
            match n {
                &Node::Lit(val) => { self.write_lit(val); },
                &Node::Expr(ref val) => { self.write_expr(&val); },
            }
        }
    }

    fn finalize(&mut self) {
        self.writeln("buf");
        self.dedent();
        self.writeln("}");
        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ctx_name: &str, tokens: &Vec<Node>) -> String {
    let mut gen = Generator::new();
    gen.init(ctx_name);
    gen.handle(tokens);
    gen.finalize();
    gen.result()
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::ops::Deref;

use types;
use types::{AliasData, Type, Generic, TcType, TypeEnv, merge};
use symbol::Symbol;
use fnv::FnvMap;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        SelfRecursive(id: Symbol) {
            description("self recursive")
            display("The use of self recursion in type `{}` could not be unified.", id)
        }
        UndefinedType(id: Symbol) {
            description("undefined type")
            display("Type `{}` does not exist.", id)
        }
    }
}

/// Removes type aliases from `typ` until it is an actual type
pub fn remove_aliases(env: &TypeEnv, mut typ: TcType) -> TcType {
    while let Ok(Some(new)) = maybe_remove_alias(env, &typ) {
        typ = new;
    }
    typ
}

pub fn remove_aliases_cow<'t>(env: &TypeEnv, typ: &'t TcType) -> Cow<'t, TcType> {
    let mut typ = match maybe_remove_alias(env, typ) {
        Ok(Some(new)) => new,
        _ => return Cow::Borrowed(typ),
    };
    while let Ok(Some(new)) = maybe_remove_alias(env, &typ) {
        typ = new;
    }
    Cow::Owned(typ)
}

/// Removes all possible aliases while checking that
pub fn remove_aliases_checked(reduced_aliases: &mut Vec<Symbol>,
                              env: &TypeEnv,
                              typ: &TcType)
                              -> Result<Option<TcType>, Error> {
    if let Some((alias_id, _)) = typ.as_alias() {
        if reduced_aliases.iter().any(|name| name == alias_id) {
            return Err(Error::SelfRecursive(alias_id.clone()));
        }
        reduced_aliases.push(alias_id.clone());
    }
    let mut typ = match try!(maybe_remove_alias(env, typ)) {
        Some(new) => new,
        None => return Ok(None),
    };
    loop {
        if let Some((alias_id, _)) = typ.as_alias() {
            if reduced_aliases.iter().any(|name| name == alias_id) {
                return Err(Error::SelfRecursive(alias_id.clone()));
            }
            reduced_aliases.push(alias_id.clone());
        }
        match try!(maybe_remove_alias(env, &typ)) {
            Some(new) => typ = new,
            None => break,
        }
    }
    Ok(Some(typ))
}

pub fn remove_alias(env: &TypeEnv, typ: TcType) -> TcType {
    maybe_remove_alias(env, &typ).unwrap_or(None).unwrap_or(typ)
}

/// Expand `typ` if it is an alias that can be expanded and return the expanded type.
/// Returns `None` if the type is not an alias or the alias could not be expanded.
pub fn maybe_remove_alias(env: &TypeEnv, typ: &TcType) -> Result<Option<TcType>, Error> {
    let maybe_alias = match **typ {
        Type::Alias(ref alias) if alias.args.is_empty() => Some(alias),
        Type::App(ref alias, ref args) => {
            match **alias {
                Type::Alias(ref alias) if alias.args.len() == args.len() => Some(alias),
                _ => None,
            }
        }
        _ => None,
    };
    let (id, args) = match typ.as_alias() {
        Some(x) => x,
        None => return Ok(None),
    };
    let alias = match maybe_alias {
        Some(alias) => alias,
        None => {
            try!(env.find_type_info(&id)
                .map(|a| &**a)
                .ok_or_else(|| Error::UndefinedType(id.clone())))
        }
    };
    Ok(type_of_alias(alias, args))
}

/// Returns the type which is aliased by `alias` if it was possible to do a substitution on the
/// type arguments of `alias` using `arguments`
///
/// Example:
///     alias = Result e t (| Err e | Ok t)
///     arguments = [Error, Option a]
///     result = | Err Error | Ok (Option a)
pub fn type_of_alias(alias: &AliasData<Symbol, TcType>, arguments: &[TcType]) -> Option<TcType> {
    let args = &alias.args;
    let mut typ = match alias.typ {
        Some(ref typ) => typ.clone(),
        None => return None,
    };
    // It is ok to take the aliased type only if the alias is fully applied or if it
    // the missing argument only appear in order at the end of the alias
    // i.e
    // type Test a b c = Type (a Int) b c
    //
    // Test a b == Type (a Int) b
    // Test a == Type (a Int)
    // Test == ??? (Impossible to do a sane substitution)

    let ok_substitution = match *typ.clone() {
        Type::App(ref d, ref arg_types) => {
            let allowed_missing_args = arg_types.iter()
                .rev()
                .zip(args.iter().rev())
                .take_while(|&(l, r)| {
                    match **l {
                        Type::Generic(ref g) => g == r,
                        _ => false,
                    }
                })
                .count();
            if args.len() - arguments.len() <= allowed_missing_args {
                // Remove the args at the end of the aliased type
                let arg_types: Vec<_> = arg_types.iter()
                    .take(arg_types.len() - (args.len() - arguments.len()))
                    .cloned()
                    .collect();
                typ = Type::app(d.clone(), arg_types);
                true
            } else {
                false
            }
        }
        _ => arguments.len() == args.len(),
    };
    if !ok_substitution {
        return None;
    }
    let typ = instantiate(typ, |gen| {
        // Replace the generic variable with the type from the list
        // or if it is not found the make a fresh variable
        args.iter()
            .zip(arguments)
            .find(|&(arg, _)| arg.id == gen.id)
            .map(|(_, typ)| typ.clone())
    });
    Some(typ)
}

#[derive(Debug, Default)]
pub struct Instantiator {
    pub named_variables: FnvMap<Symbol, TcType>,
}

impl Instantiator {
    pub fn new() -> Instantiator {
        Instantiator { named_variables: FnvMap::default() }
    }

    fn variable_for(&mut self,
                    generic: &Generic<Symbol>,
                    on_unbound: &mut FnMut(&Symbol) -> TcType)
                    -> TcType {
        let var = match self.named_variables.entry(generic.id.clone()) {
            Entry::Vacant(entry) => {
                let t = on_unbound(&generic.id);
                entry.insert(t).clone()
            }
            Entry::Occupied(entry) => entry.get().clone(),
        };
        let mut var = (*var).clone();
        if let Type::Variable(ref mut var) = var {
            var.kind = generic.kind.clone();
        }
        TcType::from(var)
    }

    /// Instantiates a type, replacing all generic variables with fresh type variables
    pub fn instantiate<F>(&mut self, typ: &TcType, on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        self.named_variables.clear();
        self.instantiate_(typ, on_unbound)
    }

    pub fn instantiate_<F>(&mut self, typ: &TcType, mut on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        instantiate(typ.clone(),
                    |id| Some(self.variable_for(id, &mut on_unbound)))
    }
}

pub fn instantiate<F>(typ: TcType, mut f: F) -> TcType
    where F: FnMut(&Generic<Symbol>) -> Option<TcType>
{
    walk_move_type_no_recurse(typ,
                              &mut |typ| {
                                  match *typ {
                                      Type::Generic(ref x) => f(x),
                                      _ => None,
                                  }
                              })
}

/// Walks through a type replacing some types
/// If a type is replaced the new type will not be traversed
fn walk_move_type_no_recurse<F, I, T>(typ: T, f: &mut F) -> T
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    walk_move_type2(&typ, f).unwrap_or(typ)
}

fn walk_move_type2<F, I, T>(typ: &Type<I, T>, f: &mut F) -> Option<T>
    where F: FnMut(&Type<I, T>) -> Option<T>,
          T: Deref<Target = Type<I, T>> + From<Type<I, T>> + Clone,
          I: Clone
{
    let new = f(typ);
    let result = match new {
        Some(new_type) => return Some(new_type),
        None => {
            let typ = new.as_ref().map_or(typ, |t| &**t);
            match *typ {
                Type::App(ref id, ref args) => {
                    let new_args = walk_move_types(args.iter(), |t| walk_move_type2(t, f));
                    merge(id, walk_move_type2(id, f), args, new_args, Type::app)
                }
                Type::Record { ref types, ref fields } => {
                    let new_types = None;
                    let new_fields = walk_move_types(fields.iter(), |field| {
                        walk_move_type2(&field.typ, f).map(|typ| {
                            types::Field {
                                name: field.name.clone(),
                                typ: typ,
                            }
                        })
                    });
                    merge(types, new_types, fields, new_fields, Type::record)
                }
                Type::Variants(ref variants) => {
                    walk_move_types(variants.iter(),
                                    |v| walk_move_type2(&v.1, f).map(|t| (v.0.clone(), t)))
                        .map(Type::variants)
                }
                Type::Hole |
                Type::Builtin(_) |
                Type::Variable(_) |
                Type::Generic(_) |
                Type::Id(_) |
                Type::Alias(_) => None,
            }
        }
    };
    result.or(new)
}
fn walk_move_types<'a, I, F, T>(types: I, mut f: F) -> Option<Vec<T>>
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    let mut out = Vec::new();
    walk_move_types2(types, false, &mut out, &mut f);
    if out.is_empty() {
        None
    } else {
        out.reverse();
        Some(out)
    }
}
fn walk_move_types2<'a, I, F, T>(mut types: I, replaced: bool, output: &mut Vec<T>, f: &mut F)
    where I: Iterator<Item = &'a T>,
          F: FnMut(&'a T) -> Option<T>,
          T: Clone + 'a
{
    if let Some(typ) = types.next() {
        let new = f(typ);
        walk_move_types2(types, replaced || new.is_some(), output, f);
        match new {
            Some(typ) => {
                output.push(typ);
            }
            None if replaced || !output.is_empty() => {
                output.push(typ.clone());
            }
            None => (),
        }
    }
}
<commit_msg>refactor(base): Remove the duplicate walk_move_type functions from instantiate.rs<commit_after>use std::borrow::Cow;
use std::collections::hash_map::Entry;

use types;
use types::{AliasData, Type, Generic, TcType, TypeEnv};
use symbol::Symbol;
use fnv::FnvMap;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        SelfRecursive(id: Symbol) {
            description("self recursive")
            display("The use of self recursion in type `{}` could not be unified.", id)
        }
        UndefinedType(id: Symbol) {
            description("undefined type")
            display("Type `{}` does not exist.", id)
        }
    }
}

/// Removes type aliases from `typ` until it is an actual type
pub fn remove_aliases(env: &TypeEnv, mut typ: TcType) -> TcType {
    while let Ok(Some(new)) = maybe_remove_alias(env, &typ) {
        typ = new;
    }
    typ
}

pub fn remove_aliases_cow<'t>(env: &TypeEnv, typ: &'t TcType) -> Cow<'t, TcType> {
    let mut typ = match maybe_remove_alias(env, typ) {
        Ok(Some(new)) => new,
        _ => return Cow::Borrowed(typ),
    };
    while let Ok(Some(new)) = maybe_remove_alias(env, &typ) {
        typ = new;
    }
    Cow::Owned(typ)
}

/// Removes all possible aliases while checking that
pub fn remove_aliases_checked(reduced_aliases: &mut Vec<Symbol>,
                              env: &TypeEnv,
                              typ: &TcType)
                              -> Result<Option<TcType>, Error> {
    if let Some((alias_id, _)) = typ.as_alias() {
        if reduced_aliases.iter().any(|name| name == alias_id) {
            return Err(Error::SelfRecursive(alias_id.clone()));
        }
        reduced_aliases.push(alias_id.clone());
    }
    let mut typ = match try!(maybe_remove_alias(env, typ)) {
        Some(new) => new,
        None => return Ok(None),
    };
    loop {
        if let Some((alias_id, _)) = typ.as_alias() {
            if reduced_aliases.iter().any(|name| name == alias_id) {
                return Err(Error::SelfRecursive(alias_id.clone()));
            }
            reduced_aliases.push(alias_id.clone());
        }
        match try!(maybe_remove_alias(env, &typ)) {
            Some(new) => typ = new,
            None => break,
        }
    }
    Ok(Some(typ))
}

pub fn remove_alias(env: &TypeEnv, typ: TcType) -> TcType {
    maybe_remove_alias(env, &typ).unwrap_or(None).unwrap_or(typ)
}

/// Expand `typ` if it is an alias that can be expanded and return the expanded type.
/// Returns `None` if the type is not an alias or the alias could not be expanded.
pub fn maybe_remove_alias(env: &TypeEnv, typ: &TcType) -> Result<Option<TcType>, Error> {
    let maybe_alias = match **typ {
        Type::Alias(ref alias) if alias.args.is_empty() => Some(alias),
        Type::App(ref alias, ref args) => {
            match **alias {
                Type::Alias(ref alias) if alias.args.len() == args.len() => Some(alias),
                _ => None,
            }
        }
        _ => None,
    };
    let (id, args) = match typ.as_alias() {
        Some(x) => x,
        None => return Ok(None),
    };
    let alias = match maybe_alias {
        Some(alias) => alias,
        None => {
            try!(env.find_type_info(&id)
                .map(|a| &**a)
                .ok_or_else(|| Error::UndefinedType(id.clone())))
        }
    };
    Ok(type_of_alias(alias, args))
}

/// Returns the type which is aliased by `alias` if it was possible to do a substitution on the
/// type arguments of `alias` using `arguments`
///
/// Example:
///     alias = Result e t (| Err e | Ok t)
///     arguments = [Error, Option a]
///     result = | Err Error | Ok (Option a)
pub fn type_of_alias(alias: &AliasData<Symbol, TcType>, arguments: &[TcType]) -> Option<TcType> {
    let args = &alias.args;
    let mut typ = match alias.typ {
        Some(ref typ) => typ.clone(),
        None => return None,
    };
    // It is ok to take the aliased type only if the alias is fully applied or if it
    // the missing argument only appear in order at the end of the alias
    // i.e
    // type Test a b c = Type (a Int) b c
    //
    // Test a b == Type (a Int) b
    // Test a == Type (a Int)
    // Test == ??? (Impossible to do a sane substitution)

    let ok_substitution = match *typ.clone() {
        Type::App(ref d, ref arg_types) => {
            let allowed_missing_args = arg_types.iter()
                .rev()
                .zip(args.iter().rev())
                .take_while(|&(l, r)| {
                    match **l {
                        Type::Generic(ref g) => g == r,
                        _ => false,
                    }
                })
                .count();
            if args.len() - arguments.len() <= allowed_missing_args {
                // Remove the args at the end of the aliased type
                let arg_types: Vec<_> = arg_types.iter()
                    .take(arg_types.len() - (args.len() - arguments.len()))
                    .cloned()
                    .collect();
                typ = Type::app(d.clone(), arg_types);
                true
            } else {
                false
            }
        }
        _ => arguments.len() == args.len(),
    };
    if !ok_substitution {
        return None;
    }
    let typ = instantiate(typ, |gen| {
        // Replace the generic variable with the type from the list
        // or if it is not found the make a fresh variable
        args.iter()
            .zip(arguments)
            .find(|&(arg, _)| arg.id == gen.id)
            .map(|(_, typ)| typ.clone())
    });
    Some(typ)
}

#[derive(Debug, Default)]
pub struct Instantiator {
    pub named_variables: FnvMap<Symbol, TcType>,
}

impl Instantiator {
    pub fn new() -> Instantiator {
        Instantiator { named_variables: FnvMap::default() }
    }

    fn variable_for(&mut self,
                    generic: &Generic<Symbol>,
                    on_unbound: &mut FnMut(&Symbol) -> TcType)
                    -> TcType {
        let var = match self.named_variables.entry(generic.id.clone()) {
            Entry::Vacant(entry) => {
                let t = on_unbound(&generic.id);
                entry.insert(t).clone()
            }
            Entry::Occupied(entry) => entry.get().clone(),
        };
        let mut var = (*var).clone();
        if let Type::Variable(ref mut var) = var {
            var.kind = generic.kind.clone();
        }
        TcType::from(var)
    }

    /// Instantiates a type, replacing all generic variables with fresh type variables
    pub fn instantiate<F>(&mut self, typ: &TcType, on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        self.named_variables.clear();
        self.instantiate_(typ, on_unbound)
    }

    pub fn instantiate_<F>(&mut self, typ: &TcType, mut on_unbound: F) -> TcType
        where F: FnMut(&Symbol) -> TcType
    {
        instantiate(typ.clone(),
                    |id| Some(self.variable_for(id, &mut on_unbound)))
    }
}

pub fn instantiate<F>(typ: TcType, mut f: F) -> TcType
    where F: FnMut(&Generic<Symbol>) -> Option<TcType>
{
    types::walk_move_type(typ,
                          &mut |typ| {
                              match *typ {
                                  Type::Generic(ref x) => f(x),
                                  _ => None,
                              }
                          })
}<|endoftext|>


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

use std::slice;

/// Allows to view uniform tuples as slices
pub trait TupleSlice<T> {
    fn as_slice(&self) -> &[T];
    fn as_mut_slice(&mut self) -> &mut [T];
}

macro_rules! impl_tuple_slice {
    ($tuple_type:ty, $size:expr) => {
        impl<T> TupleSlice<T> for $tuple_type {
            fn as_slice(&self) -> &[T] {
                unsafe {
                    let ptr = &self.0 as *const T;
                    slice::from_raw_parts(ptr, $size)
                }
            }

            fn as_mut_slice(&mut self) -> &mut [T] {
                unsafe {
                    let ptr = &mut self.0 as *mut T;
                    slice::from_raw_parts_mut(ptr, $size)
                }
            }
        }
    }
}

impl_tuple_slice!((T, T), 2);
impl_tuple_slice!((T, T, T), 3);
impl_tuple_slice!((T, T, T, T), 4);
impl_tuple_slice!((T, T, T, T, T), 5);
impl_tuple_slice!((T, T, T, T, T, T), 6);
impl_tuple_slice!((T, T, T, T, T, T, T), 7);
impl_tuple_slice!((T, T, T, T, T, T, T, T), 8);

#[test]
fn test_sliced_tuples() {
    let t2 = (100i32, 101i32);
    assert_eq!(t2.as_slice(), &[100i32, 101i32]);

    let t3 = (102i32, 103i32, 104i32);
    assert_eq!(t3.as_slice(), &[102i32, 103i32, 104i32]);

    let t4 = (105i32, 106i32, 107i32, 108i32);
    assert_eq!(t4.as_slice(), &[105i32, 106i32, 107i32, 108i32]);

    let t5 = (109i32, 110i32, 111i32, 112i32, 113i32);
    assert_eq!(t5.as_slice(), &[109i32, 110i32, 111i32, 112i32, 113i32]);
}
<commit_msg>Add additional test cases to test all arities of tuple; And remove type suffix - i32 on integers<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::slice;

/// Allows to view uniform tuples as slices
pub trait TupleSlice<T> {
    fn as_slice(&self) -> &[T];
    fn as_mut_slice(&mut self) -> &mut [T];
}

macro_rules! impl_tuple_slice {
    ($tuple_type:ty, $size:expr) => {
        impl<T> TupleSlice<T> for $tuple_type {
            fn as_slice(&self) -> &[T] {
                unsafe {
                    let ptr = &self.0 as *const T;
                    slice::from_raw_parts(ptr, $size)
                }
            }

            fn as_mut_slice(&mut self) -> &mut [T] {
                unsafe {
                    let ptr = &mut self.0 as *mut T;
                    slice::from_raw_parts_mut(ptr, $size)
                }
            }
        }
    }
}

impl_tuple_slice!((T, T), 2);
impl_tuple_slice!((T, T, T), 3);
impl_tuple_slice!((T, T, T, T), 4);
impl_tuple_slice!((T, T, T, T, T), 5);
impl_tuple_slice!((T, T, T, T, T, T), 6);
impl_tuple_slice!((T, T, T, T, T, T, T), 7);
impl_tuple_slice!((T, T, T, T, T, T, T, T), 8);

#[test]
fn test_sliced_tuples() {
    let t2 = (100, 101);
    assert_eq!(t2.as_slice(), &[100, 101]);

    let t3 = (102, 103, 104);
    assert_eq!(t3.as_slice(), &[102, 103, 104]);

    let t4 = (105, 106, 107, 108);
    assert_eq!(t4.as_slice(), &[105, 106, 107, 108]);

    let t5 = (109, 110, 111, 112, 113);
    assert_eq!(t5.as_slice(), &[109, 110, 111, 112, 113]);

    let t6 = (114, 115, 116, 117, 118, 119);
    assert_eq!(t6.as_slice(), &[114, 115, 116, 117, 118, 119]);

    let t7 = (120, 121, 122, 123, 124, 125, 126);
    assert_eq!(t7.as_slice(), &[120, 121, 122, 123, 124, 125, 126]);

    let t8 = (127, 128, 129, 130, 131, 132, 133, 134);
    assert_eq!(t8.as_slice(), &[127, 128, 129, 130, 131, 132, 133, 134]);

}
<|endoftext|>


<commit_before>// static BINARY: &'static str = concat!(env!("CARGO_TARGET_DIR"), env!("CARGO_PKG_NAME"));

use std::env;
use std::process::Command;
use std::path::PathBuf;

fn cargo_check() -> Command {
    Command::new(env::current_exe().unwrap().parent().unwrap().join("cargo-check"))
}

#[test]
fn self_test() {
    let status = cargo_check()
        .arg("check")
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
fn multiple_targets() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .arg("check")
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(status.success());
}

#[test]
fn multiple_targets_2() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .args(&["check", "--", "--cfg", "wrong_bin"])
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(!status.success());
}

// The test ensures that `cargo check` bails after first failing compilation.
#[test]
fn multiple_targets_3() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let output = cargo_check()
        .args(&["check", "--", "--cfg", "wrong_bin", "--cfg", "wrong_lib"])
        .current_dir(multiple_target_fixture)
        .output()
        .unwrap()
        .stderr;

    let output = String::from_utf8(output).unwrap();

    // This is the error message from compiling `--lib`
    assert!(output.contains("no associated item"));
    // This is the error message from compiling `--bin multitarget`.
    // This should not be present as `cargo check` should bail after first
    // failure.
    assert!(!output.contains("unresolved name"));
}

#[test]
fn multiple_targets_4() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .args(&["check", "--release"])
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(status.success());
}
<commit_msg>Fix tests on beta<commit_after>// static BINARY: &'static str = concat!(env!("CARGO_TARGET_DIR"), env!("CARGO_PKG_NAME"));

use std::env;
use std::process::Command;
use std::path::PathBuf;

fn cargo_check() -> Command {
    let mut me = env::current_exe().unwrap();
    me.pop();
    if me.ends_with("deps") {
        me.pop();
    }
    Command::new(me.join("cargo-check"))
}

#[test]
fn self_test() {
    let status = cargo_check()
        .arg("check")
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
fn multiple_targets() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .arg("check")
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(status.success());
}

#[test]
fn multiple_targets_2() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .args(&["check", "--", "--cfg", "wrong_bin"])
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(!status.success());
}

// The test ensures that `cargo check` bails after first failing compilation.
#[test]
fn multiple_targets_3() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let output = cargo_check()
        .args(&["check", "--", "--cfg", "wrong_bin", "--cfg", "wrong_lib"])
        .current_dir(multiple_target_fixture)
        .output()
        .unwrap()
        .stderr;

    let output = String::from_utf8(output).unwrap();

    // This is the error message from compiling `--lib`
    assert!(output.contains("no associated item"));
    // This is the error message from compiling `--bin multitarget`.
    // This should not be present as `cargo check` should bail after first
    // failure.
    assert!(!output.contains("unresolved name"));
}

#[test]
fn multiple_targets_4() {
    let multiple_target_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/multitarget");

    let status = cargo_check()
        .args(&["check", "--release"])
        .current_dir(multiple_target_fixture)
        .status()
        .unwrap();

    assert!(status.success());
}
<|endoftext|>


<commit_before>use self::super::{Status, MAP};
use self::super::super::http;

pub fn init(ctn: u16, pn: u16) -> Status {
    // Do we know this CTN?
    if MAP.lock().contains_key(&ctn) {
        error!("Card terminal has already been opened.");
        return Status::ErrInvalid;
    }

    let path = format!("ct_init/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn, pn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            Status::ErrHtsi
        }
    };

    match status {
        Status::OK => {
            // Store CTN
            MAP.lock().insert(ctn, pn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::init;
    use super::super::MAP;
    use rand;
    use rouille::Response;

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn))
    }

    #[test]
    fn returns_err_invalid_if_already_open() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-1, init(ctn, pn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown = test_server!((request: &Request) {
            assert_eq!(request.url(), format!("/ct_init/{}/{}", ctn, pn));

            Response::empty_404()
        });

        init(ctn, pn);

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown = test_server!((request: &Request) {
            Response::empty_404()
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown = test_server!((request: &Request) {
            Response::text("hello world")
        });

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_response_status_from_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown = test_server!((request: &Request) {
            Response::text("-11")
        });

        assert_eq!(-11, init(ctn, pn));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn returns_ok_and_init_ctn_if_server_returns_ok() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        let shutdown = test_server!((request: &Request) {
             Response::text("0")
        });

        assert_eq!(0, init(ctn, pn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));

        // kill server thread
        let _ = shutdown.send(());
    }
}
<commit_msg>use test-server for ct_init tests<commit_after>use self::super::{Status, MAP};
use self::super::super::http;

pub fn init(ctn: u16, pn: u16) -> Status {
    // Do we know this CTN?
    if MAP.lock().contains_key(&ctn) {
        error!("Card terminal has already been opened.");
        return Status::ErrInvalid;
    }

    let path = format!("ct_init/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn, pn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            Status::ErrHtsi
        }
    };

    match status {
        Status::OK => {
            // Store CTN
            MAP.lock().insert(ctn, pn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::init;
    use super::super::MAP;
    use rand;
    use std::env;
    use test_server::{self, hyper};

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn))
    }

    #[test]
    fn returns_err_invalid_if_already_open() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-1, init(ctn, pn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        init(ctn, pn);

        let (_method, uri, _version, _headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(format!("/ct_close/{}/{}", ctn, pn), uri.path());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("hello world");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-128, init(ctn, pn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_response_status_from_server() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("-11");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(-11, init(ctn, pn));
    }

    #[test]
    fn returns_ok_and_init_ctn_if_server_returns_ok() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("0");
        env::set_var("K2_BASE_URL", format!("//{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        assert_eq!(0, init(ctn, pn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }
}
<|endoftext|>


<commit_before>use std::mem;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
}

impl<T: VectorElement> CxxVector<T> {
    /// Returns the number of elements in the vector.
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { T::__get_unchecked(self, pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        T::__get_unchecked(self, pos)
    }

    /// Appends an element to the back of the vector.
    pub fn push_back(&mut self, item: &T) {
        T::__push_back(self, item);
    }
}

pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T: VectorElement> IntoIterator for &'a CxxVector<T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { v: self, index: 0 }
    }
}

impl<'a, T: VectorElement> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.index = self.index + 1;
        self.v.get(self.index - 1)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: &CxxVector<Self>, pos: usize) -> &Self;
    fn __push_back(v: &CxxVector<Self>, item: &Self);
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        unsafe impl VectorElement for $ty {
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: &CxxVector<$ty>, pos: usize) -> &$ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$get_unchecked")]
                        fn __get_unchecked(_: &CxxVector<$ty>, _: usize) -> *const $ty;
                    }
                }
                &*__get_unchecked(v, pos)
            }
            fn __push_back(v: &CxxVector<$ty>, item: &$ty) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$push_back")]
                        fn __push_back(_: &CxxVector<$ty>, _: &$ty);
                    }
                }
                unsafe { __push_back(v, item) }
            }
        }
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

const_assert_eq!(1, mem::align_of::<CxxVector<usize>>());
<commit_msg>Add C++ documentation links to CxxVector<commit_after>use std::mem;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
}

impl<T: VectorElement> CxxVector<T> {
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { T::__get_unchecked(self, pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        T::__get_unchecked(self, pos)
    }

    /// Appends an element to the back of the vector.
    pub fn push_back(&mut self, item: &T) {
        T::__push_back(self, item);
    }
}

pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T: VectorElement> IntoIterator for &'a CxxVector<T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { v: self, index: 0 }
    }
}

impl<'a, T: VectorElement> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        self.index = self.index + 1;
        self.v.get(self.index - 1)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: &CxxVector<Self>, pos: usize) -> &Self;
    fn __push_back(v: &CxxVector<Self>, item: &Self);
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        unsafe impl VectorElement for $ty {
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: &CxxVector<$ty>, pos: usize) -> &$ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$get_unchecked")]
                        fn __get_unchecked(_: &CxxVector<$ty>, _: usize) -> *const $ty;
                    }
                }
                &*__get_unchecked(v, pos)
            }
            fn __push_back(v: &CxxVector<$ty>, item: &$ty) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge02$std$vector$", stringify!($ty), "$push_back")]
                        fn __push_back(_: &CxxVector<$ty>, _: &$ty);
                    }
                }
                unsafe { __push_back(v, item) }
            }
        }
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

const_assert_eq!(1, mem::align_of::<CxxVector<usize>>());
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;

use glutin::event::{ModifiersState, VirtualKeyCode};
use log::error;
use serde::de::Error as SerdeError;
use serde::{self, Deserialize, Deserializer};
use unicode_width::UnicodeWidthChar;

use alacritty_config_derive::ConfigDeserialize;
use alacritty_terminal::config::{Percentage, Program, LOG_TARGET_CONFIG};
use alacritty_terminal::term::search::RegexSearch;

use crate::config::bell::BellConfig;
use crate::config::bindings::{
    self, Action, Binding, Key, KeyBinding, ModeWrapper, ModsWrapper, MouseBinding,
};
use crate::config::color::Colors;
use crate::config::debug::Debug;
use crate::config::font::Font;
use crate::config::mouse::Mouse;
use crate::config::window::WindowConfig;

/// Regex used for the default URL hint.
#[rustfmt::skip]
const URL_REGEX: &str = "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
                         [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+";

#[derive(ConfigDeserialize, Debug, PartialEq)]
pub struct UiConfig {
    /// Font configuration.
    pub font: Font,

    /// Window configuration.
    pub window: WindowConfig,

    pub mouse: Mouse,

    /// Debug options.
    pub debug: Debug,

    /// Send escape sequences using the alt key.
    pub alt_send_esc: bool,

    /// Live config reload.
    pub live_config_reload: bool,

    /// Bell configuration.
    pub bell: BellConfig,

    /// RGB values for colors.
    pub colors: Colors,

    /// Should draw bold text with brighter colors instead of bold font.
    pub draw_bold_text_with_bright_colors: bool,

    /// Path where config was loaded from.
    #[config(skip)]
    pub config_paths: Vec<PathBuf>,

    /// Regex hints for interacting with terminal content.
    pub hints: Hints,

    /// Keybindings.
    key_bindings: KeyBindings,

    /// Bindings for the mouse.
    mouse_bindings: MouseBindings,

    /// Background opacity from 0.0 to 1.0.
    #[config(deprecated = "use window.opacity instead")]
    window_opacity: Option<Percentage>,
}

impl Default for UiConfig {
    fn default() -> Self {
        Self {
            alt_send_esc: true,
            live_config_reload: true,
            font: Default::default(),
            window: Default::default(),
            mouse: Default::default(),
            debug: Default::default(),
            config_paths: Default::default(),
            key_bindings: Default::default(),
            mouse_bindings: Default::default(),
            window_opacity: Default::default(),
            bell: Default::default(),
            colors: Default::default(),
            draw_bold_text_with_bright_colors: Default::default(),
            hints: Default::default(),
        }
    }
}

impl UiConfig {
    /// Generate key bindings for all keyboard hints.
    pub fn generate_hint_bindings(&mut self) {
        for hint in &self.hints.enabled {
            let binding = match hint.binding {
                Some(binding) => binding,
                None => continue,
            };

            let binding = KeyBinding {
                trigger: binding.key,
                mods: binding.mods.0,
                mode: binding.mode.mode,
                notmode: binding.mode.not_mode,
                action: Action::Hint(hint.clone()),
            };

            self.key_bindings.0.push(binding);
        }
    }

    #[inline]
    pub fn window_opacity(&self) -> f32 {
        self.window_opacity.unwrap_or(self.window.opacity).as_f32()
    }

    #[inline]
    pub fn key_bindings(&self) -> &[KeyBinding] {
        self.key_bindings.0.as_slice()
    }

    #[inline]
    pub fn mouse_bindings(&self) -> &[MouseBinding] {
        self.mouse_bindings.0.as_slice()
    }
}

#[derive(Debug, PartialEq)]
struct KeyBindings(Vec<KeyBinding>);

impl Default for KeyBindings {
    fn default() -> Self {
        Self(bindings::default_key_bindings())
    }
}

impl<'de> Deserialize<'de> for KeyBindings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Self(deserialize_bindings(deserializer, Self::default().0)?))
    }
}

#[derive(Debug, PartialEq)]
struct MouseBindings(Vec<MouseBinding>);

impl Default for MouseBindings {
    fn default() -> Self {
        Self(bindings::default_mouse_bindings())
    }
}

impl<'de> Deserialize<'de> for MouseBindings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Self(deserialize_bindings(deserializer, Self::default().0)?))
    }
}

fn deserialize_bindings<'a, D, T>(
    deserializer: D,
    mut default: Vec<Binding<T>>,
) -> Result<Vec<Binding<T>>, D::Error>
where
    D: Deserializer<'a>,
    T: Copy + Eq,
    Binding<T>: Deserialize<'a>,
{
    let values = Vec::<serde_yaml::Value>::deserialize(deserializer)?;

    // Skip all invalid values.
    let mut bindings = Vec::with_capacity(values.len());
    for value in values {
        match Binding::<T>::deserialize(value) {
            Ok(binding) => bindings.push(binding),
            Err(err) => {
                error!(target: LOG_TARGET_CONFIG, "Config error: {}; ignoring binding", err);
            },
        }
    }

    // Remove matching default bindings.
    for binding in bindings.iter() {
        default.retain(|b| !b.triggers_match(binding));
    }

    bindings.extend(default);

    Ok(bindings)
}

/// A delta for a point in a 2 dimensional plane.
#[derive(ConfigDeserialize, Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Delta<T: Default> {
    /// Horizontal change.
    pub x: T,
    /// Vertical change.
    pub y: T,
}

/// Regex terminal hints.
#[derive(ConfigDeserialize, Debug, PartialEq, Eq)]
pub struct Hints {
    /// Characters for the hint labels.
    alphabet: HintsAlphabet,

    /// All configured terminal hints.
    pub enabled: Vec<Hint>,
}

impl Default for Hints {
    fn default() -> Self {
        // Add URL hint by default when no other hint is present.
        let pattern = LazyRegexVariant::Pattern(String::from(URL_REGEX));
        let regex = LazyRegex(Rc::new(RefCell::new(pattern)));

        #[cfg(not(any(target_os = "macos", windows)))]
        let action = HintAction::Command(Program::Just(String::from("xdg-open")));
        #[cfg(target_os = "macos")]
        let action = HintAction::Command(Program::Just(String::from("open")));
        #[cfg(windows)]
        let action = HintAction::Command(Program::WithArgs {
            program: String::from("cmd"),
            args: vec!["/c".to_string(), "start".to_string(), "".to_string()],
        });

        Self {
            enabled: vec![Hint {
                regex,
                action,
                post_processing: true,
                mouse: Some(HintMouse { enabled: true, mods: Default::default() }),
                binding: Some(HintBinding {
                    key: Key::Keycode(VirtualKeyCode::U),
                    mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CTRL),
                    mode: Default::default(),
                }),
            }],
            alphabet: Default::default(),
        }
    }
}

impl Hints {
    /// Characters for the hint labels.
    pub fn alphabet(&self) -> &str {
        &self.alphabet.0
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
struct HintsAlphabet(String);

impl Default for HintsAlphabet {
    fn default() -> Self {
        Self(String::from("jfkdls;ahgurieowpq"))
    }
}

impl<'de> Deserialize<'de> for HintsAlphabet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let value = String::deserialize(deserializer)?;

        let mut character_count = 0;
        for character in value.chars() {
            if character.width() != Some(1) {
                return Err(D::Error::custom("characters must be of width 1"));
            }
            character_count += 1;
        }

        if character_count < 2 {
            return Err(D::Error::custom("must include at last 2 characters"));
        }

        Ok(Self(value))
    }
}

/// Built-in actions for hint mode.
#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)]
pub enum HintInternalAction {
    /// Copy the text to the clipboard.
    Copy,
    /// Write the text to the PTY/search.
    Paste,
    /// Select the text matching the hint.
    Select,
    /// Move the vi mode cursor to the beginning of the hint.
    MoveViModeCursor,
}

/// Actions for hint bindings.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum HintAction {
    /// Built-in hint action.
    #[serde(rename = "action")]
    Action(HintInternalAction),

    /// Command the text will be piped to.
    #[serde(rename = "command")]
    Command(Program),
}

/// Hint configuration.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Hint {
    /// Regex for finding matches.
    pub regex: LazyRegex,

    /// Action executed when this hint is triggered.
    #[serde(flatten)]
    pub action: HintAction,

    /// Hint text post processing.
    #[serde(default)]
    pub post_processing: bool,

    /// Hint mouse highlighting.
    pub mouse: Option<HintMouse>,

    /// Binding required to search for this hint.
    binding: Option<HintBinding>,
}

/// Binding for triggering a keyboard hint.
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
pub struct HintBinding {
    pub key: Key,
    #[serde(default)]
    pub mods: ModsWrapper,
    #[serde(default)]
    pub mode: ModeWrapper,
}

/// Hint mouse highlighting.
#[derive(ConfigDeserialize, Default, Copy, Clone, Debug, PartialEq, Eq)]
pub struct HintMouse {
    /// Hint mouse highlighting availability.
    pub enabled: bool,

    /// Required mouse modifiers for hint highlighting.
    pub mods: ModsWrapper,
}

/// Lazy regex with interior mutability.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LazyRegex(Rc<RefCell<LazyRegexVariant>>);

impl LazyRegex {
    /// Execute a function with the compiled regex DFAs as parameter.
    pub fn with_compiled<T, F>(&self, mut f: F) -> T
    where
        F: FnMut(&RegexSearch) -> T,
    {
        f(self.0.borrow_mut().compiled())
    }
}

impl<'de> Deserialize<'de> for LazyRegex {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let regex = LazyRegexVariant::Pattern(String::deserialize(deserializer)?);
        Ok(Self(Rc::new(RefCell::new(regex))))
    }
}

/// Regex which is compiled on demand, to avoid expensive computations at startup.
#[derive(Clone, Debug)]
pub enum LazyRegexVariant {
    Compiled(Box<RegexSearch>),
    Pattern(String),
}

impl LazyRegexVariant {
    /// Get a reference to the compiled regex.
    ///
    /// If the regex is not already compiled, this will compile the DFAs and store them for future
    /// access.
    fn compiled(&mut self) -> &RegexSearch {
        // Check if the regex has already been compiled.
        let regex = match self {
            Self::Compiled(regex_search) => return regex_search,
            Self::Pattern(regex) => regex,
        };

        // Compile the regex.
        let regex_search = match RegexSearch::new(regex) {
            Ok(regex_search) => regex_search,
            Err(error) => {
                error!("hint regex is invalid: {}", error);
                RegexSearch::new("").unwrap()
            },
        };
        *self = Self::Compiled(Box::new(regex_search));

        // Return a reference to the compiled DFAs.
        match self {
            Self::Compiled(dfas) => dfas,
            Self::Pattern(_) => unreachable!(),
        }
    }
}

impl PartialEq for LazyRegexVariant {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Pattern(regex), Self::Pattern(other_regex)) => regex == other_regex,
            _ => false,
        }
    }
}
impl Eq for LazyRegexVariant {}
<commit_msg>Fix 'background_opacity' deprecation<commit_after>use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;

use glutin::event::{ModifiersState, VirtualKeyCode};
use log::error;
use serde::de::Error as SerdeError;
use serde::{self, Deserialize, Deserializer};
use unicode_width::UnicodeWidthChar;

use alacritty_config_derive::ConfigDeserialize;
use alacritty_terminal::config::{Percentage, Program, LOG_TARGET_CONFIG};
use alacritty_terminal::term::search::RegexSearch;

use crate::config::bell::BellConfig;
use crate::config::bindings::{
    self, Action, Binding, Key, KeyBinding, ModeWrapper, ModsWrapper, MouseBinding,
};
use crate::config::color::Colors;
use crate::config::debug::Debug;
use crate::config::font::Font;
use crate::config::mouse::Mouse;
use crate::config::window::WindowConfig;

/// Regex used for the default URL hint.
#[rustfmt::skip]
const URL_REGEX: &str = "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
                         [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+";

#[derive(ConfigDeserialize, Debug, PartialEq)]
pub struct UiConfig {
    /// Font configuration.
    pub font: Font,

    /// Window configuration.
    pub window: WindowConfig,

    pub mouse: Mouse,

    /// Debug options.
    pub debug: Debug,

    /// Send escape sequences using the alt key.
    pub alt_send_esc: bool,

    /// Live config reload.
    pub live_config_reload: bool,

    /// Bell configuration.
    pub bell: BellConfig,

    /// RGB values for colors.
    pub colors: Colors,

    /// Should draw bold text with brighter colors instead of bold font.
    pub draw_bold_text_with_bright_colors: bool,

    /// Path where config was loaded from.
    #[config(skip)]
    pub config_paths: Vec<PathBuf>,

    /// Regex hints for interacting with terminal content.
    pub hints: Hints,

    /// Keybindings.
    key_bindings: KeyBindings,

    /// Bindings for the mouse.
    mouse_bindings: MouseBindings,

    /// Background opacity from 0.0 to 1.0.
    #[config(deprecated = "use window.opacity instead")]
    background_opacity: Option<Percentage>,
}

impl Default for UiConfig {
    fn default() -> Self {
        Self {
            alt_send_esc: true,
            live_config_reload: true,
            font: Default::default(),
            window: Default::default(),
            mouse: Default::default(),
            debug: Default::default(),
            config_paths: Default::default(),
            key_bindings: Default::default(),
            mouse_bindings: Default::default(),
            background_opacity: Default::default(),
            bell: Default::default(),
            colors: Default::default(),
            draw_bold_text_with_bright_colors: Default::default(),
            hints: Default::default(),
        }
    }
}

impl UiConfig {
    /// Generate key bindings for all keyboard hints.
    pub fn generate_hint_bindings(&mut self) {
        for hint in &self.hints.enabled {
            let binding = match hint.binding {
                Some(binding) => binding,
                None => continue,
            };

            let binding = KeyBinding {
                trigger: binding.key,
                mods: binding.mods.0,
                mode: binding.mode.mode,
                notmode: binding.mode.not_mode,
                action: Action::Hint(hint.clone()),
            };

            self.key_bindings.0.push(binding);
        }
    }

    #[inline]
    pub fn window_opacity(&self) -> f32 {
        self.background_opacity.unwrap_or(self.window.opacity).as_f32()
    }

    #[inline]
    pub fn key_bindings(&self) -> &[KeyBinding] {
        self.key_bindings.0.as_slice()
    }

    #[inline]
    pub fn mouse_bindings(&self) -> &[MouseBinding] {
        self.mouse_bindings.0.as_slice()
    }
}

#[derive(Debug, PartialEq)]
struct KeyBindings(Vec<KeyBinding>);

impl Default for KeyBindings {
    fn default() -> Self {
        Self(bindings::default_key_bindings())
    }
}

impl<'de> Deserialize<'de> for KeyBindings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Self(deserialize_bindings(deserializer, Self::default().0)?))
    }
}

#[derive(Debug, PartialEq)]
struct MouseBindings(Vec<MouseBinding>);

impl Default for MouseBindings {
    fn default() -> Self {
        Self(bindings::default_mouse_bindings())
    }
}

impl<'de> Deserialize<'de> for MouseBindings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Self(deserialize_bindings(deserializer, Self::default().0)?))
    }
}

fn deserialize_bindings<'a, D, T>(
    deserializer: D,
    mut default: Vec<Binding<T>>,
) -> Result<Vec<Binding<T>>, D::Error>
where
    D: Deserializer<'a>,
    T: Copy + Eq,
    Binding<T>: Deserialize<'a>,
{
    let values = Vec::<serde_yaml::Value>::deserialize(deserializer)?;

    // Skip all invalid values.
    let mut bindings = Vec::with_capacity(values.len());
    for value in values {
        match Binding::<T>::deserialize(value) {
            Ok(binding) => bindings.push(binding),
            Err(err) => {
                error!(target: LOG_TARGET_CONFIG, "Config error: {}; ignoring binding", err);
            },
        }
    }

    // Remove matching default bindings.
    for binding in bindings.iter() {
        default.retain(|b| !b.triggers_match(binding));
    }

    bindings.extend(default);

    Ok(bindings)
}

/// A delta for a point in a 2 dimensional plane.
#[derive(ConfigDeserialize, Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Delta<T: Default> {
    /// Horizontal change.
    pub x: T,
    /// Vertical change.
    pub y: T,
}

/// Regex terminal hints.
#[derive(ConfigDeserialize, Debug, PartialEq, Eq)]
pub struct Hints {
    /// Characters for the hint labels.
    alphabet: HintsAlphabet,

    /// All configured terminal hints.
    pub enabled: Vec<Hint>,
}

impl Default for Hints {
    fn default() -> Self {
        // Add URL hint by default when no other hint is present.
        let pattern = LazyRegexVariant::Pattern(String::from(URL_REGEX));
        let regex = LazyRegex(Rc::new(RefCell::new(pattern)));

        #[cfg(not(any(target_os = "macos", windows)))]
        let action = HintAction::Command(Program::Just(String::from("xdg-open")));
        #[cfg(target_os = "macos")]
        let action = HintAction::Command(Program::Just(String::from("open")));
        #[cfg(windows)]
        let action = HintAction::Command(Program::WithArgs {
            program: String::from("cmd"),
            args: vec!["/c".to_string(), "start".to_string(), "".to_string()],
        });

        Self {
            enabled: vec![Hint {
                regex,
                action,
                post_processing: true,
                mouse: Some(HintMouse { enabled: true, mods: Default::default() }),
                binding: Some(HintBinding {
                    key: Key::Keycode(VirtualKeyCode::U),
                    mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CTRL),
                    mode: Default::default(),
                }),
            }],
            alphabet: Default::default(),
        }
    }
}

impl Hints {
    /// Characters for the hint labels.
    pub fn alphabet(&self) -> &str {
        &self.alphabet.0
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
struct HintsAlphabet(String);

impl Default for HintsAlphabet {
    fn default() -> Self {
        Self(String::from("jfkdls;ahgurieowpq"))
    }
}

impl<'de> Deserialize<'de> for HintsAlphabet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let value = String::deserialize(deserializer)?;

        let mut character_count = 0;
        for character in value.chars() {
            if character.width() != Some(1) {
                return Err(D::Error::custom("characters must be of width 1"));
            }
            character_count += 1;
        }

        if character_count < 2 {
            return Err(D::Error::custom("must include at last 2 characters"));
        }

        Ok(Self(value))
    }
}

/// Built-in actions for hint mode.
#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)]
pub enum HintInternalAction {
    /// Copy the text to the clipboard.
    Copy,
    /// Write the text to the PTY/search.
    Paste,
    /// Select the text matching the hint.
    Select,
    /// Move the vi mode cursor to the beginning of the hint.
    MoveViModeCursor,
}

/// Actions for hint bindings.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum HintAction {
    /// Built-in hint action.
    #[serde(rename = "action")]
    Action(HintInternalAction),

    /// Command the text will be piped to.
    #[serde(rename = "command")]
    Command(Program),
}

/// Hint configuration.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Hint {
    /// Regex for finding matches.
    pub regex: LazyRegex,

    /// Action executed when this hint is triggered.
    #[serde(flatten)]
    pub action: HintAction,

    /// Hint text post processing.
    #[serde(default)]
    pub post_processing: bool,

    /// Hint mouse highlighting.
    pub mouse: Option<HintMouse>,

    /// Binding required to search for this hint.
    binding: Option<HintBinding>,
}

/// Binding for triggering a keyboard hint.
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
pub struct HintBinding {
    pub key: Key,
    #[serde(default)]
    pub mods: ModsWrapper,
    #[serde(default)]
    pub mode: ModeWrapper,
}

/// Hint mouse highlighting.
#[derive(ConfigDeserialize, Default, Copy, Clone, Debug, PartialEq, Eq)]
pub struct HintMouse {
    /// Hint mouse highlighting availability.
    pub enabled: bool,

    /// Required mouse modifiers for hint highlighting.
    pub mods: ModsWrapper,
}

/// Lazy regex with interior mutability.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LazyRegex(Rc<RefCell<LazyRegexVariant>>);

impl LazyRegex {
    /// Execute a function with the compiled regex DFAs as parameter.
    pub fn with_compiled<T, F>(&self, mut f: F) -> T
    where
        F: FnMut(&RegexSearch) -> T,
    {
        f(self.0.borrow_mut().compiled())
    }
}

impl<'de> Deserialize<'de> for LazyRegex {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let regex = LazyRegexVariant::Pattern(String::deserialize(deserializer)?);
        Ok(Self(Rc::new(RefCell::new(regex))))
    }
}

/// Regex which is compiled on demand, to avoid expensive computations at startup.
#[derive(Clone, Debug)]
pub enum LazyRegexVariant {
    Compiled(Box<RegexSearch>),
    Pattern(String),
}

impl LazyRegexVariant {
    /// Get a reference to the compiled regex.
    ///
    /// If the regex is not already compiled, this will compile the DFAs and store them for future
    /// access.
    fn compiled(&mut self) -> &RegexSearch {
        // Check if the regex has already been compiled.
        let regex = match self {
            Self::Compiled(regex_search) => return regex_search,
            Self::Pattern(regex) => regex,
        };

        // Compile the regex.
        let regex_search = match RegexSearch::new(regex) {
            Ok(regex_search) => regex_search,
            Err(error) => {
                error!("hint regex is invalid: {}", error);
                RegexSearch::new("").unwrap()
            },
        };
        *self = Self::Compiled(Box::new(regex_search));

        // Return a reference to the compiled DFAs.
        match self {
            Self::Compiled(dfas) => dfas,
            Self::Pattern(_) => unreachable!(),
        }
    }
}

impl PartialEq for LazyRegexVariant {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Pattern(regex), Self::Pattern(other_regex)) => regex == other_regex,
            _ => false,
        }
    }
}
impl Eq for LazyRegexVariant {}
<|endoftext|>