<commit_before>use crate::spec::crt_objects::{self, CrtObjectsFallback};
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmsvcrt".to_string(),
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // Listing the library twice seems to fix that, and seems to also be done
            // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
            //
            // See https://github.com/rust-lang/rust/pull/47483
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc_eh".to_string(),
            "-l:libpthread.a".to_string(),
            "-lgcc".to_string(),
            // libpthread depends on libmsvcrt, so we need to link it *again*.
            "-lmsvcrt".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "lib".to_string(),
        staticlib_suffix: ".a".to_string(),
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects: crt_objects::pre_mingw(),
        post_link_objects: crt_objects::post_mingw(),
        pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
        post_link_objects_fallback: crt_objects::post_mingw_fallback(),
        crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<commit_msg>Rollup merge of #73241 - mati865:mingw-libs-order-comment, r=petrochenkov<commit_after>use crate::spec::crt_objects::{self, CrtObjectsFallback};
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    // Order of `late_link_args*` was found through trial and error to work with various
    // mingw-w64 versions (not tested on the CI). It's expected to change from time to time.
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmsvcrt".to_string(),
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // The library is purposely listed twice to fix that.
            //
            // See https://github.com/rust-lang/rust/pull/47483 for some more details.
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc_eh".to_string(),
            "-l:libpthread.a".to_string(),
            "-lgcc".to_string(),
            // libpthread depends on libmsvcrt, so we need to link it *again*.
            "-lmsvcrt".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "lib".to_string(),
        staticlib_suffix: ".a".to_string(),
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects: crt_objects::pre_mingw(),
        post_link_objects: crt_objects::post_mingw(),
        pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
        post_link_objects_fallback: crt_objects::post_mingw_fallback(),
        crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<|endoftext|>


<commit_before>//! Insertion sort algorithm.
//!
//! The `insertion_sort` module contains the simple sorting algorithm "Insertion Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Insertion_sort

use std::fmt::Debug;

/// Simple sort: insertion sort.
///
/// # Details
///
/// Insertion sort is one of the simplest sorting algorithm. Every elements of the list to sort
/// are picked one at a time and inserted into a the sorted list at the right location.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// In the best case scenario, the list is already sorted and the work is simply to append the
/// element at the end of the list, hence a O(N) scaling.
///
/// In the worst case scenario, the list is in reverse order. Hence, every element is compared to
/// all previous elements already sorted until this new one gets inserted at the beginning of the
/// sorted list, thus making this case O(N^2).
///
/// Insertion sort is still useful as its simplicity (and thus small overhead) makes it ideal for
/// small vectors.
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// assert_eq!(vec![3, 1, 2, 0], sorting::simplesorts::insertion::sort(&data));
/// ```
///
pub fn sort<T: Debug + PartialOrd>(input: &Vec<T>) -> Vec<usize> {
    let n = input.len();

    let mut output_index: Vec<usize> = Vec::with_capacity(n);

    if !input.is_empty() {

        // Place the first element's index (0) as the first element of the output_index vector.
        output_index.push(0);

        // Loop over input vector, skipping the first element as it's already inserted as the first
        // element of output_index.
        for (i_start_at_0,elem) in input.iter().skip(1).enumerate() {
            let i = i_start_at_0 + 1;
            println!("  i={:?} Finding where to put element {:?} (i={:?}) in output_index: {:?}", i, elem, i, output_index);

            // Verify next element if it is smaller
            // If next element is larger than the last stored index, just place that element at
            // the end.
            if *elem >= input[*output_index.last().unwrap()] {
                // Next element "elem" is already larger than the previous stored index.
                // Just use its index.
                output_index.push(i);

                println!("    1. Pushing element '{:?}' at the end.", elem);
            } else {
                println!("    2. elem ?< input[output_index[0]]");
                println!("           {:?} ?< {:?}", elem, input[output_index[0]]);
                // The next element of the input vector is smaller than the last stored on.
                // Let's find where it should go by looping back on the stored indices.
                // NOTE: we must use a loop on indices as to prevent problems with the borrow-checker.
                if *elem < input[output_index[0]] {
                    println!("        2a. Yes: --> putting i in front");
                    output_index.insert(0, i);
                } else {
                    println!("        2b. No: --> Looping back");
                    for j in (0..i).rev() {
                        println!("            j={:?}   elem={:?}   input[output_index[j]]={:?}", j, elem, input[output_index[j]]);
                        if *elem > input[output_index[j]] {
                            output_index.insert(j+1, i);
                            break;
                        }
                    }
                }
                println!("        3. output_index: {:?}", output_index);
            }

            print!("           output: [");
            for j in output_index.iter() {
                    print!("{:?}, ", input[*j]);
            }
            println!("]");
        }
    }

    println!("");
    println!("END: input:        {:?}", input);
    println!("END: output_index: {:?}", output_index);
    print!("END: output:       [");
    for j in output_index.iter() {
            print!("{:?}, ", input[*j]);
    }
    println!("]");

    assert_eq!(output_index.len(), n);

    return output_index;
}
<commit_msg>Note about implementation stability.<commit_after>//! Insertion sort algorithm.
//!
//! The `insertion_sort` module contains the simple sorting algorithm "Insertion Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Insertion_sort

use std::fmt::Debug;

/// Simple sort: insertion sort.
///
/// # Details
///
/// Insertion sort is one of the simplest sorting algorithm. Every elements of the list to sort
/// are picked one at a time and inserted into a the sorted list at the right location.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// In the best case scenario, the list is already sorted and the work is simply to append the
/// element at the end of the list, hence a O(N) scaling.
///
/// In the worst case scenario, the list is in reverse order. Hence, every element is compared to
/// all previous elements already sorted until this new one gets inserted at the beginning of the
/// sorted list, thus making this case O(N^2).
///
/// Insertion sort is still useful as its simplicity (and thus small overhead) makes it ideal for
/// small vectors.
///
/// # Notes
///
/// The implementation is 'unstable' as it does not preserve the relative order of items with
/// equal values. It could be made stable though if required.
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// assert_eq!(vec![3, 1, 2, 0], sorting::simplesorts::insertion::sort(&data));
/// ```
///
pub fn sort<T: Debug + PartialOrd>(input: &Vec<T>) -> Vec<usize> {
    let n = input.len();

    let mut output_index: Vec<usize> = Vec::with_capacity(n);

    if !input.is_empty() {

        // Place the first element's index (0) as the first element of the output_index vector.
        output_index.push(0);

        // Loop over input vector, skipping the first element as it's already inserted as the first
        // element of output_index.
        for (i_start_at_0,elem) in input.iter().skip(1).enumerate() {
            let i = i_start_at_0 + 1;
            println!("  i={:?} Finding where to put element {:?} (i={:?}) in output_index: {:?}", i, elem, i, output_index);

            // Verify next element if it is smaller
            // If next element is larger than the last stored index, just place that element at
            // the end.
            if *elem >= input[*output_index.last().unwrap()] {
                // Next element "elem" is already larger than the previous stored index.
                // Just use its index.
                output_index.push(i);

                println!("    1. Pushing element '{:?}' at the end.", elem);
            } else {
                println!("    2. elem ?< input[output_index[0]]");
                println!("           {:?} ?< {:?}", elem, input[output_index[0]]);
                // The next element of the input vector is smaller than the last stored on.
                // Let's find where it should go by looping back on the stored indices.
                // NOTE: we must use a loop on indices as to prevent problems with the borrow-checker.
                if *elem < input[output_index[0]] {
                    println!("        2a. Yes: --> putting i in front");
                    output_index.insert(0, i);
                } else {
                    println!("        2b. No: --> Looping back");
                    for j in (0..i).rev() {
                        println!("            j={:?}   elem={:?}   input[output_index[j]]={:?}", j, elem, input[output_index[j]]);
                        if *elem > input[output_index[j]] {
                            output_index.insert(j+1, i);
                            break;
                        }
                    }
                }
                println!("        3. output_index: {:?}", output_index);
            }

            print!("           output: [");
            for j in output_index.iter() {
                    print!("{:?}, ", input[*j]);
            }
            println!("]");
        }
    }

    println!("");
    println!("END: input:        {:?}", input);
    println!("END: output_index: {:?}", output_index);
    print!("END: output:       [");
    for j in output_index.iter() {
            print!("{:?}, ", input[*j]);
    }
    println!("]");

    assert_eq!(output_index.len(), n);

    return output_index;
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::event::{Event};

fn main() {
    // start sdl2 with everything
    let mut ctx = sdl2::init().everything().unwrap();

    // Create a window and show it
    let mut window  = match ctx.window("eg02", 640, 480).position_centered().opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    {
        let mut window_properties = window.properties(&ctx);
        window_properties.show();
    }

    let mut events = ctx.event_pump();

    // loop until we receive a QuitEvent
    'event : loop {
        // poll_event returns the most recent event or NoEvent if nothing has happened
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                _               => continue
            }
        }
    }
}

