<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Position, Side, Move};
use splitter;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::ops;

#[derive(Clone)]
#[derive(Copy)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum Value {
    Nimber(usize),
    Loony
}

impl ops::Add for Value {
    type Output = Value;

    fn add(self: Value, other: Value) -> Value {
        match (self, other) {
            (Value::Loony, _) => Value::Loony,
            (_, Value::Loony) => Value::Loony,
            (Value::Nimber(x), Value::Nimber(y)) => Value::Nimber(x ^ y),
        }
    }
}

impl fmt::Display for Value {
    fn fmt(self: &Value, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Nimber(v) => write!(f, "*{}", v),
            &Value::Loony => write!(f, "L"),
        }
    }
}

// Indicate whether a given position is loony
pub fn is_loony(pos: &Position) -> bool {
    for i in 0..pos.width() {
        for j in 0..pos.height() {
            if pos.valency(i, j) != 1 {
                continue
            }
            for s in Side::all() {
                if pos.is_legal_move(i, j, s) {
                    if let Some((nx, ny)) = pos.offset(i, j, s) {
                        if pos.valency(nx, ny) == 2 {
                            // We have found a capturable coin attached to a coin of valency 2 => loony
                            return true;
                        }
                    }
                    break;
                }
            }
        }
    }
    false
}

// Minimal excludant helper function
fn mex(s: HashSet<usize>) -> usize {
    let mut i = 0;
    loop {
        if !s.contains(&i) {
            return i;
        }
        i += 1;
    }
}

fn calc_value(pos: &mut Position, cache: &mut HashMap<usize, Value>) -> Value {
    // TODO: Optimise by iterating over a tighter set of moves than all legal moves
    if let Some(&v) = cache.get(&pos.zhash()) {
        return v;
    }
    if is_loony(pos) {
        cache.insert(pos.zhash(), Value::Loony);
        return Value::Loony;
    }

    // Try to split the position into independent parts which can be evaluated separately
    let parts = splitter::split(pos);
    if parts.len() > 1 {
        let mut result = Value::Nimber(0);
        for mut part in parts {
            let mut frag_cache = HashMap::new();
            let frag_value = calc_value(&mut part.pos, &mut frag_cache);
            result = result + frag_value;
        }
        cache.insert(pos.zhash(), result);
        return result;
    }

    let legal_moves = pos.legal_moves();
    for m in &legal_moves {
        if pos.would_capture(m.x, m.y, m.side) {
            pos.make_move(m.x, m.y, m.side);
            let result = calc_value(pos, cache);
            pos.undo_move(m.x, m.y, m.side);
            cache.insert(pos.zhash(), result);
            return result
        }
    }
    let mut options = HashSet::new();
    for m in &legal_moves {
        pos.make_move(m.x, m.y, m.side);
        if let Value::Nimber(n) = calc_value(pos, cache) {
            options.insert(n);
        }
        pos.undo_move(m.x, m.y, m.side);
    }
    let result = Value::Nimber(mex(options));
    cache.insert(pos.zhash(), result);
    result
}

// Calculate the Nimstring value of a position, along with the values attained
// by each of the legal moves.
pub fn calc_value_with_moves(pos: &Position) -> (Value, HashMap<Move, Value>) {
    let mut cache = HashMap::new();
    let mut pos = pos.clone();
    let val = calc_value(&mut pos, &mut cache);
    let mut per_move = HashMap::new();
    for m in pos.legal_moves() {
        pos.make_move(m.x, m.y, m.side);
        per_move.insert(m, calc_value(&mut pos, &mut cache));
        pos.undo_move(m.x, m.y, m.side);
    }
    (val, per_move)
}

#[cfg(test)]
mod tests {
    use nimstring::*;
    use game::*;
    use examples::*;

    #[test]
    fn value_display() {
        assert_eq!("*0", format!("{}", Value::Nimber(0)));
        assert_eq!("*1", format!("{}", Value::Nimber(1)));
        assert_eq!("*2", format!("{}", Value::Nimber(2)));
        assert_eq!("L", format!("{}", Value::Loony));
    }

    #[test]
    fn min_excl() {
        assert_eq!(0, mex(HashSet::new()));
        assert_eq!(0, mex([1,2,3].iter().cloned().collect()));
        assert_eq!(1, mex([0].iter().cloned().collect()));
        assert_eq!(1, mex([0,2,3].iter().cloned().collect()));
        assert_eq!(2, mex([0,1,3].iter().cloned().collect()));
        assert_eq!(3, mex([0,1,2].iter().cloned().collect()));
    }

    #[test]
    fn nimber_addition() {
        assert_eq!(Value::Nimber(3), Value::Nimber(1) + Value::Nimber(2));
        assert_eq!(Value::Nimber(2), Value::Nimber(1) + Value::Nimber(3));
        assert_eq!(Value::Nimber(1), Value::Nimber(2) + Value::Nimber(3));

        assert_eq!(Value::Nimber(6), Value::Nimber(2) + Value::Nimber(4));
        assert_eq!(Value::Nimber(4), Value::Nimber(6) + Value::Nimber(2));
        assert_eq!(Value::Nimber(2), Value::Nimber(4) + Value::Nimber(6));

        assert_eq!(Value::Loony, Value::Nimber(2) + Value::Loony);
        assert_eq!(Value::Loony, Value::Loony + Value::Nimber(2));
    }

    // Create a position consisting of a single horizontal chain of a given length.
    fn make_chain(length: usize) -> Position {
        let mut pos = Position::new_game(length, 1);
        for i in 0..length {
            pos.make_move(i, 0, Side::Top);
            pos.make_move(i, 0, Side::Bottom);
        }
        pos
    }

    #[test]
    fn basic_values() {
        let mut pos = make_chain(3);
        assert!(!is_loony(&pos));
        let mut cache = HashMap::new();
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
        pos.make_move(0, 0, Side::Left);
        assert!(is_loony(&pos));
        assert_eq!(Value::Loony, calc_value(&mut pos, &mut cache));
        pos.make_move(1, 0, Side::Left);
        assert!(is_loony(&pos));
        assert_eq!(Value::Loony, calc_value(&mut pos, &mut cache));
        pos.make_move(2, 0, Side::Left);
        assert!(!is_loony(&pos));
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
        pos.make_move(2, 0, Side::Right);
        assert!(!is_loony(&pos));
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
    }

