<commit_before>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

trait Edges {
    /// The number of edges
    fn len(&self) -> usize;

    /// Returns the target node of the nth-edge
    fn nth_edge(&self, n: usize) -> usize;

    /// Returns the nth edge weight
    fn nth_edge_weight(&self, _n: usize) -> f32 {
        panic!();
    }
}

impl<'a> Edges for &'a [Idx] {
    #[inline]
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    #[inline]
    fn nth_edge(&self, n: usize) -> usize {
        self[n] as usize
    }
}

pub trait NodeColorMatching {
    /// Determines how close or distant two nodes `node_i` of graph A,
    /// and `node_j` of graph B are. If they have different colors,
    /// this method could return 0.0 to describe that they are completely
    /// different nodes and as such the neighbor matching will try to choose
    /// a different node.
    /// NOTE: The returned value MUST be in the range [0, 1].
    fn node_color_matching(&self, node_i: usize, node_j: usize) -> f32;
}

pub struct IgnoreNodeColors;

impl NodeColorMatching for IgnoreNodeColors {
    fn node_color_matching(&self, _node_i: usize, _node_j: usize) -> f32 {
        1.0
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_edge(a), n_j.nth_edge(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[derive(Copy, Clone, Debug)]
pub struct Graph<'a> {
    in_edges: &'a [Vec<Idx>],
    out_edges: &'a [Vec<Idx>],
}

impl<'a> Graph<'a> {
    pub fn new(in_edges: &'a [Vec<Idx>], out_edges: &'a [Vec<Idx>]) -> Graph<'a> {
        assert!(in_edges.len() == out_edges.len());
        Graph {
            in_edges: in_edges,
            out_edges: out_edges,
        }
    }

    fn num_nodes(&self) -> usize {
        let n = self.in_edges.len();
        assert!(n == self.out_edges.len());
        n
    }

    fn node_degree(&self, node_idx: usize) -> usize {
        self.in_edges[node_idx].len() + self.out_edges[node_idx].len()
    }
}

#[derive(Debug)]
pub struct GraphSimilarityMatrix<'a, F: NodeColorMatching + 'a> {
    graph_a: Graph<'a>,
    graph_b: Graph<'a>,
    node_color_matching: F,
    // current version of similarity matrix
    current: DMat<f32>,
    // previous version of similarity matrix
    previous: DMat<f32>,
    // current number of iterations
    num_iterations: usize,
}

impl<'a, F> GraphSimilarityMatrix<'a, F> where F: NodeColorMatching
{
    pub fn new(graph_a: Graph<'a>,
               graph_b: Graph<'a>,
               node_color_matching: F)
               -> GraphSimilarityMatrix<'a, F> {
        // `x` is the node-similarity matrix.
        // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
        // B.edges().
        let x: DMat<f32> = DMat::from_fn(graph_a.num_nodes(), graph_b.num_nodes(), |i, j| {
            if graph_a.node_degree(i) > 0 && graph_b.node_degree(j) > 0 {
                let scale = node_color_matching.node_color_matching(i, j);
                debug_assert!(scale >= 0.0 && scale <= 1.0);
                scale
            } else {
                0.0
            }
        });

        let new_x: DMat<f32> = DMat::new_zeros(graph_a.num_nodes(), graph_b.num_nodes());

        GraphSimilarityMatrix {
            graph_a: graph_a,
            graph_b: graph_b,
            node_color_matching: node_color_matching,
            current: x,
            previous: new_x,
            num_iterations: 0,
        }
    }

    fn in_eps(&self, eps: f32) -> bool {
        self.previous.approx_eq_eps(&self.current, &eps)
    }

    /// Calculates the next iteration of the similarity matrix (x[k+1]).
    pub fn next(&mut self) {
        {
            let x = &self.current;
            let new_x = &mut self.previous;
            let shape = x.shape();

            for i in 0..shape.0 {
                for j in 0..shape.1 {
                    let in_i: &[Idx] = &self.graph_a.in_edges[i];
                    let in_j: &[Idx] = &self.graph_b.in_edges[j];
                    let out_i: &[Idx] = &self.graph_a.out_edges[i];
                    let out_j: &[Idx] = &self.graph_b.out_edges[j];
                    let scale = self.node_color_matching.node_color_matching(i, j);
                    debug_assert!(scale >= 0.0 && scale <= 1.0);
                    new_x[(i, j)] = scale * (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) / 2.0;
                }
            }
        }

        mem::swap(&mut self.previous, &mut self.current);
        self.num_iterations += 1;
    }

    #[inline]
    /// Iteratively calculate the similarity matrix.
    ///
    /// `eps`:   When to stop the iteration
    /// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
    pub fn iterate(&mut self, eps: f32, stop_after_iter: usize) {
        for _ in 0..stop_after_iter {
            if self.in_eps(eps) {
                break;
            }
            self.next();
        }
    }

    pub fn matrix(&self) -> &DMat<f32> {
        &self.current
    }

    pub fn num_iterations(&self) -> usize {
        self.num_iterations
    }

    fn optimal_node_assignment(&self, n: usize) -> Vec<(usize, usize)> {
        let x = &self.current;
        assert!(n > 0);
        let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
        let assignment = solve_assignment(&mut w);
        assert!(assignment.len() == n);
        assignment
    }

    fn score_optimal_sum(&self, n: usize) -> f32 {
        self.optimal_node_assignment(n).iter().fold(0.0, |acc, &ab| acc + self.current[ab])
    }

    /// Calculate a measure how good the edge weights match up.
    ///
    /// We start by calculating the optimal node assignment between nodes of graph A and
    /// graph B, then compare all outgoing edges of similar nodes by again using an
    /// assignment.
    pub fn score_outgoing_edge_weights(&self) -> f32 {
        // XXX
        0.0
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    pub fn score_sum_norm_min_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            self.score_optimal_sum(n) / n as f32
        } else {
            0.0
        }
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    pub fn score_sum_norm_max_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        let m = cmp::max(x.nrows(), x.ncols());

        if n > 0 {
            assert!(m > 0);
            self.score_optimal_sum(n) / m as f32
        } else {
            0.0
        }
    }

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    pub fn score_average(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            sum / len as f32
        } else {
            0.0
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 100);

    // println!("{:?}", s);
    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 1);

    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 100);

    assert_eq!(1, s.num_iterations());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_min_degree());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_max_degree());
}
<commit_msg>Enable debug output of GraphSimilarityMatrix<commit_after>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;
use std::fmt;

pub type Idx = u32;

trait Edges {
    /// The number of edges
    fn len(&self) -> usize;

    /// Returns the target node of the nth-edge
    fn nth_edge(&self, n: usize) -> usize;

    /// Returns the nth edge weight
    fn nth_edge_weight(&self, _n: usize) -> f32 {
        panic!();
    }
}

impl<'a> Edges for &'a [Idx] {
    #[inline]
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    #[inline]
    fn nth_edge(&self, n: usize) -> usize {
        self[n] as usize
    }
}

pub trait NodeColorMatching: fmt::Debug {
    /// Determines how close or distant two nodes `node_i` of graph A,
    /// and `node_j` of graph B are. If they have different colors,
    /// this method could return 0.0 to describe that they are completely
    /// different nodes and as such the neighbor matching will try to choose
    /// a different node.
    /// NOTE: The returned value MUST be in the range [0, 1].
    fn node_color_matching(&self, node_i: usize, node_j: usize) -> f32;
}

#[derive(Debug)]
pub struct IgnoreNodeColors;

impl NodeColorMatching for IgnoreNodeColors {
    fn node_color_matching(&self, _node_i: usize, _node_j: usize) -> f32 {
        1.0
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_edge(a), n_j.nth_edge(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[derive(Copy, Clone, Debug)]
pub struct Graph<'a> {
    in_edges: &'a [Vec<Idx>],
    out_edges: &'a [Vec<Idx>],
}

impl<'a> Graph<'a> {
    pub fn new(in_edges: &'a [Vec<Idx>], out_edges: &'a [Vec<Idx>]) -> Graph<'a> {
        assert!(in_edges.len() == out_edges.len());
        Graph {
            in_edges: in_edges,
            out_edges: out_edges,
        }
    }

    fn num_nodes(&self) -> usize {
        let n = self.in_edges.len();
        assert!(n == self.out_edges.len());
        n
    }

    fn node_degree(&self, node_idx: usize) -> usize {
        self.in_edges[node_idx].len() + self.out_edges[node_idx].len()
    }
}

#[derive(Debug)]
pub struct GraphSimilarityMatrix<'a, F: NodeColorMatching + 'a> {
    graph_a: Graph<'a>,
    graph_b: Graph<'a>,
    node_color_matching: F,
    // current version of similarity matrix
    current: DMat<f32>,
    // previous version of similarity matrix
    previous: DMat<f32>,
    // current number of iterations
    num_iterations: usize,
}

impl<'a, F> GraphSimilarityMatrix<'a, F> where F: NodeColorMatching
{
    pub fn new(graph_a: Graph<'a>,
               graph_b: Graph<'a>,
               node_color_matching: F)
               -> GraphSimilarityMatrix<'a, F> {
        // `x` is the node-similarity matrix.
        // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
        // B.edges().
        let x: DMat<f32> = DMat::from_fn(graph_a.num_nodes(), graph_b.num_nodes(), |i, j| {
            if graph_a.node_degree(i) > 0 && graph_b.node_degree(j) > 0 {
                let scale = node_color_matching.node_color_matching(i, j);
                debug_assert!(scale >= 0.0 && scale <= 1.0);
                scale
            } else {
                0.0
            }
        });