<commit_msg>Fix eg02<commit_after>extern crate sdl2;

use sdl2::event::{Event};

fn main() {
    // start sdl2 with everything
    let ctx = sdl2::init().unwrap();
    let video_ctx = ctx.video().unwrap();

    // Create a window and show it
    let mut window  = match video_ctx.window("eg02", 640, 480).position_centered().opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    {
        window.show();
    }

    let mut events = ctx.event_pump().unwrap();

    // loop until we receive a QuitEvent
    'event : loop {
        // poll_event returns the most recent event or NoEvent if nothing has happened
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                _               => continue
            }
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 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.

/*!
 * C-like enums have to be represented as LLVM ints, not wrapped in a
 * struct, because it's important for the FFI that they interoperate
 * with C integers/enums, and the ABI can treat structs differently.
 * For example, on i686-linux-gnu, a struct return value is passed by
 * storing to a hidden out parameter, whereas an integer would be
 * returned in a register.
 *
 * This test just checks that the ABIs for the enum and the plain
 * integer are compatible, rather than actually calling C code.
 * The unused parameter to `foo` is to increase the likelihood of
 * crashing if something goes wrong here.
 */

#[repr(u32)]
enum Foo {
  A = 0,
  B = 23
}

#[inline(never)]
extern "C" fn foo(_x: uint) -> Foo { B }

pub fn main() {
  unsafe {
    let f: extern "C" fn(uint) -> u32 = std::cast::transmute(foo);
    assert_eq!(f(0xDEADBEEF), B as u32);
  }
}
<commit_msg>Fix the usual check-fast scoping mistake.<commit_after>// Copyright 2013 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.

/*!
 * C-like enums have to be represented as LLVM ints, not wrapped in a
 * struct, because it's important for the FFI that they interoperate
 * with C integers/enums, and the ABI can treat structs differently.
 * For example, on i686-linux-gnu, a struct return value is passed by
 * storing to a hidden out parameter, whereas an integer would be
 * returned in a register.
 *
 * This test just checks that the ABIs for the enum and the plain
 * integer are compatible, rather than actually calling C code.
 * The unused parameter to `foo` is to increase the likelihood of
 * crashing if something goes wrong here.
 */

#[repr(u32)]
enum Foo {
  A = 0,
  B = 23
}

#[inline(never)]
extern "C" fn foo(_x: uint) -> Foo { B }

pub fn main() {
  unsafe {
    let f: extern "C" fn(uint) -> u32 = ::std::cast::transmute(foo);
    assert_eq!(f(0xDEADBEEF), B as u32);
  }
}
<|endoftext|>


<commit_before>// compile-flags: -Z unstable-options --edition 2021

macro_rules! demo2 {
    ( $a:tt $b:tt ) => { println!("two tokens") };
}

macro_rules! demo3 {
    ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
}

macro_rules! demo4 {
    ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
}