    #[test]
    fn nonzero_value() {
        let mut pos = make_chain(7);
        pos.undo_move(3, 0, Side::Top);
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 3, y: 0, side: Side::Top}).unwrap());
    }

    #[test]
    fn right_capture_detection() {
        let mut pos = make_chain(5);
        pos.undo_move(3, 0, Side::Top);
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 4, y: 0, side: Side::Right}).unwrap());
    }

    #[test]
    fn p50_top_value() {
        let pos = p50_top();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 3, y: 0, side: Side::Top}).unwrap());
    }

    #[test]
    fn p50_bottomleft_value() {
        let pos = p50_bottomleft();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(4), val);
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Left}).unwrap());
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Bottom}).unwrap());
        assert_eq!(&Value::Nimber(3),
                   per_move.get(&Move{x: 0, y: 1, side: Side::Right}).or(per_move.get(&Move{x: 0, y: 2, side: Side::Left})).unwrap());
    }

    #[test]
    fn p50_bottomright_value() {
        let pos = p50_bottomright();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(2), val);
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Right}).unwrap());
    }

    #[test]
    fn p50_value() {
        let pos = p50();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(7), val);
        let zero_moves: Vec<&Move> = per_move.keys().filter(|m| &Value::Nimber(0) == per_move.get(m).unwrap()).collect();
        assert_eq!(3, zero_moves.len());
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Bottom}));
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Left}));
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Right}));
    }
}
<commit_msg>Check splits after captures (closes #33<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Position, Side, Move};
use splitter;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::ops;

#[derive(Clone)]
#[derive(Copy)]
#[derive(PartialEq)]
#[derive(Debug)]
pub enum Value {
    Nimber(usize),
    Loony
}

impl ops::Add for Value {
    type Output = Value;

    fn add(self: Value, other: Value) -> Value {
        match (self, other) {
            (Value::Loony, _) => Value::Loony,
            (_, Value::Loony) => Value::Loony,
            (Value::Nimber(x), Value::Nimber(y)) => Value::Nimber(x ^ y),
        }
    }
}

impl fmt::Display for Value {
    fn fmt(self: &Value, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Nimber(v) => write!(f, "*{}", v),
            &Value::Loony => write!(f, "L"),
        }
    }
}

// Indicate whether a given position is loony
pub fn is_loony(pos: &Position) -> bool {
    for i in 0..pos.width() {
        for j in 0..pos.height() {
            if pos.valency(i, j) != 1 {
                continue
            }
            for s in Side::all() {
                if pos.is_legal_move(i, j, s) {
                    if let Some((nx, ny)) = pos.offset(i, j, s) {
                        if pos.valency(nx, ny) == 2 {
                            // We have found a capturable coin attached to a coin of valency 2 => loony
                            return true;
                        }
                    }
                    break;
                }
            }
        }
    }
    false
}

// Minimal excludant helper function
fn mex(s: HashSet<usize>) -> usize {
    let mut i = 0;
    loop {
        if !s.contains(&i) {
            return i;
        }
        i += 1;
    }
}

fn calc_value(pos: &mut Position, cache: &mut HashMap<usize, Value>) -> Value {
    // TODO: Optimise by iterating over a tighter set of moves than all legal moves
    if let Some(&v) = cache.get(&pos.zhash()) {
        return v;
    }
    if is_loony(pos) {
        cache.insert(pos.zhash(), Value::Loony);
        return Value::Loony;
    }

    let legal_moves = pos.legal_moves();
    for m in &legal_moves {
        if pos.would_capture(m.x, m.y, m.side) {
            pos.make_move(m.x, m.y, m.side);
            let result = calc_value(pos, cache);
            pos.undo_move(m.x, m.y, m.side);
            cache.insert(pos.zhash(), result);
            return result
        }
    }

    // Try to split the position into independent parts which can be evaluated separately
    let parts = splitter::split(pos);
    if parts.len() > 1 {
        let mut result = Value::Nimber(0);
        for mut part in parts {
            let mut frag_cache = HashMap::new();
            let frag_value = calc_value(&mut part.pos, &mut frag_cache);
            result = result + frag_value;
        }
        cache.insert(pos.zhash(), result);
        return result;
    }

    let mut options = HashSet::new();
    for m in &legal_moves {
        pos.make_move(m.x, m.y, m.side);
        if let Value::Nimber(n) = calc_value(pos, cache) {
            options.insert(n);
        }
        pos.undo_move(m.x, m.y, m.side);
    }
    let result = Value::Nimber(mex(options));
    cache.insert(pos.zhash(), result);
    result
}

// Calculate the Nimstring value of a position, along with the values attained
// by each of the legal moves.
pub fn calc_value_with_moves(pos: &Position) -> (Value, HashMap<Move, Value>) {
    let mut cache = HashMap::new();
    let mut pos = pos.clone();
    let val = calc_value(&mut pos, &mut cache);
    let mut per_move = HashMap::new();
    for m in pos.legal_moves() {
        pos.make_move(m.x, m.y, m.side);
        per_move.insert(m, calc_value(&mut pos, &mut cache));
        pos.undo_move(m.x, m.y, m.side);
    }
    (val, per_move)
}

#[cfg(test)]
mod tests {
    use nimstring::*;
    use game::*;
    use examples::*;

    #[test]
    fn value_display() {
        assert_eq!("*0", format!("{}", Value::Nimber(0)));
        assert_eq!("*1", format!("{}", Value::Nimber(1)));
        assert_eq!("*2", format!("{}", Value::Nimber(2)));
        assert_eq!("L", format!("{}", Value::Loony));
    }

    #[test]
    fn min_excl() {
        assert_eq!(0, mex(HashSet::new()));
        assert_eq!(0, mex([1,2,3].iter().cloned().collect()));
        assert_eq!(1, mex([0].iter().cloned().collect()));
        assert_eq!(1, mex([0,2,3].iter().cloned().collect()));
        assert_eq!(2, mex([0,1,3].iter().cloned().collect()));
        assert_eq!(3, mex([0,1,2].iter().cloned().collect()));
    }

    #[test]
    fn nimber_addition() {
        assert_eq!(Value::Nimber(3), Value::Nimber(1) + Value::Nimber(2));
        assert_eq!(Value::Nimber(2), Value::Nimber(1) + Value::Nimber(3));
        assert_eq!(Value::Nimber(1), Value::Nimber(2) + Value::Nimber(3));

        assert_eq!(Value::Nimber(6), Value::Nimber(2) + Value::Nimber(4));
        assert_eq!(Value::Nimber(4), Value::Nimber(6) + Value::Nimber(2));
        assert_eq!(Value::Nimber(2), Value::Nimber(4) + Value::Nimber(6));

        assert_eq!(Value::Loony, Value::Nimber(2) + Value::Loony);
        assert_eq!(Value::Loony, Value::Loony + Value::Nimber(2));
    }

    // Create a position consisting of a single horizontal chain of a given length.
    fn make_chain(length: usize) -> Position {
        let mut pos = Position::new_game(length, 1);
        for i in 0..length {
            pos.make_move(i, 0, Side::Top);
            pos.make_move(i, 0, Side::Bottom);
        }
        pos
    }

    #[test]
    fn basic_values() {
        let mut pos = make_chain(3);
        assert!(!is_loony(&pos));
        let mut cache = HashMap::new();
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
        pos.make_move(0, 0, Side::Left);
        assert!(is_loony(&pos));
        assert_eq!(Value::Loony, calc_value(&mut pos, &mut cache));
        pos.make_move(1, 0, Side::Left);
        assert!(is_loony(&pos));
        assert_eq!(Value::Loony, calc_value(&mut pos, &mut cache));
        pos.make_move(2, 0, Side::Left);
        assert!(!is_loony(&pos));
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
        pos.make_move(2, 0, Side::Right);
        assert!(!is_loony(&pos));
        assert_eq!(Value::Nimber(0), calc_value(&mut pos, &mut cache));
    }

