<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Calculate alignments with a generalized variant of the Smith Waterman algorithm.
//! Complexity: O(n * m) for strings of length m and n.
//!
//! # Example
//!
//! ```
//! use bio::alignment::pairwise::Aligner;
//! use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
//! let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
//! let alignment = aligner.semiglobal(x, y);
//! assert_eq!(alignment.ystart, 4);
//! assert_eq!(alignment.xstart, 0);
//! assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
//! ```

use std::i32;
use std::iter::repeat;
use std::cmp::max;

use alignment::{Alignment, AlignmentOperation};
use data_structures::bitenc::BitEnc;

/// Current internal state of alignment.
struct AlignmentState {
    m: usize,
    n: usize,
    best: i32,
    best_i: usize,
    best_j: usize,
    i: usize,
    j: usize,
    score: i32,
    col: usize
}

macro_rules! align {
    (
        $aligner:ident, $x:ident, $y:ident, $state:ident,
        $init:block, $inner:block, $outer:block, $ret:block
    ) => (
        {
            let mut $state = AlignmentState {
                m: $x.len(), n: $y.len(),
                best: 0, best_i: 0, best_j: 0,
                i: 1, j: 1,
                score: 0,
                col: 0
            };

            while $state.i <= $state.n {
                $state.col = $state.i % 2;
                let prev = 1 - $state.col;

                // init code
                $init

                // read next y symbol
                let b = $y[$state.i - 1];
                $state.j = 1;

                while $state.j <= $state.m {
                    // read next x symbol
                    let a = $x[$state.j - 1];

                    // score for deletion
                    let d_score = max(
                        $aligner.S[prev][$state.j] + $aligner.gap_open,
                        $aligner.D[prev][$state.j] + $aligner.gap_extend
                    );
                    // score for insertion
                    let i_score = max(
                        $aligner.S[$state.col][$state.j-1] + $aligner.gap_open,
                        $aligner.I[$state.col][$state.j-1] + $aligner.gap_extend
                    );
                    // score for substitution
                    $state.score = $aligner.S[prev][$state.j-1] + ($aligner.score)(a, b);

                    if d_score > $state.score {
                        $state.score = d_score;
                        $aligner.traceback.del($state.i, $state.j);
                    }
                    else if i_score > $state.score {
                        $state.score = i_score;
                        $aligner.traceback.ins($state.i, $state.j);
                    }
                    else {
                        $aligner.traceback.subst($state.i, $state.j);
                    }

                    // inner code
                    $inner

                    $aligner.S[$state.col][$state.j] = $state.score;
                    $aligner.D[$state.col][$state.j] = d_score;
                    $aligner.I[$state.col][$state.j] = i_score;

                    $state.j += 1;
                }

                // outer code
                $outer

                $state.i += 1;
            }

            // return code
            $ret
        }
    );
}

/// A generalized Smith-Waterman aligner.
#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F,
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = || Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, global: bool) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2 {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            if global {
                let ref mut s = self.S[k];
                let mut score = self.gap_open;
                for _ in 0..m+1 {
                    s.push(score);
                    score += self.gap_extend;
                }
            }
            else {
                self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    /// Calculate global alignment.
    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, true);
        self.traceback.init(m, n, true);

        align!(
            self, x, y, state,
            {
                self.S[state.col][0] = self.gap_open + (state.i as i32 - 1) * self.gap_extend;
                self.traceback.del(state.i, 0);
            }, {}, {},
            {
                self.traceback.alignment(state.n, state.m, x, y, state.score)
            }
        )
    }

    /// Calculate semiglobal alignment.
    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, x, y, state,
            { self.S[state.col][0] = 0; },
            {},
            {
                if state.score > state.best {
                    state.best = state.score;
                    state.best_i = state.i;
                    state.best_j = state.m;
                }
            },
            { self.traceback.alignment(state.best_i, state.best_j, x, y, state.best) }
        )
    }

    /// Calculate local alignment.
    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, x, y, state,
            { self.S[state.col][0] = 0; },
            {
                if state.score < 0 {
                    self.traceback.start(state.i, state.j);
                    state.score = 0;
                }
                else if state.score > state.best {
                    state.best = state.score;
                    state.best_i = state.i;
                    state.best_j = state.j;
                }
            },
            {},
            { self.traceback.alignment(state.best_i, state.best_j, x, y, state.best) }
        )
    }
}

/// Internal traceback.
struct Traceback {
    matrix: Vec<BitEnc>
}

const TBSTART: u8 = 0b00;
const TBSUBST: u8 = 0b01;
const TBINS: u8   = 0b10;
const TBDEL: u8   = 0b11;

impl Traceback {

    fn with_capacity(m: usize, n: usize) -> Self {
        let mut matrix = Vec::with_capacity(n+1);
        for _ in 0..n+1 {
            matrix.push(BitEnc::with_capacity(2, m + 1));
        }
        Traceback {
            matrix: matrix
        }
    }

    fn init(&mut self, m: usize, n: usize, global: bool) {
        if global {
            // set the first cell to start, the rest to deletions
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBDEL);
            }
            self.matrix[0].set(0, TBSTART);
        }
        else {
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBSTART);
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSTART);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSUBST);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBDEL);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBINS);
    }

    fn get(&self, i: usize, j: usize) -> u8 {
        self.matrix[i].get(j).unwrap()
    }

    fn alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = match self.get(i, j) {
                TBSUBST => {
                    let op = if y[i-1] == x[j-1] {
                        AlignmentOperation::Match
                    }
                    else {
                        AlignmentOperation::Subst
                    };
                    (i - 1, j - 1, op)
                }
                TBDEL => {
                    (i - 1, j, AlignmentOperation::Del)
                }
                TBINS => {
                    (i, j - 1, AlignmentOperation::Ins)
                }
                _ => {
                    break;
                }
            };

            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { ystart: i, xstart: j, xlen: x.len(), operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        println!("{:?}", alignment);
        assert_eq!(alignment.ystart, 4);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.ystart, 4);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.ystart, 0);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }
}
<commit_msg>add drafts for tests<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Calculate alignments with a generalized variant of the Smith Waterman algorithm.
//! Complexity: O(n * m) for strings of length m and n.
//!
//! # Example
//!
//! ```
//! use bio::alignment::pairwise::Aligner;
//! use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
//! let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
//! let alignment = aligner.semiglobal(x, y);
//! assert_eq!(alignment.ystart, 4);
//! assert_eq!(alignment.xstart, 0);
//! assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
//! ```

use std::i32;
use std::iter::repeat;
use std::cmp::max;

use alignment::{Alignment, AlignmentOperation};
use data_structures::bitenc::BitEnc;

/// Current internal state of alignment.
struct AlignmentState {
    m: usize,
    n: usize,
    best: i32,
    best_i: usize,
    best_j: usize,
    i: usize,
    j: usize,
    score: i32,
    col: usize
}