        let new_x: DMat<f32> = DMat::new_zeros(graph_a.num_nodes(), graph_b.num_nodes());

        GraphSimilarityMatrix {
            graph_a: graph_a,
            graph_b: graph_b,
            node_color_matching: node_color_matching,
            current: x,
            previous: new_x,
            num_iterations: 0,
        }
    }

    fn in_eps(&self, eps: f32) -> bool {
        self.previous.approx_eq_eps(&self.current, &eps)
    }

    /// Calculates the next iteration of the similarity matrix (x[k+1]).
    pub fn next(&mut self) {
        {
            let x = &self.current;
            let new_x = &mut self.previous;
            let shape = x.shape();

            for i in 0..shape.0 {
                for j in 0..shape.1 {
                    let in_i: &[Idx] = &self.graph_a.in_edges[i];
                    let in_j: &[Idx] = &self.graph_b.in_edges[j];
                    let out_i: &[Idx] = &self.graph_a.out_edges[i];
                    let out_j: &[Idx] = &self.graph_b.out_edges[j];
                    let scale = self.node_color_matching.node_color_matching(i, j);
                    debug_assert!(scale >= 0.0 && scale <= 1.0);
                    new_x[(i, j)] = scale * (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) / 2.0;
                }
            }
        }

        mem::swap(&mut self.previous, &mut self.current);
        self.num_iterations += 1;
    }

    #[inline]
    /// Iteratively calculate the similarity matrix.
    ///
    /// `eps`:   When to stop the iteration
    /// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
    pub fn iterate(&mut self, eps: f32, stop_after_iter: usize) {
        for _ in 0..stop_after_iter {
            if self.in_eps(eps) {
                break;
            }
            self.next();
        }
    }

    pub fn matrix(&self) -> &DMat<f32> {
        &self.current
    }

    pub fn num_iterations(&self) -> usize {
        self.num_iterations
    }

    fn optimal_node_assignment(&self, n: usize) -> Vec<(usize, usize)> {
        let x = &self.current;
        assert!(n > 0);
        let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
        let assignment = solve_assignment(&mut w);
        assert!(assignment.len() == n);
        assignment
    }

    fn score_optimal_sum(&self, n: usize) -> f32 {
        self.optimal_node_assignment(n).iter().fold(0.0, |acc, &ab| acc + self.current[ab])
    }

    /// Calculate a measure how good the edge weights match up.
    ///
    /// We start by calculating the optimal node assignment between nodes of graph A and
    /// graph B, then compare all outgoing edges of similar nodes by again using an
    /// assignment.
    pub fn score_outgoing_edge_weights(&self) -> f32 {
        // XXX
        0.0
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    pub fn score_sum_norm_min_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            self.score_optimal_sum(n) / n as f32
        } else {
            0.0
        }
    }

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    pub fn score_sum_norm_max_degree(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        let m = cmp::max(x.nrows(), x.ncols());

        if n > 0 {
            assert!(m > 0);
            self.score_optimal_sum(n) / m as f32
        } else {
            0.0
        }
    }

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    pub fn score_average(&self) -> f32 {
        let x = &self.current;
        let n = cmp::min(x.nrows(), x.ncols());
        if n > 0 {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            sum / len as f32
        } else {
            0.0
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 100);

    println!("{:?}", s);
    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 1);

    assert_eq!(1, s.num_iterations());
    let mat = s.matrix();
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let mut s = GraphSimilarityMatrix::new(Graph::new(&in_a, &out_a),
                                           Graph::new(&in_b, &out_b),
                                           IgnoreNodeColors);
    s.iterate(0.1, 100);

    assert_eq!(1, s.num_iterations());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_min_degree());

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, s.score_sum_norm_max_degree());
}
<|endoftext|>


<commit_before>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use std::ffi::CString;
use libc::*;

const IW_AUTH_WPA_VERSION_DISABLED: u8 = 0x00000001;
const IW_AUTH_WPA_VERSION_WPA: u8 = 0x00000002;
const IW_AUTH_WPA_VERSION_WPA2: u8 = 0x00000004;
const IW_MAX_BITRATES: usize = 32;
const IW_MAX_ENCODING_SIZES: usize = 8;
const IW_MAX_FREQUENCIES: usize = 32;
const IW_MAX_TXPOWER: usize = 8;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
}

#[repr(C)]
struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

impl Default for priv_iw_quality {
    fn default() -> priv_iw_quality {
        priv_iw_quality {
            qual: 0,
            level: 0,
            noise: 0,
            updated: 0
        }
    }
}

#[repr(C)]
struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