    #[test]
    fn nonzero_value() {
        let mut pos = make_chain(7);
        pos.undo_move(3, 0, Side::Top);
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 3, y: 0, side: Side::Top}).unwrap());
    }

    #[test]
    fn right_capture_detection() {
        let mut pos = make_chain(5);
        pos.undo_move(3, 0, Side::Top);
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 4, y: 0, side: Side::Right}).unwrap());
    }

    #[test]
    fn p50_top_value() {
        let pos = p50_top();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(1), val);
        assert_eq!(&Value::Nimber(0), per_move.get(&Move{x: 3, y: 0, side: Side::Top}).unwrap());
    }

    #[test]
    fn p50_bottomleft_value() {
        let pos = p50_bottomleft();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(4), val);
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Left}).unwrap());
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Bottom}).unwrap());
        assert_eq!(&Value::Nimber(3),
                   per_move.get(&Move{x: 0, y: 1, side: Side::Right}).or(per_move.get(&Move{x: 0, y: 2, side: Side::Left})).unwrap());
    }

    #[test]
    fn p50_bottomright_value() {
        let pos = p50_bottomright();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(2), val);
        assert_eq!(&Value::Nimber(3), per_move.get(&Move{x: 0, y: 1, side: Side::Right}).unwrap());
    }

    #[test]
    fn p50_value() {
        let pos = p50();
        let (val, per_move) = calc_value_with_moves(&pos);
        assert_eq!(Value::Nimber(7), val);
        let zero_moves: Vec<&Move> = per_move.keys().filter(|m| &Value::Nimber(0) == per_move.get(m).unwrap()).collect();
        assert_eq!(3, zero_moves.len());
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Bottom}));
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Left}));
        assert!(zero_moves.contains(&&Move{x: 0, y: 3, side: Side::Right}));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to
