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

//! Generic types for CSS values related to borders.

use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};

/// A generic value for a single side of a `border-image-width` property.
#[derive(
    Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
)]
pub enum BorderImageSideWidth<LengthPercentage, Number> {
    /// `<length-or-percentage>`
    Length(LengthPercentage),
    /// `<number>`
    Number(Number),
    /// `auto`
    Auto,
}

/// A generic value for the `border-image-slice` property.
#[derive(
    Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
)]
#[repr(C)]
pub struct GenericBorderImageSlice<NumberOrPercentage> {
    /// The offsets.
    #[css(field_bound)]
    pub offsets: Rect<NumberOrPercentage>,
    /// Whether to fill the middle part.
    #[css(represents_keyword)]
    pub fill: bool,
}

pub use self::GenericBorderImageSlice as BorderImageSlice;

/// A generic value for the `border-*-radius` longhand properties.
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToAnimatedZero,
    ToComputedValue,
    ToCss,
)]
pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size<L>);

impl<L> BorderCornerRadius<L> {
    /// Trivially create a `BorderCornerRadius`.
    pub fn new(w: L, h: L) -> Self {
        BorderCornerRadius(Size::new(w, h))
    }
}

/// A generic value for the `border-spacing` property.
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToAnimatedZero,
    ToComputedValue,
    ToCss,
)]
pub struct BorderSpacing<L>(#[css(field_bound)] pub Size<L>);

impl<L> BorderSpacing<L> {
    /// Trivially create a `BorderCornerRadius`.
    pub fn new(w: L, h: L) -> Self {
        BorderSpacing(Size::new(w, h))
    }
}

/// A generic value for `border-radius`, `outline-radius` and `inset()`.
///
/// <https://drafts.csswg.org/css-backgrounds-3/#border-radius>
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToComputedValue,
)]
pub struct BorderRadius<LengthPercentage> {
    /// The top left radius.
    pub top_left: BorderCornerRadius<LengthPercentage>,
    /// The top right radius.
    pub top_right: BorderCornerRadius<LengthPercentage>,
    /// The bottom right radius.
    pub bottom_right: BorderCornerRadius<LengthPercentage>,
    /// The bottom left radius.
    pub bottom_left: BorderCornerRadius<LengthPercentage>,
}

impl<L> BorderRadius<L> {
    /// Returns a new `BorderRadius<L>`.
    #[inline]
    pub fn new(
        tl: BorderCornerRadius<L>,
        tr: BorderCornerRadius<L>,
        br: BorderCornerRadius<L>,
        bl: BorderCornerRadius<L>,
    ) -> Self {
        BorderRadius {
            top_left: tl,
            top_right: tr,
            bottom_right: br,
            bottom_left: bl,
        }
    }
}

impl<L> BorderRadius<L>
where
    L: PartialEq + ToCss,
{
    /// Serialises two given rects following the syntax of the `border-radius``
    /// property.
    pub fn serialize_rects<W>(
        widths: Rect<&L>,
        heights: Rect<&L>,
        dest: &mut CssWriter<W>,
    ) -> fmt::Result
    where
        W: Write,
    {
        widths.to_css(dest)?;
        if widths.0 != heights.0 ||
            widths.1 != heights.1 ||
            widths.2 != heights.2 ||
            widths.3 != heights.3
        {
            dest.write_str(" / ")?;
            heights.to_css(dest)?;
        }
        Ok(())
    }
}

impl<L> ToCss for BorderRadius<L>
where
    L: PartialEq + ToCss,
{
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
        let BorderRadius {
            top_left: BorderCornerRadius(ref tl),
            top_right: BorderCornerRadius(ref tr),
            bottom_right: BorderCornerRadius(ref br),
            bottom_left: BorderCornerRadius(ref bl),
        } = *self;

        let widths = Rect::new(&tl.0.width, &tr.0.width, &br.0.width, &bl.0.width);
        let heights = Rect::new(&tl.0.height, &tr.0.height, &br.0.height, &bl.0.height);

        Self::serialize_rects(widths, heights, dest)
    }
}
<commit_msg>style: Simplify border-radius serialization.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Generic types for CSS values related to borders.

use crate::values::generics::rect::Rect;
use crate::values::generics::size::Size;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};

/// A generic value for a single side of a `border-image-width` property.
#[derive(
    Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
)]
pub enum BorderImageSideWidth<LengthPercentage, Number> {
    /// `<length-or-percentage>`
    Length(LengthPercentage),
    /// `<number>`
    Number(Number),
    /// `auto`
    Auto,
}

/// A generic value for the `border-image-slice` property.
#[derive(
    Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
)]
#[repr(C)]
pub struct GenericBorderImageSlice<NumberOrPercentage> {
    /// The offsets.
    #[css(field_bound)]
    pub offsets: Rect<NumberOrPercentage>,
    /// Whether to fill the middle part.
    #[css(represents_keyword)]
    pub fill: bool,
}

pub use self::GenericBorderImageSlice as BorderImageSlice;

/// A generic value for the `border-*-radius` longhand properties.
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToAnimatedZero,
    ToComputedValue,
    ToCss,
)]
pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size<L>);

impl<L> BorderCornerRadius<L> {
    /// Trivially create a `BorderCornerRadius`.
    pub fn new(w: L, h: L) -> Self {
        BorderCornerRadius(Size::new(w, h))
    }
}

/// A generic value for the `border-spacing` property.
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToAnimatedZero,
    ToComputedValue,
    ToCss,
)]
pub struct BorderSpacing<L>(#[css(field_bound)] pub Size<L>);

impl<L> BorderSpacing<L> {
    /// Trivially create a `BorderCornerRadius`.
    pub fn new(w: L, h: L) -> Self {
        BorderSpacing(Size::new(w, h))
    }
}

/// A generic value for `border-radius`, `outline-radius` and `inset()`.
///
/// <https://drafts.csswg.org/css-backgrounds-3/#border-radius>
#[derive(
    Animate,
    Clone,
    ComputeSquaredDistance,
    Copy,
    Debug,
    MallocSizeOf,
    PartialEq,
    SpecifiedValueInfo,
    ToAnimatedValue,
    ToComputedValue,
)]
pub struct BorderRadius<LengthPercentage> {
    /// The top left radius.
    pub top_left: BorderCornerRadius<LengthPercentage>,
    /// The top right radius.
    pub top_right: BorderCornerRadius<LengthPercentage>,
    /// The bottom right radius.
    pub bottom_right: BorderCornerRadius<LengthPercentage>,
    /// The bottom left radius.
    pub bottom_left: BorderCornerRadius<LengthPercentage>,
}

impl<L> BorderRadius<L> {
    /// Returns a new `BorderRadius<L>`.
    #[inline]
    pub fn new(
        tl: BorderCornerRadius<L>,
        tr: BorderCornerRadius<L>,
        br: BorderCornerRadius<L>,
        bl: BorderCornerRadius<L>,
    ) -> Self {
        BorderRadius {
            top_left: tl,
            top_right: tr,
            bottom_right: br,
            bottom_left: bl,
        }
    }
}

impl<L> BorderRadius<L>
where
    L: PartialEq + ToCss,
{
    /// Serialises two given rects following the syntax of the `border-radius``
    /// property.
    pub fn serialize_rects<W>(
        widths: Rect<&L>,
        heights: Rect<&L>,
        dest: &mut CssWriter<W>,
    ) -> fmt::Result
    where
        W: Write,
    {
        widths.to_css(dest)?;
        if widths != heights {
            dest.write_str(" / ")?;
            heights.to_css(dest)?;
        }
        Ok(())
    }
}

impl<L> ToCss for BorderRadius<L>
where
    L: PartialEq + ToCss,
{
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
        let BorderRadius {
            top_left: BorderCornerRadius(ref tl),
            top_right: BorderCornerRadius(ref tr),
            bottom_right: BorderCornerRadius(ref br),
            bottom_left: BorderCornerRadius(ref bl),
        } = *self;

        let widths = Rect::new(&tl.0.width, &tr.0.width, &br.0.width, &bl.0.width);
        let heights = Rect::new(&tl.0.height, &tr.0.height, &br.0.height, &bl.0.height);

        Self::serialize_rects(widths, heights, dest)
    }
}
<|endoftext|>


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

//
// Utilities.
//

// returns an infinite iterator of repeated applications of f to x,
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
fn iterate<'a, T>(f: &'a fn(&T) -> T, x: T) -> Iterate<'a, T> {
    Iterate::new(f, x)
}
struct Iterate<'self, T> {
    priv f: &'self fn(&T) -> T,
    priv next: T
}
impl<'self, T> Iterate<'self, T> {
    fn new<'a>(f: &'a fn(&T) -> T, x: T) -> Iterate<'a, T> {
        Iterate {f: f, next: x}
    }
}
impl<'self, T> Iterator<T> for Iterate<'self, T> {
    fn next(&mut self) -> Option<T> {
        let mut res = (self.f)(&self.next);
        std::util::swap(&mut res, &mut self.next);
        Some(res)
    }
}