impl Default for priv_iw_freq {
    fn default() -> priv_iw_freq {
        priv_iw_freq {
            m: 0,
            e: 0,
            i: 0,
            flags: 0
        }
    }
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

impl Default for iw_range {
    fn default() -> iw_range {
        iw_range {
            min_nwid: 0,
            max_nwid: 0,
            old_num_channels: 0,
            old_num_frequency: 0,
            event_capa: [0; ..6u],
            sensitivity: 0,
            max_qual: priv_iw_quality, /* Quality of the link */
            avg_qual: priv_iw_quality, /* Quality of the link */
            num_bitrates: 0, /* Number of entries in the list */
            bitrate: [0; ..IW_MAX_BITRATES], /* list, in bps */
            min_rts: 0, /* Minimal RTS threshold */
            max_rts: 0, /* Maximal RTS threshold */
            min_frag: 0, /* Minimal frag threshold */
            max_frag: 0, /* Maximal frag threshold */
            min_pmp: 0, /* Minimal PM period */
            max_pmp: 0, /* Maximal PM period */
            min_pmt: 0, /* Minimal PM timeout */
            max_pmt: 0, /* Maximal PM timeout */
            pmp_flags: 0, /* How to decode max/min PM period */
            pmt_flags: 0, /* How to decode max/min PM timeout */
            pm_capa: 0, /* What PM options are supported */
            encoding_size: [0; ..IW_MAX_ENCODING_SIZES], /* Different token sizes */
            num_encoding_sizes: 0, /* Number of entry in the list */
            max_encoding_tokens: 0, /* Max number of tokens */
            encoding_login_index: 0, /* token index for login token */
            txpower_capa: 0, /* What options are supported */
            num_txpower: 0, /* Number of entries in the list */
            txpower: [0; ..IW_MAX_TXPOWER], /* list, in bps */
            we_version_compiled: 0, /* Must be WIRELESS_EXT */
            we_version_source: 0, /* Last update of source */
            retry_capa: 0, /* What retry options are supported */
            retry_flags: 0, /* How to decode max/min retry limit */
            r_time_flags: 0, /* How to decode max/min retry life */
            min_retry: 0, /* Minimal number of retries */
            max_retry: 0, /* Maximal number of retries */
            min_r_time: 0, /* Minimal retry lifetime */
            max_r_time: 0, /* Maximal retry lifetime */
            num_channels: 0, /* Number of channels [0, num - 1] */
            num_frequency: 0, /* Number of entry in the list */
            freq: [priv_iw_freq; ..IW_MAX_FREQUENCIES], /* list */
            enc_capa: 0, /* IW_ENC_CAPA_* bit field */
            min_pms: 0, /* Minimal PM saving */
            max_pms: 0, /* Maximal PM saving */
            pms_flags: 0, /* How to decode max/min PM saving */
            modul_capa: 0, /* IW_MODUL_* bit field */
            bitrate_capa: 0, /* Types of bitrates supported */
        }
    }
}

#[link(name="iwlib")]
extern {
    fn iw_socket_open() -> c_int;
    fn iw_get_range_info(socket: c_int,
                         interface: CString,
                         range: &iw_range) -> c_int;
    fn iw_scan(socket: c_int,
               interface: CString,
               version: c_int,
               head: &wireless_scan_head) -> c_int;
}

pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    pub fn scan(interface: String) -> Result<WifiScan<'a>, WifiScanError> {
        // Scan things here
        unsafe { // TODO: Slim down unsafe blocks.
            // First get an iw socket.
            let sock = iw_socket_open();
            let interface_name = CString::new(interface).unwrap(); // TODO: Make the interface name configurable.
            let range: iw_range;
            let head: wireless_scan_head;
            if iw_get_range_info(sock, interface_name, &range) < 0 {
                // We have to make this call in order to get the version of the library on the computer
                Err("Got an error from the iw library")
            }
            if iw_scan(sock, interface_name, range.we_version_compiled, &head) <0 {
                // This is the actual scan call that fills in the `head` struct with information about the visible networks.
                Err("Got an error from the iw library")
            }
            let result = head.result;
            let mut list = Vec::new();
            while result != ptr::null {
                // The scan results are a linked list of structs with a bunch of information about each network
                // The type of encryption is encoded in a bitflag called `key_flags` which we check by doing
                // a bitwise and against the known bitflags.
                let answer = if result.b.key_flags & IW_AUTH_WPA_VERSION_DISABLED > 0 {
                    "None".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA > 0 {
                    "WPA".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA2 > 0 {
                    "WPA2".to_string()
                } ;
                list.push(WirelessNetwork {
                    SSID: result.b.essid.to_string(),
                    encryption: answer, // TODO Figure out how to get encryption type from `result`
                    strength: result.stats
                });
                result = result.next;
            }
        }
        Ok( WifiScan { networks: list });
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Make substantial changes<commit_after>extern crate libc;

use std::net::{SocketAddrV4, SocketAddrV6};
use std::ffi::CString;
use libc::*;

const IW_AUTH_WPA_VERSION_DISABLED: u8 = 0x00000001;
const IW_AUTH_WPA_VERSION_WPA: u8 = 0x00000002;
const IW_AUTH_WPA_VERSION_WPA2: u8 = 0x00000004;
const IW_MAX_BITRATES: usize = 32;
const IW_MAX_ENCODING_SIZES: usize = 8;
const IW_MAX_FREQUENCIES: usize = 32;
const IW_MAX_TXPOWER: usize = 8;

pub enum WirelessMode {
    Auto, /* Let the driver decide */
    AdHoc, /* Single cell network */
    Infra, /* Multi cell network, roaming, ... */
    Master, /* Synchronisation master or Access Point */
    Repeat, /* Wireless Repeater (forwarder) */
    Second, /* Secondary master/repeater (backup) */
    Monitor, /* Passive monitor (listen only) */
}

pub struct IwQuality {
    quality: u8,
    level: u8,
    noise: u8,
}

pub struct IwStats {
    status: uint16_t,
    quality: IwQuality,
}

pub struct WirelessKey<'a> {
    key: &'a [u8],
    size: u32,
    flags: i32,
}

/// The WirelessNetwork struct holds details about a single network,
/// including ssid, encryption type, bitrate, and signal strength.
pub struct WirelessNetwork<'a> {
    ap_addr4: Option<SocketAddrV4>,
    ap_addr6: Option<SocketAddrV6>,
    stats: Option<IwStats>,
    maxbitrate: Option<i32>,
    name: String,
    freq: Option<f64>,
    key: Option<WirelessKey<'a>>,
    essid: Option<String>,
    mode: Option<WirelessMode>,
    encryption: String
}

#[repr(C)]
struct priv_iw_quality {
    qual: uint8_t,
    level: uint8_t,
    noise: uint8_t,
    updated: uint8_t,
}

impl Default for priv_iw_quality {
    fn default() -> priv_iw_quality {
        priv_iw_quality {
            qual: 0,
            level: 0,
            noise: 0,
            updated: 0
        }
    }
}

#[repr(C)]
struct priv_iw_freq {
    m: int32_t,
    e: int16_t,
    i: uint8_t,
    flags: uint8_t,
}

impl Default for priv_iw_freq {
    fn default() -> priv_iw_freq {
        priv_iw_freq {
            m: 0,
            e: 0,
            i: 0,
            flags: 0
        }
    }
}

#[repr(C)]
struct iw_range {
    /* Informative stuff (to choose between different interface) */
    throughput: uint32_t, /* To give an idea... */
    /* In theory this value should be the maximum benchmarked
     * TCP/IP throughput, because with most of these devices the
     * bit rate is meaningless (overhead an co) to estimate how
     * fast the connection will go and pick the fastest one.
     * I suggest people to play with Netperf or any benchmark...
     */

    /* NWID (or domain id) */
    min_nwid: uint32_t, /* Minimal NWID we are able to set */
    max_nwid: uint32_t, /* Maximal NWID we are able to set */

    /* Old Frequency (backward compat - moved lower ) */
    old_num_channels: uint16_t,
    old_num_frequency: uint8_t,

    /* Wireless event capability bitmasks */
    event_capa: [uint32_t; 6],

    /* signal level threshold range */
    sensitivity: int32_t,

    /* Quality of link & SNR stuff */
    /* Quality range (link, level, noise)
     * If the quality is absolute, it will be in the range [0 , max_qual],
     * if the quality is dBm, it will be in the range [max_qual , 0].
     * Don't forget that we use 8 bit arithmetics... */
    max_qual: priv_iw_quality, /* Quality of the link */
    /* This should contain the average/typical values of the quality
     * indicator. This should be the threshold between a "good" and
     * a "bad" link (example : monitor going from green to orange).
     * Currently, user space apps like quality monitors don't have any
     * way to calibrate the measurement. With this, they can split
     * the range between 0 and max_qual in different quality level
     * (using a geometric subdivision centered on the average).
     * I expect that people doing the user space apps will feedback
     * us on which value we need to put in each driver... */
    avg_qual: priv_iw_quality, /* Quality of the link */

    /* Rates */
    num_bitrates: uint8_t, /* Number of entries in the list */
    bitrate: [int32_t; IW_MAX_BITRATES], /* list, in bps */

    /* RTS threshold */
    min_rts: int32_t, /* Minimal RTS threshold */
    max_rts: int32_t, /* Maximal RTS threshold */

    /* Frag threshold */
    min_frag: int32_t, /* Minimal frag threshold */
    max_frag: int32_t, /* Maximal frag threshold */

    /* Power Management duration & timeout */
    min_pmp: int32_t, /* Minimal PM period */
    max_pmp: int32_t, /* Maximal PM period */
    min_pmt: int32_t, /* Minimal PM timeout */
    max_pmt: int32_t, /* Maximal PM timeout */
    pmp_flags: uint16_t, /* How to decode max/min PM period */
    pmt_flags: uint16_t, /* How to decode max/min PM timeout */
    pm_capa: uint16_t, /* What PM options are supported */

    /* Encoder stuff */
    encoding_size: [uint16_t; IW_MAX_ENCODING_SIZES], /* Different token sizes */
    num_encoding_sizes: uint8_t, /* Number of entry in the list */
    max_encoding_tokens: uint8_t, /* Max number of tokens */
    /* For drivers that need a "login/passwd" form */
    encoding_login_index: uint8_t, /* token index for login token */

    /* Transmit power */
    txpower_capa: uint16_t, /* What options are supported */
    num_txpower: uint8_t, /* Number of entries in the list */
    txpower: [int32_t; IW_MAX_TXPOWER], /* list, in bps */

    /* Wireless Extension version info */
    we_version_compiled: uint8_t, /* Must be WIRELESS_EXT */
    we_version_source: uint8_t, /* Last update of source */

    /* Retry limits and lifetime */
    retry_capa: uint16_t, /* What retry options are supported */
    retry_flags: uint16_t, /* How to decode max/min retry limit */
    r_time_flags: uint16_t, /* How to decode max/min retry life */
    min_retry: int32_t, /* Minimal number of retries */
    max_retry: int32_t, /* Maximal number of retries */
    min_r_time: int32_t, /* Minimal retry lifetime */
    max_r_time: int32_t, /* Maximal retry lifetime */

    /* Frequency */
    num_channels: uint16_t, /* Number of channels [0, num - 1] */
    num_frequency: uint8_t, /* Number of entry in the list */
    freq: [priv_iw_freq; IW_MAX_FREQUENCIES], /* list */
    /* Note : this frequency list doesn't need to fit channel numbers,
     * because each entry contain its channel index */
    enc_capa: uint32_t, /* IW_ENC_CAPA_* bit field */