//! keep the window alive for at least as long as the surface exists. In many cases Surface
//! may be able to do this for you, if you pass it ownership of your Window (or a
//! reference-counting container for it).
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # use std::sync::Arc;
//! # struct Window(*const u32);
//! # impl Window {
//! # fn hwnd(&self) -> *const u32 { self.0 }
//! # }
//! #
//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with
//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`):
//!
//! ```no_run
//! # use vulkano::instance::DeviceExtensions;
//! let ext = DeviceExtensions {
//!     khr_swapchain: true,
//!     .. DeviceExtensions::none()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
//! and choose which values you are going to use.
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> {
//! let caps = surface.capabilities(device.physical_device())?;
//!
//! // Use the current window size or some fixed resolution.
//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
//! let buffers_count = match caps.max_image_count {
//!     None => max(2, caps.min_image_count),
//!     Some(limit) => min(max(2, caps.min_image_count), limit)
//! };
//!
//! // Preserve the current surface transform.
//! let transform = caps.current_transform;
//!
//! // Use the first available format.
//! let (format, color_space) = caps.supported_formats[0];
//! # Ok(())
//! # }
//! ```
//!
//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha};
//! # fn create_swapchain(
//! #     device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>,
//! #     buffers_count: u32, format: Format, dimensions: [u32; 2],
//! #     surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, present_mode: PresentMode
//! # ) -> Result<(), Box<std::error::Error>> {
//! // The created swapchain will be used as a color attachment for rendering.
//! let usage = ImageUsage {
//!     color_attachment: true,
//!     .. ImageUsage::none()
//! };
//!
//! let sharing_mode = SharingMode::Exclusive(present_queue.family().id());
//!
//! // Create the swapchain and its buffers.
//! let (swapchain, buffers) = Swapchain::new(
//!     // Create the swapchain in this `device`'s memory.
//!     device,
//!     // The surface where the images will be presented.
//!     surface,
//!     // How many buffers to use in the swapchain.
//!     buffers_count,
//!     // The format of the images.
//!     format,
//!     // The size of each image.
//!     dimensions,
//!     // How many layers each image has.
//!     1,
//!     // What the images are going to be used for.
//!     usage,
//!     // Describes which queues will interact with the swapchain.
//!     sharing_mode,
//!     // What transformation to use with the surface.
//!     surface_transform,
//!     // How to handle the alpha channel.
//!     composite_alpha,
//!     // How to present images.
//!     present_mode,
//!     // Clip the parts of the buffer which aren't visible.
//!     true,
//!     // No previous swapchain.
//!     None
//! )?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain::acquire_next_image(None).unwrap();
//!     draw(images[index]);
//!     swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence();
//!
//!     final_future.flush().unwrap();      // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquireError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<commit_msg>Fix warning when running `cargo doc` (#1016)<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to
//! keep the window alive for at least as long as the surface exists. In many cases Surface
//! may be able to do this for you, if you pass it ownership of your Window (or a
//! reference-counting container for it).
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # use std::sync::Arc;
//! # struct Window(*const u32);
//! # impl Window {
//! # fn hwnd(&self) -> *const u32 { self.0 }
//! # }
//! #
//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with
//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`):
//!
//! ```no_run
//! # use vulkano::instance::DeviceExtensions;
//! let ext = DeviceExtensions {
//!     khr_swapchain: true,
//!     .. DeviceExtensions::none()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
//! and choose which values you are going to use.
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> {
//! let caps = surface.capabilities(device.physical_device())?;
//!
//! // Use the current window size or some fixed resolution.
//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
//! let buffers_count = match caps.max_image_count {
//!     None => max(2, caps.min_image_count),
//!     Some(limit) => min(max(2, caps.min_image_count), limit)
//! };
//!
//! // Preserve the current surface transform.
//! let transform = caps.current_transform;
//!
//! // Use the first available format.
//! let (format, color_space) = caps.supported_formats[0];
//! # Ok(())
//! # }
//! ```
//!
//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha};
//! # fn create_swapchain(
//! #     device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>,
//! #     buffers_count: u32, format: Format, dimensions: [u32; 2],
//! #     surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, present_mode: PresentMode
//! # ) -> Result<(), Box<std::error::Error>> {
//! // The created swapchain will be used as a color attachment for rendering.
//! let usage = ImageUsage {
//!     color_attachment: true,
//!     .. ImageUsage::none()
//! };
//!
//! let sharing_mode = SharingMode::Exclusive(present_queue.family().id());
//!
//! // Create the swapchain and its buffers.
//! let (swapchain, buffers) = Swapchain::new(
//!     // Create the swapchain in this `device`'s memory.
//!     device,
//!     // The surface where the images will be presented.
//!     surface,
//!     // How many buffers to use in the swapchain.
//!     buffers_count,
//!     // The format of the images.
//!     format,
//!     // The size of each image.
//!     dimensions,
//!     // How many layers each image has.
//!     1,
//!     // What the images are going to be used for.
//!     usage,
//!     // Describes which queues will interact with the swapchain.
//!     sharing_mode,
//!     // What transformation to use with the surface.
//!     surface_transform,
//!     // How to handle the alpha channel.
//!     composite_alpha,
//!     // How to present images.
//!     present_mode,
//!     // Clip the parts of the buffer which aren't visible.
//!     true,
//!     // No previous swapchain.
//!     None
//! )?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retrieved all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! ```
//! use vulkano::swapchain;
//! use vulkano::sync::GpuFuture;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain<()>> = return;
//! // let mut (swapchain, images) = Swapchain::new(...);
//! loop {
//!     # let mut command_buffer: ::vulkano::command_buffer::AutoCommandBuffer<()> = return;
//!     let (image_num, acquire_future)
//!         = swapchain::acquire_next_image(swapchain.clone(), None).unwrap();
//!
//!     // The command_buffer contains the draw commands that modify the framebuffer
//!     // constructed from images[image_num]
//!     acquire_future
//!         .then_execute(queue.clone(), command_buffer).unwrap()
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
//!         .then_signal_fence_and_flush().unwrap();
//! }
//! ```
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence_and_flush().unwrap(); // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquireError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<|endoftext|>


<commit_before><commit_msg>Add inverted BEQ Integration test<commit_after><|endoftext|>


<commit_before>use std::fmt;
use std::hashmap::HashMap;
pub use lexer::{Location, Located};

pub struct Module {
    name : ~str,
    bindings : ~[Binding],
    typeDeclarations : ~[TypeDeclaration],
    classes : ~[Class],
    instances : ~[Instance],
    dataDefinitions : ~[DataDefinition]
}
#[deriving(Clone)]
pub struct Class {
    name : ~str,
    variable: TypeVariable,
    declarations : ~[TypeDeclaration]
}

pub struct Instance {
    bindings : ~[Binding],
    constraints: ~[Constraint],
    typ : Type,
    classname : ~str
}

#[deriving(Eq)]
pub struct Binding {
    name : ~str,
    expression : TypedExpr,
    typeDecl : TypeDeclaration,
    arity : uint
}

#[deriving(Eq, Clone)]
pub struct Constructor {
    name : ~str,
    typ : Type,
    tag : int,
    arity : int
}

#[deriving(Eq, Clone)]
pub struct DataDefinition {
    constructors: ~[Constructor],
    typ: Type,
    parameters: HashMap<~str, int>
}

#[deriving(Clone, Eq, Default)]
pub struct TypeDeclaration {
    context : ~[Constraint],
    typ : Type,
    name : ~str
}

#[deriving(Clone, Default, Eq, ToStr, IterBytes)]
pub struct TypeOperator {
    name : ~str
}
#[deriving(Clone, Eq, Default, ToStr, IterBytes)]
pub struct TypeVariable {
    id : int
}
#[deriving(Clone, Eq, ToStr, IterBytes)]
pub enum Type_ {
    TypeVariable(TypeVariable),
    TypeOperator(TypeOperator)
}

#[deriving(Clone, Eq, ToStr, IterBytes)]
pub struct Constraint {
    class: ~str,
    variables: ~[TypeVariable]
}

#[deriving(Clone, ToStr, IterBytes)]
pub struct Type {
    typ: Type_,
    types: ~[Type]
}

impl Default for Type {
    fn default() -> Type {
        Type::new_var(-1)
    }
}
impl fmt::Default for TypeVariable {
    fn fmt(var : &TypeVariable, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", var.id)
    }
}
impl fmt::Default for TypeOperator {
    fn fmt(op: &TypeOperator, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", op.name)
    }
}
impl fmt::Default for Type {
    fn fmt(typ : &Type, f: &mut fmt::Formatter) {
        if typ.types.len() == 0 {
            match &typ.typ {
                &TypeVariable(ref var) => write!(f.buf, "{}", *var),
                &TypeOperator(ref op) => write!(f.buf, "{}", *op)
            }
        }
        else {
            write!(f.buf, "(");
            match &typ.typ {
                &TypeVariable(ref var) => write!(f.buf, "{}", *var),
                &TypeOperator(ref op) => write!(f.buf, "{}", *op)
            }
            for t in typ.types.iter() {
                write!(f.buf, " {}", *t);
            }
            write!(f.buf, ")");
        }
    }
}
impl fmt::Default for Constraint {
    fn fmt(constraint : &Constraint, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", constraint.class);
        for var in constraint.variables.iter() {
            write!(f.buf, " {}", *var);
        }
    }
}
impl fmt::Default for TypeDeclaration {
    fn fmt(typ : &TypeDeclaration, f: &mut fmt::Formatter) {
        for constraint in typ.context.iter() {
            write!(f.buf, "{} ", *constraint);
        }
        if typ.context.len() > 0 {
            write!(f.buf, "=> ");
        }
        write!(f.buf, "{}", typ.typ)
    }
}

fn type_eq<'a>(mapping: &mut HashMap<&'a TypeVariable, &'a TypeVariable>, lhs: &'a Type, rhs: &'a Type) -> bool {
    let equal = match (&lhs.typ, &rhs.typ) {
        (&TypeOperator(ref l), &TypeOperator(ref r)) => l == r,
        (&TypeVariable(ref r), &TypeVariable(ref l)) => {
            match mapping.find(&l) {
                Some(x) => return x.id == r.id,
                None => ()
            }
            mapping.insert(l, r);
            true
        }
        _ => false
    };
    equal && lhs.types.len() == rhs.types.len()
    && lhs.types.iter().zip(rhs.types.iter()).all(|(l, r)| type_eq(mapping, l, r))
}

impl Eq for Type {
    fn eq(&self, other: &Type) -> bool {
        let mut mapping = HashMap::new();
        type_eq(&mut mapping, self, other)
    }
}

impl Type {
    pub fn new_var(id : int) -> Type {
        Type { typ: TypeVariable(TypeVariable { id : id }), types: ~[] }
    }
    pub fn new_op(name : ~str, types : ~[Type]) -> Type {
        Type { typ: TypeOperator(TypeOperator { name : name }), types : types }
    }

    pub fn var<'a>(&'a self) -> &'a TypeVariable {
        match &self.typ {
            &TypeVariable(ref var) => var,
            _ => fail!("Tried to unwrap TypeOperator as a TypeVariable")
        }
    }
    #[allow(dead_code)]
    pub fn op<'a>(&'a self) -> &'a TypeOperator {
        match &self.typ {
            &TypeOperator(ref op) => op,
            _ => fail!("Tried to unwrap TypeVariable as a TypeOperator")
        }
    }
}

pub struct TypedExpr {
    expr : Expr,
    typ : Type,
    location : Location
}

impl Eq for TypedExpr {
    fn eq(&self, other : &TypedExpr) -> bool {
        self.expr == other.expr
    }
}

impl fmt::Default for ~TypedExpr {
    fn fmt(expr: &~TypedExpr, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", expr.expr)
    }
}

impl TypedExpr {
    pub fn new(expr : Expr) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : Location { column : -1, row : -1, absolute : -1 } }
    }
    pub fn with_location(expr : Expr, loc : Location) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : loc }
    }
}

#[deriving(Eq)]
pub struct Alternative {
    pattern : Located<Pattern>,
    expression : TypedExpr
}

#[deriving(Eq)]
pub enum Pattern {
    NumberPattern(int),
    IdentifierPattern(~str),
    ConstructorPattern(~str, ~[Pattern])
}