// a linked list using borrowed next.
enum List<'self, T> {
    Nil,
    Cons(T, &'self List<'self, T>)
}
struct ListIterator<'self, T> {
    priv cur: &'self List<'self, T>
}
impl<'self, T> List<'self, T> {
    fn iter(&'self self) -> ListIterator<'self, T> {
        ListIterator{cur: self}
    }
}
impl<'self, T> Iterator<&'self T> for ListIterator<'self, T> {
    fn next(&mut self) -> Option<&'self T> {
        match *self.cur {
            Nil => None,
            Cons(ref elt, next) => {
                self.cur = next;
                Some(elt)
            }
        }
    }
}

//
// preprocess
//

// Takes a pieces p on the form [(y1, x1), (y2, x2), ...] and returns
// every possible transformations (the 6 rotations with their
// corresponding mirrored piece), with, as minimum coordinates, (0,
// 0).  If all is false, only generate half of the possibilities (used
// to break the symetry of the board).
fn transform(p: ~[(int, int)], all: bool) -> ~[~[(int, int)]] {
    let mut res =
        // rotations
        iterate(|p| p.iter().map(|&(y, x)| (x + y, -y)).collect(), p)
        .take(if all {6} else {3})
        // mirror
        .flat_map(|p| {
            iterate(|p| p.iter().map(|&(y, x)| (x, y)).collect(), p).take(2)
        }).to_owned_vec();

    // translating to (0, 0) as minimum coordinates.
    for p in res.mut_iter() {
        let (dy, dx) = *p.iter().min_by(|e| *e).unwrap();
        for &(ref mut y, ref mut x) in p.mut_iter() {
            *y -= dy; *x -= dx;
        }
    }

    res
}

// A mask is a piece somewere on the board.  It is represented as a
// u64: for i in the first 50 bits, m[i] = 1 if the cell at (i/5, i%5)
// is occuped.  m[50 + id] = 1 if the identifier of the piece is id.

// Takes a piece with minimum coordinate (0, 0) (as generated by
// transform).  Returns the corresponding mask if p translated by (dy,
// dx) is on the board.
fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option<u64> {
    let mut m = 1 << (50 + id);
    for &(y, x) in p.iter() {
        let x = x + dx + (y + (dy % 2)) / 2;
        if x < 0 || x > 4 {return None;}
        let y = y + dy;
        if y < 0 || y > 9 {return None;}
        m |= 1 << (y * 5 + x);
    }
    Some(m)
}

// Makes every possible masks.  masks[id][i] correspond to every
// possible masks for piece with identifier id with minimum coordinate
// (i/5, i%5).
fn make_masks() -> ~[~[~[u64]]] {
    let pieces = ~[
        ~[(0,0),(0,1),(0,2),(0,3),(1,3)],
        ~[(0,0),(0,2),(0,3),(1,0),(1,1)],
        ~[(0,0),(0,1),(0,2),(1,2),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,1),(2,1)],
        ~[(0,0),(0,2),(1,0),(1,1),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,1),(1,2)],
        ~[(0,0),(0,1),(1,1),(1,2),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,0),(1,2)],
        ~[(0,0),(0,1),(0,2),(1,2),(1,3)],
        ~[(0,0),(0,1),(0,2),(0,3),(1,2)]];
    let mut res = ~[];
    for (id, p) in pieces.move_iter().enumerate() {
        // To break the central symetry of the problem, every
        // transformation must be taken except for one piece (piece 3
        // here).
        let trans = transform(p, id != 3);
        let mut cur_piece = ~[];
        for dy in range(0, 10) {
            for dx in range(0, 5) {
                let masks =
                    trans.iter()
                    .filter_map(|t| mask(dy, dx, id, *t))
                    .collect();
                cur_piece.push(masks);
            }
        }
        res.push(cur_piece);
    }
    res
}

// Check if all coordinates can be covered by an unused piece and that
// all unused piece can be placed on the board.
fn is_board_unfeasible(board: u64, masks: &[~[~[u64]]]) -> bool {
    let mut coverable = board;
    for i in range(0, 50).filter(|&i| board & 1 << i == 0) {
        for (cur_id, pos_masks) in masks.iter().enumerate() {
            if board & 1 << (50 + cur_id) != 0 {continue;}
            for &cur_m in pos_masks[i].iter() {
                if cur_m & board == 0 {coverable |= cur_m;}
            }
        }
        if coverable & (1 << i) == 0 {return true;}
    }
    // check if every coordinates can be covered and every piece can
    // be used.
    coverable != (1 << 60) - 1
}

// Filter the masks that we can prove to result to unfeasible board.
fn filter_masks(masks: &[~[~[u64]]]) -> ~[~[~[u64]]] {
    masks.iter().map(
        |p| p.iter().map(
            |p| p.iter()
                .map(|&m| m)
                .filter(|&m| !is_board_unfeasible(m, masks))
                .collect())
            .collect())
        .collect()
}

// Gets the identifier of a mask.
fn get_id(m: u64) -> u8 {
    for id in range(0, 10) {
        if m & (1 << (id + 50)) != 0 {return id as u8;}
    }
    fail!("{:016x} does not have a valid identifier", m);
}

// Converts a list of mask to a ~str.
fn to_utf8(raw_sol: &List<u64>) -> ~str {
    let mut sol: ~[u8] = std::vec::from_elem(50, '.' as u8);
    for &m in raw_sol.iter() {
        let id = get_id(m);
        for i in range(0, 50) {
            if m & 1 << i != 0 {sol[i] = '0' as u8 + id;}
        }
    }
    std::str::from_utf8_owned(sol)
}

// Prints a solution in ~str form.
fn print_sol(sol: &str) {
    for (i, c) in sol.iter().enumerate() {
        if (i) % 5 == 0 {println("");}
        if (i + 5) % 10 == 0 {print(" ");}
        print!("{} ", c);
    }
    println("");
}

// The data managed during the search
struct Data {
    // If more than stop_after is found, stop the search.
    stop_after: int,
    // Number of solution found.
    nb: int,
    // Lexicographically minimal solution found.
    min: ~str,
    // Lexicographically maximal solution found.
    max: ~str
}

// Records a new found solution.  Returns false if the search must be
// stopped.
fn handle_sol(raw_sol: &List<u64>, data: &mut Data) -> bool {
    // because we break the symetry, 2 solutions correspond to a call
    // to this method: the normal solution, and the same solution in
    // reverse order, i.e. the board rotated by half a turn.
    data.nb += 2;
    let sol1 = to_utf8(raw_sol);
    let sol2: ~str = sol1.iter().invert().collect();

    if data.nb == 2 {
        data.min = sol1.clone();
        data.max = sol1.clone();
    }

    if sol1 < data.min {data.min = sol1.clone();}
    if sol2 < data.min {data.min = sol2.clone();}
    if sol1 > data.max {data.max = sol1;}
    if sol2 > data.max {data.max = sol2;}
    data.nb < data.stop_after
}

// Search for every solutions.  Returns false if the search was
// stopped before the end.
fn search(
    masks: &[~[~[u64]]],
    board: u64,
    mut i: int,
    cur: List<u64>,
    data: &mut Data)
    -> bool
{
    // Search for the lesser empty coordinate.
    while board & (1 << i)  != 0 && i < 50 {i += 1;}
    // the board is full: a solution is found.
    if i >= 50 {return handle_sol(&cur, data);}

    // for every unused piece
    for id in range(0, 10).filter(|id| board & (1 << (id + 50)) == 0) {
        // for each mask that fits on the board
        for &m in masks[id][i].iter().filter(|&m| board & *m == 0) {
            // This check is too costy.
            //if is_board_unfeasible(board | m, masks) {continue;}
            if !search(masks, board | m, i + 1, Cons(m, &cur), data) {
                return false;
            }
        }
    }
    return true;
}

fn main () {
    let args = std::os::args();
    let stop_after = if args.len() <= 1 {
        2098
    } else {
        from_str(args[1]).unwrap()
    };
    let masks = make_masks();
    let masks = filter_masks(masks);
    let mut data = Data {stop_after: stop_after, nb: 0, min: ~"", max: ~""};
    search(masks, 0, 0, Nil, &mut data);
    println!("{} solutions found", data.nb);
    print_sol(data.min);
    print_sol(data.max);
    println("");
}
<commit_msg>remove useless Iterate impl, and permute the order of the argument of iterate<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//
// Utilities.
//