    /* More power management stuff */
    min_pms: int32_t, /* Minimal PM saving */
    max_pms: int32_t, /* Maximal PM saving */
    pms_flags: int16_t, /* How to decode max/min PM saving */

    /* All available modulations for driver (hw may support less) */
    modul_capa: uint32_t, /* IW_MODUL_* bit field */

    /* More bitrate stuff */
    bitrate_capa: uint32_t, /* Types of bitrates supported */
}

impl Default for iw_range {
    fn default() -> iw_range {
        iw_range {
            min_nwid: 0,
            max_nwid: 0,
            old_num_channels: 0,
            old_num_frequency: 0,
            event_capa: [0; ..6u],
            sensitivity: 0,
            max_qual: Default::default(), /* Quality of the link */
            avg_qual: Default::default(), /* Quality of the link */
            num_bitrates: 0, /* Number of entries in the list */
            bitrate: [0; ..IW_MAX_BITRATES], /* list, in bps */
            min_rts: 0, /* Minimal RTS threshold */
            max_rts: 0, /* Maximal RTS threshold */
            min_frag: 0, /* Minimal frag threshold */
            max_frag: 0, /* Maximal frag threshold */
            min_pmp: 0, /* Minimal PM period */
            max_pmp: 0, /* Maximal PM period */
            min_pmt: 0, /* Minimal PM timeout */
            max_pmt: 0, /* Maximal PM timeout */
            pmp_flags: 0, /* How to decode max/min PM period */
            pmt_flags: 0, /* How to decode max/min PM timeout */
            pm_capa: 0, /* What PM options are supported */
            encoding_size: [0; ..IW_MAX_ENCODING_SIZES], /* Different token sizes */
            num_encoding_sizes: 0, /* Number of entry in the list */
            max_encoding_tokens: 0, /* Max number of tokens */
            encoding_login_index: 0, /* token index for login token */
            txpower_capa: 0, /* What options are supported */
            num_txpower: 0, /* Number of entries in the list */
            txpower: [0; ..IW_MAX_TXPOWER], /* list, in bps */
            we_version_compiled: 0, /* Must be WIRELESS_EXT */
            we_version_source: 0, /* Last update of source */
            retry_capa: 0, /* What retry options are supported */
            retry_flags: 0, /* How to decode max/min retry limit */
            r_time_flags: 0, /* How to decode max/min retry life */
            min_retry: 0, /* Minimal number of retries */
            max_retry: 0, /* Maximal number of retries */
            min_r_time: 0, /* Minimal retry lifetime */
            max_r_time: 0, /* Maximal retry lifetime */
            num_channels: 0, /* Number of channels [0, num - 1] */
            num_frequency: 0, /* Number of entry in the list */
            freq: [Default::default(); ..IW_MAX_FREQUENCIES], /* list */
            enc_capa: 0, /* IW_ENC_CAPA_* bit field */
            min_pms: 0, /* Minimal PM saving */
            max_pms: 0, /* Maximal PM saving */
            pms_flags: 0, /* How to decode max/min PM saving */
            modul_capa: 0, /* IW_MODUL_* bit field */
            bitrate_capa: 0, /* Types of bitrates supported */
        }
    }
}

#[link(name="iwlib")]
extern {
    fn iw_socket_open() -> c_int;
    fn iw_get_range_info(socket: c_int,
                         interface: CString,
                         range: &iw_range) -> c_int;
    fn iw_scan(socket: c_int,
               interface: CString,
               version: c_int,
               head: &wireless_scan_head) -> c_int;
}

/// The WifiScan struct is the base object for the dradis library.
/// This struct runs the scan when created and consists of an array of available networks.
pub struct WifiScan<'a> {
    networks: Vec<WirelessNetwork<'a>>,
}

impl<'a> WifiScan<'a> {
    /// Run a scan of the local wifi networks and return a Result with either
    /// a WifiScan instance that contains a `Vec<WirelessNetwork>` called `networks`.
    /// `interface` is a `String` containing the name of the wireless interface to be scanned.
    ///
    /// ```
    /// use dradis::WifiScan;
    ///
    /// let local_networks = match WifiScan::scan("wlan0".to_string()) {
    ///     Ok(scan) => scan,
    ///     Err(err) => panic!("Failed to scan for wireless networks: {}", err)
    /// }
    ///
    /// local_networks.networks.map(|network| {
    ///                             println!("{}: Encryption: {}", network.essid,
    ///                             network.encryption); });
    /// ```
    ///
    pub fn scan(interface: String) -> Result<WifiScan<'a>, WifiScanError> {
        // Scan things here
        unsafe { // TODO: Slim down unsafe blocks.
            // First get an iw socket.
            let sock = iw_socket_open();
            let interface_name = CString::new(interface).unwrap(); // TODO: Make the interface name configurable.
            let range: iw_range;
            let head: wireless_scan_head;
            if iw_get_range_info(sock, interface_name, &range) < 0 {
                // We have to make this call in order to get the version of the library on the computer
                Err("Got an error from the iw library")
            }
            if iw_scan(sock, interface_name, range.we_version_compiled, &head) <0 {
                // This is the actual scan call that fills in the `head` struct with information about the visible networks.
                Err("Got an error from the iw library")
            }
            let result = head.result;
            let mut list = Vec::new();
            while result != ptr::null {
                // The scan results are a linked list of structs with a bunch of information about each network
                // The type of encryption is encoded in a bitflag called `key_flags` which we check by doing
                // a bitwise and against the known bitflags.
                let answer = if result.b.key_flags & IW_AUTH_WPA_VERSION_DISABLED > 0 {
                    "None".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA > 0 {
                    "WPA".to_string()
                } else if result.b.key_flags & IW_AUTH_WPA_VERSION_WPA2 > 0 {
                    "WPA2".to_string()
                } ;
                list.push(WirelessNetwork {
                    SSID: result.b.essid.to_string(),
                    encryption: answer, // TODO Figure out how to get encryption type from `result`
                    strength: result.stats
                });
                result = result.next;
            }
        }
        Ok( WifiScan { networks: list });
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A dataset library.

use std::any::Any;

/// Implemented by all data sets.
pub trait DataSet {
    /// Gets the table description of the data set.
    fn tables(&self) -> &[Table];

    /// Read usize data from a column.
    fn read<T: Any>(&self, table: &str, column: &str) -> Option<ReadData<T>>;
}

/// Implemented by datasets that has a table.
pub trait HasTable<T>: DataSet {
    /// Get access to the full table.
    /// Uses a raw pointer to access multiple tables at the same time.
    fn raw_table(&mut self) -> *mut Vec<T>;

    /// Gets an immutable view into table.
    fn get_table(&self) -> &[T];

    /// Adds a value.
    fn add(&mut self, val: T) -> usize {
        let mut table: &mut Vec<T> = unsafe { &mut *self.raw_table() };
        table.push(val);
        table.len() - 1
    }
}

/// Contains table information.
pub struct Table<'a> {
    /// The name of table.
    pub name: &'a str,
    /// The columns.
    pub columns: &'a [Column<'a>],
}

/// Contains column information.
pub struct Column<'a> {
    /// The name of column.
    pub name: &'a str,
    /// The type of column.
    pub column_type: ColumnType,
}

/// The type of column.
pub enum ColumnType {
    /// A pointer sized integer.
    Usize,
    /// The column is a string.
    String,
}

/// Reads data.
pub struct ReadData<T> {
    /// The current pointer.
    pub ptr: *const T,
    /// The number of data left.
    pub len: usize,
    /// The number of bytes to jump to next pointer.
    pub size: usize,
}

impl<T> ReadData<T> {
    /// Gets pointer at index location.
    pub fn get(&self, index: usize) -> Option<*const T> {
        if index >= self.len { None }
        else {
            Some(unsafe {
                (self.ptr as *const u8)
                    .offset((self.size * index) as isize) as *const T
            })
        }
    }
}

impl<T> Iterator for ReadData<T> {
    type Item = *const T;

    fn next(&mut self) -> Option<*const T> {
        if self.len == 0 { None }
        else {
            self.len -= 1;
            let res = self.ptr;
            self.ptr = unsafe {
                (self.ptr as *const u8)
                    .offset(self.size as isize) as *const T
            };
            Some(res)
        }
    }
}

#[macro_export]
macro_rules! has_table_impls {
    ($x:path { $($n:ident : $t:path),* }) => {

        $(
        impl HasTable<$t> for $x {
            fn raw_table(&mut self) -> *mut Vec<$t> {
                &mut self.$n as *mut _
            }

            fn get_table(&self) -> &[$t] {
                &self.$n[0..]
            }
        }
        )*

    }
}