macro_rules! align {
    (
        $aligner:ident, $x:ident, $y:ident, $state:ident,
        $init:block, $inner:block, $outer:block, $ret:block
    ) => (
        {
            let mut $state = AlignmentState {
                m: $x.len(), n: $y.len(),
                best: 0, best_i: 0, best_j: 0,
                i: 1, j: 1,
                score: 0,
                col: 0
            };

            while $state.i <= $state.n {
                $state.col = $state.i % 2;
                let prev = 1 - $state.col;

                // init code
                $init

                // read next y symbol
                let b = $y[$state.i - 1];
                $state.j = 1;

                while $state.j <= $state.m {
                    // read next x symbol
                    let a = $x[$state.j - 1];

                    // score for deletion
                    let d_score = max(
                        $aligner.S[prev][$state.j] + $aligner.gap_open,
                        $aligner.D[prev][$state.j] + $aligner.gap_extend
                    );
                    // score for insertion
                    let i_score = max(
                        $aligner.S[$state.col][$state.j-1] + $aligner.gap_open,
                        $aligner.I[$state.col][$state.j-1] + $aligner.gap_extend
                    );
                    // score for substitution
                    $state.score = $aligner.S[prev][$state.j-1] + ($aligner.score)(a, b);

                    if d_score > $state.score {
                        $state.score = d_score;
                        $aligner.traceback.del($state.i, $state.j);
                    }
                    else if i_score > $state.score {
                        $state.score = i_score;
                        $aligner.traceback.ins($state.i, $state.j);
                    }
                    else {
                        $aligner.traceback.subst($state.i, $state.j);
                    }

                    // inner code
                    $inner

                    $aligner.S[$state.col][$state.j] = $state.score;
                    $aligner.D[$state.col][$state.j] = d_score;
                    $aligner.I[$state.col][$state.j] = i_score;

                    $state.j += 1;
                }

                // outer code
                $outer

                $state.i += 1;
            }

            // return code
            $ret
        }
    );
}

/// A generalized Smith-Waterman aligner.
#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F,
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = || Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, global: bool) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2 {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            if global {
                let ref mut s = self.S[k];
                let mut score = self.gap_open;
                for _ in 0..m+1 {
                    s.push(score);
                    score += self.gap_extend;
                }
            }
            else {
                self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    /// Calculate global alignment.
    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, true);
        self.traceback.init(m, n, true);

        align!(
            self, x, y, state,
            {
                self.S[state.col][0] = self.gap_open + (state.i as i32 - 1) * self.gap_extend;
                self.traceback.del(state.i, 0);
            }, {}, {},
            {
                self.traceback.alignment(state.n, state.m, x, y, state.score)
            }
        )
    }

    /// Calculate semiglobal alignment.
    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, x, y, state,
            { self.S[state.col][0] = 0; },
            {},
            {
                if state.score > state.best {
                    state.best = state.score;
                    state.best_i = state.i;
                    state.best_j = state.m;
                }
            },
            { self.traceback.alignment(state.best_i, state.best_j, x, y, state.best) }
        )
    }

    /// Calculate local alignment.
    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, x, y, state,
            { self.S[state.col][0] = 0; },
            {
                if state.score < 0 {
                    self.traceback.start(state.i, state.j);
                    state.score = 0;
                }
                else if state.score > state.best {
                    state.best = state.score;
                    state.best_i = state.i;
                    state.best_j = state.j;
                }
            },
            {},
            { self.traceback.alignment(state.best_i, state.best_j, x, y, state.best) }
        )
    }
}

/// Internal traceback.
struct Traceback {
    matrix: Vec<BitEnc>
}

const TBSTART: u8 = 0b00;
const TBSUBST: u8 = 0b01;
const TBINS: u8   = 0b10;
const TBDEL: u8   = 0b11;

impl Traceback {

    fn with_capacity(m: usize, n: usize) -> Self {
        let mut matrix = Vec::with_capacity(n+1);
        for _ in 0..n+1 {
            matrix.push(BitEnc::with_capacity(2, m + 1));
        }
        Traceback {
            matrix: matrix
        }
    }

    fn init(&mut self, m: usize, n: usize, global: bool) {
        if global {
            // set the first cell to start, the rest to deletions
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBDEL);
            }
            self.matrix[0].set(0, TBSTART);
        }
        else {
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBSTART);
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSTART);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSUBST);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBDEL);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBINS);
    }

    fn get(&self, i: usize, j: usize) -> u8 {
        self.matrix[i].get(j).unwrap()
    }

    fn alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = match self.get(i, j) {
                TBSUBST => {
                    let op = if y[i-1] == x[j-1] {
                        AlignmentOperation::Match
                    }
                    else {
                        AlignmentOperation::Subst
                    };
                    (i - 1, j - 1, op)
                }
                TBDEL => {
                    (i - 1, j, AlignmentOperation::Del)
                }
                TBINS => {
                    (i, j - 1, AlignmentOperation::Ins)
                }
                _ => {
                    break;
                }
            };

            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { ystart: i, xstart: j, xlen: x.len(), operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        println!("{:?}", alignment);
        assert_eq!(alignment.ystart, 4);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.ystart, 4);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.ystart, 0);
        assert_eq!(alignment.xstart, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_macro_semiglobal() {
        // align_semiglobal!
        assert_eq!(false)
    }

    #[test]
    fn test_macro_local() {
        // align_local!
        assert_eq!(false)
    }

    #[test]
    fn test_macro_global() {
        // align_global!
        assert_eq!(false)
    }

    #[test]
    fn test_pretty_alignment()) {
        // println!(alignment.pretty(x, y))
        // println!(pretty_alignment!(x, y))
        assert_eq!(false)
    }

    #[test]
    fn test_hamming_dist_wo_traceback() {
        // hamm_dist!()
        assert_eq!(false)
    }

    #[test]
    fn test_levenshtein_dist_wo_traceback() {
        // lev_dist!()
        assert_eq!(false)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Application launching — Startup notification for applications

use glib::translate::*;
use glib::types::{StaticType, Type};
use object::Object;
use screen::Screen;
use ffi;

// FIXME: should inherit from GAppLaunchContext
pub type AppLaunchContext = Object<ffi::GdkAppLaunchContext>;

impl StaticType for AppLaunchContext {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_app_launch_context_get_type()) } }
}

impl AppLaunchContext {
    pub fn set_screen(&self, screen: &Screen) {
        unsafe {
            ffi::gdk_app_launch_context_set_screen(self.to_glib_none().0, screen.to_glib_none().0)
        }
    }

    pub fn set_desktop(&self, desktop: i32) {
        unsafe { ffi::gdk_app_launch_context_set_desktop(self.to_glib_none().0, desktop) }
    }

    pub fn set_timestamp(&self, timestamp: u32) {
        unsafe { ffi::gdk_app_launch_context_set_timestamp(self.to_glib_none().0, timestamp) }
    }

    /*pub fn set_icon(&self, icon: GIO::Icon) {
        unsafe { ffi::gdk_app_launch_context_set_timestamp(self.to_glib_none().0, icon.to_glib_none().0) }
    }*/

    pub fn set_icon_name(&self, icon_name: &str) {
        unsafe {
            ffi::gdk_app_launch_context_set_icon_name(self.to_glib_none().0,
                                                      icon_name.to_glib_none().0)
        }
    }
}
<commit_msg>Add documentation<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Application launching — Startup notification for applications

use glib::translate::*;
use glib::types::{StaticType, Type};
use object::Object;
use screen::Screen;
use display::Display;
use ffi;

// FIXME: should inherit from GAppLaunchContext
pub type AppLaunchContext = Object<ffi::GdkAppLaunchContext>;

impl StaticType for AppLaunchContext {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_app_launch_context_get_type()) } }
}

impl AppLaunchContext {
    /// Sets the display on which applications will be launched when using this context. See also
    /// `AppLaunchContext::set_screen()`.
    pub fn set_display(&self, display: &Display) {
        unsafe {
            ffi::gdk_app_launch_context_set_display(self.to_glib_none().0, display.to_glib_none().0)
        }
    }