#[deriving(Eq)]
pub enum Expr {
    Identifier(~str),
    Apply(~TypedExpr, ~TypedExpr),
    Number(int),
    Rational(f64),
    String(~str),
    Char(char),
    Lambda(~str, ~TypedExpr),
    Let(~[Binding], ~TypedExpr),
    Case(~TypedExpr, ~[Alternative])
}

impl fmt::Default for Expr {
    fn fmt(expr: &Expr, f: &mut fmt::Formatter) {
        match expr {
            &Identifier(ref s) => write!(f.buf, "{}", *s),
            &Apply(ref func, ref arg) => write!(f.buf, "({} {})", *func, *arg),
            &Number(num) => write!(f.buf, "{}", num),
            &Rational(num) => write!(f.buf, "{}", num),
            &String(ref s) => write!(f.buf, "\"{}\"", *s),
            &Char(c) => write!(f.buf, "'{}'", c),
            &Lambda(ref arg, ref body) => write!(f.buf, "({} -> {})", *arg, *body),
            &Let(_,_) => write!(f.buf, "Let ... "),
            &Case(_,_) => write!(f.buf, "Case ...")
        }
    }
}
impl fmt::Default for ~Expr {
    fn fmt(expr: &~Expr, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", *expr)
    }
}
<commit_msg>Formatting Types skips wrapping parentheses and outputs functions in infix form<commit_after>use std::fmt;
use std::hashmap::HashMap;
pub use lexer::{Location, Located};

pub struct Module {
    name : ~str,
    bindings : ~[Binding],
    typeDeclarations : ~[TypeDeclaration],
    classes : ~[Class],
    instances : ~[Instance],
    dataDefinitions : ~[DataDefinition]
}
#[deriving(Clone)]
pub struct Class {
    name : ~str,
    variable: TypeVariable,
    declarations : ~[TypeDeclaration]
}

pub struct Instance {
    bindings : ~[Binding],
    constraints: ~[Constraint],
    typ : Type,
    classname : ~str
}

#[deriving(Eq)]
pub struct Binding {
    name : ~str,
    expression : TypedExpr,
    typeDecl : TypeDeclaration,
    arity : uint
}

#[deriving(Eq, Clone)]
pub struct Constructor {
    name : ~str,
    typ : Type,
    tag : int,
    arity : int
}

#[deriving(Eq, Clone)]
pub struct DataDefinition {
    constructors: ~[Constructor],
    typ: Type,
    parameters: HashMap<~str, int>
}

#[deriving(Clone, Eq, Default)]
pub struct TypeDeclaration {
    context : ~[Constraint],
    typ : Type,
    name : ~str
}

#[deriving(Clone, Default, Eq, ToStr, IterBytes)]
pub struct TypeOperator {
    name : ~str
}
#[deriving(Clone, Eq, Default, ToStr, IterBytes)]
pub struct TypeVariable {
    id : int
}
#[deriving(Clone, Eq, ToStr, IterBytes)]
pub enum Type_ {
    TypeVariable(TypeVariable),
    TypeOperator(TypeOperator)
}

#[deriving(Clone, Eq, ToStr, IterBytes)]
pub struct Constraint {
    class: ~str,
    variables: ~[TypeVariable]
}

#[deriving(Clone, ToStr, IterBytes)]
pub struct Type {
    typ: Type_,
    types: ~[Type]
}

impl Default for Type {
    fn default() -> Type {
        Type::new_var(-1)
    }
}
impl fmt::Default for TypeVariable {
    fn fmt(var : &TypeVariable, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", var.id)
    }
}
impl fmt::Default for TypeOperator {
    fn fmt(op: &TypeOperator, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", op.name)
    }
}
impl fmt::Default for Type_ {
    fn fmt(typ : &Type_, f: &mut fmt::Formatter) {
        match typ {
            &TypeVariable(ref var) => write!(f.buf, "{}", *var),
            &TypeOperator(ref op) => write!(f.buf, "{}", *op)
        }
    }
}
impl fmt::Default for Type {
    fn fmt(typ : &Type, f: &mut fmt::Formatter) {
        if typ.types.len() == 0 {
            write!(f.buf, "{}", typ.typ);
        }
        else {
            let is_list = match &typ.typ {
                &TypeOperator(ref op) => "[]" == op.name,
                _ => false
            };
            let is_func = match &typ.typ {
                &TypeOperator(ref op) => "->" == op.name,
                _ => false
            };
            if is_list {
                write!(f.buf, "[");
            }
            else if is_func {
                let is_lhs_func = match &typ.types[0].typ {
                    &TypeOperator(ref op) => "->" == op.name,
                    _ => false
                };
                if is_lhs_func {
                    write!(f.buf, "({}) -> {}", typ.types[0], typ.types[1]);
                }
                else {
                    write!(f.buf, "{} -> {}", typ.types[0], typ.types[1]);
                }
                return;
            }
            else {
                write!(f.buf, "({}", typ.typ);
            }
            for t in typ.types.iter() {
                write!(f.buf, " {}", *t);
            }
            if is_list {
                write!(f.buf, "]");
            }
            else {
                write!(f.buf, ")");
            }
        }
    }
}
impl fmt::Default for Constraint {
    fn fmt(constraint : &Constraint, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", constraint.class);
        for var in constraint.variables.iter() {
            write!(f.buf, " {}", *var);
        }
    }
}
impl fmt::Default for TypeDeclaration {
    fn fmt(typ : &TypeDeclaration, f: &mut fmt::Formatter) {
        for constraint in typ.context.iter() {
            write!(f.buf, "{} ", *constraint);
        }
        if typ.context.len() > 0 {
            write!(f.buf, "=> ");
        }
        write!(f.buf, "{}", typ.typ)
    }
}

fn type_eq<'a>(mapping: &mut HashMap<&'a TypeVariable, &'a TypeVariable>, lhs: &'a Type, rhs: &'a Type) -> bool {
    let equal = match (&lhs.typ, &rhs.typ) {
        (&TypeOperator(ref l), &TypeOperator(ref r)) => l == r,
        (&TypeVariable(ref r), &TypeVariable(ref l)) => {
            match mapping.find(&l) {
                Some(x) => return x.id == r.id,
                None => ()
            }
            mapping.insert(l, r);
            true
        }
        _ => false
    };
    equal && lhs.types.len() == rhs.types.len()
    && lhs.types.iter().zip(rhs.types.iter()).all(|(l, r)| type_eq(mapping, l, r))
}

impl Eq for Type {
    fn eq(&self, other: &Type) -> bool {
        let mut mapping = HashMap::new();
        type_eq(&mut mapping, self, other)
    }
}

impl Type {
    pub fn new_var(id : int) -> Type {
        Type { typ: TypeVariable(TypeVariable { id : id }), types: ~[] }
    }
    pub fn new_op(name : ~str, types : ~[Type]) -> Type {
        Type { typ: TypeOperator(TypeOperator { name : name }), types : types }
    }