// returns an infinite iterator of repeated applications of f to x,
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
fn iterate<'a, T>(x: T, f: &'a fn(&T) -> T) -> Iterate<'a, T> {
    Iterate {f: f, next: x}
}
struct Iterate<'self, T> {
    priv f: &'self fn(&T) -> T,
    priv next: T
}
impl<'self, T> Iterator<T> for Iterate<'self, T> {
    fn next(&mut self) -> Option<T> {
        let mut res = (self.f)(&self.next);
        std::util::swap(&mut res, &mut self.next);
        Some(res)
    }
}

// a linked list using borrowed next.
enum List<'self, T> {
    Nil,
    Cons(T, &'self List<'self, T>)
}
struct ListIterator<'self, T> {
    priv cur: &'self List<'self, T>
}
impl<'self, T> List<'self, T> {
    fn iter(&'self self) -> ListIterator<'self, T> {
        ListIterator{cur: self}
    }
}
impl<'self, T> Iterator<&'self T> for ListIterator<'self, T> {
    fn next(&mut self) -> Option<&'self T> {
        match *self.cur {
            Nil => None,
            Cons(ref elt, next) => {
                self.cur = next;
                Some(elt)
            }
        }
    }
}

//
// preprocess
//

// Takes a pieces p on the form [(y1, x1), (y2, x2), ...] and returns
// every possible transformations (the 6 rotations with their
// corresponding mirrored piece), with, as minimum coordinates, (0,
// 0).  If all is false, only generate half of the possibilities (used
// to break the symetry of the board).
fn transform(p: ~[(int, int)], all: bool) -> ~[~[(int, int)]] {
    let mut res =
        // rotations
        iterate(p, |p| p.iter().map(|&(y, x)| (x + y, -y)).collect())
        .take(if all {6} else {3})
        // mirror
        .flat_map(|p| {
            iterate(p, |p| p.iter().map(|&(y, x)| (x, y)).collect()).take(2)
        }).to_owned_vec();

    // translating to (0, 0) as minimum coordinates.
    for p in res.mut_iter() {
        let (dy, dx) = *p.iter().min_by(|e| *e).unwrap();
        for &(ref mut y, ref mut x) in p.mut_iter() {
            *y -= dy; *x -= dx;
        }
    }

    res
}

// A mask is a piece somewere on the board.  It is represented as a
// u64: for i in the first 50 bits, m[i] = 1 if the cell at (i/5, i%5)
// is occuped.  m[50 + id] = 1 if the identifier of the piece is id.

// Takes a piece with minimum coordinate (0, 0) (as generated by
// transform).  Returns the corresponding mask if p translated by (dy,
// dx) is on the board.
fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option<u64> {
    let mut m = 1 << (50 + id);
    for &(y, x) in p.iter() {
        let x = x + dx + (y + (dy % 2)) / 2;
        if x < 0 || x > 4 {return None;}
        let y = y + dy;
        if y < 0 || y > 9 {return None;}
        m |= 1 << (y * 5 + x);
    }
    Some(m)
}

// Makes every possible masks.  masks[id][i] correspond to every
// possible masks for piece with identifier id with minimum coordinate
// (i/5, i%5).
fn make_masks() -> ~[~[~[u64]]] {
    let pieces = ~[
        ~[(0,0),(0,1),(0,2),(0,3),(1,3)],
        ~[(0,0),(0,2),(0,3),(1,0),(1,1)],
        ~[(0,0),(0,1),(0,2),(1,2),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,1),(2,1)],
        ~[(0,0),(0,2),(1,0),(1,1),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,1),(1,2)],
        ~[(0,0),(0,1),(1,1),(1,2),(2,1)],
        ~[(0,0),(0,1),(0,2),(1,0),(1,2)],
        ~[(0,0),(0,1),(0,2),(1,2),(1,3)],
        ~[(0,0),(0,1),(0,2),(0,3),(1,2)]];
    let mut res = ~[];
    for (id, p) in pieces.move_iter().enumerate() {
        // To break the central symetry of the problem, every
        // transformation must be taken except for one piece (piece 3
        // here).
        let trans = transform(p, id != 3);
        let mut cur_piece = ~[];
        for dy in range(0, 10) {
            for dx in range(0, 5) {
                let masks =
                    trans.iter()
                    .filter_map(|t| mask(dy, dx, id, *t))
                    .collect();
                cur_piece.push(masks);
            }
        }
        res.push(cur_piece);
    }
    res
}

// Check if all coordinates can be covered by an unused piece and that
// all unused piece can be placed on the board.
fn is_board_unfeasible(board: u64, masks: &[~[~[u64]]]) -> bool {
    let mut coverable = board;
    for i in range(0, 50).filter(|&i| board & 1 << i == 0) {
        for (cur_id, pos_masks) in masks.iter().enumerate() {
            if board & 1 << (50 + cur_id) != 0 {continue;}
            for &cur_m in pos_masks[i].iter() {
                if cur_m & board == 0 {coverable |= cur_m;}
            }
        }
        if coverable & (1 << i) == 0 {return true;}
    }
    // check if every coordinates can be covered and every piece can
    // be used.
    coverable != (1 << 60) - 1
}

// Filter the masks that we can prove to result to unfeasible board.
fn filter_masks(masks: &[~[~[u64]]]) -> ~[~[~[u64]]] {
    masks.iter().map(
        |p| p.iter().map(
            |p| p.iter()
                .map(|&m| m)
                .filter(|&m| !is_board_unfeasible(m, masks))
                .collect())
            .collect())
        .collect()
}

// Gets the identifier of a mask.
fn get_id(m: u64) -> u8 {
    for id in range(0, 10) {
        if m & (1 << (id + 50)) != 0 {return id as u8;}
    }
    fail!("{:016x} does not have a valid identifier", m);
}

// Converts a list of mask to a ~str.
fn to_utf8(raw_sol: &List<u64>) -> ~str {
    let mut sol: ~[u8] = std::vec::from_elem(50, '.' as u8);
    for &m in raw_sol.iter() {
        let id = get_id(m);
        for i in range(0, 50) {
            if m & 1 << i != 0 {sol[i] = '0' as u8 + id;}
        }
    }
    std::str::from_utf8_owned(sol)
}

// Prints a solution in ~str form.
fn print_sol(sol: &str) {
    for (i, c) in sol.iter().enumerate() {
        if (i) % 5 == 0 {println("");}
        if (i + 5) % 10 == 0 {print(" ");}
        print!("{} ", c);
    }
    println("");
}

// The data managed during the search
struct Data {
    // If more than stop_after is found, stop the search.
    stop_after: int,
    // Number of solution found.
    nb: int,
    // Lexicographically minimal solution found.
    min: ~str,
    // Lexicographically maximal solution found.
    max: ~str
}

// Records a new found solution.  Returns false if the search must be
// stopped.
fn handle_sol(raw_sol: &List<u64>, data: &mut Data) -> bool {
    // because we break the symetry, 2 solutions correspond to a call
    // to this method: the normal solution, and the same solution in
    // reverse order, i.e. the board rotated by half a turn.
    data.nb += 2;
    let sol1 = to_utf8(raw_sol);
    let sol2: ~str = sol1.iter().invert().collect();

    if data.nb == 2 {
        data.min = sol1.clone();
        data.max = sol1.clone();
    }

    if sol1 < data.min {data.min = sol1.clone();}
    if sol2 < data.min {data.min = sol2.clone();}
    if sol1 > data.max {data.max = sol1;}
    if sol2 > data.max {data.max = sol2;}
    data.nb < data.stop_after
}

// Search for every solutions.  Returns false if the search was
// stopped before the end.
fn search(
    masks: &[~[~[u64]]],
    board: u64,
    mut i: int,
    cur: List<u64>,
    data: &mut Data)
    -> bool
{
    // Search for the lesser empty coordinate.
    while board & (1 << i)  != 0 && i < 50 {i += 1;}
    // the board is full: a solution is found.
    if i >= 50 {return handle_sol(&cur, data);}

    // for every unused piece
    for id in range(0, 10).filter(|id| board & (1 << (id + 50)) == 0) {
        // for each mask that fits on the board
        for &m in masks[id][i].iter().filter(|&m| board & *m == 0) {
            // This check is too costy.
            //if is_board_unfeasible(board | m, masks) {continue;}
            if !search(masks, board | m, i + 1, Cons(m, &cur), data) {
                return false;
            }
        }
    }
    return true;
}