    /// Sets the screen on which applications will be launched when using this context. See also
    /// `AppLaunchContext::set_display()`.
    ///
    /// If both screen and display are set, the screen takes priority. If neither screen or display
    /// are set, the default screen and display are used.
    pub fn set_screen(&self, screen: &Screen) {
        unsafe {
            ffi::gdk_app_launch_context_set_screen(self.to_glib_none().0, screen.to_glib_none().0)
        }
    }

    /// Sets the workspace on which applications will be launched when using this context when running
    /// under a window manager that supports multiple workspaces, as described in the
    /// Extended Window Manager Hints.
    ///
    /// When the workspace is not specified or desktop is set to -1, it is up to the window manager to
    /// pick one, typically it will be the current workspace.
    pub fn set_desktop(&self, desktop: i32) {
        unsafe { ffi::gdk_app_launch_context_set_desktop(self.to_glib_none().0, desktop) }
    }

    /// Sets the timestamp of self. The timestamp should ideally be taken from the event that triggered
    /// the launch.
    ///
    /// Window managers can use this information to avoid moving the focus to the newly launched application
    /// when the user is busy typing in another window. This is also known as 'focus stealing prevention'.
    pub fn set_timestamp(&self, timestamp: u32) {
        unsafe { ffi::gdk_app_launch_context_set_timestamp(self.to_glib_none().0, timestamp) }
    }

    /*pub fn set_icon(&self, icon: GIO::Icon) {
        unsafe { ffi::gdk_app_launch_context_set_timestamp(self.to_glib_none().0, icon.to_glib_none().0) }
    }*/

    /// Sets the icon for applications that are launched with this context. The icon_name will be
    /// interpreted in the same way as the Icon field in desktop files. See also `AppLaunchContext::set_icon()`.
    ///
    /// If both icon and icon_name are set, the icon_name takes priority. If neither icon or icon_name is set,
    /// the icon is taken from either the file that is passed to launched application or from the GAppInfo for
    /// the launched application itself.
    pub fn set_icon_name(&self, icon_name: &str) {
        unsafe {
            ffi::gdk_app_launch_context_set_icon_name(self.to_glib_none().0,
                                                      icon_name.to_glib_none().0)
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;
use glutin::{PossiblyCurrent as Pc, NotCurrent};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new(
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        let gl_window = unsafe {
            gl_window.treat_as_current()
        };
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug(gl_window: glutin::WindowedContext<Pc>, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild(
        &self,
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<NotCurrent>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe {
            new_gl_window.treat_as_current()
        };

        // Replace the stored WindowedContext with the new one.
        {
            let mut gl_window = self.gl_window.borrow_mut();
            Takeable::insert(&mut gl_window, new_gl_window);
        }

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        try!(unsafe { self.context.rebuild(backend) });

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.description())
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("I/O Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::OsError(e)) => panic!("OS Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
		let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.get_inner_size()
            .map(|logical_size| logical_size.to_physical(gl_window.get_hidpi_factor()))
            .map(Into::into)
            // TODO: 800x600 ?
            .unwrap_or((800, 600));
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<commit_msg>Address review<commit_after>#![cfg(feature = "glutin")]
/*!

Backend implementation for the glutin library

# Features

Only available if the 'glutin' feature is enabled.

*/
pub extern crate glutin;

pub mod headless;

use takeable_option::Takeable;
use {Frame, IncompatibleOpenGl, SwapBuffersError};
use debug;
use context;
use backend;
use backend::Context;
use backend::Backend;
use std::cell::{Cell, RefCell, Ref};
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::ops::Deref;
use std::os::raw::c_void;
use glutin::{PossiblyCurrent as Pc, ContextCurrentState};

/// A GL context combined with a facade for drawing upon.
///
/// The `Display` uses **glutin** for the **Window** and its associated GL **Context**.
///
/// These are stored alongside a glium-specific context.
#[derive(Clone)]
pub struct Display {
    // contains everything related to the current context and its state
    context: Rc<context::Context>,
    // The glutin Window alongside its associated GL Context.
    gl_window: Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>,
    // Used to check whether the framebuffer dimensions have changed between frames. If they have,
    // the glutin context must be resized accordingly.
    last_framebuffer_dimensions: Cell<(u32, u32)>,
}

/// An implementation of the `Backend` trait for glutin.
#[derive(Clone)]
pub struct GlutinBackend(Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>);

/// Error that can happen while creating a glium display.
#[derive(Debug)]
pub enum DisplayCreationError {
    /// An error has happened while creating the backend.
    GlutinCreationError(glutin::CreationError),
    /// The OpenGL implementation is too old.
    IncompatibleOpenGl(IncompatibleOpenGl),
}

impl Display {
    /// Create a new glium `Display` from the given context and window builders.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn new<T: ContextCurrentState>(
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<Self, DisplayCreationError>
    {
        let gl_window = cb.build_windowed(wb, events_loop)?;
        Self::from_gl_window(gl_window).map_err(From::from)
    }

    /// Create a new glium `Display`.
    ///
    /// Performs a compatibility check to make sure that all core elements of glium are supported
    /// by the implementation.
    pub fn from_gl_window<T: ContextCurrentState>(gl_window: glutin::WindowedContext<T>) -> Result<Self, IncompatibleOpenGl> {
        Self::with_debug(gl_window, Default::default())
    }

    /// Create a new glium `Display`.
    ///
    /// This function does the same as `build_glium`, except that the resulting context
    /// will assume that the current OpenGL context will never change.
    pub unsafe fn unchecked(gl_window: glutin::WindowedContext<Pc>) -> Result<Self, IncompatibleOpenGl> {
        Self::unchecked_with_debug(gl_window, Default::default())
    }

    /// The same as the `new` constructor, but allows for specifying debug callback behaviour.
    pub fn with_debug<T: ContextCurrentState>(gl_window: glutin::WindowedContext<T>, debug: debug::DebugCallbackBehavior)
        -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, true)
    }

    /// The same as the `unchecked` constructor, but allows for specifying debug callback behaviour.
    pub unsafe fn unchecked_with_debug(
        gl_window: glutin::WindowedContext<Pc>,
        debug: debug::DebugCallbackBehavior,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        Self::new_inner(gl_window, debug, false)
    }

    fn new_inner<T: ContextCurrentState>(
        gl_window: glutin::WindowedContext<T>,
        debug: debug::DebugCallbackBehavior,
        checked: bool,
    ) -> Result<Self, IncompatibleOpenGl>
    {
        let gl_window = unsafe {
            gl_window.treat_as_current()
        };
        let gl_window = Rc::new(RefCell::new(Takeable::new(gl_window)));
        let glutin_backend = GlutinBackend(gl_window.clone());
        let framebuffer_dimensions = glutin_backend.get_framebuffer_dimensions();
        let context = try!(unsafe { context::Context::new(glutin_backend, checked, debug) });
        Ok(Display {
            gl_window: gl_window,
            context: context,
            last_framebuffer_dimensions: Cell::new(framebuffer_dimensions),
        })
    }

    /// Rebuilds the Display's `WindowedContext` with the given window and context builders.
    ///
    /// This method ensures that the new `WindowedContext`'s `Context` will share the display lists of the
    /// original `WindowedContext`'s `Context`.
    pub fn rebuild<T: ContextCurrentState>(
        &self,
        wb: glutin::WindowBuilder,
        cb: glutin::ContextBuilder<T>,
        events_loop: &glutin::EventsLoop,
    ) -> Result<(), DisplayCreationError>
    {
        // Share the display lists of the existing context.
        let new_gl_window = {
            let gl_window = self.gl_window.borrow();
            let cb = cb.with_shared_lists(gl_window.context());
            cb.build_windowed(wb, events_loop)?
        };
        let new_gl_window = unsafe {
            new_gl_window.treat_as_current()
        };

        // Replace the stored WindowedContext with the new one.
        {
            let mut gl_window = self.gl_window.borrow_mut();
            Takeable::insert(&mut gl_window, new_gl_window);
        }

        // Rebuild the Context.
        let backend = GlutinBackend(self.gl_window.clone());
        try!(unsafe { self.context.rebuild(backend) });

        Ok(())
    }

    /// Borrow the inner glutin WindowedContext.
    #[inline]
    pub fn gl_window(&self) -> Ref<Takeable<glutin::WindowedContext<Pc>>> {
        self.gl_window.borrow()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    ///
    /// If the framebuffer dimensions have changed since the last call to `draw`, the inner glutin
    /// context will be resized accordingly before returning the `Frame`.
    #[inline]
    pub fn draw(&self) -> Frame {
        let (w, h) = self.get_framebuffer_dimensions();

        // If the size of the framebuffer has changed, resize the context.
        if self.last_framebuffer_dimensions.get() != (w, h) {
            self.last_framebuffer_dimensions.set((w, h));
            self.gl_window.borrow().resize((w, h).into());
        }

        Frame::new(self.context.clone(), (w, h))
    }
}

impl fmt::Display for DisplayCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.description())
    }
}

impl Error for DisplayCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => err.description(),
            DisplayCreationError::IncompatibleOpenGl(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match *self {
            DisplayCreationError::GlutinCreationError(ref err) => Some(err),
            DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
        }
    }
}

impl From<glutin::CreationError> for DisplayCreationError {
    #[inline]
    fn from(err: glutin::CreationError) -> DisplayCreationError {
        DisplayCreationError::GlutinCreationError(err)
    }
}

impl From<IncompatibleOpenGl> for DisplayCreationError {
    #[inline]
    fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
        DisplayCreationError::IncompatibleOpenGl(err)
    }
}