    pub fn var<'a>(&'a self) -> &'a TypeVariable {
        match &self.typ {
            &TypeVariable(ref var) => var,
            _ => fail!("Tried to unwrap TypeOperator as a TypeVariable")
        }
    }
    #[allow(dead_code)]
    pub fn op<'a>(&'a self) -> &'a TypeOperator {
        match &self.typ {
            &TypeOperator(ref op) => op,
            _ => fail!("Tried to unwrap TypeVariable as a TypeOperator")
        }
    }
}

pub struct TypedExpr {
    expr : Expr,
    typ : Type,
    location : Location
}

impl Eq for TypedExpr {
    fn eq(&self, other : &TypedExpr) -> bool {
        self.expr == other.expr
    }
}

impl fmt::Default for ~TypedExpr {
    fn fmt(expr: &~TypedExpr, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", expr.expr)
    }
}

impl TypedExpr {
    pub fn new(expr : Expr) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : Location { column : -1, row : -1, absolute : -1 } }
    }
    pub fn with_location(expr : Expr, loc : Location) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : loc }
    }
}

#[deriving(Eq)]
pub struct Alternative {
    pattern : Located<Pattern>,
    expression : TypedExpr
}

#[deriving(Eq)]
pub enum Pattern {
    NumberPattern(int),
    IdentifierPattern(~str),
    ConstructorPattern(~str, ~[Pattern])
}

#[deriving(Eq)]
pub enum Expr {
    Identifier(~str),
    Apply(~TypedExpr, ~TypedExpr),
    Number(int),
    Rational(f64),
    String(~str),
    Char(char),
    Lambda(~str, ~TypedExpr),
    Let(~[Binding], ~TypedExpr),
    Case(~TypedExpr, ~[Alternative])
}

impl fmt::Default for Expr {
    fn fmt(expr: &Expr, f: &mut fmt::Formatter) {
        match expr {
            &Identifier(ref s) => write!(f.buf, "{}", *s),
            &Apply(ref func, ref arg) => write!(f.buf, "({} {})", *func, *arg),
            &Number(num) => write!(f.buf, "{}", num),
            &Rational(num) => write!(f.buf, "{}", num),
            &String(ref s) => write!(f.buf, "\"{}\"", *s),
            &Char(c) => write!(f.buf, "'{}'", c),
            &Lambda(ref arg, ref body) => write!(f.buf, "({} -> {})", *arg, *body),
            &Let(_,_) => write!(f.buf, "Let ... "),
            &Case(_,_) => write!(f.buf, "Case ...")
        }
    }
}
impl fmt::Default for ~Expr {
    fn fmt(expr: &~Expr, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", *expr)
    }
}
<|endoftext|>


<commit_before>#![warn(clippy::out_of_bounds_indexing)]
#![allow(clippy::no_effect, clippy::unnecessary_operation)]

fn main() {
    let empty: [i8; 0] = [];
    empty[0]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
    &empty[1..5];
    &empty[0..=4];
    &empty[..=4];
    &empty[1..];
    &empty[..4];
    &empty[0..=0];
    &empty[..=0];

    &empty[0..]; // Ok, should not produce stderr.
    &empty[0..0]; // Ok, should not produce stderr.
    &empty[..0]; // Ok, should not produce stderr.
    &empty[..]; // Ok, should not produce stderr.
}
<commit_msg>Remove comment<commit_after>#![warn(clippy::out_of_bounds_indexing)]
#![allow(clippy::no_effect, clippy::unnecessary_operation)]

fn main() {
    let empty: [i8; 0] = [];
    empty[0];
    &empty[1..5];
    &empty[0..=4];
    &empty[..=4];
    &empty[1..];
    &empty[..4];
    &empty[0..=0];
    &empty[..=0];

    &empty[0..]; // Ok, should not produce stderr.
    &empty[0..0]; // Ok, should not produce stderr.
    &empty[..0]; // Ok, should not produce stderr.
    &empty[..]; // Ok, should not produce stderr.
}
<|endoftext|>


<commit_before>static N: uint = 100000000;
fn main() {
  stieve_atkin();
}

fn stieve_atkin() {
  let nsqrt: uint = ((N as float).sqrt() + 1.0) as uint;
  let mut is_prime = ~[false, ..N];
  let mut n: uint;
  let mut primes = ~[];

  for x in range(1, nsqrt) {
    for y in range(1, nsqrt) {
      n = 4 * (x*x) + (y*y);
      if n <= N && (n % 12 == 1 || n % 12 == 5) { is_prime[n] = !is_prime[n]; }

      n = 3 * (x*x) + y*y;
      if n <= N && n % 12 == 7 { is_prime[n] = !is_prime[n]; }

      n = 3 * (x*x) - y*y;
      if x > y && n <= N && n % 12 == 11 { is_prime[n] = !is_prime[n]; }
    }
  }

  for x in range(5, nsqrt) {
    if is_prime[x] {
      let mut y = x*x;
      while y < N {
        is_prime[y] = false;
        y += x*x;
      }
    }
  }

  is_prime[2] = true;
  is_prime[3] = true;

  for x in range(0, N) { if is_prime[x] { primes.push(x) } }
}
<commit_msg>make code more elegant<commit_after>static N: uint = 100000000;
fn main() {
  stieve_atkin();
}

fn stieve_atkin() {
  let nsqrt: uint = ((N as float).sqrt() + 1.0) as uint;
  let mut is_prime = ~[false, ..N];
  let mut n: uint;
  let mut primes = ~[];

  for x in range(1, nsqrt) {
    for y in range(1, nsqrt) {
      n = 4 * (x*x) + (y*y);
      if n <= N && (n % 12 == 1 || n % 12 == 5) { is_prime[n] = !is_prime[n]; }

      n = 3 * (x*x) + y*y;
      if n <= N && n % 12 == 7 { is_prime[n] = !is_prime[n]; }

      n = 3 * (x*x) - y*y;
      if x > y && n <= N && n % 12 == 11 { is_prime[n] = !is_prime[n]; }
    }
  }

  for x in range(5, nsqrt).filter(|i| is_prime[*i]) {
    let mut y = x*x;
    while y < N {
      is_prime[y] = false;
      y += x*x;
    }
  }

  is_prime[2] = true;
  is_prime[3] = true;

  for x in range(0, N).filter(|i| is_prime[*i]) { primes.push(x) }
  println(fmt!("%u", primes.len()))
}
<|endoftext|>


<commit_before>extern crate cairo;

use std::str::FromStr;

use error::*;
use parsers::ParseError;
use parsers;

/* Keep this in sync with rsvg-private.h:RsvgViewBox */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RsvgViewBox {
    pub rect:   cairo::Rectangle,
    pub active: bool
}

impl RsvgViewBox {
    pub fn new_inactive () -> RsvgViewBox {
        RsvgViewBox {
            rect: cairo::Rectangle { x: 0.0,
                                     y: 0.0,
                                     width: 0.0,
                                     height: 0.0 },
            active: false
        }
    }
}

impl Default for RsvgViewBox {
    fn default () -> RsvgViewBox {
        RsvgViewBox::new_inactive ()
    }
}

impl FromStr for RsvgViewBox {
    type Err = AttributeError;