#[macro_export]
macro_rules! column_type {
    (usize) => { ColumnType::Usize };
    (String) => { ColumnType::String }
}

#[macro_export]
macro_rules! tables {
    ($($x:path { $($n:ident : $t:ident),* })*) => {

    }
}

/// Generates an impl of `DataSet` for a type.
#[macro_export]
macro_rules! dataset_impl {
    ($dataset:ident { $($table_name:ident : $table_type:ident { $($n:ident : $t:ident),* })* }) => {

    impl DataSet for $dataset {

        fn tables(&self) -> &[Table] {
            static TABLES: &'static [Table<'static>] = &[
                $(
                Table { name: stringify!($table_type), columns: &[
                    $(
                    Column { name: stringify!($n), column_type: column_type!($t) },
                    )*
                ] },
                )*
            ];

            TABLES
        }

        fn read<T: Any>(&self, table: &str, column: &str) -> Option<ReadData<T>> {
            use std::mem::{ size_of, transmute };
            use std::ptr::null;

            match (table, column) {
                $($(
                (stringify!($table_type), stringify!($n)) => {
                    if TypeId::of::<T>() == TypeId::of::<$t>() {
                        if self.$table_name.len() == 0 {
                            Some(ReadData {
                                ptr: null(),
                                len: 0,
                                size: 0,
                            })
                        } else {
                            Some(unsafe {transmute(ReadData {
                                ptr: &self.$table_name[0].$n,
                                len: self.$table_name.len(),
                                size: size_of::<$table_type>()
                            })})
                        }
                    } else {
                        None
                    }
                }
                )*)*
                _ => None
            }
        }

    }

    }
}
<commit_msg>Removed `ColumnType`<commit_after>#![deny(missing_docs)]

//! A dataset library.

use std::any::Any;

/// Implemented by data sets for runtime reflection.
/// A data set is a collection of tables, usually `Vec<T>`.
pub trait DataSet {
    /// Gets the table descriptions of the data set.
    fn tables(&self) -> &[Table];

    /// Read data from a column.
    /// The type T is the column type.
    /// Returns a `ReadData` which points directly inside the table.
    fn read<T: Any>(&self, table: &str, column: &str) -> Option<ReadData<T>>;
}

/// Implemented by datasets that has a table for generic programming.
pub trait HasTable<T>: DataSet {
    /// Get access to the full table.
    /// Uses a raw pointer to access multiple tables at the same time.
    fn raw_table(&mut self) -> *mut Vec<T>;

    /// Gets an immutable view into table.
    fn get_table(&self) -> &[T];

    /// Adds a value.
    fn add(&mut self, val: T) -> usize {
        let mut table: &mut Vec<T> = unsafe { &mut *self.raw_table() };
        table.push(val);
        table.len() - 1
    }
}

/// Contains table information.
pub struct Table<'a> {
    /// The name of table.
    pub name: &'a str,
    /// The columns.
    pub columns: &'a [Column<'a>],
}

/// Contains column information.
pub struct Column<'a> {
    /// The name of column.
    pub name: &'a str,
    /// The type of column.
    pub column_type: &'a str,
}

/// Reads data.
pub struct ReadData<T> {
    /// The current pointer.
    pub ptr: *const T,
    /// The number of data left.
    pub len: usize,
    /// The number of bytes to jump to next pointer.
    pub size: usize,
}

impl<T> ReadData<T> {
    /// Gets pointer at index location.
    pub fn get(&self, index: usize) -> Option<*const T> {
        if index >= self.len { None }
        else {
            Some(unsafe {
                (self.ptr as *const u8)
                    .offset((self.size * index) as isize) as *const T
            })
        }
    }
}

impl<T> Iterator for ReadData<T> {
    type Item = *const T;

    fn next(&mut self) -> Option<*const T> {
        if self.len == 0 { None }
        else {
            self.len -= 1;
            let res = self.ptr;
            self.ptr = unsafe {
                (self.ptr as *const u8)
                    .offset(self.size as isize) as *const T
            };
            Some(res)
        }
    }
}

#[macro_export]
macro_rules! has_table_impls {
    ($x:path { $($n:ident : $t:path),* }) => {

        $(
        impl HasTable<$t> for $x {
            fn raw_table(&mut self) -> *mut Vec<$t> {
                &mut self.$n as *mut _
            }

            fn get_table(&self) -> &[$t] {
                &self.$n[0..]
            }
        }
        )*

    }
}

/// Generates an impl of `DataSet` for a type.
#[macro_export]
macro_rules! dataset_impl {
    ($dataset:ident { $($table_name:ident : $table_type:ident { $($n:ident : $t:ident),* })* }) => {

    impl DataSet for $dataset {

        fn tables(&self) -> &[Table] {
            static TABLES: &'static [Table<'static>] = &[
                $(
                Table { name: stringify!($table_type), columns: &[
                    $(
                    Column { name: stringify!($n), column_type: stringify!($t) },
                    )*
                ] },
                )*
            ];

            TABLES
        }

        fn read<T: Any>(&self, table: &str, column: &str) -> Option<ReadData<T>> {
            use std::mem::{ size_of, transmute };
            use std::ptr::null;

            match (table, column) {
                $($(
                (stringify!($table_type), stringify!($n)) => {
                    if TypeId::of::<T>() == TypeId::of::<$t>() {
                        if self.$table_name.len() == 0 {
                            Some(ReadData {
                                ptr: null(),
                                len: 0,
                                size: 0,
                            })
                        } else {
                            Some(unsafe {transmute(ReadData {
                                ptr: &self.$table_name[0].$n,
                                len: self.$table_name.len(),
                                size: size_of::<$table_type>()
                            })})
                        }
                    } else {
                        None
                    }
                }
                )*)*
                _ => None
            }
        }

    }

    }
}
<|endoftext|>


<commit_before>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_deriving)]

extern crate libc;

use std::c_str::CString;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub fn run_with_fds(args: Vec<String>, read_fd: i32, write_fd: i32) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| s.as_slice().to_c_str()).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main(vp.len() as i32, p_vp, read_fd, write_fd) }
}

pub fn run(args: Vec<String>) -> i32 {
    run_with_fds(args, -1, -1)
}

pub fn serialize_request(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let c_str = method.to_c_str();
        let vim_str = ffi::C_String {data: c_str.as_ptr(), size: c_str.len() as u64};
        ffi::vim_serialize_request(id, vim_str, *args.get_pointer(), buf);
        let s = String::from_raw_buf_len((*buf).data as *const u8, (*buf).size as uint);
        ffi::vim_msgpack_free(buf);
        s
    }
}

#[deriving(Copy)]
pub struct Array {
    pointer: *mut ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            pointer: ::std::ptr::null_mut()
        }
    }

    pub fn add_buffer(&mut self, val: ffi::Buffer) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_buffer(val, self.pointer) }
    }

    pub fn add_window(&mut self, val: ffi::Window) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_window(val, self.pointer) }
    }

    pub fn add_tabpage(&mut self, val: ffi::Tabpage) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_tabpage(val, self.pointer) }
    }

    pub fn add_nil(&mut self) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_nil(self.pointer) }
    }

    pub fn add_boolean(&mut self, val: ffi::Boolean) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_boolean(val, self.pointer) }
    }

    pub fn add_integer(&mut self, val: ffi::Integer) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_integer(val, self.pointer) }
    }

    pub fn add_float(&mut self, val: ffi::Float) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_float(val, self.pointer) }
    }

    pub fn add_string(&mut self, val: &str) {
        self.check_pointer();
        unsafe {
            let c_str = val.to_c_str();
            let vim_str = ffi::C_String {data: c_str.as_ptr(), size: c_str.len() as u64};
            ffi::vim_array_add_string(vim_str, self.pointer)
        }
    }

    pub fn add_array(&mut self, val: Array) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_array(*val.get_pointer(), self.pointer) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_dictionary(val, self.pointer) }
    }

    pub fn clear(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::vim_array_free(self.pointer) };
        }
        self.pointer = ::std::ptr::null_mut();
    }

    pub fn len(&self) -> u64 {
        if !self.pointer.is_null() {
            unsafe { (*self.pointer).size }
        } else {
            0
        }
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_Array {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_array: *mut ffi::C_Array) -> Array {
        Array {
            pointer: c_array
        }
    }

    fn check_pointer(&mut self) {
        if self.pointer.is_null() {
            self.pointer = unsafe { ffi::vim_array_new() };
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        self.clear();
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    println!("{}", serialize_request(1, "attach_ui", &args));
}
<commit_msg>Fix the add_string function<commit_after>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_deriving)]