impl Deref for Display {
    type Target = Context;
    #[inline]
    fn deref(&self) -> &Context {
        &self.context
    }
}

impl backend::Facade for Display {
    #[inline]
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

impl Deref for GlutinBackend {
    type Target = Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>>;
    #[inline]
    fn deref(&self) -> &Rc<RefCell<Takeable<glutin::WindowedContext<Pc>>>> {
        &self.0
    }
}

unsafe impl Backend for GlutinBackend {
    #[inline]
    fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
        match self.borrow().swap_buffers() {
            Ok(()) => Ok(()),
            Err(glutin::ContextError::IoError(e)) => panic!("I/O Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::OsError(e)) => panic!("OS Error while swapping buffers: {:?}", e),
            Err(glutin::ContextError::ContextLost) => Err(SwapBuffersError::ContextLost),
        }
    }

    #[inline]
    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.borrow().get_proc_address(symbol) as *const _
    }

    #[inline]
    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let gl_window_takeable = self.borrow();
        let gl_window = gl_window_takeable.window();
        let (width, height) = gl_window.get_inner_size()
            .map(|logical_size| logical_size.to_physical(gl_window.get_hidpi_factor()))
            .map(Into::into)
            // TODO: 800x600 ?
            .unwrap_or((800, 600));
        (width, height)
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.borrow().is_current()
    }

    #[inline]
    unsafe fn make_current(&self) {
        let mut gl_window_takeable = self.borrow_mut();
        let gl_window = Takeable::take(&mut gl_window_takeable);
        let new_gl_window = gl_window.make_current().unwrap();
        Takeable::insert(&mut gl_window_takeable, new_gl_window);
    }
}
<|endoftext|>


<commit_before>use std::{
    fmt,
    fs,
    path::{Path, PathBuf},
};

use walkdir::{DirEntry, WalkDir};
use thread_worker::{WorkerHandle};
use relative_path::RelativePathBuf;

use crate::VfsRoot;

pub(crate) struct Task {
    pub(crate) root: VfsRoot,
    pub(crate) path: PathBuf,
    pub(crate) filter: Box<Fn(&DirEntry) -> bool + Send>,
}

pub struct TaskResult {
    pub(crate) root: VfsRoot,
    pub(crate) files: Vec<(RelativePathBuf, String)>,
}

impl fmt::Debug for TaskResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("TaskResult { ... }")
    }
}

pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>;

pub(crate) fn start() -> (Worker, WorkerHandle) {
    thread_worker::spawn("vfs", 128, |input_receiver, output_sender| {
        input_receiver
            .map(handle_task)
            .for_each(|it| output_sender.send(it))
    })
}

fn handle_task(task: Task) -> TaskResult {
    let Task { root, path, filter } = task;
    log::debug!("loading {} ...", path.as_path().display());
    let files = load_root(path.as_path(), &*filter);
    log::debug!("... loaded {}", path.as_path().display());
    TaskResult { root, files }
}

fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> {
    let mut res = Vec::new();
    for entry in WalkDir::new(root).into_iter().filter_entry(filter) {
        let entry = match entry {
            Ok(entry) => entry,
            Err(e) => {
                log::warn!("watcher error: {}", e);
                continue;
            }
        };
        if !entry.file_type().is_file() {
            continue;
        }
        let path = entry.path();
        if path.extension().and_then(|os| os.to_str()) != Some("rs") {
            continue;
        }
        let text = match fs::read_to_string(path) {
            Ok(text) => text,
            Err(e) => {
                log::warn!("watcher error: {}", e);
                continue;
            }
        };
        let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap();
        res.push((path.to_owned(), text))
    }
    res
}
<commit_msg>Reuse has_rs_extension in io.rs<commit_after>use std::{
    fmt,
    fs,
    path::{Path, PathBuf},
};

use walkdir::{DirEntry, WalkDir};
use thread_worker::{WorkerHandle};
use relative_path::RelativePathBuf;

use crate::{VfsRoot, has_rs_extension};

pub(crate) struct Task {
    pub(crate) root: VfsRoot,
    pub(crate) path: PathBuf,
    pub(crate) filter: Box<Fn(&DirEntry) -> bool + Send>,
}

pub struct TaskResult {
    pub(crate) root: VfsRoot,
    pub(crate) files: Vec<(RelativePathBuf, String)>,
}

impl fmt::Debug for TaskResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("TaskResult { ... }")
    }
}

pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>;

pub(crate) fn start() -> (Worker, WorkerHandle) {
    thread_worker::spawn("vfs", 128, |input_receiver, output_sender| {
        input_receiver
            .map(handle_task)
            .for_each(|it| output_sender.send(it))
    })
}

fn handle_task(task: Task) -> TaskResult {
    let Task { root, path, filter } = task;
    log::debug!("loading {} ...", path.as_path().display());
    let files = load_root(path.as_path(), &*filter);
    log::debug!("... loaded {}", path.as_path().display());
    TaskResult { root, files }
}

fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> {
    let mut res = Vec::new();
    for entry in WalkDir::new(root).into_iter().filter_entry(filter) {
        let entry = match entry {
            Ok(entry) => entry,
            Err(e) => {
                log::warn!("watcher error: {}", e);
                continue;
            }
        };
        if !entry.file_type().is_file() {
            continue;
        }
        let path = entry.path();
        if !has_rs_extension(path) {
            continue;
        }
        let text = match fs::read_to_string(path) {
            Ok(text) => text,
            Err(e) => {
                log::warn!("watcher error: {}", e);
                continue;
            }
        };
        let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap();
        res.push((path.to_owned(), text))
    }
    res
}
<|endoftext|>