    fn from_str (s: &str) -> Result<RsvgViewBox, AttributeError> {
        let result = parsers::view_box (s.trim ().as_bytes ()).to_full_result ();

        match result {
            Ok ((x, y, w, h)) => {
                if w >= 0.0 && h >= 0.0 {
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: x,
                                                               y: y,
                                                               width: w,
                                                               height: h },
                                      active: true })
                } else {
                    Err (AttributeError::Value ("width and height must not be negative".to_string ()))
                }
            },

            Err (_) => {
                Err (AttributeError::Parse (ParseError::new ("string does not match 'x [,] y [,] w [,] h'")))
            }
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes () {
        assert_eq! (RsvgViewBox::from_str ("  1 2 3 4"),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: 1.0,
                                                               y: 2.0,
                                                               width: 3.0,
                                                               height: 4.0 },
                                      active: true }));

        assert_eq! (RsvgViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: -1.5,
                                                               y: -25.0,
                                                               width: 34.0,
                                                               height: 5600.0 },
                                      active: true }));
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error () {
        assert! (is_parse_error (&RsvgViewBox::from_str ("")));

        assert! (is_value_error (&RsvgViewBox::from_str (" 1,2,-3,-4 ")));

        assert! (is_parse_error (&RsvgViewBox::from_str ("qwerasdfzxcv")));

        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 3 4   5")));
    }
}
<commit_msg>viewbox.rs: Use gboolean, not bool for field in a repr(C) struct<commit_after>extern crate cairo;
extern crate glib;

use std::str::FromStr;

use error::*;
use parsers::ParseError;
use parsers;

use glib::translate::*;

/* Keep this in sync with rsvg-private.h:RsvgViewBox */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RsvgViewBox {
    pub rect:   cairo::Rectangle,
    pub active: glib::ffi::gboolean
}

impl RsvgViewBox {
    pub fn new_inactive () -> RsvgViewBox {
        RsvgViewBox {
            rect: cairo::Rectangle { x: 0.0,
                                     y: 0.0,
                                     width: 0.0,
                                     height: 0.0 },
            active: false
        }
    }
}

impl Default for RsvgViewBox {
    fn default () -> RsvgViewBox {
        RsvgViewBox::new_inactive ()
    }
}

impl FromStr for RsvgViewBox {
    type Err = AttributeError;

    fn from_str (s: &str) -> Result<RsvgViewBox, AttributeError> {
        let result = parsers::view_box (s.trim ().as_bytes ()).to_full_result ();

        match result {
            Ok ((x, y, w, h)) => {
                if w >= 0.0 && h >= 0.0 {
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: x,
                                                               y: y,
                                                               width: w,
                                                               height: h },
                                      active: true })
                } else {
                    Err (AttributeError::Value ("width and height must not be negative".to_string ()))
                }
            },

            Err (_) => {
                Err (AttributeError::Parse (ParseError::new ("string does not match 'x [,] y [,] w [,] h'")))
            }
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes () {
        assert_eq! (RsvgViewBox::from_str ("  1 2 3 4"),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: 1.0,
                                                               y: 2.0,
                                                               width: 3.0,
                                                               height: 4.0 },
                                      active: true }));

        assert_eq! (RsvgViewBox::from_str (" -1.5 -2.5e1,34,56e2  "),
                    Ok (RsvgViewBox { rect: cairo::Rectangle { x: -1.5,
                                                               y: -25.0,
                                                               width: 34.0,
                                                               height: 5600.0 },
                                      active: true }));
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error () {
        assert! (is_parse_error (&RsvgViewBox::from_str ("")));

        assert! (is_value_error (&RsvgViewBox::from_str (" 1,2,-3,-4 ")));

        assert! (is_parse_error (&RsvgViewBox::from_str ("qwerasdfzxcv")));

        assert! (is_parse_error (&RsvgViewBox::from_str (" 1 2 3 4   5")));
    }
}
<|endoftext|>


<commit_before>extern crate hmacsha1;

use std::fmt;

/// This implementation of HMAC-Based One Time Passwords proceeds in three
/// stages, as per [RFC 4226](https://www.ietf.org/rfc/rfc4226.txt):
///
/// 1. Generate an HMAC-SHA-1 value given a shared secret `key` and a
/// moving factor `counter` that *should* change on every use
/// 2. Extraction of a 4-byte value from the SHA-1 digest
/// 3. Deriving a final HOTP value between 0 and
/// 10^{`desired_code_length`}-1 from the 4-byte value extracted
/// in the last step.
///
/// Note that it is the responsibility of the caller to:
///
/// * Fulfill the precondition that `counter` is an 8-byte value
/// * Increment the counter accordingly per invocation
///
/// # Examples
///
/// To generate an HOTP value between 0 and 10^6 - 1, given the shared
/// secret ASCII key `"Hello world!"` and current counter `0`:
///
/// ```
/// let six_digit_result = rusthotp::hotp(6, "Hello world!".as_bytes(), &[0; 8]);
/// assert_eq!(format!("{}", six_digit_result), "124111");
/// ```
///
/// To generate an HOTP value between 0 and 10^8 - 1, given the shared
/// secret ASCII key `"12345678901234567890"` and current counter `1`:
///
/// ```
/// let eight_digit_result = rusthotp::hotp(8, "12345678901234567890".as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 1]);
/// assert_eq!(format!("{}", eight_digit_result), "94287082");
/// ```

pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8]) -> HotpOutput {
    let hmac_value = hmacsha1::hmac_sha1(key, counter);
    let dbc = sbits(&hmac_value);
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}
<commit_msg>hotp counter's length is now checked at compile time<commit_after>extern crate hmacsha1;

use std::fmt;

/// This implementation of HMAC-Based One Time Passwords proceeds in three
/// stages, as per [RFC 4226](https://www.ietf.org/rfc/rfc4226.txt):
///
/// 1. Generate an HMAC-SHA-1 value given a shared secret `key` and a
/// moving factor `counter` that *should* change on every use
/// 2. Extraction of a 4-byte value from the SHA-1 digest
/// 3. Deriving a final HOTP value between 0 and
/// 10^{`desired_code_length`}-1 from the 4-byte value extracted
/// in the last step.
///
/// Note that it is the responsibility of the caller to:
///
/// * Increment the counter accordingly per invocation
///
/// # Examples
///
/// To generate an HOTP value between 0 and 10^6 - 1, given the shared
/// secret ASCII key `"Hello world!"` and current counter `0`:
///
/// ```
/// let six_digit_result = rusthotp::hotp(6, "Hello world!".as_bytes(), &[0; 8]);
/// assert_eq!(format!("{}", six_digit_result), "124111");
/// ```
///
/// To generate an HOTP value between 0 and 10^8 - 1, given the shared
/// secret ASCII key `"12345678901234567890"` and current counter `1`:
///
/// ```
/// let eight_digit_result = rusthotp::hotp(8, "12345678901234567890".as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 1]);
/// assert_eq!(format!("{}", eight_digit_result), "94287082");
/// ```

pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8; 8]) -> HotpOutput {
    let hmac_value = hmacsha1::hmac_sha1(key, counter);
    let dbc = sbits(&hmac_value);
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}
<|endoftext|>