extern crate libc;

use std::c_str::CString;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub fn run_with_fds(args: Vec<String>, read_fd: i32, write_fd: i32) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| s.as_slice().to_c_str()).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main(vp.len() as i32, p_vp, read_fd, write_fd) }
}

pub fn run(args: Vec<String>) -> i32 {
    run_with_fds(args, -1, -1)
}

pub fn serialize_request(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let c_str = method.to_c_str();
        let vim_str = ffi::C_String {data: c_str.as_ptr(), size: c_str.len() as u64};
        ffi::vim_serialize_request(id, vim_str, *args.get_pointer(), buf);
        let s = String::from_raw_buf_len((*buf).data as *const u8, (*buf).size as uint);
        ffi::vim_msgpack_free(buf);
        s
    }
}

#[deriving(Copy)]
pub struct Array {
    pointer: *mut ffi::C_Array
}

impl Array {
    pub fn new() -> Array {
        Array {
            pointer: ::std::ptr::null_mut()
        }
    }

    pub fn add_buffer(&mut self, val: ffi::Buffer) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_buffer(val, self.pointer) }
    }

    pub fn add_window(&mut self, val: ffi::Window) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_window(val, self.pointer) }
    }

    pub fn add_tabpage(&mut self, val: ffi::Tabpage) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_tabpage(val, self.pointer) }
    }

    pub fn add_nil(&mut self) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_nil(self.pointer) }
    }

    pub fn add_boolean(&mut self, val: ffi::Boolean) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_boolean(val, self.pointer) }
    }

    pub fn add_integer(&mut self, val: ffi::Integer) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_integer(val, self.pointer) }
    }

    pub fn add_float(&mut self, val: ffi::Float) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_float(val, self.pointer) }
    }

    pub fn add_string(&mut self, val: &str) {
        self.check_pointer();
        unsafe {
            let vim_str = ffi::C_String {data: val.as_ptr() as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, self.pointer)
        }
    }

    pub fn add_array(&mut self, val: Array) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_array(*val.get_pointer(), self.pointer) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        self.check_pointer();
        unsafe { ffi::vim_array_add_dictionary(val, self.pointer) }
    }

    pub fn clear(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::vim_array_free(self.pointer) };
        }
        self.pointer = ::std::ptr::null_mut();
    }

    pub fn len(&self) -> u64 {
        if !self.pointer.is_null() {
            unsafe { (*self.pointer).size }
        } else {
            0
        }
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_Array {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_array: *mut ffi::C_Array) -> Array {
        Array {
            pointer: c_array
        }
    }

    fn check_pointer(&mut self) {
        if self.pointer.is_null() {
            self.pointer = unsafe { ffi::vim_array_new() };
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        self.clear();
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");
    println!("{}", serialize_request(1, "attach_ui", &args));
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::{mpsc, Arc, Mutex, Condvar};

pub enum ControlFlow {
    Series,
    Parallel,
    //ParallelLimit(u16)
}

pub struct Deferred<T,E> {
    starter  : Arc<(Mutex<bool>, Condvar)>,
    receiver : mpsc::Receiver<Result<T,E>>
}

impl<T,E> Deferred<T,E> where T: Send + 'static , E: Send + 'static {
    pub fn new<F>(f:F) -> Deferred<T,E> where F: Send + 'static + FnOnce() -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        let pair = Arc::new((Mutex::new(false), Condvar::new()));
        let pair_c = pair.clone();
        thread::spawn(move|| {
            // wait for the thread to start up
            let &(ref lock, ref cvar) = &*pair_c;
            let mut started = lock.lock().unwrap();
            while !*started {  started = cvar.wait(started).unwrap(); }
            tx.send(f())
        });
        Deferred {
            starter  : pair,
            receiver : rx
        }
    }

    pub fn to_promise(self) -> Promise<T,E> {
        self.unlock();
        Promise { receiver: self.receiver }
    }

    pub fn vec_to_promise(vector:Vec<Deferred<T,E>>, control: ControlFlow) -> Promise<Vec<T>,Vec<Result<T,E>>> {
        match control {
            ControlFlow::Series => {
                let (tx,rx) = mpsc::channel();
                thread::spawn(move || {
                    let mut results:Vec<T> = Vec::new();
                    for defer in vector {
                        defer.unlock();
                        match defer.receiver.recv().unwrap() {
                            Ok(t) => results.push(t),
                            Err(e) => {
                                let mut results_error:Vec<Result<T,E>> = Vec::new();
                                for t in results { results_error.push(Ok(t)) }
                                results_error.push(Err(e));
                                let res:Result<Vec<T>,Vec<Result<T,E>>> = Err(results_error);
                                tx.send(res).unwrap();
                                return
                            }
                        }
                    }
                    let ok_results:Result<Vec<T>, Vec<Result<T,E>>> = Ok(results);
                    tx.send(ok_results).unwrap()
                });
                Promise::<Vec<T>, Vec<Result<T,E>>> { receiver: rx }
            },
            ControlFlow::Parallel => {
                let mut vector_promises:Vec<Promise<T,E>> = Vec::new();
                for defer in vector { vector_promises.push(defer.to_promise())};
                Promise::all(vector_promises)
            }
        }
    }

    fn unlock(&self) {
        let &(ref lock, ref cvar) = &*self.starter;
        let mut started = lock.lock().unwrap();
        *started = true;
        cvar.notify_one();
    }
}

pub struct Promise<T,E> {
    receiver : mpsc::Receiver<Result<T,E>>
}

impl<T,E> Promise<T,E> where T: Send + 'static , E: Send + 'static {

    pub fn new<F>(f:F) -> Promise<T,E> where F: Send + 'static + FnOnce() -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || { tx.send(f()) });
        Promise::<T,E> { receiver: rx }
    }

    pub fn all(vector:Vec<Promise<T,E>>) -> Promise<Vec<T>, Vec<Result<T,E>>> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let results:Vec<Result<T,E>> = vector.iter().map(|p| p.receiver.recv().unwrap() ).collect();
            let is_error = results.iter().find(|r| r.is_err()).is_some();
            let ok_results:Result<Vec<T>, Vec<Result<T,E>>> = match is_error {
                false => {
                    let mut v:Vec<T> = Vec::new();
                    for r in results { v.push(match r { Ok(t) => t, Err(_) => unreachable!() })}
                    Ok(v)
                },
                true  => Err(results)
            };
            tx.send(ok_results).unwrap()
        });
        Promise::<Vec<T>, Vec<Result<T,E>>> { receiver: rx }
    }

    pub fn then<TT,F>(self,f:F) -> Promise<TT,E> where F: Send + 'static + FnOnce(T) -> Result<TT,E>, TT: Send + 'static {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => tx.send(f(t)),
                Err(e) => tx.send(Err(e))
            }
        });
        Promise::<TT,E> { receiver: rx }
    }

    pub fn fail<F>(self,f:F) -> Promise<T,E> where F: Send + 'static + FnOnce(E) -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => tx.send(Ok(t)),
                Err(e) => tx.send(f(e))
            }
        });
        Promise::<T,E> { receiver: rx }
    }

    pub fn finally<FT,FE>(self, ft:FT, fe:FE) where FT: Send + 'static + FnOnce(T) , FE: Send + 'static + FnOnce(E) {
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => ft(t),
                Err(e) => fe(e)
            };
        });
    }

    pub fn finally_sync<FT,FE>(self, ft:FT, fe:FE) where FT: Send + 'static + FnOnce(T) , FE: Send + 'static +FnOnce(E) {
        match self.sync() {
            Ok(t) => ft(t),
            Err(e) => fe(e)
        };
    }

    pub fn sync(self) -> Result<T,E> {
        self.receiver.recv().unwrap()
    }
}

#[cfg(test)]
mod test {
    use std::thread;
    use super::*;

    #[test]
    fn promises() {
        for x in 0..10 {
            let promise = Promise::<u32,&str>::new(move || {
                match x {
                    0 => Err("Division by zero"),
                    _ => Ok(x * 2)
                }
            }).then(move |res| {
                assert_eq!(res, x * 2);
                Ok(res * 2)
            }).fail(|error| {
                assert_eq!(error, "Division by zero");
                Err(error)
            }) ;

            let result = promise.sync();

            match x {
                0 => assert!(result.is_err()),
                _ => {
                    assert!(result.is_ok());
                    assert_eq!(result.unwrap(), x * 4);
                }
            }
        }
    }