fn main() {
    demo3!(foo#bar);   //~ ERROR prefix `foo` is unknown
    demo2!(foo"bar");  //~ ERROR prefix `foo` is unknown
    demo2!(foo'b');    //~ ERROR prefix `foo` is unknown

    demo2!(foo'b);     //~ ERROR prefix `foo` is unknown
    demo3!(foo# bar);  //~ ERROR prefix `foo` is unknown
    demo4!(foo#! bar); //~ ERROR prefix `foo` is unknown
    demo4!(foo## bar); //~ ERROR prefix `foo` is unknown

    demo4!(foo#bar#);
    //~^ ERROR prefix `foo` is unknown
    //~| ERROR prefix `bar` is unknown

    demo3!(foo # bar);
    demo3!(foo #bar);
    demo4!(foo!#bar);
    demo4!(foo ##bar);

    demo3!(r"foo"#bar);
    demo3!(r#foo#bar);
}
<commit_msg>No longer pass -Z unstable-options for edition 2021 in test.<commit_after>// edition:2021

macro_rules! demo2 {
    ( $a:tt $b:tt ) => { println!("two tokens") };
}

macro_rules! demo3 {
    ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
}

macro_rules! demo4 {
    ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
}

fn main() {
    demo3!(foo#bar);   //~ ERROR prefix `foo` is unknown
    demo2!(foo"bar");  //~ ERROR prefix `foo` is unknown
    demo2!(foo'b');    //~ ERROR prefix `foo` is unknown

    demo2!(foo'b);     //~ ERROR prefix `foo` is unknown
    demo3!(foo# bar);  //~ ERROR prefix `foo` is unknown
    demo4!(foo#! bar); //~ ERROR prefix `foo` is unknown
    demo4!(foo## bar); //~ ERROR prefix `foo` is unknown

    demo4!(foo#bar#);
    //~^ ERROR prefix `foo` is unknown
    //~| ERROR prefix `bar` is unknown

    demo3!(foo # bar);
    demo3!(foo #bar);
    demo4!(foo!#bar);
    demo4!(foo ##bar);

    demo3!(r"foo"#bar);
    demo3!(r#foo#bar);
}
<|endoftext|>


<commit_before>use core::mem;
use core::ops::{Index, IndexMut};
use hil;

use common::take_cell::TakeCell;

use peripheral_registers::{GPIO_BASE, GPIO};

#[allow(non_snake_case)]
fn GPIO() -> &'static GPIO {
    unsafe { mem::transmute(GPIO_BASE as usize) }
}

pub struct GPIOPin {
    pin: u8,
    client: TakeCell<&'static hil::gpio::Client>,
}

impl GPIOPin {
    const fn new(pin: u8) -> GPIOPin {
        GPIOPin {
            pin: pin,
            client: TakeCell::empty(),
        }
    }

    pub fn set_client<C: hil::gpio::Client>(&self, client: &'static C) {
        self.client.replace(client);
    }

}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&self) {
        GPIO().pin_cnf[self.pin as usize].set((1 << 0) | (1 << 1) | (0 << 2) | (0 << 8) | (0 << 16));
    }

    fn enable_input(&self, _mode: hil::gpio::InputMode) {
        unimplemented!();
    }

    fn disable(&self) {
        unimplemented!();
    }

    fn set(&self) {
        GPIO().outset.set(1 << self.pin);
    }

    fn clear(&self) {
        GPIO().outclr.set(1 << self.pin);
    }

    fn toggle(&self) {
        unimplemented!();
    }

    fn read(&self) -> bool {
        unimplemented!();
    }

    fn enable_interrupt(&self, _client_data: usize, _mode: hil::gpio::InterruptMode) {
        unimplemented!();
    }

    fn disable_interrupt(&self) {
        unimplemented!();
    }
}

pub struct Port {
    pins: [GPIOPin; 32]
}

impl Index<usize> for Port {
    type Output = GPIOPin;

    fn index(&self, index: usize) -> &GPIOPin {
        &self.pins[index]
    }
}

impl IndexMut<usize> for Port {
    fn index_mut(&mut self, index: usize) -> &mut GPIOPin {
        &mut self.pins[index]
    }
}

pub static mut PA : Port = Port {
    pins: [
        GPIOPin::new(0), GPIOPin::new(1), GPIOPin::new(2), GPIOPin::new(3),
        GPIOPin::new(4), GPIOPin::new(5), GPIOPin::new(6), GPIOPin::new(7),
        GPIOPin::new(8), GPIOPin::new(9), GPIOPin::new(10), GPIOPin::new(11),
        GPIOPin::new(12), GPIOPin::new(13), GPIOPin::new(14), GPIOPin::new(15),
        GPIOPin::new(16), GPIOPin::new(17), GPIOPin::new(18), GPIOPin::new(19),
        GPIOPin::new(20), GPIOPin::new(21), GPIOPin::new(22), GPIOPin::new(23),
        GPIOPin::new(24), GPIOPin::new(25), GPIOPin::new(26), GPIOPin::new(27),
        GPIOPin::new(28), GPIOPin::new(29), GPIOPin::new(30), GPIOPin::new(31),
    ],
};
<commit_msg>nrf51822: Implement GPIO toggle() method<commit_after>use core::mem;
use core::ops::{Index, IndexMut};
use hil;

use common::take_cell::TakeCell;

use peripheral_registers::{GPIO_BASE, GPIO};

#[allow(non_snake_case)]
fn GPIO() -> &'static GPIO {
    unsafe { mem::transmute(GPIO_BASE as usize) }
}

pub struct GPIOPin {
    pin: u8,
    client: TakeCell<&'static hil::gpio::Client>,
}

impl GPIOPin {
    const fn new(pin: u8) -> GPIOPin {
        GPIOPin {
            pin: pin,
            client: TakeCell::empty(),
        }
    }

    pub fn set_client<C: hil::gpio::Client>(&self, client: &'static C) {
        self.client.replace(client);
    }

}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&self) {
        GPIO().pin_cnf[self.pin as usize].set((1 << 0) | (1 << 1) | (0 << 2) | (0 << 8) | (0 << 16));
    }

    fn enable_input(&self, _mode: hil::gpio::InputMode) {
        unimplemented!();
    }

    fn disable(&self) {
        unimplemented!();
    }

    fn set(&self) {
        GPIO().outset.set(1 << self.pin);
    }

    fn clear(&self) {
        GPIO().outclr.set(1 << self.pin);
    }

    fn toggle(&self) {
        // TODO: check need for a atomic XOR operator
        GPIO().out.set((1 << self.pin) ^ GPIO().out.get());
    }

    fn read(&self) -> bool {
        unimplemented!();
    }

    fn enable_interrupt(&self, _client_data: usize, _mode: hil::gpio::InterruptMode) {
        unimplemented!();
    }

    fn disable_interrupt(&self) {
        unimplemented!();
    }
}

pub struct Port {
    pins: [GPIOPin; 32]
}

impl Index<usize> for Port {
    type Output = GPIOPin;

    fn index(&self, index: usize) -> &GPIOPin {
        &self.pins[index]
    }
}

impl IndexMut<usize> for Port {
    fn index_mut(&mut self, index: usize) -> &mut GPIOPin {
        &mut self.pins[index]
    }
}

pub static mut PA : Port = Port {
    pins: [
        GPIOPin::new(0), GPIOPin::new(1), GPIOPin::new(2), GPIOPin::new(3),
        GPIOPin::new(4), GPIOPin::new(5), GPIOPin::new(6), GPIOPin::new(7),
        GPIOPin::new(8), GPIOPin::new(9), GPIOPin::new(10), GPIOPin::new(11),
        GPIOPin::new(12), GPIOPin::new(13), GPIOPin::new(14), GPIOPin::new(15),
        GPIOPin::new(16), GPIOPin::new(17), GPIOPin::new(18), GPIOPin::new(19),
        GPIOPin::new(20), GPIOPin::new(21), GPIOPin::new(22), GPIOPin::new(23),
        GPIOPin::new(24), GPIOPin::new(25), GPIOPin::new(26), GPIOPin::new(27),
        GPIOPin::new(28), GPIOPin::new(29), GPIOPin::new(30), GPIOPin::new(31),
    ],
};
<|endoftext|>


<commit_before>use crate::NibbleVec;
use endian_type::{BigEndian, LittleEndian};
use std::ffi::OsString;
use std::path::{Path, PathBuf};

/// Trait for types which can be used to key a Radix Trie.
///
/// Types that implement this trait should be convertible to a vector of half-bytes (nibbles)
/// such that no two instances of the type convert to the same vector.
/// To protect against faulty behaviour, the trie will **panic** if it finds two distinct keys
/// of type `K` which encode to the same `NibbleVec`, so be careful!
///
/// If you would like to implement this trait for your own type, you need to implement
/// *either* `encode_bytes` or `encode`. You only need to implement one of the two.
/// If you don't implement one, your code will **panic** as soon you use the trie.
/// There is no performance penalty for implementing `encode_bytes` instead of `encode`,
/// so it is preferred except in the case where you require half-byte precision.
///
/// Many standard types implement this trait already. Integer types are encoded *big-endian*
/// by default but can be encoded little-endian using the `LittleEndian<T>` wrapper type.
pub trait TrieKey: PartialEq + Eq {
    /// Encode a value as a vector of bytes.
    fn encode_bytes(&self) -> Vec<u8> {
        panic!("implement this method or TrieKey::encode");
    }

    /// Encode a value as a NibbleVec.
    fn encode(&self) -> NibbleVec {
        NibbleVec::from_byte_vec(self.encode_bytes())
    }
}

/// Key comparison result.
#[derive(Debug)]
pub enum KeyMatch {
    /// The keys match up to the given index.
    Partial(usize),
    /// The first key is a prefix of the second.
    FirstPrefix,
    /// The second key is a prefix of the first.
    SecondPrefix,
    /// The keys match exactly.
    Full,
}

/// Compare two Trie keys.
///
/// Compares `first[start_idx .. ]` to `second`, i.e. only looks at a slice of the first key.
pub fn match_keys(start_idx: usize, first: &NibbleVec, second: &NibbleVec) -> KeyMatch {
    let first_len = first.len() - start_idx;
    let min_length = ::std::cmp::min(first_len, second.len());

    for i in 0..min_length {
        if first.get(start_idx + i) != second.get(i) {
            return KeyMatch::Partial(i);
        }
    }

    match (first_len, second.len()) {
        (x, y) if x < y => KeyMatch::FirstPrefix,
        (x, y) if x == y => KeyMatch::Full,
        _ => KeyMatch::SecondPrefix,
    }
}

/// Check two keys for equality and panic if they differ.
pub fn check_keys<K: ?Sized>(key1: &K, key2: &K)
where
    K: TrieKey,
{
    if *key1 != *key2 {
        panic!("multiple-keys with the same bit representation.");
    }
}

// --- TrieKey Implementations for standard types --- ///

// This blanket implementation goes into play when specialization is stabilized
// impl<T> TrieKey for T where T: Into<Vec<u8>> + Clone + Eq + PartialEq {
// fn encode_bytes(&self) -> Vec<u8> {
// self.clone().into()
// }
// }

impl TrieKey for Vec<u8> {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone()
    }
}

impl TrieKey for [u8] {
    fn encode_bytes(&self) -> Vec<u8> {
        self.to_vec()
    }
}

impl TrieKey for String {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl TrieKey for str {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a mut T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl TrieKey for i8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self as u8);
        v
    }
}

impl TrieKey for u8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self);
        v
    }
}

#[cfg(unix)]
impl TrieKey for PathBuf {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStringExt;
        let str: OsString = self.clone().into();
        str.into_vec()
    }
}

#[cfg(unix)]
impl TrieKey for Path {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStrExt;
        self.as_os_str().as_bytes().encode_bytes()
    }
}

#[cfg(windows)]
impl TrieKey for PathBuf {
    fn encode_bytes(&self) -> Vec<u8> {
        let str: OsString = self.clone().into();
        str.into_string()
            .unwrap()
            .as_str()
            .as_bytes()
            .encode_bytes()
    }
}

#[cfg(windows)]
impl TrieKey for Path {
    fn encode_bytes(&self) -> Vec<u8> {
        self.to_str().unwrap().as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for LittleEndian<T>
where
    T: Eq + Copy,
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for BigEndian<T>
where
    T: Eq + Copy,
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! int_keys {
    ( $( $t:ty ),* ) => {
        $(
        impl TrieKey for $t {
            fn encode_bytes(&self) -> Vec<u8> {
                let be: BigEndian<$t> = From::from(*self);
                be.encode_bytes()
            }
        }
        )*
    };
}

int_keys!(u16, u32, u64, i16, i32, i64, usize, isize);
<commit_msg>Remove panicky TrieKey impl for Path/PathBuf<commit_after>use crate::NibbleVec;
use endian_type::{BigEndian, LittleEndian};
use std::ffi::OsString;
use std::path::{Path, PathBuf};

/// Trait for types which can be used to key a Radix Trie.
///
/// Types that implement this trait should be convertible to a vector of half-bytes (nibbles)
/// such that no two instances of the type convert to the same vector.
/// To protect against faulty behaviour, the trie will **panic** if it finds two distinct keys
/// of type `K` which encode to the same `NibbleVec`, so be careful!
///
/// If you would like to implement this trait for your own type, you need to implement
/// *either* `encode_bytes` or `encode`. You only need to implement one of the two.
/// If you don't implement one, your code will **panic** as soon you use the trie.
/// There is no performance penalty for implementing `encode_bytes` instead of `encode`,
/// so it is preferred except in the case where you require half-byte precision.
///
/// Many standard types implement this trait already. Integer types are encoded *big-endian*
/// by default but can be encoded little-endian using the `LittleEndian<T>` wrapper type.
pub trait TrieKey: PartialEq + Eq {
    /// Encode a value as a vector of bytes.
    fn encode_bytes(&self) -> Vec<u8> {
        panic!("implement this method or TrieKey::encode");
    }

    /// Encode a value as a NibbleVec.
    fn encode(&self) -> NibbleVec {
        NibbleVec::from_byte_vec(self.encode_bytes())
    }
}

/// Key comparison result.
#[derive(Debug)]
pub enum KeyMatch {
    /// The keys match up to the given index.
    Partial(usize),
    /// The first key is a prefix of the second.
    FirstPrefix,
    /// The second key is a prefix of the first.
    SecondPrefix,
    /// The keys match exactly.
    Full,
}

/// Compare two Trie keys.
///
/// Compares `first[start_idx .. ]` to `second`, i.e. only looks at a slice of the first key.
pub fn match_keys(start_idx: usize, first: &NibbleVec, second: &NibbleVec) -> KeyMatch {
    let first_len = first.len() - start_idx;
    let min_length = ::std::cmp::min(first_len, second.len());

    for i in 0..min_length {
        if first.get(start_idx + i) != second.get(i) {
            return KeyMatch::Partial(i);
        }
    }

    match (first_len, second.len()) {
        (x, y) if x < y => KeyMatch::FirstPrefix,
        (x, y) if x == y => KeyMatch::Full,
        _ => KeyMatch::SecondPrefix,
    }
}

/// Check two keys for equality and panic if they differ.
pub fn check_keys<K: ?Sized>(key1: &K, key2: &K)
where
    K: TrieKey,
{
    if *key1 != *key2 {
        panic!("multiple-keys with the same bit representation.");
    }
}

// --- TrieKey Implementations for standard types --- ///

// This blanket implementation goes into play when specialization is stabilized
// impl<T> TrieKey for T where T: Into<Vec<u8>> + Clone + Eq + PartialEq {
// fn encode_bytes(&self) -> Vec<u8> {
// self.clone().into()
// }
// }

impl TrieKey for Vec<u8> {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone()
    }
}

impl TrieKey for [u8] {
    fn encode_bytes(&self) -> Vec<u8> {
        self.to_vec()
    }
}

impl TrieKey for String {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl TrieKey for str {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a mut T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl TrieKey for i8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self as u8);
        v
    }
}

impl TrieKey for u8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self);
        v
    }
}

#[cfg(unix)]
impl TrieKey for PathBuf {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStringExt;
        let str: OsString = self.clone().into();
        str.into_vec()
    }
}

#[cfg(unix)]
impl TrieKey for Path {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStrExt;
        self.as_os_str().as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for LittleEndian<T>
where
    T: Eq + Copy,
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for BigEndian<T>
where
    T: Eq + Copy,
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! int_keys {
    ( $( $t:ty ),* ) => {
        $(
        impl TrieKey for $t {
            fn encode_bytes(&self) -> Vec<u8> {
                let be: BigEndian<$t> = From::from(*self);
                be.encode_bytes()
            }
        }
        )*
    };
}

int_keys!(u16, u32, u64, i16, i32, i64, usize, isize);
<|endoftext|>


<commit_before>//! Implements a command for uploading dSYM files.
use std::collections::BTreeSet;
use std::str::{self, FromStr};

use anyhow::{bail, format_err, Result};
use clap::{Arg, ArgMatches, Command};
use console::style;
use log::info;
use symbolic::common::DebugId;
use symbolic::debuginfo::FileFormat;

use crate::api::Api;
use crate::config::Config;
use crate::utils::args::{validate_id, ArgExt};
use crate::utils::dif::ObjectDifFeatures;
use crate::utils::dif_upload::{DifFormat, DifUpload};
use crate::utils::progress::{ProgressBar, ProgressStyle};
use crate::utils::system::QuietExit;
use crate::utils::xcode::{InfoPlist, MayDetach};

static DERIVED_DATA: &str = "Library/Developer/Xcode/DerivedData";

pub fn make_command(command: Command) -> Command {
    command.about("Upload debugging information files.")
        .org_arg()
        .project_arg(false)
        .arg(
            Arg::new("paths")
                .value_name("PATH")
                .help("A path to search recursively for symbol files.")
                .multiple_occurrences(true)
                .index(1),
        )
        .arg(
            Arg::new("types")
                .long("type")
                .short('t')
                .value_name("TYPE")
                .multiple_occurrences(true)
                .possible_values(&[
                    "dsym",
                    "elf",
                    "breakpad",
                    "pdb",
                    "pe",
                    "sourcebundle",
                    "bcsymbolmap",
                ])
                .help(
                    "Only consider debug information files of the given \
                     type.  By default, all types are considered.",
                ),
        )
        .arg(
            Arg::new("no_unwind")
                .long("no-unwind")
                .alias("no-bin")
                .help(
                    "Do not scan for stack unwinding information. Specify \
                     this flag for builds with disabled FPO, or when \
                     stackwalking occurs on the device. This usually \
                     excludes executables and dynamic libraries. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
                ),
        )
        .arg(
            Arg::new("no_debug")
                .long("no-debug")
                .help(
                    "Do not scan for debugging information. This will \
                     usually exclude debug companion files. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
                )
                .conflicts_with("no_unwind"),
        )
        .arg(
            Arg::new("no_sources")
                .long("no-sources")
                .help(
                    "Do not scan for source information. This will \
                     usually exclude source bundle files. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
                )
                .conflicts_with("no_sources"),
        )
        .arg(
            Arg::new("ids")
                .value_name("ID")
                .long("id")
                .help("Search for specific debug identifiers.")
                .validator(validate_id)
                .multiple_occurrences(true),
        )
        .arg(
            Arg::new("require_all")
                .long("require-all")
                .help("Errors if not all identifiers specified with --id could be found."),
        )
        .arg(
            Arg::new("symbol_maps")
                .long("symbol-maps")
                .value_name("PATH")
                .help(
                    "Optional path to BCSymbolMap files which are used to \
                     resolve hidden symbols in dSYM files downloaded from \
                     iTunes Connect.  This requires the dsymutil tool to be \
                     available.  This should not be used when using the App \
                     Store Connect integration, the .bcsymbolmap files needed \
                     for the integration are uploaded without this option if \
                     they are found in the PATH searched for symbol files.",
                ),
        )
        .arg(
            Arg::new("derived_data")
                .long("derived-data")
                .help("Search for debug symbols in Xcode's derived data."),
        )
        .arg(
            Arg::new("no_zips")
                .long("no-zips")
                .help("Do not search in ZIP files."),
        )
        .arg(
            Arg::new("info_plist")
                .long("info-plist")
                .value_name("PATH")
                .help(
                    "Optional path to the Info.plist.{n}We will try to find this \
                     automatically if run from Xcode.  Providing this information \
                     will associate the debug symbols with a specific ITC application \
                     and build in Sentry.  Note that if you provide the plist \
                     explicitly it must already be processed.",
                ),
        )
        .arg(
            Arg::new("no_reprocessing")
                .long("no-reprocessing")
                .help("Do not trigger reprocessing after uploading."),
        )
        .arg(Arg::new("no_upload").long("no-upload").help(
            "Disable the actual upload.{n}This runs all steps for the \
             processing but does not trigger the upload (this also \
             automatically disables reprocessing).  This is useful if you \
             just want to verify the setup or skip the upload in tests.",
        ))
        .arg(Arg::new("force_foreground").long("force-foreground").help(
            "Wait for the process to finish.{n}\
                     By default, the upload process will detach and continue in the \
                     background when triggered from Xcode.  When an error happens, \
                     a dialog is shown.  If this parameter is passed Xcode will wait \
                     for the process to finish before the build finishes and output \
                     will be shown in the Xcode build output.",
        ))
        .arg(Arg::new("include_sources").long("include-sources").help(
            "Include sources from the local file system and upload \
                     them as source bundles.",
        ))
        .arg(Arg::new("wait").long("wait").help(
            "Wait for the server to fully process uploaded files. Errors \
             can only be displayed if --wait is specified, but this will \
             significantly slow down the upload process.",
        ))
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
    let config = Config::current();
    let (org, project) = config.get_org_and_project(matches)?;

    let ids = matches
        .values_of("ids")
        .unwrap_or_default()
        .filter_map(|s| DebugId::from_str(s).ok());

    info!(
        "Issuing a command for Organization: {} Project: {}",
        org, project
    );

    // Build generic upload parameters
    let mut upload = DifUpload::new(org.clone(), project.clone());
    upload
        .wait(matches.is_present("wait"))
        .search_paths(matches.values_of("paths").unwrap_or_default())
        .allow_zips(!matches.is_present("no_zips"))
        .filter_ids(ids);

    // Restrict symbol types, if specified by the user
    for ty in matches.values_of("types").unwrap_or_default() {
        match ty {
            "dsym" => upload.filter_format(DifFormat::Object(FileFormat::MachO)),
            "elf" => upload.filter_format(DifFormat::Object(FileFormat::Elf)),
            "breakpad" => upload.filter_format(DifFormat::Object(FileFormat::Breakpad)),
            "pdb" => upload.filter_format(DifFormat::Object(FileFormat::Pdb)),
            "pe" => upload.filter_format(DifFormat::Object(FileFormat::Pe)),
            "sourcebundle" => upload.filter_format(DifFormat::Object(FileFormat::SourceBundle)),
            "bcsymbolmap" => {
                upload.filter_format(DifFormat::BcSymbolMap);
                upload.filter_format(DifFormat::PList)
            }
            other => bail!("Unsupported type: {}", other),
        };
    }

    upload.filter_features(ObjectDifFeatures {
        // Allow stripped debug symbols. These are dSYMs, ELF binaries generated
        // with `objcopy --only-keep-debug` or Breakpad symbols. As a fallback,
        // we also upload all files with a public symbol table.
        debug: !matches.is_present("no_debug"),
        symtab: !matches.is_present("no_debug"),
        // Allow executables and dynamic/shared libraries, but not object files.
        // They are guaranteed to contain unwind info, for instance `eh_frame`,
        // and may optionally contain debugging information such as DWARF.
        unwind: !matches.is_present("no_unwind"),
        sources: !matches.is_present("no_sources"),
    });

    upload.include_sources(matches.is_present("include_sources"));

    // Configure BCSymbolMap resolution, if possible
    if let Some(symbol_map) = matches.value_of("symbol_maps") {
        upload
            .symbol_map(symbol_map)
            .map_err(|_| format_err!("--symbol-maps requires Apple dsymutil to be available."))?;
    }

    // Add a path to XCode's DerivedData, if configured
    if matches.is_present("derived_data") {
        let derived_data = dirs::home_dir().map(|x| x.join(DERIVED_DATA));
        if let Some(path) = derived_data {
            if path.is_dir() {
                upload.search_path(path);
            }
        }
    }

    // Try to resolve the Info.plist either by path or from Xcode
    let info_plist = match matches.value_of("info_plist") {
        Some(path) => Some(InfoPlist::from_path(path)?),
        None => InfoPlist::discover_from_env()?,
    };

    if matches.is_present("no_upload") {
        println!("{} skipping upload.", style(">").dim());
        return Ok(());
    }

    MayDetach::wrap("Debug symbol upload", |handle| {
        // Optionally detach if run from Xcode
        if !matches.is_present("force_foreground") {
            handle.may_detach()?;
        }

        // Execute the upload
        let (uploaded, has_processing_errors) = upload.upload()?;
        let api = Api::current();

        // Associate the dSYMs with the Info.plist data, if available
        if let Some(ref info_plist) = info_plist {
            let progress_style = ProgressStyle::default_spinner()
                .template("{spinner} Associating dSYMs with {msg}...");

            let pb = ProgressBar::new_spinner();
            pb.enable_steady_tick(100);
            pb.set_style(progress_style);
            pb.set_message(&info_plist.to_string());

            let checksums = uploaded.iter().map(|dif| dif.checksum.clone()).collect();
            let response = api.associate_apple_dsyms(&org, &project, info_plist, checksums)?;
            pb.finish_and_clear();

            if let Some(association) = response {
                if association.associated_dsyms.is_empty() {
                    println!("{} No new debug symbols to associate.", style(">").dim());
                } else {
                    println!(
                        "{} Associated {} debug symbols with the build.",
                        style(">").dim(),
                        style(association.associated_dsyms.len()).yellow()
                    );
                }
            } else {
                info!("Server does not support dSYM associations. Ignoring.");
            }
        }

        // Trigger reprocessing only if requested by user
        if matches.is_present("no_reprocessing") {
            println!("{} skipped reprocessing", style(">").dim());
        } else if !api.trigger_reprocessing(&org, &project)? {
            println!("{} Server does not support reprocessing.", style(">").dim());
        }

        // Did we miss explicitly requested symbols?
        if matches.is_present("require_all") {
            let required_ids: BTreeSet<_> = matches
                .values_of("ids")
                .unwrap_or_default()
                .filter_map(|s| DebugId::from_str(s).ok())
                .collect();

            let found_ids = uploaded.into_iter().map(|dif| dif.id()).collect();
            let missing_ids: Vec<_> = required_ids.difference(&found_ids).collect();

            if !missing_ids.is_empty() {
                eprintln!();
                eprintln!("{}", style("Error: Some symbols could not be found!").red());
                eprintln!("The following symbols are still missing:");
                for id in missing_ids {
                    println!("  {}", id);
                }

                return Err(QuietExit(1).into());
            }
        }

        // report a non 0 status code if the server encountered issues.
        if has_processing_errors {
            eprintln!();
            eprintln!("{}", style("Error: some symbols did not process correctly"));
            return Err(QuietExit(1).into());
        }

        Ok(())
    })
}
<commit_msg>fix: Remove conflicts_with option from no_sources in upload-dif command<commit_after>//! Implements a command for uploading dSYM files.
use std::collections::BTreeSet;
use std::str::{self, FromStr};

use anyhow::{bail, format_err, Result};
use clap::{Arg, ArgMatches, Command};
use console::style;
use log::info;
use symbolic::common::DebugId;
use symbolic::debuginfo::FileFormat;

use crate::api::Api;
use crate::config::Config;
use crate::utils::args::{validate_id, ArgExt};
use crate::utils::dif::ObjectDifFeatures;
use crate::utils::dif_upload::{DifFormat, DifUpload};
use crate::utils::progress::{ProgressBar, ProgressStyle};
use crate::utils::system::QuietExit;
use crate::utils::xcode::{InfoPlist, MayDetach};

static DERIVED_DATA: &str = "Library/Developer/Xcode/DerivedData";

pub fn make_command(command: Command) -> Command {
    command
        .about("Upload debugging information files.")
        .org_arg()
        .project_arg(false)
        .arg(
            Arg::new("paths")
                .value_name("PATH")
                .help("A path to search recursively for symbol files.")
                .multiple_occurrences(true)
                .index(1),
        )
        .arg(
            Arg::new("types")
                .long("type")
                .short('t')
                .value_name("TYPE")
                .multiple_occurrences(true)
                .possible_values(&[
                    "dsym",
                    "elf",
                    "breakpad",
                    "pdb",
                    "pe",
                    "sourcebundle",
                    "bcsymbolmap",
                ])
                .help(
                    "Only consider debug information files of the given \
                     type.  By default, all types are considered.",
                ),
        )
        .arg(
            Arg::new("no_unwind")
                .long("no-unwind")
                .alias("no-bin")
                .help(
                    "Do not scan for stack unwinding information. Specify \
                     this flag for builds with disabled FPO, or when \
                     stackwalking occurs on the device. This usually \
                     excludes executables and dynamic libraries. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
                ),
        )
        .arg(
            Arg::new("no_debug")
                .long("no-debug")
                .help(
                    "Do not scan for debugging information. This will \
                     usually exclude debug companion files. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
                )
                .conflicts_with("no_unwind"),
        )
        .arg(Arg::new("no_sources").long("no-sources").help(
            "Do not scan for source information. This will \
                     usually exclude source bundle files. They might \
                     still be uploaded, if they contain additional \
                     processable information (see other flags).",
        ))
        .arg(
            Arg::new("ids")
                .value_name("ID")
                .long("id")
                .help("Search for specific debug identifiers.")
                .validator(validate_id)
                .multiple_occurrences(true),
        )
        .arg(
            Arg::new("require_all")
                .long("require-all")
                .help("Errors if not all identifiers specified with --id could be found."),
        )
        .arg(
            Arg::new("symbol_maps")
                .long("symbol-maps")
                .value_name("PATH")
                .help(
                    "Optional path to BCSymbolMap files which are used to \
                     resolve hidden symbols in dSYM files downloaded from \
                     iTunes Connect.  This requires the dsymutil tool to be \
                     available.  This should not be used when using the App \
                     Store Connect integration, the .bcsymbolmap files needed \
                     for the integration are uploaded without this option if \
                     they are found in the PATH searched for symbol files.",
                ),
        )
        .arg(
            Arg::new("derived_data")
                .long("derived-data")
                .help("Search for debug symbols in Xcode's derived data."),
        )
        .arg(
            Arg::new("no_zips")
                .long("no-zips")
                .help("Do not search in ZIP files."),
        )
        .arg(
            Arg::new("info_plist")
                .long("info-plist")
                .value_name("PATH")
                .help(
                    "Optional path to the Info.plist.{n}We will try to find this \
                     automatically if run from Xcode.  Providing this information \
                     will associate the debug symbols with a specific ITC application \
                     and build in Sentry.  Note that if you provide the plist \
                     explicitly it must already be processed.",
                ),
        )
        .arg(
            Arg::new("no_reprocessing")
                .long("no-reprocessing")
                .help("Do not trigger reprocessing after uploading."),
        )
        .arg(Arg::new("no_upload").long("no-upload").help(
            "Disable the actual upload.{n}This runs all steps for the \
             processing but does not trigger the upload (this also \
             automatically disables reprocessing).  This is useful if you \
             just want to verify the setup or skip the upload in tests.",
        ))
        .arg(Arg::new("force_foreground").long("force-foreground").help(
            "Wait for the process to finish.{n}\
                     By default, the upload process will detach and continue in the \
                     background when triggered from Xcode.  When an error happens, \
                     a dialog is shown.  If this parameter is passed Xcode will wait \
                     for the process to finish before the build finishes and output \
                     will be shown in the Xcode build output.",
        ))
        .arg(Arg::new("include_sources").long("include-sources").help(
            "Include sources from the local file system and upload \
                     them as source bundles.",
        ))
        .arg(Arg::new("wait").long("wait").help(
            "Wait for the server to fully process uploaded files. Errors \
             can only be displayed if --wait is specified, but this will \
             significantly slow down the upload process.",
        ))
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
    let config = Config::current();
    let (org, project) = config.get_org_and_project(matches)?;

    let ids = matches
        .values_of("ids")
        .unwrap_or_default()
        .filter_map(|s| DebugId::from_str(s).ok());

    info!(
        "Issuing a command for Organization: {} Project: {}",
        org, project
    );

    // Build generic upload parameters
    let mut upload = DifUpload::new(org.clone(), project.clone());
    upload
        .wait(matches.is_present("wait"))
        .search_paths(matches.values_of("paths").unwrap_or_default())
        .allow_zips(!matches.is_present("no_zips"))
        .filter_ids(ids);

    // Restrict symbol types, if specified by the user
    for ty in matches.values_of("types").unwrap_or_default() {
        match ty {
            "dsym" => upload.filter_format(DifFormat::Object(FileFormat::MachO)),
            "elf" => upload.filter_format(DifFormat::Object(FileFormat::Elf)),
            "breakpad" => upload.filter_format(DifFormat::Object(FileFormat::Breakpad)),
            "pdb" => upload.filter_format(DifFormat::Object(FileFormat::Pdb)),
            "pe" => upload.filter_format(DifFormat::Object(FileFormat::Pe)),
            "sourcebundle" => upload.filter_format(DifFormat::Object(FileFormat::SourceBundle)),
            "bcsymbolmap" => {
                upload.filter_format(DifFormat::BcSymbolMap);
                upload.filter_format(DifFormat::PList)
            }
            other => bail!("Unsupported type: {}", other),
        };
    }

    upload.filter_features(ObjectDifFeatures {
        // Allow stripped debug symbols. These are dSYMs, ELF binaries generated
        // with `objcopy --only-keep-debug` or Breakpad symbols. As a fallback,
        // we also upload all files with a public symbol table.
        debug: !matches.is_present("no_debug"),
        symtab: !matches.is_present("no_debug"),
        // Allow executables and dynamic/shared libraries, but not object files.
        // They are guaranteed to contain unwind info, for instance `eh_frame`,
        // and may optionally contain debugging information such as DWARF.
        unwind: !matches.is_present("no_unwind"),
        sources: !matches.is_present("no_sources"),
    });

    upload.include_sources(matches.is_present("include_sources"));

    // Configure BCSymbolMap resolution, if possible
    if let Some(symbol_map) = matches.value_of("symbol_maps") {
        upload
            .symbol_map(symbol_map)
            .map_err(|_| format_err!("--symbol-maps requires Apple dsymutil to be available."))?;
    }

    // Add a path to XCode's DerivedData, if configured
    if matches.is_present("derived_data") {
        let derived_data = dirs::home_dir().map(|x| x.join(DERIVED_DATA));
        if let Some(path) = derived_data {
            if path.is_dir() {
                upload.search_path(path);
            }
        }
    }

    // Try to resolve the Info.plist either by path or from Xcode
    let info_plist = match matches.value_of("info_plist") {
        Some(path) => Some(InfoPlist::from_path(path)?),
        None => InfoPlist::discover_from_env()?,
    };

    if matches.is_present("no_upload") {
        println!("{} skipping upload.", style(">").dim());
        return Ok(());
    }

    MayDetach::wrap("Debug symbol upload", |handle| {
        // Optionally detach if run from Xcode
        if !matches.is_present("force_foreground") {
            handle.may_detach()?;
        }

        // Execute the upload
        let (uploaded, has_processing_errors) = upload.upload()?;
        let api = Api::current();

        // Associate the dSYMs with the Info.plist data, if available
        if let Some(ref info_plist) = info_plist {
            let progress_style = ProgressStyle::default_spinner()
                .template("{spinner} Associating dSYMs with {msg}...");

            let pb = ProgressBar::new_spinner();
            pb.enable_steady_tick(100);
            pb.set_style(progress_style);
            pb.set_message(&info_plist.to_string());

            let checksums = uploaded.iter().map(|dif| dif.checksum.clone()).collect();
            let response = api.associate_apple_dsyms(&org, &project, info_plist, checksums)?;
            pb.finish_and_clear();

            if let Some(association) = response {
                if association.associated_dsyms.is_empty() {
                    println!("{} No new debug symbols to associate.", style(">").dim());
                } else {
                    println!(
                        "{} Associated {} debug symbols with the build.",
                        style(">").dim(),
                        style(association.associated_dsyms.len()).yellow()
                    );
                }
            } else {
                info!("Server does not support dSYM associations. Ignoring.");
            }
        }

        // Trigger reprocessing only if requested by user
        if matches.is_present("no_reprocessing") {
            println!("{} skipped reprocessing", style(">").dim());
        } else if !api.trigger_reprocessing(&org, &project)? {
            println!("{} Server does not support reprocessing.", style(">").dim());
        }

        // Did we miss explicitly requested symbols?
        if matches.is_present("require_all") {
            let required_ids: BTreeSet<_> = matches
                .values_of("ids")
                .unwrap_or_default()
                .filter_map(|s| DebugId::from_str(s).ok())
                .collect();

            let found_ids = uploaded.into_iter().map(|dif| dif.id()).collect();
            let missing_ids: Vec<_> = required_ids.difference(&found_ids).collect();

            if !missing_ids.is_empty() {
                eprintln!();
                eprintln!("{}", style("Error: Some symbols could not be found!").red());
                eprintln!("The following symbols are still missing:");
                for id in missing_ids {
                    println!("  {}", id);
                }

                return Err(QuietExit(1).into());
            }
        }

        // report a non 0 status code if the server encountered issues.
        if has_processing_errors {
            eprintln!();
            eprintln!("{}", style("Error: some symbols did not process correctly"));
            return Err(QuietExit(1).into());
        }

        Ok(())
    })
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Remove empty binary<commit_after><|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;
extern crate vitral;
extern crate serde;
extern crate calx_color;
#[macro_use]
extern crate calx_resource;

mod backend;

use std::hash;
use image::GenericImage;
use std::collections::HashMap;
use std::ops::Deref;
use calx_color::color::*;
pub use euclid::{Point2D, Rect, Size2D};
pub use glium::{DisplayBuild, glutin};
pub use backend::Backend;
pub use calx_resource::{Loadable, Resource, ResourceCache, ResourceStore};

#[derive(Clone)]
struct DynamicImageShim(image::DynamicImage);

impl Loadable for DynamicImageShim {
    fn load(key: &String) -> Option<Self>
        where Self: Sized
    {
        image::open(key).ok().map(|x| DynamicImageShim(x))
    }
}

impl_store!(DYNAMIC_IMAGE, String, DynamicImageShim);

pub type Color = [f32; 4];

pub type ImageRef = usize;

#[derive(Copy, Clone, Debug)]
pub struct Frame {
    pub image: ImageRef,
    pub offset: Point2D<f32>,
    pub color: Color,
}

pub type Splat = Vec<Frame>;

#[derive(Clone)]
pub struct Brush(pub Vec<Splat>);

impl Deref for Brush {
    type Target = Vec<Splat>;

    #[inline(always)]
    fn deref(&self) -> &Vec<Splat> {
        &self.0
    }
}

// Brush implements Loadable so we can have a cache for it, but there's no actual implicit load
// method, brushes must be inserted manually in code.
//
// (We *could* make a load method later and have it read configuration files or something that
// specify te brush.)
impl Loadable for Brush {}

impl_store!(BRUSH, String, Brush);

type FrameImage = image::ImageBuffer<image::Rgba<u8>, Vec<u8>>;

#[derive(Clone, PartialEq, Eq, Debug)]
struct SubImageSpec {
    image: Resource<DynamicImageShim>,
    bounds: euclid::Rect<u32>,
}

impl SubImageSpec {
    pub fn new(path: String, bounds: euclid::Rect<u32>) -> Option<SubImageSpec> {
        if let Some(image) = Resource::new(path) {
            Some(SubImageSpec {
                image: image,
                bounds: bounds,
            })
        } else {
            None
        }
    }
}

impl Loadable<SubImageSpec> for FrameImage {
    fn load(spec: &SubImageSpec) -> Option<Self>
        where Self: Sized
    {
        // XXX: Using sub_image on spec.image would be neater, but can't use it here
        // because current image::SubImage must get a mutable access to the parent image and the
        // resource handle is immutable.
        Some(image::ImageBuffer::from_fn(spec.bounds.size.width, spec.bounds.size.height, |x, y| {
            spec.image.0.get_pixel(spec.bounds.origin.x + x, spec.bounds.origin.y + y)
        }))
    }
}

impl hash::Hash for SubImageSpec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.image.hash(state);
        self.bounds.origin.hash(state);
        self.bounds.size.hash(state);
    }
}

impl_store!(FRAME_IMAGE, SubImageSpec, FrameImage);

struct BrushBuilder<'a, V: 'a> {
    builder: &'a mut vitral::Builder<V>,
    image_file: Option<String>,
    brush: Vec<Splat>,
    frame_images: HashMap<SubImageSpec, usize>,
}

impl<'a, V: Copy + Eq + 'a> BrushBuilder<'a, V> {
    pub fn new(builder: &'a mut vitral::Builder<V>) -> BrushBuilder<'a, V> {
        BrushBuilder {
            builder: builder,
            image_file: None,
            brush: Vec::new(),
            frame_images: HashMap::new(),
        }
    }

    pub fn file(mut self, name: &str) -> Self {
        self.image_file = Some(name.to_string());
        self
    }

    fn get_frame(&mut self, key: &SubImageSpec) -> usize {
        // XXX: Crashy-crash unwrapping if you feed it bad data.
        if let Some(ret) = self.frame_images.get(key) {
            return *ret;
        }

        let image: Resource<FrameImage, SubImageSpec> = Resource::new(key.clone()).unwrap();
        let ret = self.builder.add_image(&*image);

        self.frame_images.insert(key.clone(), ret);

        ret
    }

    /// Add a new frame with the given bounding rectangle to the current splat.
    pub fn frame(mut self, x: u32, y: u32, w: u32, h: u32) -> Self {
        if self.brush.is_empty() {
            self.brush.push(Vec::new());
        }
        let filename = self.image_file.clone().expect("Image file not set");
        let spec = SubImageSpec::new(filename,
            Rect::new(Point2D::new(x, y), Size2D::new(w, h))).unwrap();

        let image = self.get_frame(&spec);

        let idx = self.brush.len() - 1;
        self.brush[idx].push(Frame { image: image, offset: Point2D::new(0.0, 0.0), color: [1.0, 1.0, 1.0, 1.0] });

        self
    }

    /// Set the color of the last frame.
    pub fn color<C: Into<calx_color::Rgba>>(mut self, c: C) -> Self {
        assert!(!self.brush.is_empty());
        let i = self.brush.len() - 1;
        assert!(!self.brush[i].is_empty());
        let j = self.brush[i].len() - 1;

        let c: calx_color::Rgba = c.into();

        self.brush[i][j].color = [c.r, c.g, c.b, c.a];

        self
    }

    /// Set the offset of the last frame.
    pub fn offset(mut self, x: i32, y: i32) -> Self {
        assert!(!self.brush.is_empty());
        let i = self.brush.len() - 1;
        assert!(!self.brush[i].is_empty());
        let j = self.brush[i].len() - 1;

        // Internally offset is floats because all screen geometry stuff is, but on the data spec
        // level we're pretty much operating on per-pixel level.
        self.brush[i][j].offset = Point2D::new(x as f32, y as f32);

        self
    }

    /// Start a new splat in the current brush.
    pub fn splat(mut self) -> Self {
        self.brush.push(Vec::new());
        self
    }

    /// Finish and name the current brush and start a new one.
    pub fn brush(mut self, name: &str) -> Self {
        use std::mem;

        let name = name.to_string();
        // Must be an original name.
        assert!(Brush::get_resource(&name).is_none());

        // Zero cached brush and copy the old value here so we can insert it.
        let mut brush = Vec::new();
        mem::swap(&mut brush, &mut self.brush);
        assert!(!brush.is_empty());

        Brush::insert_resource(name, Brush(brush));

        self
    }
}

fn init_brushes<V: Copy + Eq>(builder: &mut vitral::Builder<V>) {
    BrushBuilder::new(builder)
        .file("content/assets/floors.png")

        .frame(0, 0, 32, 32).offset(16, 16).brush("blank_floor")

        .frame(32, 0, 32, 32).offset(16, 16).color(DARKGREEN).brush("grass")

        .frame(64, 0, 32, 32).offset(16, 16).color(DARKGREEN).brush("grass2")

        .frame(32, 0, 32, 32).offset(16, 16).color(SLATEGRAY).brush("ground")

        .frame(96, 0, 32, 32).offset(16, 16).color(ROYALBLUE).brush("water")

        .file("content/assets/props.png")

        .frame(32, 0, 32, 32).color(RED).brush("cursor")

        .frame(160, 64, 32, 32).offset(16, 16).color(SADDLEBROWN)
        .frame(192, 64, 32, 32).offset(16, 16).color(GREEN).brush("tree")

        ;
}

fn draw_splat(context: &mut backend::Context, offset: Point2D<f32>, splat: &Splat) {
    for frame in splat.iter() {
        context.draw_image(frame.image, offset + frame.offset, frame.color);
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Kind {
    Floor,
    Block,
    Water,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Form {
    Simple,
    Block,
    Wall,
}

#[derive(Clone)]
pub struct Tile {
    pub brush: Resource<Brush>,
    pub kind: Kind,
    pub form: Form,
}

impl Loadable<u8> for Tile {}

impl_store!(TILE, u8, Tile);

pub fn main() {
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    // Construct Vitral context.
    let mut context: backend::Context;
    let mut builder = vitral::Builder::new();

    init_brushes(&mut builder);

    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    loop {
        context.begin_frame();

        context.draw_text(font,
                          Point2D::new(4.0, 20.0),
                          [1.0, 1.0, 1.0, 1.0],
                          "Hello, world!");

        draw_splat(&mut context, Point2D::new(50.0, 50.0), &Brush::get_resource(&"tree".to_string()).unwrap()[0]);

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<commit_msg>Brush definition machninery<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;
extern crate vitral;
extern crate serde;
extern crate calx_color;
#[macro_use]
extern crate calx_resource;

mod backend;

use std::hash;
use image::GenericImage;
use std::collections::HashMap;
use std::ops::Deref;
use calx_color::Rgba;
use calx_color::color::*;
pub use euclid::{Point2D, Rect, Size2D};
pub use glium::{DisplayBuild, glutin};
pub use backend::Backend;
pub use calx_resource::{Loadable, Resource, ResourceCache, ResourceStore};

#[derive(Clone)]
struct DynamicImageShim(image::DynamicImage);

impl Loadable for DynamicImageShim {
    fn load(key: &String) -> Option<Self>
        where Self: Sized
    {
        image::open(key).ok().map(|x| DynamicImageShim(x))
    }
}

impl_store!(DYNAMIC_IMAGE, String, DynamicImageShim);

pub type Color = [f32; 4];

pub type ImageRef = usize;

#[derive(Copy, Clone, Debug)]
pub struct Frame {
    pub image: ImageRef,
    pub offset: Point2D<f32>,
    pub color: Color,
}

pub type Splat = Vec<Frame>;

#[derive(Clone)]
pub struct Brush(pub Vec<Splat>);

impl Deref for Brush {
    type Target = Vec<Splat>;

    #[inline(always)]
    fn deref(&self) -> &Vec<Splat> {
        &self.0
    }
}

// Brush implements Loadable so we can have a cache for it, but there's no actual implicit load
// method, brushes must be inserted manually in code.
//
// (We *could* make a load method later and have it read configuration files or something that
// specify te brush.)
impl Loadable for Brush {}

impl_store!(BRUSH, String, Brush);

type FrameImage = image::ImageBuffer<image::Rgba<u8>, Vec<u8>>;

#[derive(Clone, PartialEq, Eq, Debug)]
struct SubImageSpec {
    image: Resource<DynamicImageShim>,
    bounds: euclid::Rect<u32>,
}

impl SubImageSpec {
    pub fn new(path: String, bounds: euclid::Rect<u32>) -> Option<SubImageSpec> {
        if let Some(image) = Resource::new(path) {
            Some(SubImageSpec {
                image: image,
                bounds: bounds,
            })
        } else {
            None
        }
    }
}

impl Loadable<SubImageSpec> for FrameImage {
    fn load(spec: &SubImageSpec) -> Option<Self>
        where Self: Sized
    {
        // XXX: Using sub_image on spec.image would be neater, but can't use it here
        // because current image::SubImage must get a mutable access to the parent image and the
        // resource handle is immutable.
        Some(image::ImageBuffer::from_fn(spec.bounds.size.width, spec.bounds.size.height, |x, y| {
            spec.image.0.get_pixel(spec.bounds.origin.x + x, spec.bounds.origin.y + y)
        }))
    }
}

impl hash::Hash for SubImageSpec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.image.hash(state);
        self.bounds.origin.hash(state);
        self.bounds.size.hash(state);
    }
}

impl_store!(FRAME_IMAGE, SubImageSpec, FrameImage);

struct BrushBuilder<'a, V: 'a> {
    builder: &'a mut vitral::Builder<V>,
    image_file: Option<String>,
    brush: Vec<Splat>,
    frame_images: HashMap<SubImageSpec, usize>,
    color: Rgba,
}

impl<'a, V: Copy + Eq + 'a> BrushBuilder<'a, V> {
    pub fn new(builder: &'a mut vitral::Builder<V>) -> BrushBuilder<'a, V> {
        BrushBuilder {
            builder: builder,
            image_file: None,
            brush: Vec::new(),
            frame_images: HashMap::new(),
            color: WHITE,
        }
    }

    pub fn file(mut self, name: &str) -> Self {
        self.image_file = Some(name.to_string());
        self
    }

    fn get_frame(&mut self, key: &SubImageSpec) -> usize {
        // XXX: Crashy-crash unwrapping if you feed it bad data.
        if let Some(ret) = self.frame_images.get(key) {
            return *ret;
        }

        let image: Resource<FrameImage, SubImageSpec> = Resource::new(key.clone()).unwrap();
        let ret = self.builder.add_image(&*image);

        self.frame_images.insert(key.clone(), ret);

        ret
    }

    /// Add a new frame with the given bounding rectangle to the current splat.
    pub fn frame(mut self, x: u32, y: u32, w: u32, h: u32) -> Self {
        if self.brush.is_empty() {
            self.brush.push(Vec::new());
        }
        let filename = self.image_file.clone().expect("Image file not set");
        let spec = SubImageSpec::new(filename,
            Rect::new(Point2D::new(x, y), Size2D::new(w, h))).unwrap();

        let image = self.get_frame(&spec);

        let idx = self.brush.len() - 1;
        self.brush[idx].push(Frame { image: image, offset: Point2D::new(0.0, 0.0), color: [self.color.r, self.color.g, self.color.b, self.color.a] });

        self
    }

    /// Set the color for the next frames.
    pub fn color<C: Into<calx_color::Rgba>>(mut self, c: C) -> Self {
        self.color = c.into();
        self
    }

    /// Set the offset of the last frame.
    pub fn offset(mut self, x: i32, y: i32) -> Self {
        assert!(!self.brush.is_empty());
        let i = self.brush.len() - 1;
        assert!(!self.brush[i].is_empty());
        let j = self.brush[i].len() - 1;

        // Internally offset is floats because all screen geometry stuff is, but on the data spec
        // level we're pretty much operating on per-pixel level.
        self.brush[i][j].offset = Point2D::new(x as f32, y as f32);

        self
    }

    /// Helper for regular tiles.
    pub fn tile(self, x: u32, y: u32) -> Self {
        self.frame(x, y, 32, 32).offset(16, 16)
    }

    /// Helper for block chunks.
    ///
    /// Blocks are built from three 96x32 strips. First one contains the vertical edges, the second
    /// contains the rear block and the third contains the block front. The vertical and rear
    /// frames are nondescript and will probably be reused extensively.
    ///
    /// Block shaping is somewhat complicated and requires a large number of frames.
    pub fn block(self, vert_x: u32, vert_y: u32, rear_x: u32, rear_y: u32, x: u32, y: u32) -> Self {
        self.frame(vert_x, vert_y, 16, 32).offset(16, 16)               // 0: Top left
            .splat().frame(vert_x + 16, vert_y, 16, 32).offset(0, 16)   // 1: Top right
            .splat().frame(vert_x + 32, vert_y, 16, 32).offset(16, 16)  // 2: Middle left
            .splat().frame(vert_x + 48, vert_y, 16, 32).offset(0, 16)   // 3: Middle right
            .splat().frame(vert_x + 64, vert_y, 16, 32).offset(16, 16)  // 4: Bottom left
            .splat().frame(vert_x + 80, vert_y, 16, 32).offset(0, 16)   // 5: Bottom right

            .splat().frame(rear_x, rear_y, 10, 32).offset(16, 16)       // 6: Left half

            .splat().frame(rear_x + 10, rear_y, 6, 32).offset(6, 16)    // 7: Front
            .splat().frame(rear_x + 16, rear_y, 6, 32).offset(0, 16)    // 8

            .splat().frame(rear_x + 22, rear_y, 10, 32).offset(-6, 16)  // 9: Right half

            .splat().frame(rear_x + 32, rear_y, 10, 32).offset(16, 16)  // 10: Y-axis slope
            .splat().frame(rear_x + 42, rear_y, 6, 32).offset(6, 16)    // 11
            .splat().frame(rear_x + 48, rear_y, 6, 32).offset(0, 16)    // 12
            .splat().frame(rear_x + 54, rear_y, 10, 32).offset(-6, 16)  // 13

            .splat().frame(rear_x + 64, rear_y, 10, 32).offset(16, 16)  // 14: X-axis slope
            .splat().frame(rear_x + 74, rear_y, 6, 32).offset(6, 16)    // 15
            .splat().frame(rear_x + 80, rear_y, 6, 32).offset(0, 16)    // 16
            .splat().frame(rear_x + 86, rear_y, 10, 32).offset(-6, 16)  // 17

            .splat().frame(x, y, 10, 32).offset(16, 16)                 // 18 Left half

            .splat().frame(x + 10, y, 6, 32).offset(6, 16)              // 19: Front
            .splat().frame(x + 16, y, 6, 32).offset(0, 16)              // 20

            .splat().frame(x + 22, y, 10, 32).offset(-6, 16)            // 21: Right half

            .splat().frame(x + 32, y, 10, 32).offset(16, 16)            // 22: Y-axis slope
            .splat().frame(x + 42, y, 6, 32).offset(6, 16)              // 23
            .splat().frame(x + 48, y, 6, 32).offset(0, 16)              // 24
            .splat().frame(x + 54, y, 10, 32).offset(-6, 16)            // 25

            .splat().frame(x + 64, y, 10, 32).offset(16, 16)            // 26: X-axis slope
            .splat().frame(x + 74, y, 6, 32).offset(6, 16)              // 27
            .splat().frame(x + 80, y, 6, 32).offset(0, 16)              // 28
            .splat().frame(x + 86, y, 10, 32).offset(-6, 16)            // 29
    }

    /// Helper for wall tiles
    ///
    /// Wall tiles are chopped up from two 32x32 images. One contains the center pillar wallform
    /// and the other contains the two long sides wallform.
    pub fn wall(self, center_x: u32, center_y: u32, sides_x: u32, sides_y: u32) -> Self {
        self.frame(center_x, center_y, 16, 32).offset(16, 16)
            .splat().frame(center_x + 16, center_y, 16, 32).offset(0, 16)
            .splat().frame(sides_x, sides_y, 16, 32).offset(16, 16)
            .splat().frame(sides_x + 16, sides_y, 16, 32).offset(0, 16)
    }

    /// Start a new splat in the current brush.
    pub fn splat(mut self) -> Self {
        self.brush.push(Vec::new());
        self
    }

    /// Finish and name the current brush and start a new one.
    pub fn brush(mut self, name: &str) -> Self {
        use std::mem;

        let name = name.to_string();
        // Must be an original name.
        assert!(Brush::get_resource(&name).is_none());

        // Zero cached brush and copy the old value here so we can insert it.
        let mut brush = Vec::new();
        mem::swap(&mut brush, &mut self.brush);
        assert!(!brush.is_empty());

        Brush::insert_resource(name, Brush(brush));

        // Reset color
        self.color = WHITE;

        self
    }
}

fn init_brushes<V: Copy + Eq>(builder: &mut vitral::Builder<V>) {
    BrushBuilder::new(builder)
        .file("content/assets/floors.png")

        .frame(0, 0, 32, 32).offset(16, 16).brush("blank_floor")

        .color(DARKGREEN).tile(32, 0).brush("grass")

        .color(DARKGREEN).tile(64, 0).brush("grass2")

        .color(SLATEGRAY).tile(32, 0).brush("ground")

        .color(ROYALBLUE).tile(96, 0).brush("water")

        .file("content/assets/props.png")

        .color(RED).frame(32, 0, 32, 32).brush("cursor")

        .color(SADDLEBROWN).tile(160, 64)
        .color(GREEN).tile(192, 64).brush("tree")

        .file("content/assets/walls.png")
        .color(LIGHTSLATEGRAY)
        .wall(0, 0, 32, 0).brush("wall")

        .file("content/assets/blocks.png")
        .color(DARKGOLDENROD)
        .block(0, 0, 0, 32, 0, 64).brush("rock")

        ;
}

fn draw_splat(context: &mut backend::Context, offset: Point2D<f32>, splat: &Splat) {
    for frame in splat.iter() {
        context.draw_image(frame.image, offset + frame.offset, frame.color);
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Kind {
    Floor,
    Block,
    Water,
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Form {
    Simple,
    Block,
    Wall,
}

#[derive(Clone)]
pub struct Tile {
    pub brush: Resource<Brush>,
    pub kind: Kind,
    pub form: Form,
}

impl Loadable<u8> for Tile {}

impl_store!(TILE, u8, Tile);

fn init_terrain() {
    unimplemented!();
}

pub fn main() {
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    // Construct Vitral context.
    let mut context: backend::Context;
    let mut builder = vitral::Builder::new();

    init_brushes(&mut builder);

    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    loop {
        context.begin_frame();

        context.draw_text(font,
                          Point2D::new(4.0, 20.0),
                          [1.0, 1.0, 1.0, 1.0],
                          "Hello, world!");

        draw_splat(&mut context, Point2D::new(50.0, 50.0), &Brush::get_resource(&"tree".to_string()).unwrap()[0]);

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<|endoftext|>