fn main () {
    let args = std::os::args();
    let stop_after = if args.len() <= 1 {
        2098
    } else {
        from_str(args[1]).unwrap()
    };
    let masks = make_masks();
    let masks = filter_masks(masks);
    let mut data = Data {stop_after: stop_after, nb: 0, min: ~"", max: ~""};
    search(masks, 0, 0, Nil, &mut data);
    println!("{} solutions found", data.nb);
    print_sol(data.min);
    print_sol(data.max);
    println("");
}
<|endoftext|>


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

#![feature(asm)]

use std::io::process::Command;
use std::os;

// lifted from the test module
// Inlining to avoid llvm turning the recursive functions into tail calls,
// which doesn't consume stack.
#[inline(always)]
pub fn black_box<T>(dummy: T) { unsafe { asm!("" : : "r"(&dummy)) } }

fn silent_recurse() {
    let buf = [0i, ..1000];
    black_box(buf);
    silent_recurse();
}

fn loud_recurse() {
    println!("hello!");
    loud_recurse();
    black_box(()); // don't optimize this into a tail call. please.
}

fn main() {
    let args = os::args();
    let args = args.as_slice();
    if args.len() > 1 && args[1].as_slice() == "silent" {
        silent_recurse();
    } else if args.len() > 1 && args[1].as_slice() == "loud" {
        loud_recurse();
    } else {
        let silent = Command::new(args[0].as_slice()).arg("silent").output().unwrap();
        assert!(!silent.status.success());
        let error = String::from_utf8_lossy(silent.error.as_slice());
        assert!(error.as_slice().contains("has overflowed its stack"));

        let loud = Command::new(args[0].as_slice()).arg("loud").output().unwrap();
        assert!(!loud.status.success());
        let error = String::from_utf8_lossy(silent.error.as_slice());
        assert!(error.as_slice().contains("has overflowed its stack"));
    }
}
<commit_msg>Disable stack overflow test on android, which seems to be failing spuriously.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android: FIXME (#20004)

#![feature(asm)]

use std::io::process::Command;
use std::os;

// lifted from the test module
// Inlining to avoid llvm turning the recursive functions into tail calls,
// which doesn't consume stack.
#[inline(always)]
pub fn black_box<T>(dummy: T) { unsafe { asm!("" : : "r"(&dummy)) } }

fn silent_recurse() {
    let buf = [0i, ..1000];
    black_box(buf);
    silent_recurse();
}

fn loud_recurse() {
    println!("hello!");
    loud_recurse();
    black_box(()); // don't optimize this into a tail call. please.
}

fn main() {
    let args = os::args();
    let args = args.as_slice();
    if args.len() > 1 && args[1].as_slice() == "silent" {
        silent_recurse();
    } else if args.len() > 1 && args[1].as_slice() == "loud" {
        loud_recurse();
    } else {
        let silent = Command::new(args[0].as_slice()).arg("silent").output().unwrap();
        assert!(!silent.status.success());
        let error = String::from_utf8_lossy(silent.error.as_slice());
        assert!(error.as_slice().contains("has overflowed its stack"));

        let loud = Command::new(args[0].as_slice()).arg("loud").output().unwrap();
        assert!(!loud.status.success());
        let error = String::from_utf8_lossy(silent.error.as_slice());
        assert!(error.as_slice().contains("has overflowed its stack"));
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Tool that converts a jed to a json file

use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

extern crate yosys_netlist_json;
use yosys_netlist_json::*;

fn main() {
    let args = ::std::env::args().collect::<Vec<_>>();

    if args.len() != 2 {
        println!("Usage: {} file.jed", args[0]);
        ::std::process::exit(1);
    }

    // Load the jed
    let mut f = File::open(&args[1]).expect("failed to open file");
    let mut data = Vec::new();
    f.read_to_end(&mut data).expect("failed to read data");

    let bits_result = read_jed(&data);
    let (bits, device_name_option) = bits_result.expect("failed to read jed");
    let device_name = device_name_option.expect("missing device name in jed");

    let bitstream_result = XC2Bitstream::from_jed(&bits, &device_name);
    let bitstream = bitstream_result.expect("failed to process jed");

    // Because of how the closures work, we unfortunately need to use a RefCell here
    let output_netlist = RefCell::new(Netlist::default());
    let node_vec = RefCell::new(Vec::new());
    // Skip 0 and 1 just like yosys does
    let wire_idx = RefCell::new(2);

    // Create common/global stuff ahead of time
    {
        let mut output_netlist_mut = output_netlist.borrow_mut();
        // TOOD: Proper version number
        output_netlist_mut.creator = String::from("xc2bit xc2jed2json utility - DEVELOPMENT VERSION");

        let mut module = Module::default();
        module.attributes.insert(String::from("PART_NAME"),
            AttributeVal::S(format!("{}", bitstream.bits.device_type())));
        module.attributes.insert(String::from("PART_SPEED"),
            AttributeVal::S(format!("{}", bitstream.speed_grade)));
        module.attributes.insert(String::from("PART_PKG"),
            AttributeVal::S(format!("{}", bitstream.package)));

        output_netlist_mut.modules.insert(String::from("top"), module);
    }

    // Call the giant structure callback
    get_device_structure(bitstream.bits.device_type(),
        |node_name: &str, node_type: &str, fb: u32, idx: u32| {
            // Start constructing the cell object
            let cell;

            match node_type {
                "BUFG" | "BUFGSR" | "BUFGTS" => {
                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                "IOBUFE" => {
                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(format!("PAD_{}", idx), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(format!("PAD_{}", idx), Port {
                            direction: PortDirection::InOut,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("E"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("IO"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                // FIXME: Boilerplate
                "IBUF" => {
                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(String::from("INPAD"), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(String::from("INPAD"), Port {
                            direction: PortDirection::Input,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut connections = HashMap::new();
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("I"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                _ => {
                    // FIXME
                    println!("{} is not implemented!", node_type);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: String::from("FIXME FIXME FIXME"),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: HashMap::new(),
                    }
                },
            }

            // Create the cell in the output module
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut cells = &mut output_netlist_mut.modules.get_mut("top").unwrap().cells;
            cells.insert(node_name.to_owned(), cell);

            // Memoization needed for the callback interface
            let mut node_vec = node_vec.borrow_mut();
            node_vec.push((node_name.to_owned(), node_type.to_owned(), fb, idx));
            node_vec.len() - 1
        },
        |wire_name: &str| {
            // Create the net in the output module
            let orig_wire_idx = {*wire_idx.borrow()};
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
            netnames.insert(wire_name.to_owned(), Netname {
                hide_name: 0,
                bits: vec![BitVal::N(orig_wire_idx)],
                attributes: HashMap::new(),
            });

            // Return the current wire index
            *wire_idx.borrow_mut() += 1;
            orig_wire_idx
        },
        |node_ref: usize, wire_ref: usize, port_name: &str, port_idx: u32| {
        }
    );

    // Write the final output
    output_netlist.borrow().to_writer(&mut ::std::io::stdout()).expect("failed to write json");
}
<commit_msg>xc2bit-jed2json: Output all cell types to json<commit_after>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Tool that converts a jed to a json file

use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

extern crate yosys_netlist_json;
use yosys_netlist_json::*;

fn main() {
    let args = ::std::env::args().collect::<Vec<_>>();

    if args.len() != 2 {
        println!("Usage: {} file.jed", args[0]);
        ::std::process::exit(1);
    }

    // Load the jed
    let mut f = File::open(&args[1]).expect("failed to open file");
    let mut data = Vec::new();
    f.read_to_end(&mut data).expect("failed to read data");

    let bits_result = read_jed(&data);
    let (bits, device_name_option) = bits_result.expect("failed to read jed");
    let device_name = device_name_option.expect("missing device name in jed");

    let bitstream_result = XC2Bitstream::from_jed(&bits, &device_name);
    let bitstream = bitstream_result.expect("failed to process jed");

    // Because of how the closures work, we unfortunately need to use a RefCell here
    let output_netlist = RefCell::new(Netlist::default());
    let node_vec = RefCell::new(Vec::new());
    // Skip 0 and 1 just like yosys does
    let wire_idx = RefCell::new(2);

    // Create common/global stuff ahead of time
    {
        let mut output_netlist_mut = output_netlist.borrow_mut();
        // TOOD: Proper version number
        output_netlist_mut.creator = String::from("xc2bit xc2jed2json utility - DEVELOPMENT VERSION");

        let mut module = Module::default();
        module.attributes.insert(String::from("PART_NAME"),
            AttributeVal::S(format!("{}", bitstream.bits.device_type())));
        module.attributes.insert(String::from("PART_SPEED"),
            AttributeVal::S(format!("{}", bitstream.speed_grade)));
        module.attributes.insert(String::from("PART_PKG"),
            AttributeVal::S(format!("{}", bitstream.package)));

        output_netlist_mut.modules.insert(String::from("top"), module);
    }

    // Call the giant structure callback
    get_device_structure(bitstream.bits.device_type(),
        |node_name: &str, node_type: &str, fb: u32, idx: u32| {
            // Start constructing the cell object
            let cell;

            match node_type {
                "BUFG" | "BUFGSR" | "BUFGTS" => {
                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes: HashMap::new(),
                        port_directions: HashMap::new(),
                        connections: connections,
                    }
                },
                "IOBUFE" => {
                    let (fb, mc) = iob_num_to_fb_mc_num(bitstream.bits.device_type(), idx).unwrap();

                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(format!("PAD_FB{}_{}", fb + 1, mc + 1), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(format!("PAD_FB{}_{}", fb + 1, mc + 1), Port {
                            direction: PortDirection::InOut,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(format!("FB{}_{}", fb + 1, mc + 1)));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("I"), Vec::new());
                    connections.insert(String::from("E"), Vec::new());
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("IO"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                // FIXME: Boilerplate, copy-pasta
                "IBUF" => {
                    // Construct the wire for the toplevel port
                    let toplevel_wire = {
                        let orig_wire_idx = {*wire_idx.borrow()};
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
                        netnames.insert(String::from("INPAD"), Netname {
                            hide_name: 0,
                            bits: vec![BitVal::N(orig_wire_idx)],
                            attributes: HashMap::new(),
                        });

                        // Return the current wire index
                        *wire_idx.borrow_mut() += 1;
                        orig_wire_idx
                    };

                    // Construct the toplevel port
                    {
                        let mut output_netlist_mut = output_netlist.borrow_mut();
                        let mut ports = &mut output_netlist_mut.modules.get_mut("top").unwrap().ports;
                        ports.insert(String::from("INPAD"), Port {
                            direction: PortDirection::Input,
                            bits: vec![BitVal::N(toplevel_wire)],
                        });
                    }

                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(String::from("INPAD")));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("O"), Vec::new());
                    connections.insert(String::from("I"), vec![BitVal::N(toplevel_wire)]);
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                "ANDTERM" => {
                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(format!("FB{}_P{}", fb + 1, idx)));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("IN"), Vec::new());
                    connections.insert(String::from("IN_B"), Vec::new());
                    connections.insert(String::from("OUT"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                "ORTERM" => {
                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(format!("FB{}_{}", fb + 1, idx + 1)));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("IN"), Vec::new());
                    connections.insert(String::from("OUT"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                "MACROCELL_XOR" => {
                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(format!("FB{}_{}", fb + 1, idx + 1)));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("IN_PTC"), Vec::new());
                    connections.insert(String::from("IN_ORTERM"), Vec::new());
                    connections.insert(String::from("OUT"), Vec::new());
                    cell = Cell {
                        hide_name: 0,
                        cell_type: node_type.to_owned(),
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                "REG" => {
                    let mut attributes = HashMap::new();
                    attributes.insert(String::from("LOC"), AttributeVal::S(format!("FB{}_{}", fb + 1, idx + 1)));
                    let mut connections = HashMap::new();
                    connections.insert(String::from("Q"), Vec::new());
                    connections.insert(String::from("PRE"), Vec::new());
                    connections.insert(String::from("CLR"), Vec::new());

                    let cell_type;
                    let mc = &bitstream.bits.get_fb()[fb as usize].mcs[idx as usize];
                    match mc.reg_mode {
                        XC2MCRegMode::DFF => {
                            connections.insert(String::from("C"), Vec::new());
                            connections.insert(String::from("D"), Vec::new());

                            if mc.is_ddr {
                                cell_type = String::from("FDDCP");
                            } else {
                                if !mc.clk_invert_pol {
                                    cell_type = String::from("FDCP");
                                } else {
                                    cell_type = String::from("FDCP_N");
                                }
                            }
                        },
                        XC2MCRegMode::LATCH => {
                            connections.insert(String::from("G"), Vec::new());
                            connections.insert(String::from("D"), Vec::new());

                            if !mc.clk_invert_pol {
                                cell_type = String::from("LDCP");
                            } else {
                                cell_type = String::from("LDCP_N");
                            }
                        },
                        XC2MCRegMode::TFF => {
                            connections.insert(String::from("C"), Vec::new());
                            connections.insert(String::from("T"), Vec::new());

                            if mc.is_ddr {
                                cell_type = String::from("FTDCP");
                            } else {
                                if !mc.clk_invert_pol {
                                    cell_type = String::from("FTCP");
                                } else {
                                    cell_type = String::from("FTCP_N");
                                }
                            }
                        },
                        XC2MCRegMode::DFFCE => {
                            connections.insert(String::from("C"), Vec::new());
                            connections.insert(String::from("D"), Vec::new());
                            connections.insert(String::from("CE"), Vec::new());

                            if mc.is_ddr {
                                cell_type = String::from("FDDCPE");
                            } else {
                                if !mc.clk_invert_pol {
                                    cell_type = String::from("FDCPE");
                                } else {
                                    cell_type = String::from("FDCPE_N");
                                }
                            }
                        }
                    }

                    cell = Cell {
                        hide_name: 0,
                        cell_type,
                        parameters: HashMap::new(),
                        attributes,
                        port_directions: HashMap::new(),
                        connections,
                    }
                },
                _ => unreachable!()
            }

            // Create the cell in the output module
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut cells = &mut output_netlist_mut.modules.get_mut("top").unwrap().cells;
            cells.insert(node_name.to_owned(), cell);

            // Memoization needed for the callback interface
            let mut node_vec = node_vec.borrow_mut();
            node_vec.push((node_name.to_owned(), node_type.to_owned(), fb, idx));
            node_vec.len() - 1
        },
        |wire_name: &str| {
            // Create the net in the output module
            let orig_wire_idx = {*wire_idx.borrow()};
            let mut output_netlist_mut = output_netlist.borrow_mut();
            let mut netnames = &mut output_netlist_mut.modules.get_mut("top").unwrap().netnames;
            netnames.insert(wire_name.to_owned(), Netname {
                hide_name: 0,
                bits: vec![BitVal::N(orig_wire_idx)],
                attributes: HashMap::new(),
            });

            // Return the current wire index
            *wire_idx.borrow_mut() += 1;
            orig_wire_idx
        },
        |node_ref: usize, wire_ref: usize, port_name: &str, port_idx: u32| {
        }
    );

    // Write the final output
    output_netlist.borrow().to_writer(&mut ::std::io::stdout()).expect("failed to write json");
}
<|endoftext|>


<commit_before>use crate::types;

use super::auto::{HasInner, Abstract, Spawnable};
use super::container::AContainer;
use super::item_clickable::{ItemClickable, ItemClickableInner};
use super::adapted::{AAdapted, Adapted, AdaptedInner};
use super::control::{AControl, Control, ControlInner};
use super::member::{AMember, Member};
use super::adapter::Node;

define! {
    Tree: Control + Adapted + ItemClickable {
	    /*base: {
            pub on_item_click: Option<OnItemClick>,
        }*/
	    inner: {}
	    outer: {}
	    constructor: {
    	    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree>;
	    }
	    extends: { ItemClickable }
    }
}

/*impl<T: TreeInner + 'static> ATree<T> {
    #[inline]
    pub fn with_inner(inner: T) -> Self {
        Self { base: TreeBase { on_item_click: None }, inner }
    }
}*/
impl<II: TreeInner, T: HasInner<I = II> + Abstract + 'static> TreeInner for T {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        <<Self as HasInner>::I as TreeInner>::with_adapter(adapter)
    }
}
impl<T: TreeInner> NewTree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        T::with_adapter(adapter)
    }
}
// hello E0119
/*impl<T: TreeInner> ItemClickable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn on_item_click(&mut self, cb: Option<OnItemClick>) {
        self.inner.inner.inner.inner.base.on_item_click = cb;
    }
    #[inline]
    fn item_click(&mut self, arg: usize, item_view: &mut dyn Control, skip_callbacks: bool) {
        if !skip_callbacks{
            let self2 = self as *mut Self;
            if let Some(ref mut callback) = self.inner.inner.inner.inner.base.on_item_click {
                (callback.as_mut())(unsafe { &mut *self2 }, arg, item_view)
            }
        }
    }
    #[inline]
    fn as_item_clickable(&self) -> &dyn ItemClickable {
        self
    }
    #[inline]
    fn as_item_clickable_mut(&mut self) -> &mut dyn ItemClickable {
        self
    }
    #[inline]
    fn into_item_clickable(self: Box<Self>) -> Box<dyn ItemClickable> {
        self
    }
}*/

impl<T: TreeInner> Tree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn as_tree(&self) -> &dyn Tree {
        self
    }
    #[inline]
    fn as_tree_mut(&mut self) -> &mut dyn Tree {
        self
    }
    #[inline]
    fn into_tree(self: Box<Self>) -> Box<dyn Tree> {
        self
    }
}

impl<T: TreeInner> Spawnable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    fn spawn() -> Box<dyn Control> {
        <T as Spawnable>::spawn()
    }
}

pub struct TreeNode<T: Sized> {
    pub node: Node,
    pub root: Box<dyn Control>,
    pub native: T,
    pub branches: Vec<Self>,
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNode<T> {
	type Output = Self;
	fn index(&self, index: I) -> &Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNode<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &mut ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

pub struct TreeNodeList<T: Sized> (pub Vec<TreeNode<T>>);

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNodeList<T> {
	type Output = TreeNode<T>;
	fn index(&self, index: I) -> &Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&self.0.as_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNodeList<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&mut self.0.as_mut_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized> std::ops::Deref for TreeNodeList<T> {
	type Target = [TreeNode<T>];
	fn deref(&self) -> &Self::Target {
		self.0.as_slice()
	}
}
impl<T: Sized> std::ops::DerefMut for TreeNodeList<T> {
	fn deref_mut(&mut self) -> &mut Self::Target {
		self.0.as_mut_slice()
	}
}
<commit_msg>Tree item width update<commit_after>use crate::types;

use super::auto::{HasInner, Abstract, Spawnable};
use super::container::AContainer;
use super::item_clickable::{ItemClickable, ItemClickableInner};
use super::adapted::{AAdapted, Adapted, AdaptedInner};
use super::control::{AControl, Control, ControlInner};
use super::member::{AMember, Member};
use super::adapter::Node;

define! {
    Tree: Control + Adapted + ItemClickable {
	    /*base: {
            pub on_item_click: Option<OnItemClick>,
        }*/
	    inner: {}
	    outer: {}
	    constructor: {
    	    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree>;
	    }
	    extends: { ItemClickable }
    }
}

/*impl<T: TreeInner + 'static> ATree<T> {
    #[inline]
    pub fn with_inner(inner: T) -> Self {
        Self { base: TreeBase { on_item_click: None }, inner }
    }
}*/
impl<II: TreeInner, T: HasInner<I = II> + Abstract + 'static> TreeInner for T {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        <<Self as HasInner>::I as TreeInner>::with_adapter(adapter)
    }
}
impl<T: TreeInner> NewTree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn with_adapter(adapter: Box<dyn types::Adapter>) -> Box<dyn Tree> {
        T::with_adapter(adapter)
    }
}
// hello E0119
/*impl<T: TreeInner> ItemClickable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn on_item_click(&mut self, cb: Option<OnItemClick>) {
        self.inner.inner.inner.inner.base.on_item_click = cb;
    }
    #[inline]
    fn item_click(&mut self, arg: usize, item_view: &mut dyn Control, skip_callbacks: bool) {
        if !skip_callbacks{
            let self2 = self as *mut Self;
            if let Some(ref mut callback) = self.inner.inner.inner.inner.base.on_item_click {
                (callback.as_mut())(unsafe { &mut *self2 }, arg, item_view)
            }
        }
    }
    #[inline]
    fn as_item_clickable(&self) -> &dyn ItemClickable {
        self
    }
    #[inline]
    fn as_item_clickable_mut(&mut self) -> &mut dyn ItemClickable {
        self
    }
    #[inline]
    fn into_item_clickable(self: Box<Self>) -> Box<dyn ItemClickable> {
        self
    }
}*/

impl<T: TreeInner> Tree for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    #[inline]
    fn as_tree(&self) -> &dyn Tree {
        self
    }
    #[inline]
    fn as_tree_mut(&mut self) -> &mut dyn Tree {
        self
    }
    #[inline]
    fn into_tree(self: Box<Self>) -> Box<dyn Tree> {
        self
    }
}

impl<T: TreeInner> Spawnable for AMember<AControl<AContainer<AAdapted<ATree<T>>>>> {
    fn spawn() -> Box<dyn Control> {
        <T as Spawnable>::spawn()
    }
}

pub struct TreeNode<T: Sized> {
    pub expanded: bool,
    pub root: Box<dyn Control>,
    pub native: T,
    pub branches: Vec<Self>,
}

impl<T: Sized> TreeNode<T> {
	pub fn node(&self) -> Node {
		if self.branches.len() == 0 {
			Node::Leaf
		} else {
			Node::Branch(self.expanded)
		}
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNode<T> {
	type Output = Self;
	fn index(&self, index: I) -> &Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNode<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let mut i = 0;
		let index = index.as_ref();
		let mut ret = self;
		while i < index.len() {
			ret = &mut ret.branches[index[i]];
			i += 1;
		}
		ret
	}
}

pub struct TreeNodeList<T: Sized> (pub Vec<TreeNode<T>>);

impl<T: Sized, I: AsRef<[usize]>> std::ops::Index<I> for TreeNodeList<T> {
	type Output = TreeNode<T>;
	fn index(&self, index: I) -> &Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&self.0.as_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized, I: AsRef<[usize]>> std::ops::IndexMut<I> for TreeNodeList<T> {
	fn index_mut(&mut self, index: I) -> &mut Self::Output {
		let index = index.as_ref();
		if index.len() < 1 {
			panic!("Empty index!");
		}
		&mut self.0.as_mut_slice()[index[0]][index[1..].as_ref()]
	}
}

impl<T: Sized> std::ops::Deref for TreeNodeList<T> {
	type Target = [TreeNode<T>];
	fn deref(&self) -> &Self::Target {
		self.0.as_slice()
	}
}
impl<T: Sized> std::ops::DerefMut for TreeNodeList<T> {
	fn deref_mut(&mut self) -> &mut Self::Target {
		self.0.as_mut_slice()
	}
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

type Context = vitral::Context<usize, Vertex>;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: &glium::Display) -> Backend {
        let program = program!(
            display,
            150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex_coord;

                out vec4 v_color;
                out vec2 v_tex_coord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    v_color = color;
                    v_tex_coord = tex_coord;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 v_color;
                in vec2 v_tex_coord;
                out vec4 f_color;

                void main() {
                    f_color = v_color * texture(tex, v_tex_coord);
                }
            "})
                          .unwrap();

        Backend {
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, display: &glium::Display, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(), dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(display, raw).unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self,
                         display: &glium::Display,
                         context: &mut vitral::Context<usize, V>)
                         -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => context.input_mouse_move(x, y),
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    if let Some(vk) = match vk {
                        Tab => Some(vitral::Keycode::Tab),
                        LShift | RShift => Some(vitral::Keycode::Shift),
                        LControl | RControl => Some(vitral::Keycode::Ctrl),
                        NumpadEnter | Return => Some(vitral::Keycode::Enter),
                        Back => Some(vitral::Keycode::Backspace),
                        Delete => Some(vitral::Keycode::Del),
                        Numpad8 | Up => Some(vitral::Keycode::Up),
                        Numpad2 | Down => Some(vitral::Keycode::Down),
                        Numpad4 | Left => Some(vitral::Keycode::Left),
                        Numpad6 | Right => Some(vitral::Keycode::Right),
                        _ => None,
                    } {
                        context.input_key_state(vk, is_down);
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self,
                     display: &glium::Display,
                     context: &mut vitral::Context<usize, V>)
                     -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(display, &batch.vertices).unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(display, context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex_coord: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex_coord);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], tex_coord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex_coord: tex_coord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

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

    // Construct Vitral context.
    let mut context: Context;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png")).unwrap());
    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image, Point2D::new(100.0, 100.0), [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<commit_msg>Don't use compressed textures<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

type Context = vitral::Context<usize, Vertex>;

type GliumTexture = glium::texture::SrgbTexture2d;

struct Backend {
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: &glium::Display) -> Backend {
        let program = program!(
            display,
            150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex_coord;

                out vec4 v_color;
                out vec2 v_tex_coord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    v_color = color;
                    v_tex_coord = tex_coord;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 v_color;
                in vec2 v_tex_coord;
                out vec4 f_color;

                void main() {
                    f_color = v_color * texture(tex, v_tex_coord);
                }
            "})
                          .unwrap();

        Backend {
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, display: &glium::Display, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(), dim);
        let tex = glium::texture::SrgbTexture2d::new(display, raw).unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self,
                         display: &glium::Display,
                         context: &mut vitral::Context<usize, V>)
                         -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => context.input_mouse_move(x, y),
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    if let Some(vk) = match vk {
                        Tab => Some(vitral::Keycode::Tab),
                        LShift | RShift => Some(vitral::Keycode::Shift),
                        LControl | RControl => Some(vitral::Keycode::Ctrl),
                        NumpadEnter | Return => Some(vitral::Keycode::Enter),
                        Back => Some(vitral::Keycode::Backspace),
                        Delete => Some(vitral::Keycode::Del),
                        Numpad8 | Up => Some(vitral::Keycode::Up),
                        Numpad2 | Down => Some(vitral::Keycode::Down),
                        Numpad4 | Left => Some(vitral::Keycode::Left),
                        Numpad6 | Right => Some(vitral::Keycode::Right),
                        _ => None,
                    } {
                        context.input_key_state(vk, is_down);
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self,
                     display: &glium::Display,
                     context: &mut vitral::Context<usize, V>)
                     -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(display, &batch.vertices).unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(display, context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex_coord: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex_coord);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], tex_coord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex_coord: tex_coord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

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

    // Construct Vitral context.
    let mut context: Context;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png")).unwrap());
    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image, Point2D::new(100.0, 100.0), [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

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


<commit_before>#[link(name = "fuse",
uuid = "d37c5c30-fdcd-459d-bfca-ebb8da04b2a0",
url = "https://github.com/MicahChalmer/rust-fuse")];

#[comment = "FUSE bindings"];
#[license = "MIT"];
#[crate_type = "lib"];

use std::libc::{
    c_char,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    uid_t,
    gid_t
};

use std::ptr;
use std::str;
use std::vec;
use std::sys::size_of;

// A cfuncptr is used here to stand in for a C function pointer.
// For this struct, see fuse.h
type cfuncptr = *u8;
struct c_fuse_operations {
    getattr: cfuncptr,
    readlink: cfuncptr,
    getdir: cfuncptr,
    mknod: cfuncptr,
    mkdir: cfuncptr,
    unlink: cfuncptr,
    rmdir: cfuncptr,
    symlink: cfuncptr,
    rename: cfuncptr,
    link: cfuncptr,
    chmod: cfuncptr,
    chown: cfuncptr,
    truncate: cfuncptr,
    utime: cfuncptr,
    open: cfuncptr,
    read: cfuncptr,
    write: cfuncptr,
    statfs: cfuncptr,
    flush: cfuncptr,
    release: cfuncptr,
    fsync: cfuncptr,
    setxattr: cfuncptr,
    getxattr: cfuncptr,
    listxattr: cfuncptr,
    removexattr: cfuncptr,
    opendir: cfuncptr,
    readdir: cfuncptr,
    releasedir: cfuncptr,
    fsyncdir: cfuncptr,
    init: cfuncptr,
    destroy: cfuncptr,
    access: cfuncptr,
    create: cfuncptr,
    ftruncate: cfuncptr,
    fgetattr: cfuncptr,
    lock: cfuncptr,
    utimens: cfuncptr,
    bmap: cfuncptr,

    flag_nullpath_ok: uint,
    flag_nopath: uint,
    flag_utime_omit_ok: uint,
    flag_reserved: uint,

    ioctl: cfuncptr,
    poll: cfuncptr,
    write_buf: cfuncptr,
    read_buf: cfuncptr,
    flock: cfuncptr
}

// TODO: this should not be public
pub struct fuse_file_info {
    flags: c_int,
    fh_old: c_ulong, // Old file handle, don't use
    writepage: c_int,
    direct_io: c_uint,
    keep_cache: c_uint,
    flush: c_uint,
    nonseekable: c_uint,
    flock_release: c_uint,
    padding: c_uint, // Padding.  Do not use
    fh: u64,
    lock_owner: u64
}

struct c_fuse_context {
    fuse: *c_void,
    uid: uid_t,
    gid: gid_t,
    pid: pid_t,
    private_data: *rust_fuse_data,  // we use this to know what object to call
    umask: mode_t
}

struct rust_fuse_data {
    ops: ~FuseOperations
}

extern {
    fn fuse_main_real(argc:c_int, argv:**c_char,
                      op:*c_fuse_operations, op_size: size_t,
                      user_data: *c_void) -> c_int;

    fn fuse_get_context() -> *c_fuse_context;

    // Workaround for the fact that we can't call into c via a function ptr right
    // from rust
    fn call_filler_function(filler: cfuncptr, buf: *c_void, name: *c_char, stbuf: *stat,
                           off: off_t) -> c_int;
}

// Used for return values from FS operations
pub type errno = c_int;

pub type fuse_fill_dir_func<'self> = &'self fn (&str, Option<stat>, off_t) -> c_int;

pub type filehandle = u64;

pub struct dir_entry {
    name: ~str,
    stat: Option<stat>,
    off: off_t
}

#[deriving(Clone, Eq, ToStr)]
pub enum ErrorOrResult<E, T> {
    Error(E),
    Result(T)
}

pub trait FuseOperations {
    fn getattr(&self, path:&str) -> ErrorOrResult<errno, stat>;
    fn readdir(&self, path:&str, filler: fuse_fill_dir_func,
               offset: off_t, info: &fuse_file_info) -> ErrorOrResult<errno, ()>;
    fn open(&self, path:&str, info: &fuse_file_info) -> ErrorOrResult<errno, filehandle>;
    fn read(&self, path:&str, buf:&mut [u8], size: size_t, offset: off_t,
            info: &fuse_file_info) -> ErrorOrResult<errno, c_int>;
}

unsafe fn get_context_ops() -> &~FuseOperations {
    &((*(*fuse_get_context()).private_data).ops)
}

extern fn c_getattr(path: *c_char, stbuf: *mut stat) -> errno {
    unsafe {
        let ops = get_context_ops();
        ptr::zero_memory(stbuf, 1);
        match ops.getattr(str::raw::from_c_str(path)) {
            Error(e) => -e,
            Result(st) => { ptr::copy_memory(stbuf, &st, 1); 0 }
        }
    }
}

unsafe fn option_to_ptr<T>(opt: Option<T>) -> *T {
    match opt {
        Some(ref t) => ptr::to_unsafe_ptr(t),
        None => ptr::null()
    }
}

extern fn c_readdir(path: *c_char, buf: *c_void, filler: cfuncptr,
                    offset: off_t, fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        let fill_func: fuse_fill_dir_func = |name, st, ofs| -> c_int {
            do name.as_c_str |c_name| {
                call_filler_function(filler, buf, c_name, option_to_ptr(st), ofs)
            }
        };
        match ops.readdir(str::raw::from_c_str(path), fill_func, offset, &*fi) {
            Error(e) => -e,
            Result(_) => 0
        }
    }
}

extern fn c_open(path: *c_char, info: *mut fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        match ops.open(str::raw::from_c_str(path), &*info) {
            Error(e) => -e,
            Result(fh) => { (*info).fh = fh; 0 }
        }
    }
}

extern fn c_read(path: *c_char, buf: *mut u8, size: size_t, offset: off_t,
                 fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        do vec::raw::mut_buf_as_slice(buf, size as uint) |slice| {
            match ops.read(str::raw::from_c_str(path), slice, size, offset, &*fi) {
                Error(e) => -e,
                Result(sz) => sz
            }
        }
    }
}

pub fn fuse_main<T: FuseOperations>(args: ~[~str], ops: ~T) -> c_int {
    let cfo = c_fuse_operations {
        getattr: c_getattr,
        readdir: c_readdir,
        open: c_open,
        read: c_read,

        readlink: ptr::null(),
        getdir: ptr::null(),
        mknod: ptr::null(),
        mkdir: ptr::null(),
        unlink: ptr::null(),
        rmdir: ptr::null(),
        symlink: ptr::null(),
        rename: ptr::null(),
        link: ptr::null(),
        chmod: ptr::null(),
        chown: ptr::null(),
        truncate: ptr::null(),
        utime: ptr::null(),
        write: ptr::null(),
        statfs: ptr::null(),
        flush: ptr::null(),
        release: ptr::null(),
        fsync: ptr::null(),
        setxattr: ptr::null(),
        getxattr: ptr::null(),
        listxattr: ptr::null(),
        removexattr: ptr::null(),
        opendir: ptr::null(),
        releasedir: ptr::null(),
        fsyncdir: ptr::null(),
        init: ptr::null(),
        destroy: ptr::null(),
        access: ptr::null(),
        create: ptr::null(),
        ftruncate: ptr::null(),
        fgetattr: ptr::null(),
        lock: ptr::null(),
        utimens: ptr::null(),
        bmap: ptr::null(),

        flag_nullpath_ok: 0,
        flag_nopath: 0,
        flag_utime_omit_ok: 0,
        flag_reserved: 29,

        ioctl: ptr::null(),
        poll: ptr::null(),
        write_buf: ptr::null(),
        read_buf: ptr::null(),
        flock: ptr::null()
    };
    unsafe {
        let arg_c_strs = vec::raw::to_ptr(args.map(|s| vec::raw::to_ptr(s.as_bytes_with_null())));
        fuse_main_real(args.len() as c_int, std::cast::transmute(arg_c_strs),
                       &cfo, size_of::<c_fuse_operations>() as size_t,
                       std::cast::transmute(&ops))
    }
}
<commit_msg>Change lib to rust-fuse so it does not conflict with the real libfuse<commit_after>#[link(name = "rust-fuse",
uuid = "d37c5c30-fdcd-459d-bfca-ebb8da04b2a0",
url = "https://github.com/MicahChalmer/rust-fuse")];

#[comment = "FUSE bindings"];
#[license = "MIT"];
#[crate_type = "lib"];

use std::libc::{
    c_char,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    uid_t,
    gid_t
};

use std::ptr;
use std::str;
use std::vec;
use std::sys::size_of;

// A cfuncptr is used here to stand in for a C function pointer.
// For this struct, see fuse.h
type cfuncptr = *u8;
struct c_fuse_operations {
    getattr: cfuncptr,
    readlink: cfuncptr,
    getdir: cfuncptr,
    mknod: cfuncptr,
    mkdir: cfuncptr,
    unlink: cfuncptr,
    rmdir: cfuncptr,
    symlink: cfuncptr,
    rename: cfuncptr,
    link: cfuncptr,
    chmod: cfuncptr,
    chown: cfuncptr,
    truncate: cfuncptr,
    utime: cfuncptr,
    open: cfuncptr,
    read: cfuncptr,
    write: cfuncptr,
    statfs: cfuncptr,
    flush: cfuncptr,
    release: cfuncptr,
    fsync: cfuncptr,
    setxattr: cfuncptr,
    getxattr: cfuncptr,
    listxattr: cfuncptr,
    removexattr: cfuncptr,
    opendir: cfuncptr,
    readdir: cfuncptr,
    releasedir: cfuncptr,
    fsyncdir: cfuncptr,
    init: cfuncptr,
    destroy: cfuncptr,
    access: cfuncptr,
    create: cfuncptr,
    ftruncate: cfuncptr,
    fgetattr: cfuncptr,
    lock: cfuncptr,
    utimens: cfuncptr,
    bmap: cfuncptr,

    flag_nullpath_ok: uint,
    flag_nopath: uint,
    flag_utime_omit_ok: uint,
    flag_reserved: uint,

    ioctl: cfuncptr,
    poll: cfuncptr,
    write_buf: cfuncptr,
    read_buf: cfuncptr,
    flock: cfuncptr
}

// TODO: this should not be public
pub struct fuse_file_info {
    flags: c_int,
    fh_old: c_ulong, // Old file handle, don't use
    writepage: c_int,
    direct_io: c_uint,
    keep_cache: c_uint,
    flush: c_uint,
    nonseekable: c_uint,
    flock_release: c_uint,
    padding: c_uint, // Padding.  Do not use
    fh: u64,
    lock_owner: u64
}

struct c_fuse_context {
    fuse: *c_void,
    uid: uid_t,
    gid: gid_t,
    pid: pid_t,
    private_data: *rust_fuse_data,  // we use this to know what object to call
    umask: mode_t
}

struct rust_fuse_data {
    ops: ~FuseOperations
}

extern {
    fn fuse_main_real(argc:c_int, argv:**c_char,
                      op:*c_fuse_operations, op_size: size_t,
                      user_data: *c_void) -> c_int;

    fn fuse_get_context() -> *c_fuse_context;

    // Workaround for the fact that we can't call into c via a function ptr right
    // from rust
    fn call_filler_function(filler: cfuncptr, buf: *c_void, name: *c_char, stbuf: *stat,
                           off: off_t) -> c_int;
}

// Used for return values from FS operations
pub type errno = c_int;

pub type fuse_fill_dir_func<'self> = &'self fn (&str, Option<stat>, off_t) -> c_int;

pub type filehandle = u64;

pub struct dir_entry {
    name: ~str,
    stat: Option<stat>,
    off: off_t
}

#[deriving(Clone, Eq, ToStr)]
pub enum ErrorOrResult<E, T> {
    Error(E),
    Result(T)
}

pub trait FuseOperations {
    fn getattr(&self, path:&str) -> ErrorOrResult<errno, stat>;
    fn readdir(&self, path:&str, filler: fuse_fill_dir_func,
               offset: off_t, info: &fuse_file_info) -> ErrorOrResult<errno, ()>;
    fn open(&self, path:&str, info: &fuse_file_info) -> ErrorOrResult<errno, filehandle>;
    fn read(&self, path:&str, buf:&mut [u8], size: size_t, offset: off_t,
            info: &fuse_file_info) -> ErrorOrResult<errno, c_int>;
}

unsafe fn get_context_ops() -> &~FuseOperations {
    &((*(*fuse_get_context()).private_data).ops)
}

extern fn c_getattr(path: *c_char, stbuf: *mut stat) -> errno {
    unsafe {
        let ops = get_context_ops();
        ptr::zero_memory(stbuf, 1);
        match ops.getattr(str::raw::from_c_str(path)) {
            Error(e) => -e,
            Result(st) => { ptr::copy_memory(stbuf, &st, 1); 0 }
        }
    }
}

unsafe fn option_to_ptr<T>(opt: Option<T>) -> *T {
    match opt {
        Some(ref t) => ptr::to_unsafe_ptr(t),
        None => ptr::null()
    }
}

extern fn c_readdir(path: *c_char, buf: *c_void, filler: cfuncptr,
                    offset: off_t, fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        let fill_func: fuse_fill_dir_func = |name, st, ofs| -> c_int {
            do name.as_c_str |c_name| {
                call_filler_function(filler, buf, c_name, option_to_ptr(st), ofs)
            }
        };
        match ops.readdir(str::raw::from_c_str(path), fill_func, offset, &*fi) {
            Error(e) => -e,
            Result(_) => 0
        }
    }
}

extern fn c_open(path: *c_char, info: *mut fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        match ops.open(str::raw::from_c_str(path), &*info) {
            Error(e) => -e,
            Result(fh) => { (*info).fh = fh; 0 }
        }
    }
}

extern fn c_read(path: *c_char, buf: *mut u8, size: size_t, offset: off_t,
                 fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        do vec::raw::mut_buf_as_slice(buf, size as uint) |slice| {
            match ops.read(str::raw::from_c_str(path), slice, size, offset, &*fi) {
                Error(e) => -e,
                Result(sz) => sz
            }
        }
    }
}

pub fn fuse_main<T: FuseOperations>(args: ~[~str], ops: ~T) -> c_int {
    let cfo = c_fuse_operations {
        getattr: c_getattr,
        readdir: c_readdir,
        open: c_open,
        read: c_read,

        readlink: ptr::null(),
        getdir: ptr::null(),
        mknod: ptr::null(),
        mkdir: ptr::null(),
        unlink: ptr::null(),
        rmdir: ptr::null(),
        symlink: ptr::null(),
        rename: ptr::null(),
        link: ptr::null(),
        chmod: ptr::null(),
        chown: ptr::null(),
        truncate: ptr::null(),
        utime: ptr::null(),
        write: ptr::null(),
        statfs: ptr::null(),
        flush: ptr::null(),
        release: ptr::null(),
        fsync: ptr::null(),
        setxattr: ptr::null(),
        getxattr: ptr::null(),
        listxattr: ptr::null(),
        removexattr: ptr::null(),
        opendir: ptr::null(),
        releasedir: ptr::null(),
        fsyncdir: ptr::null(),
        init: ptr::null(),
        destroy: ptr::null(),
        access: ptr::null(),
        create: ptr::null(),
        ftruncate: ptr::null(),
        fgetattr: ptr::null(),
        lock: ptr::null(),
        utimens: ptr::null(),
        bmap: ptr::null(),

        flag_nullpath_ok: 0,
        flag_nopath: 0,
        flag_utime_omit_ok: 0,
        flag_reserved: 29,

        ioctl: ptr::null(),
        poll: ptr::null(),
        write_buf: ptr::null(),
        read_buf: ptr::null(),
        flock: ptr::null()
    };
    unsafe {
        let arg_c_strs = vec::raw::to_ptr(args.map(|s| vec::raw::to_ptr(s.as_bytes_with_null())));
        fuse_main_real(args.len() as c_int, std::cast::transmute(arg_c_strs),
                       &cfo, size_of::<c_fuse_operations>() as size_t,
                       std::cast::transmute(&ops))
    }
}
<|endoftext|>