    #[test]
    fn promises_parallel() {
        let promise1 = Promise::<u32,&str>::new(|| {
            Ok(1u32)
        });
        let promise2 = Promise::<u32,&str>::new(|| {
            Ok(2u32)
        });
        let promise3 = Promise::<u32,&str>::new(|| {
            Ok(3u32)
        });
        let promise4 = Promise::<u32,&str>::new(|| {
            Err("Error")
        });
        let promise5 = Promise::<u32,&str>::new(|| {
            Ok(5u32)
        });
        Promise::all(vec![promise1, promise2, promise3]).finally_sync(|res| {
            assert_eq!(res, vec![1u32,2u32,3u32]);
        }, |err| {
            unreachable!("{:?}", err);
        });
        Promise::all(vec![promise4, promise5]).finally_sync(|res| {
            unreachable!("{:?}", res);
        }, |err:Vec<Result<u32,&str>>| {
            assert!(err[0].is_err());
            assert!(err[1].is_ok());
        });
    }

    #[test]
    fn deferred_to_promise() {
        Deferred::<u32,&str>::new(|| {
            Ok(88u32)
        }).to_promise().finally_sync(|r| {
            assert_eq!(r, 88u32);
        }, |e| {
            panic!("Error not expected {} ", e);
        });
    }

    #[test]
    fn deferred_in_series() {
        // TODO: Acumulate string in Mutex to check serial
        let d1 = Deferred::<u32, &str>::new(||{
            thread::sleep_ms(200);
            Ok(1u32)
        });
        let d2 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(2u32)
        });
        let d3 = Deferred::<u32, &str>::new(||{
            thread::sleep_ms(200);
            Ok(3u32)
        });
        let d4 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(4u32)
        });
        let d5 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Err("Error")
        });
        let d6 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(6u32)
        });

        let r = Deferred::vec_to_promise(vec![d1, d2, d3], ControlFlow::Series)
            .then(|res| {
                assert_eq!(vec![1u32,2u32, 3u32], res);
                Ok(0u32)
            }).sync();
        assert_eq!(r, Ok(0u32));

        Deferred::vec_to_promise(vec![d4,d5,d6], ControlFlow::Series)
            .finally_sync(|res| {
                unreachable!("Res: {:?}", res);
            }, |errors| {
                assert_eq!(errors.len(), 2);
                assert_eq!(errors[0], Ok(4u32));
                assert_eq!(errors[1], Err("Error"));
            });
    }

    #[test]
    fn deferred_in_parallel() {
        // TODO: Acumulate string in Mutex to check parallel
        let d1 = Deferred::<u32, &str>::new(||{
            thread::sleep_ms(200);
            Ok(1u32)
        });
        let d2 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(2u32)
        });
        let d3 = Deferred::<u32, &str>::new(||{
            thread::sleep_ms(200);
            Ok(3u32)
        });
        let d4 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(4u32)
        });
        let d5 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Err("Error")
        });
        let d6 = Deferred::<u32, &str>::new(|| {
            thread::sleep_ms(100);
            Ok(6u32)
        });

        let r = Deferred::vec_to_promise(vec![d1, d2, d3], ControlFlow::Parallel)
            .then(|res| {
                assert_eq!(vec![1u32,2u32, 3u32], res);
                Ok(0u32)
            }).sync();
        assert_eq!(r, Ok(0u32));

        Deferred::vec_to_promise(vec![d4,d5,d6], ControlFlow::Parallel)
            .finally_sync(|res| {
                unreachable!("Res: {:?}", res);
            }, |errors| {
                assert_eq!(errors.len(), 3);
                assert_eq!(errors[0], Ok(4u32));
                assert_eq!(errors[1], Err("Error"));
                assert_eq!(errors[2], Ok(6u32));
            });
    }
}<commit_msg>Update documentation, tests and examples<commit_after>/*!
A **promise** based asynchronous library

This library will provide an usefull way to invoke functions (clousures) in a **Promise Style**. A Promise
is a Struct that represents the return value or the error that the funcion produces and it's executed in
a separated thread.

[Project github page](https://github.com/bcndanos/asynchronous)

This project is based on the [Q Promise](https://github.com/kriskowal/q) library for Node JS .

# Examples

This is a simple setup for a promise based execution:

```rust
use asynchronous::Promise;

Promise::new(|| {
  // Do something in another thread
  let ret = 10.0 / 3.0;
  if ret > 0.0 { Ok(ret) } else { Err("Value Incorrect") }
}).then(|res| {            // res has type f64
  // Do something if the previous result is correct
  let res_int = res as u32 * 2;
  Ok(res_int)
}).finally_sync(|res| {    // res has type u32
  // Catch a correct result
  println!("Result produced: {:?}" , res);  // res is 6u32
}, |error| {
  // Catch an incorrect result
  println!("Error produced: {:?} ", error);
});
```

Using deferred execution of 3 tasks in Parallel and 2 tasks in Series:

```rust
use asynchronous::Deferred;
use asynchronous::ControlFlow;

let d1 = Deferred::<u32, &str>::new(|| { Ok(1u32) });
let d2 = Deferred::<u32, &str>::new(|| { Err("Error") });
let d3 = Deferred::<u32, &str>::new(|| { Ok(3u32) });
let d4 = Deferred::<u32, &str>::new(|| { Ok(4u32) });
let d5 = Deferred::<u32, &str>::new(|| { Ok(5u32) });

let promise_parallel = Deferred::vec_to_promise(vec![d1,d2,d3], ControlFlow::Parallel);
let promise_series = Deferred::vec_to_promise(vec![d4,d5], ControlFlow::Series);

promise_parallel.then(|res| {
    // Catch the result. In this case, tasks d4 and d5 never will be executed
    Ok(res)
}).fail(|error| {
    // Catch the error and execute another Promise
    promise_series.sync()
}).finally_sync(|vector_results| {   // vector_results : Vec<u32>
    // Do something here
}, |vector_errors| { // vector_errors : Vec<Result<u32,&str>>
    // Do something here.
});

```

TODO: ControlFlow::ParallelLimit(limit) => execution in parallel with a maximum of **limit** tasks executing at any time.

*/

use std::thread;
use std::sync::{mpsc, Arc, Mutex, Condvar};

pub enum ControlFlow {
    Series,
    Parallel,
    //ParallelLimit(u16)
}

pub struct Deferred<T,E> {
    starter  : Arc<(Mutex<bool>, Condvar)>,
    receiver : mpsc::Receiver<Result<T,E>>
}

impl<T,E> Deferred<T,E> where T: Send + 'static , E: Send + 'static {
    pub fn new<F>(f:F) -> Deferred<T,E> where F: Send + 'static + FnOnce() -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        let pair = Arc::new((Mutex::new(false), Condvar::new()));
        let pair_c = pair.clone();
        thread::spawn(move|| {
            // wait for the thread to start up
            let &(ref lock, ref cvar) = &*pair_c;
            let mut started = lock.lock().unwrap();
            while !*started {  started = cvar.wait(started).unwrap(); }
            tx.send(f())
        });
        Deferred {
            starter  : pair,
            receiver : rx
        }
    }

    pub fn to_promise(self) -> Promise<T,E> {
        self.unlock();
        Promise { receiver: self.receiver }
    }

    pub fn vec_to_promise(vector:Vec<Deferred<T,E>>, control: ControlFlow) -> Promise<Vec<T>,Vec<Result<T,E>>> {
        match control {
            ControlFlow::Series => {
                let (tx,rx) = mpsc::channel();
                thread::spawn(move || {
                    let mut results:Vec<T> = Vec::new();
                    for defer in vector {
                        defer.unlock();
                        match defer.receiver.recv().unwrap() {
                            Ok(t) => results.push(t),
                            Err(e) => {
                                let mut results_error:Vec<Result<T,E>> = Vec::new();
                                for t in results { results_error.push(Ok(t)) }
                                results_error.push(Err(e));
                                let res:Result<Vec<T>,Vec<Result<T,E>>> = Err(results_error);
                                tx.send(res).unwrap();
                                return
                            }
                        }
                    }
                    let ok_results:Result<Vec<T>, Vec<Result<T,E>>> = Ok(results);
                    tx.send(ok_results).unwrap()
                });
                Promise::<Vec<T>, Vec<Result<T,E>>> { receiver: rx }
            },
            ControlFlow::Parallel => {
                let mut vector_promises:Vec<Promise<T,E>> = Vec::new();
                for defer in vector { vector_promises.push(defer.to_promise())};
                Promise::all(vector_promises)
            }
        }
    }

    fn unlock(&self) {
        let &(ref lock, ref cvar) = &*self.starter;
        let mut started = lock.lock().unwrap();
        *started = true;
        cvar.notify_one();
    }
}