<commit_before>extern crate hmacsha1;

use std::fmt;

/// This implementation of HMAC-Based One Time Passwords proceeds in three
/// stages, as per [RFC 4226](https://www.ietf.org/rfc/rfc4226.txt):
///
/// 1. Generate an HMAC-SHA-1 value given a shared secret `key` and a
/// moving factor `counter` that *should* change on every use
/// 2. Extraction of a 4-byte value from the SHA-1 digest
/// 3. Deriving a final HOTP value between 0 and
/// 10^{`desired_code_length`}-1 from the 4-byte value extracted
/// in the last step.
///
/// Note that it is the responsibility of the caller to:
///
/// * Increment the counter accordingly per invocation
///
/// # Examples
///
/// To generate an HOTP value between 0 and 10^6 - 1, given the shared
/// secret ASCII key `"Hello world!"` and current counter `0`:
///
/// ```
/// let six_digit_result = rusthotp::hotp(6, "Hello world!".as_bytes(), &[0; 8]);
/// assert_eq!(format!("{}", six_digit_result), "124111");
/// ```
///
/// To generate an HOTP value between 0 and 10^8 - 1, given the shared
/// secret ASCII key `"12345678901234567890"` and current counter `1`:
///
/// ```
/// let eight_digit_result = rusthotp::hotp(8, "12345678901234567890".as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 1]);
/// assert_eq!(format!("{}", eight_digit_result), "94287082");
/// ```

pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8; 8]) -> HotpOutput {
    let hmac_value = hmacsha1::hmac_sha1(key, counter);
    let dbc = sbits(&hmac_value);
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}
<commit_msg>Improves hotp documentation<commit_after>extern crate hmacsha1;

use std::fmt;

/// This implementation of HMAC-Based One Time Passwords proceeds in three
/// stages, as per [RFC 4226](https://www.ietf.org/rfc/rfc4226.txt):
///
/// 1. Generate an HMAC-SHA-1 value given a shared secret `key` and a
/// moving factor `counter` that *should* change on every use
/// 2. Extraction of a 4-byte value from the SHA-1 digest
/// 3. Deriving a final HOTP value between 0 and
/// 10^{`desired_code_length`}-1 from the 4-byte value extracted
/// in the last step.
///
/// Note that it is the responsibility of the caller to increment the counter accordingly per invocation
///
/// # Examples
///
/// To generate an HOTP value between 0 and 10^6 - 1, given the shared
/// secret ASCII key `"Hello world!"` and current counter `0`:
///
/// ```
/// let six_digit_result = rusthotp::hotp(6, "Hello world!".as_bytes(), &[0; 8]);
/// assert_eq!(format!("{}", six_digit_result), "124111");
/// ```
///
/// To generate an HOTP value between 0 and 10^8 - 1, given the shared
/// secret ASCII key `"12345678901234567890"` and current counter `1`:
///
/// ```
/// let eight_digit_result = rusthotp::hotp(8, "12345678901234567890".as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 1]);
/// assert_eq!(format!("{}", eight_digit_result), "94287082");
/// ```

pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8; 8]) -> HotpOutput {
    let hmac_value = hmacsha1::hmac_sha1(key, counter);
    let dbc = sbits(&hmac_value);
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}
<|endoftext|>


<commit_before>// run-pass

#![allow(stable_features)]
#![allow(unused_variables)]

// #45662

#![feature(repr_align)]

#[repr(align(16))]
pub struct A(i64);

#[allow(improper_ctypes)]
pub extern "C" fn foo(x: A) {}

fn main() {
    foo(A(0));
}
<commit_msg>tests: add `#[repr(C)]` to test<commit_after>// run-pass

#![allow(stable_features)]
#![allow(unused_variables)]

// #45662

#![feature(repr_align)]

#[repr(align(16), C)]
pub struct A(i64);

pub extern "C" fn foo(x: A) {}

fn main() {
    foo(A(0));
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
#[cfg(feature = "mem")]
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = Vec::new();

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	#[cfg(feature = "mem")]
	{
		// Kernel and user space has its own versions of memcpy, memset, etc,
		// Consequently, we rename the functions in the libos to avoid collisions.
		// In addition, it provides us the offer to create a optimized version of memcpy
		// in user space.

		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		let symbols: [&str; 5] = ["memcpy", "memmove", "memset", "memcmp", "bcmp"];
		for symbol in symbols.iter() {
			// determine llvm_objcopy
			let llvm_objcopy = llvm_tools
				.tool(&llvm_tools::exe("llvm-objcopy"))
				.expect("llvm_objcopy not found in llvm-tools");

			// rename symbols
			let mut cmd = Command::new(llvm_objcopy);
			cmd.arg("--redefine-sym")
				.arg(String::from(*symbol) + &String::from("=kernel") + &String::from(*symbol))
				.arg(lib.display().to_string());

			println!("cmd {:?}", cmd);
			let output = cmd.output().expect("Unable to rename symbols");
			let stdout = std::string::String::from_utf8(output.stdout);
			let stderr = std::string::String::from_utf8(output.stderr);
			println!("Rename symbols output-status: {}", output.status);
			println!("Rename symbols output-stdout: {}", stdout.unwrap());
			println!("Rename symbols output-stderr: {}", stderr.unwrap());
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let cargo_download = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.output()
			.expect("could not launch cargo download");
		if !cargo_download.status.success() {
			panic!("Unable to download rusty-hermit. Is `cargo-download` installed?.");
		}
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>Disable mutable-noalias<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
#[cfg(feature = "mem")]
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = Vec::new();
	rustflags.push("-Zmutable-noalias=no".to_string());

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	#[cfg(feature = "mem")]
	{
		// Kernel and user space has its own versions of memcpy, memset, etc,
		// Consequently, we rename the functions in the libos to avoid collisions.
		// In addition, it provides us the offer to create a optimized version of memcpy
		// in user space.

		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		let symbols: [&str; 5] = ["memcpy", "memmove", "memset", "memcmp", "bcmp"];
		for symbol in symbols.iter() {
			// determine llvm_objcopy
			let llvm_objcopy = llvm_tools
				.tool(&llvm_tools::exe("llvm-objcopy"))
				.expect("llvm_objcopy not found in llvm-tools");

			// rename symbols
			let mut cmd = Command::new(llvm_objcopy);
			cmd.arg("--redefine-sym")
				.arg(String::from(*symbol) + &String::from("=kernel") + &String::from(*symbol))
				.arg(lib.display().to_string());

			println!("cmd {:?}", cmd);
			let output = cmd.output().expect("Unable to rename symbols");
			let stdout = std::string::String::from_utf8(output.stdout);
			let stderr = std::string::String::from_utf8(output.stderr);
			println!("Rename symbols output-status: {}", output.status);
			println!("Rename symbols output-stdout: {}", stdout.unwrap());
			println!("Rename symbols output-stderr: {}", stderr.unwrap());
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let cargo_download = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.output()
			.expect("could not launch cargo download");
		if !cargo_download.status.success() {
			panic!("Unable to download rusty-hermit. Is `cargo-download` installed?.");
		}
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>