<commit_before>extern crate libc;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct roaring_bitmap_s {
    pub high_low_container: *mut roaring_array_s,
    pub copy_on_write: bool
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct roaring_array_s {
    pub size: ::libc::int32_t,
    pub allocation_size: ::libc::int32_t,
    pub keys: *mut ::libc::uint16_t,
    pub containers: *mut *mut ::std::os::raw::c_void,
    pub typecodes: *mut ::libc::uint8_t,
    pub shared: *mut ::libc::uint8_t,
}

#[link(name = "roaring", kind = "static")]
extern "C" {
    pub fn roaring_bitmap_create() -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_create_with_capacity(cap: ::libc::uint32_t) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_of_ptr(n_args: ::libc::size_t, vals: *const ::libc::uint32_t) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_of(n: ::libc::size_t, ...) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_copy(r: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_printf(ra: *const roaring_bitmap_s);
    pub fn roaring_bitmap_and(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_and_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_or(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_or_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_or_many(number: ::libc::size_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_or_many_heap(number: ::libc::uint32_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_xor(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_xor_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_flip(x1: *const roaring_bitmap_s,
                               range_start: ::libc::uint64_t, range_end: ::libc::uint64_t)
                               -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_flip_inplace(x1: *mut roaring_bitmap_s,
                                       range_start: ::libc::uint64_t,
                                       range_end: ::libc::uint64_t);
    pub fn roaring_bitmap_xor_many(number: ::libc::size_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_andnot(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_andnot_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_free(r: *mut roaring_bitmap_s);
    pub fn roaring_bitmap_add(r: *mut roaring_bitmap_s, x: ::libc::uint32_t);
    pub fn roaring_bitmap_remove(r: *mut roaring_bitmap_s, x: ::libc::uint32_t);
    pub fn roaring_bitmap_contains(r: *const roaring_bitmap_s, x: ::libc::uint32_t) -> bool;
    pub fn roaring_bitmap_get_cardinality(ra: *const roaring_bitmap_s) -> ::libc::uint64_t;
    pub fn roaring_bitmap_to_uint32_array(ra: *const roaring_bitmap_s, cardinality: *mut ::libc::uint32_t);
    pub fn roaring_bitmap_remove_run_compression(r: *mut roaring_bitmap_s) -> bool;
    pub fn roaring_bitmap_run_optimize(r: *mut roaring_bitmap_s) -> bool;
    pub fn roaring_bitmap_serialize(ra: *mut roaring_bitmap_s, serialize_len: *mut ::libc::uint32_t) -> *mut ::libc::c_char;
    pub fn roaring_bitmap_deserialize(buf: *const ::libc::c_void, buf_len: ::libc::uint32_t) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_portable_deserialize(buf: *const ::libc::c_char) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_portable_size_in_bytes(ra: *const roaring_bitmap_s) -> ::libc::size_t;
    pub fn roaring_bitmap_portable_serialize(ra: *const roaring_bitmap_s, buf: *mut ::libc::c_char) -> ::libc::size_t;
    pub fn roaring_bitmap_is_empty(ra: *const roaring_bitmap_s) -> bool;
    /* TODO  pub fn roaring_iterate(ra: *mut roaring_bitmap_s,
                                    iterator: roaring_iterator,
                                    ptr: *mut ::libc::c_void) -> bool; */
    pub fn roaring_bitmap_equals(ra1: *mut roaring_bitmap_s, ra2: *mut roaring_bitmap_s) -> bool;
}
<commit_msg>Adjust FFI declarations after CRoaring upgrade<commit_after>extern crate libc;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct roaring_bitmap_s {
    pub high_low_container: roaring_array_s,
    pub copy_on_write: bool
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct roaring_array_s {
    pub size: ::libc::int32_t,
    pub allocation_size: ::libc::int32_t,
    pub containers: *mut *mut ::std::os::raw::c_void,
    pub keys: *mut ::libc::uint16_t,
    pub typecodes: *mut ::libc::uint8_t
}

#[link(name = "roaring", kind = "static")]
extern "C" {
    pub fn roaring_bitmap_create() -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_create_with_capacity(cap: ::libc::uint32_t) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_of_ptr(n_args: ::libc::size_t, vals: *const ::libc::uint32_t) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_of(n: ::libc::size_t, ...) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_copy(r: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_printf(ra: *const roaring_bitmap_s);
    pub fn roaring_bitmap_and(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_and_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_or(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_or_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_or_many(number: ::libc::size_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_or_many_heap(number: ::libc::uint32_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_xor(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_xor_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_flip(x1: *const roaring_bitmap_s,
                               range_start: ::libc::uint64_t, range_end: ::libc::uint64_t)
                               -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_flip_inplace(x1: *mut roaring_bitmap_s,
                                       range_start: ::libc::uint64_t,
                                       range_end: ::libc::uint64_t);
    pub fn roaring_bitmap_xor_many(number: ::libc::size_t, x: *mut *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_andnot(x1: *const roaring_bitmap_s, x2: *const roaring_bitmap_s) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_andnot_inplace(x1: *mut roaring_bitmap_s, x2: *const roaring_bitmap_s);
    pub fn roaring_bitmap_free(r: *mut roaring_bitmap_s);
    pub fn roaring_bitmap_add(r: *mut roaring_bitmap_s, x: ::libc::uint32_t);
    pub fn roaring_bitmap_remove(r: *mut roaring_bitmap_s, x: ::libc::uint32_t);
    pub fn roaring_bitmap_contains(r: *const roaring_bitmap_s, x: ::libc::uint32_t) -> bool;
    pub fn roaring_bitmap_get_cardinality(ra: *const roaring_bitmap_s) -> ::libc::uint64_t;
    pub fn roaring_bitmap_to_uint32_array(ra: *const roaring_bitmap_s, cardinality: *mut ::libc::uint32_t);
    pub fn roaring_bitmap_remove_run_compression(r: *mut roaring_bitmap_s) -> bool;
    pub fn roaring_bitmap_run_optimize(r: *mut roaring_bitmap_s) -> bool;
    pub fn roaring_bitmap_serialize(ra: *const roaring_bitmap_s, buf: *mut ::libc::c_char) -> ::libc::size_t;
    pub fn roaring_bitmap_deserialize(buf: *const ::libc::c_void) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_portable_deserialize(buf: *const ::libc::c_char) -> *mut roaring_bitmap_s;
    pub fn roaring_bitmap_portable_size_in_bytes(ra: *const roaring_bitmap_s) -> ::libc::size_t;
    pub fn roaring_bitmap_portable_serialize(ra: *const roaring_bitmap_s, buf: *mut ::libc::c_char) -> ::libc::size_t;
    pub fn roaring_bitmap_is_empty(ra: *const roaring_bitmap_s) -> bool;
    /* TODO  pub fn roaring_iterate(ra: *mut roaring_bitmap_s,
                                    iterator: roaring_iterator,
                                    ptr: *mut ::libc::c_void) -> bool; */
    pub fn roaring_bitmap_equals(ra1: *mut roaring_bitmap_s, ra2: *mut roaring_bitmap_s) -> bool;
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn translate_char(current : char, previous : char) -> char
{
  // TODO: FIXME.
  'a'
}

pub fn translate(text : &string)
{
  let mut result = String::with_capacity(text.capacity());

  let mut previous = '';
  for
  {
    previous = ...;
  }
}

pub fn test()
{
  println!("transliterator!")

  let mut test = HashMap::new();

  test.insert(('a', 'a'), 'a');
  test.insert(('a', 'b'), 'b');
}
<commit_msg>'translate' implementation<commit_after>use std::collections::HashMap;

pub fn translate_char(current : char, previous : char) -> char
{
  // TODO: FIXME.
  'a'
}

pub fn translate(text : &str) -> String
{
  let mut result = String::with_capacity(text.len() * std::mem::size_of::<char>());

  let mut previous = ' ';
  for c in text.chars()
  {
    previous = translate_char(c, previous);
    result.push(previous);
  }

  result
}

pub fn test()
{
  println!("transliterator!")

  let mut test = HashMap::new();

  test.insert(('a', 'a'), 'a');
  test.insert(('a', 'b'), 'b');
}
<|endoftext|>


<commit_before>#![cfg(feature = "interchange")]

use crate::chip::Chip;
use crate::database::Database;
use std::collections::{HashSet, HashMap};

use crate::bba::idstring::*;
use crate::bba::idxset::*;
use crate::bba::tiletype::{Neighbour, TileTypes};

use crate::sites::*;
use crate::wires::*;

// A tile type from the interchange format perspective
// this is not the same as a database tile type; because the Oxide graph can have
// more than one tile at a grid location whereas the interchange grid is one tile
// per location

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct TileTypeKey {
    pub tile_types: Vec<String>,
}
impl TileTypeKey {
    pub fn new() -> TileTypeKey {
        TileTypeKey { tile_types: Vec::new() }
    }
}

pub struct IcTileType {
    pub key: TileTypeKey,
    pub wires: IndexedMap<IdString, IcWire>,
    pub pips: Vec<IcPip>,
    pub site_types: Vec<Site>,
    // TODO: constants, sites, etc
}

impl IcTileType {
    pub fn new(key: TileTypeKey, family: &str, db: &mut Database) -> IcTileType {
        let mut site_types = Vec::new();
        for tt in key.tile_types.iter() {
            site_types.extend(build_sites(&tt, &db.tile_bitdb(family, &tt).db));
        }
        IcTileType {
            key: key,
            wires: IndexedMap::new(),
            pips: Vec::new(),
            site_types: site_types,
        }
    }
    pub fn wire(&mut self, name: IdString) -> usize {
        self.wires.add(&name, IcWire::new(name))
    }
    pub fn add_pip(&mut self, src: IdString, dst: IdString) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
            pseudo_cells: Vec::new(),
        });
    }
    pub fn add_ppip(&mut self, src: IdString, dst: IdString, pseudo_cells: Vec<IcPseudoCell>) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
            pseudo_cells: pseudo_cells,
        });
    }
}

pub struct IcWire {
    pub name: IdString,
}

impl IcWire {
    pub fn new(name: IdString) -> IcWire {
        IcWire {
            name: name,
        }
    }
}

pub struct IcPseudoCell {
    pub bel: IdString,
    pub pins: Vec<IdString>,
}

pub struct IcPip {
    pub src_wire: usize,
    pub dst_wire: usize,
    pub pseudo_cells: Vec<IcPseudoCell>,
}

// A tile instance
pub struct IcTileInst {
    pub name: IdString,
    pub x: u32,
    pub y: u32,
    pub type_idx: usize,
    // mapping between wires and nodes
    wire_to_node: HashMap<IdString, usize>,
}

impl IcTileInst {
    pub fn new(ids: &mut IdStringDB, x: u32, y: u32) -> IcTileInst {
        IcTileInst {
            name: ids.id(&format!("R{}C{}", y, x)),
            x: x,
            y: y,
            type_idx: 0,
            wire_to_node: HashMap::new(),
        }
    }
}

// A reference to a tile wire
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct IcWireRef {
    pub tile_name: IdString,
    pub wire_name: IdString,
}

// A node instance
pub struct IcNode {
    // list of tile wires in the node
    pub wires: HashSet<IcWireRef>,
    pub root_wire: IcWireRef,
}

impl IcNode {
    pub fn new(root_wire: IcWireRef) -> IcNode {
        IcNode {
            wires: [root_wire.clone()].iter().cloned().collect(),
            root_wire: root_wire,
        }
    }
}

// The overall routing resource graph
pub struct IcGraph {
    pub tile_types: IndexedMap<TileTypeKey, IcTileType>,
    pub tiles: Vec<IcTileInst>,
    pub nodes: Vec<IcNode>,
    pub width: u32,
    pub height: u32,
}

impl IcGraph {
    pub fn new(ids: &mut IdStringDB, width: u32, height: u32) -> IcGraph {
        IcGraph {
            tile_types: IndexedMap::new(),
            tiles: (0..width*height).map(|i| IcTileInst::new(ids, i%width, i/width)).collect(),
            nodes: Vec::new(),
            width: width,
            height: height
        }
    }
    pub fn tile_idx(&self, x: u32, y: u32) -> usize {
        assert!(x < self.width);
        assert!(y < self.height);
        ((y * self.width) + x) as usize
    }
    pub fn tile_at(&mut self, x: u32, y: u32) -> &mut IcTileInst {
        let idx = self.tile_idx(x, y);
        &mut self.tiles[idx]
    }
    pub fn type_at(&mut self, x: u32, y: u32) -> &mut IcTileType {
        let idx = self.tile_at(x, y).type_idx;
        self.tile_types.value_mut(idx)
    }
    pub fn map_node(&mut self, root_x: u32, root_y: u32, root_wire: IdString, wire_x: u32, wire_y: u32, wire: IdString) {
        // Make sure wire exists in both tiles
        self.type_at(root_x, root_y).wire(root_wire);
        self.type_at(wire_x, wire_y).wire(wire);
        // Update wire-node mapping
        let root_tile_idx = self.tile_idx(root_x, root_y);
        let node_idx = match self.tiles[root_tile_idx].wire_to_node.get(&root_wire) {
            Some(i) => *i,
            None => {
                let idx = self.nodes.len();
                self.nodes.push(IcNode::new(IcWireRef { tile_name: self.tiles[root_tile_idx].name, wire_name: root_wire }));
                self.tiles[root_tile_idx].wire_to_node.insert(root_wire, idx);
                idx
            }
        };
        let wire_tile_idx = self.tile_idx(wire_x, wire_y);
        self.nodes[node_idx].wires.insert(IcWireRef {tile_name: self.tiles[wire_tile_idx].name, wire_name: wire });
        self.tiles[wire_tile_idx].wire_to_node.insert(wire, node_idx);
    }
}

pub struct GraphBuilder<'a> {
    g: IcGraph,
    ids: &'a mut IdStringDB,
    chip: &'a Chip,
    db: &'a mut Database,
    tiletypes_by_xy: HashMap<(u32, u32), TileTypeKey>,
    orig_tts: TileTypes,
}

impl <'a> GraphBuilder<'a> {
    fn new(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> GraphBuilder<'a> {
        let mut width = 0;
        let mut height = 0;
        let mut tiletypes_by_xy = HashMap::new();
        for t in chip.tiles.iter() {
            tiletypes_by_xy.entry((t.x, t.y)).or_insert(TileTypeKey::new()).tile_types.push(t.tiletype.to_string());
            width = std::cmp::max(width, t.x + 1);
            height = std::cmp::max(height, t.y + 1);
        }

        let orig_tts = TileTypes::new(db, ids, &chip.family, &[&chip.device]);

        GraphBuilder {
            g: IcGraph::new(ids, width, height),
            ids: ids,
            chip: chip,
            db: db,
            tiletypes_by_xy: tiletypes_by_xy,
            // the original tiletypes from the database
            orig_tts: orig_tts,
        }
    }
    fn setup_tiletypes(&mut self) {
        for t in self.g.tiles.iter_mut() {
            let key = self.tiletypes_by_xy.get(&(t.x, t.y)).unwrap();
            t.type_idx = self.g.tile_types.add(key, IcTileType::new(key.clone(), &self.chip.family, self.db));
        }
        for (key, lt) in self.g.tile_types.iter_mut() {
            // setup wires for site pins
            let site_wires : Vec<String> = lt.site_types.iter().map(|s| s.pins.iter()).flatten().map(|p| p.tile_wire.clone()).collect();
            for w in site_wires {
                lt.wire(self.ids.id(&w));
            }
            for tt in key.tile_types.iter() {
                // setup wires for all sub-tile-types
                let tt_data = self.orig_tts.get(tt).unwrap();
                for wire in tt_data.wire_ids.iter() {
                    lt.wire(*wire);
                }
                // setup pips, both fixed and not
                // TODO: skip site wires and pips and deal with these later
                let tdb = &self.db.tile_bitdb(&self.chip.family, tt).db;
                for (to_wire, pips) in tdb.pips.iter() {
                    for pip in pips.iter() {
                        if is_site_wire(tt, &pip.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&pip.from_wire), self.ids.id(to_wire));
                    }
                }
                for (to_wire, conns) in tdb.conns.iter() {
                    for conn in conns.iter() {
                        if is_site_wire(tt, &conn.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&conn.from_wire), self.ids.id(to_wire));
                    }
                }
            }
            // Create pseudo-ground drivers for LUT outputs
            if lt.site_types.iter().find(|s| s.site_type == "PLC").is_some() {
                let gnd_wire = self.ids.id("G:GND");
                lt.wire(gnd_wire);
                for i in 0..8 {
                    lt.add_ppip(gnd_wire, self.ids.id(&format!("JF{}", i)),
                        vec![
                            IcPseudoCell {
                                bel: self.ids.id(&format!("SLICE{}_LUT{}", &"ABCD"[(i/2)..(i/2)+1], i%2)),
                                pins: vec![self.ids.id("F")],
                            }
                        ]);
                }
            }
        }
    }
    // Convert a neighbour to a coordinate
    pub fn neighbour_tile(&self, x: u32, y: u32, n: &Neighbour) -> Option<(u32, u32)> {
        match n {
            Neighbour::RelXY { rel_x, rel_y } => {
                let nx = (x as i32) + rel_x;
                let ny = (y as i32) + rel_y;
                if nx >= 0 && ny >= 0 && (nx as u32) < self.g.width && (ny as u32) < self.g.height {
                    Some((nx as u32, ny as u32))
                } else {
                    None
                }
            }
            // TODO: globals
            _ => None
        }
    }
    fn setup_wire2node(&mut self) {
        for ((x, y), key) in self.tiletypes_by_xy.iter() {
            for tt in key.tile_types.iter() {
                for wire in self.orig_tts.get(tt).unwrap().wires.iter() {
                    let (neigh, base_wire) = Neighbour::parse_wire(wire);
                    if let Some(neigh) = neigh {
                        // it's a neighbour wire, map to the base tile
                        if let Some((root_x, root_y)) = self.neighbour_tile(*x, *y, &neigh) {
                            self.g.map_node(root_x, root_y, self.ids.id(base_wire), *x, *y, self.ids.id(wire));
                        }

                    } else {
                        // root node, map to itself
                        self.g.map_node(*x, *y, self.ids.id(base_wire), *x, *y, self.ids.id(base_wire));
                    }
                }
            }
        }
    }

    pub fn run(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> IcGraph {
        let mut builder = GraphBuilder::new(ids, chip, db);
        builder.setup_tiletypes();
        builder.setup_wire2node();
        builder.g
    }
}
<commit_msg>interchange: Add LUT route-throughs<commit_after>#![cfg(feature = "interchange")]

use crate::chip::Chip;
use crate::database::Database;
use std::collections::{HashSet, HashMap};

use crate::bba::idstring::*;
use crate::bba::idxset::*;
use crate::bba::tiletype::{Neighbour, TileTypes};

use crate::sites::*;
use crate::wires::*;

// A tile type from the interchange format perspective
// this is not the same as a database tile type; because the Oxide graph can have
// more than one tile at a grid location whereas the interchange grid is one tile
// per location

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct TileTypeKey {
    pub tile_types: Vec<String>,
}
impl TileTypeKey {
    pub fn new() -> TileTypeKey {
        TileTypeKey { tile_types: Vec::new() }
    }
}

pub struct IcTileType {
    pub key: TileTypeKey,
    pub wires: IndexedMap<IdString, IcWire>,
    pub pips: Vec<IcPip>,
    pub site_types: Vec<Site>,
    // TODO: constants, sites, etc
}

impl IcTileType {
    pub fn new(key: TileTypeKey, family: &str, db: &mut Database) -> IcTileType {
        let mut site_types = Vec::new();
        for tt in key.tile_types.iter() {
            site_types.extend(build_sites(&tt, &db.tile_bitdb(family, &tt).db));
        }
        IcTileType {
            key: key,
            wires: IndexedMap::new(),
            pips: Vec::new(),
            site_types: site_types,
        }
    }
    pub fn wire(&mut self, name: IdString) -> usize {
        self.wires.add(&name, IcWire::new(name))
    }
    pub fn add_pip(&mut self, src: IdString, dst: IdString) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
            pseudo_cells: Vec::new(),
        });
    }
    pub fn add_ppip(&mut self, src: IdString, dst: IdString, pseudo_cells: Vec<IcPseudoCell>) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
            pseudo_cells: pseudo_cells,
        });
    }
}

pub struct IcWire {
    pub name: IdString,
}

impl IcWire {
    pub fn new(name: IdString) -> IcWire {
        IcWire {
            name: name,
        }
    }
}

pub struct IcPseudoCell {
    pub bel: IdString,
    pub pins: Vec<IdString>,
}

pub struct IcPip {
    pub src_wire: usize,
    pub dst_wire: usize,
    pub pseudo_cells: Vec<IcPseudoCell>,
}

// A tile instance
pub struct IcTileInst {
    pub name: IdString,
    pub x: u32,
    pub y: u32,
    pub type_idx: usize,
    // mapping between wires and nodes
    wire_to_node: HashMap<IdString, usize>,
}

impl IcTileInst {
    pub fn new(ids: &mut IdStringDB, x: u32, y: u32) -> IcTileInst {
        IcTileInst {
            name: ids.id(&format!("R{}C{}", y, x)),
            x: x,
            y: y,
            type_idx: 0,
            wire_to_node: HashMap::new(),
        }
    }
}

// A reference to a tile wire
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct IcWireRef {
    pub tile_name: IdString,
    pub wire_name: IdString,
}

// A node instance
pub struct IcNode {
    // list of tile wires in the node
    pub wires: HashSet<IcWireRef>,
    pub root_wire: IcWireRef,
}

impl IcNode {
    pub fn new(root_wire: IcWireRef) -> IcNode {
        IcNode {
            wires: [root_wire.clone()].iter().cloned().collect(),
            root_wire: root_wire,
        }
    }
}

// The overall routing resource graph
pub struct IcGraph {
    pub tile_types: IndexedMap<TileTypeKey, IcTileType>,
    pub tiles: Vec<IcTileInst>,
    pub nodes: Vec<IcNode>,
    pub width: u32,
    pub height: u32,
}

impl IcGraph {
    pub fn new(ids: &mut IdStringDB, width: u32, height: u32) -> IcGraph {
        IcGraph {
            tile_types: IndexedMap::new(),
            tiles: (0..width*height).map(|i| IcTileInst::new(ids, i%width, i/width)).collect(),
            nodes: Vec::new(),
            width: width,
            height: height
        }
    }
    pub fn tile_idx(&self, x: u32, y: u32) -> usize {
        assert!(x < self.width);
        assert!(y < self.height);
        ((y * self.width) + x) as usize
    }
    pub fn tile_at(&mut self, x: u32, y: u32) -> &mut IcTileInst {
        let idx = self.tile_idx(x, y);
        &mut self.tiles[idx]
    }
    pub fn type_at(&mut self, x: u32, y: u32) -> &mut IcTileType {
        let idx = self.tile_at(x, y).type_idx;
        self.tile_types.value_mut(idx)
    }
    pub fn map_node(&mut self, root_x: u32, root_y: u32, root_wire: IdString, wire_x: u32, wire_y: u32, wire: IdString) {
        // Make sure wire exists in both tiles
        self.type_at(root_x, root_y).wire(root_wire);
        self.type_at(wire_x, wire_y).wire(wire);
        // Update wire-node mapping
        let root_tile_idx = self.tile_idx(root_x, root_y);
        let node_idx = match self.tiles[root_tile_idx].wire_to_node.get(&root_wire) {
            Some(i) => *i,
            None => {
                let idx = self.nodes.len();
                self.nodes.push(IcNode::new(IcWireRef { tile_name: self.tiles[root_tile_idx].name, wire_name: root_wire }));
                self.tiles[root_tile_idx].wire_to_node.insert(root_wire, idx);
                idx
            }
        };
        let wire_tile_idx = self.tile_idx(wire_x, wire_y);
        self.nodes[node_idx].wires.insert(IcWireRef {tile_name: self.tiles[wire_tile_idx].name, wire_name: wire });
        self.tiles[wire_tile_idx].wire_to_node.insert(wire, node_idx);
    }
}

pub struct GraphBuilder<'a> {
    g: IcGraph,
    ids: &'a mut IdStringDB,
    chip: &'a Chip,
    db: &'a mut Database,
    tiletypes_by_xy: HashMap<(u32, u32), TileTypeKey>,
    orig_tts: TileTypes,
}

impl <'a> GraphBuilder<'a> {
    fn new(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> GraphBuilder<'a> {
        let mut width = 0;
        let mut height = 0;
        let mut tiletypes_by_xy = HashMap::new();
        for t in chip.tiles.iter() {
            tiletypes_by_xy.entry((t.x, t.y)).or_insert(TileTypeKey::new()).tile_types.push(t.tiletype.to_string());
            width = std::cmp::max(width, t.x + 1);
            height = std::cmp::max(height, t.y + 1);
        }

        let orig_tts = TileTypes::new(db, ids, &chip.family, &[&chip.device]);

        GraphBuilder {
            g: IcGraph::new(ids, width, height),
            ids: ids,
            chip: chip,
            db: db,
            tiletypes_by_xy: tiletypes_by_xy,
            // the original tiletypes from the database
            orig_tts: orig_tts,
        }
    }
    fn setup_tiletypes(&mut self) {
        for t in self.g.tiles.iter_mut() {
            let key = self.tiletypes_by_xy.get(&(t.x, t.y)).unwrap();
            t.type_idx = self.g.tile_types.add(key, IcTileType::new(key.clone(), &self.chip.family, self.db));
        }
        for (key, lt) in self.g.tile_types.iter_mut() {
            // setup wires for site pins
            let site_wires : Vec<String> = lt.site_types.iter().map(|s| s.pins.iter()).flatten().map(|p| p.tile_wire.clone()).collect();
            for w in site_wires {
                lt.wire(self.ids.id(&w));
            }
            for tt in key.tile_types.iter() {
                // setup wires for all sub-tile-types
                let tt_data = self.orig_tts.get(tt).unwrap();
                for wire in tt_data.wire_ids.iter() {
                    lt.wire(*wire);
                }
                // setup pips, both fixed and not
                // TODO: skip site wires and pips and deal with these later
                let tdb = &self.db.tile_bitdb(&self.chip.family, tt).db;
                for (to_wire, pips) in tdb.pips.iter() {
                    for pip in pips.iter() {
                        if is_site_wire(tt, &pip.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&pip.from_wire), self.ids.id(to_wire));
                    }
                }
                for (to_wire, conns) in tdb.conns.iter() {
                    for conn in conns.iter() {
                        if is_site_wire(tt, &conn.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&conn.from_wire), self.ids.id(to_wire));
                    }
                }
            }
            if lt.site_types.iter().find(|s| s.site_type == "PLC").is_some() {
                let gnd_wire = self.ids.id("G:GND");
                lt.wire(gnd_wire);
                for i in 0..8 {
                    // Create pseudo-ground drivers for LUT outputs
                    lt.add_ppip(gnd_wire, self.ids.id(&format!("JF{}", i)),
                        vec![
                            IcPseudoCell {
                                bel: self.ids.id(&format!("SLICE{}_LUT{}", &"ABCD"[(i/2)..(i/2)+1], i%2)),
                                pins: vec![self.ids.id("F")],
                            }
                        ]);
                    // Create LUT route-through PIPs
                    for j in &["A", "B", "C", "D"] {
                        lt.add_ppip(self.ids.id(&format!("J{}{}", j, i)), self.ids.id(&format!("JF{}", i)),
                        vec![
                            IcPseudoCell {
                                bel: self.ids.id(&format!("SLICE{}_LUT{}", &"ABCD"[(i/2)..(i/2)+1], i%2)),
                                pins: vec![self.ids.id(j), self.ids.id("F")],
                            }
                        ]);
                    }
                }
            }
        }
    }
    // Convert a neighbour to a coordinate
    pub fn neighbour_tile(&self, x: u32, y: u32, n: &Neighbour) -> Option<(u32, u32)> {
        match n {
            Neighbour::RelXY { rel_x, rel_y } => {
                let nx = (x as i32) + rel_x;
                let ny = (y as i32) + rel_y;
                if nx >= 0 && ny >= 0 && (nx as u32) < self.g.width && (ny as u32) < self.g.height {
                    Some((nx as u32, ny as u32))
                } else {
                    None
                }
            }
            // TODO: globals
            _ => None
        }
    }
    fn setup_wire2node(&mut self) {
        for ((x, y), key) in self.tiletypes_by_xy.iter() {
            for tt in key.tile_types.iter() {
                for wire in self.orig_tts.get(tt).unwrap().wires.iter() {
                    let (neigh, base_wire) = Neighbour::parse_wire(wire);
                    if let Some(neigh) = neigh {
                        // it's a neighbour wire, map to the base tile
                        if let Some((root_x, root_y)) = self.neighbour_tile(*x, *y, &neigh) {
                            self.g.map_node(root_x, root_y, self.ids.id(base_wire), *x, *y, self.ids.id(wire));
                        }

                    } else {
                        // root node, map to itself
                        self.g.map_node(*x, *y, self.ids.id(base_wire), *x, *y, self.ids.id(base_wire));
                    }
                }
            }
        }
    }

    pub fn run(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> IcGraph {
        let mut builder = GraphBuilder::new(ids, chip, db);
        builder.setup_tiletypes();
        builder.setup_wire2node();
        builder.g
    }
}
<|endoftext|>