pub struct Promise<T,E> {
    receiver : mpsc::Receiver<Result<T,E>>
}

impl<T,E> Promise<T,E> where T: Send + 'static , E: Send + 'static {

    pub fn new<F>(f:F) -> Promise<T,E> where F: Send + 'static + FnOnce() -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || { tx.send(f()) });
        Promise::<T,E> { receiver: rx }
    }

    pub fn all(vector:Vec<Promise<T,E>>) -> Promise<Vec<T>, Vec<Result<T,E>>> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let results:Vec<Result<T,E>> = vector.iter().map(|p| p.receiver.recv().unwrap() ).collect();
            let is_error = results.iter().find(|r| r.is_err()).is_some();
            let ok_results:Result<Vec<T>, Vec<Result<T,E>>> = match is_error {
                false => {
                    let mut v:Vec<T> = Vec::new();
                    for r in results { v.push(match r { Ok(t) => t, Err(_) => unreachable!() })}
                    Ok(v)
                },
                true  => Err(results)
            };
            tx.send(ok_results).unwrap()
        });
        Promise::<Vec<T>, Vec<Result<T,E>>> { receiver: rx }
    }

    pub fn then<TT,F>(self,f:F) -> Promise<TT,E> where F: Send + 'static + FnOnce(T) -> Result<TT,E>, TT: Send + 'static {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => tx.send(f(t)),
                Err(e) => tx.send(Err(e))
            }
        });
        Promise::<TT,E> { receiver: rx }
    }

    pub fn fail<F>(self,f:F) -> Promise<T,E> where F: Send + 'static + FnOnce(E) -> Result<T,E> {
        let (tx,rx) = mpsc::channel();
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => tx.send(Ok(t)),
                Err(e) => tx.send(f(e))
            }
        });
        Promise::<T,E> { receiver: rx }
    }

    pub fn finally<FT,FE>(self, ft:FT, fe:FE) where FT: Send + 'static + FnOnce(T) , FE: Send + 'static + FnOnce(E) {
        thread::spawn(move || {
            let res = self.receiver.recv().unwrap();
            match res {
                Ok(t) => ft(t),
                Err(e) => fe(e)
            };
        });
    }

    pub fn finally_sync<FT,FE>(self, ft:FT, fe:FE) where FT: Send + 'static + FnOnce(T) , FE: Send + 'static +FnOnce(E) {
        match self.sync() {
            Ok(t) => ft(t),
            Err(e) => fe(e)
        };
    }

    pub fn sync(self) -> Result<T,E> {
        self.receiver.recv().unwrap()
    }
}

#[cfg(test)]
mod test {
    use std::sync::{Arc, Mutex};
    use std::thread;
    use super::*;

    #[test]
    fn promises() {
        for x in 0..10 {
            let promise = Promise::<u32,&str>::new(move || {
                match x {
                    0 => Err("Division by zero"),
                    _ => Ok(x * 2)
                }
            }).then(move |res| {
                assert_eq!(res, x * 2);
                Ok(res * 2)
            }).fail(|error| {
                assert_eq!(error, "Division by zero");
                Err(error)
            }) ;

            let result = promise.sync();

            match x {
                0 => assert!(result.is_err()),
                _ => {
                    assert!(result.is_ok());
                    assert_eq!(result.unwrap(), x * 4);
                }
            }
        }
    }

    #[test]
    fn promises_parallel() {
        let promise1 = Promise::<u32,&str>::new(|| {
            Ok(1u32)
        });
        let promise2 = Promise::<u32,&str>::new(|| {
            Ok(2u32)
        });
        let promise3 = Promise::<u32,&str>::new(|| {
            Ok(3u32)
        });
        let promise4 = Promise::<u32,&str>::new(|| {
            Err("Error")
        });
        let promise5 = Promise::<u32,&str>::new(|| {
            Ok(5u32)
        });
        Promise::all(vec![promise1, promise2, promise3]).finally_sync(|res| {
            assert_eq!(res, vec![1u32,2u32,3u32]);
        }, |err| {
            unreachable!("{:?}", err);
        });
        Promise::all(vec![promise4, promise5]).finally_sync(|res| {
            unreachable!("{:?}", res);
        }, |err:Vec<Result<u32,&str>>| {
            assert!(err[0].is_err());
            assert!(err[1].is_ok());
        });
    }

    #[test]
    fn deferred_to_promise() {
        Deferred::<u32,&str>::new(|| {
            Ok(88u32)
        }).to_promise().finally_sync(|r| {
            assert_eq!(r, 88u32);
        }, |e| {
            panic!("Error not expected {} ", e);
        });
    }

    #[test]
    fn deferred_in_series() {
        let st = Arc::new(Mutex::new(String::new()));

        let lock1 = st.clone();
        let d1 = Deferred::<u32, &str>::new(move ||{
            thread::sleep_ms(200);
            lock1.lock().unwrap().push_str("Def1");
            Ok(1u32)
        });

        let lock2 = st.clone();
        let d2 = Deferred::<u32, &str>::new(move || {
            thread::sleep_ms(100);
            lock2.lock().unwrap().push_str("Def2");
            Ok(2u32)
        });

        let lock3 = st.clone();
        let d3 = Deferred::<u32, &str>::new(move ||{
            thread::sleep_ms(200);
            lock3.lock().unwrap().push_str("Def3");
            Ok(3u32)
        });

        let d4 = Deferred::<u32, &str>::new(|| {
            Ok(4u32)
        });
        let d5 = Deferred::<u32, &str>::new(|| {
            Err("Error")
        });
        let d6 = Deferred::<u32, &str>::new(|| {
            Ok(6u32)
        });

        let r = Deferred::vec_to_promise(vec![d1, d2, d3], ControlFlow::Series)
            .then(|res| {
                assert_eq!(vec![1u32,2u32, 3u32], res);
                Ok(0u32)
            }).sync();
        assert_eq!(r, Ok(0u32));
        assert_eq!(*st.lock().unwrap(),"Def1Def2Def3");

        Deferred::vec_to_promise(vec![d4,d5,d6], ControlFlow::Series)
            .finally_sync(|res| {
                unreachable!("Res: {:?}", res);
            }, |errors| {
                assert_eq!(errors.len(), 2);
                assert_eq!(errors[0], Ok(4u32));
                assert_eq!(errors[1], Err("Error"));
            });
    }

    #[test]
    fn deferred_in_parallel() {
        let st = Arc::new(Mutex::new(String::new()));

        let lock1 = st.clone();
        let d1 = Deferred::<u32, &str>::new(move ||{
            thread::sleep_ms(200);
            lock1.lock().unwrap().push_str("Def1");
            Ok(1u32)
        });
        let lock2 = st.clone();
        let d2 = Deferred::<u32, &str>::new(move || {
            thread::sleep_ms(300);
            lock2.lock().unwrap().push_str("Def2");
            Ok(2u32)
        });
        let lock3 = st.clone();
        let d3 = Deferred::<u32, &str>::new(move ||{
            thread::sleep_ms(50);
            lock3.lock().unwrap().push_str("Def3");
            Ok(3u32)
        });
        let d4 = Deferred::<u32, &str>::new(|| {
            Ok(4u32)
        });
        let d5 = Deferred::<u32, &str>::new(|| {
            Err("Error")
        });
        let d6 = Deferred::<u32, &str>::new(|| {
            Ok(6u32)
        });

        let r = Deferred::vec_to_promise(vec![d1, d2, d3], ControlFlow::Parallel)
            .then(|res| {
                assert_eq!(vec![1u32,2u32, 3u32], res);
                Ok(0u32)
            }).sync();
        assert_eq!(r, Ok(0u32));
        assert_eq!(*st.lock().unwrap(),"Def3Def1Def2");

        Deferred::vec_to_promise(vec![d4,d5,d6], ControlFlow::Parallel)
            .finally_sync(|res| {
                unreachable!("Res: {:?}", res);
            }, |errors| {
                assert_eq!(errors.len(), 3);
                assert_eq!(errors[0], Ok(4u32));
                assert_eq!(errors[1], Err("Error"));
                assert_eq!(errors[2], Ok(6u32));
            });
    }
}<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]
#![allow(unstable)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)] extern crate std;
extern crate core;

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<commit_msg>Allow unstable more specifically and fix an int<commit_after>#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)]
extern crate std;

#[allow(unstable)]
extern crate core;

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

#[allow(unstable)]
unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>