<commit_before>use russell_lab::{Matrix, Vector};

/// Defines a tetrahedron with 10 nodes (quadratic faces)
///
/// ![tet10](https://raw.githubusercontent.com/cpmech/gemlab/main/data/figures/test_draw_shape_tet10.svg)
///
/// # Local IDs of nodes
///
/// ```text
///               t               r    s    t
///               |         p:0 [0.0, 0.0, 0.0]
///               3         p:1 [1.0, 0.0, 0.0]
///              /|`.       p:2 [0.0, 1.0, 0.0]
///              ||  `,     p:3 [0.0, 0.0, 1.0]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           9,
///           |   |             \
///          /    |              `.
///          8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /              ``''-.,,_  ',
///       |    /                        ``-2-,_s
///       |  4'                       ,.-`` 2
///      |  ,                    _,-'`
///      ' /                 ,.'`
///     | /             _5-``      r    s    t
///     '/          ,-'`     p:4 [0.5, 0.0, 0.0]
///    |/      ,.-``         p:5 [0.5, 0.5, 0.0]
///    /  _,-``              p:6 [0.0, 0.5, 0.0]
///   1 '`                   p:7 [0.0, 0.0, 0.5]
///  /                       p:8 [0.5, 0.0, 0.5]
/// r                        p:9 [0.0, 0.5, 0.5]
/// ```
///
/// # Local IDs of edges
///
/// ```text
///               t                    p0  p1 p2
///               |                e:0 [0, 1, 4]
///               3                e:1 [1, 2, 5]
///              /|`.              e:2 [2, 0, 6]
///              ||  `,            e:3 [0, 3, 7]
///             / |    ',          e:4 [1, 3, 8]
///             | |      \         e:5 [2, 3, 9]
///            /  |       `.
///            |  |         `,
///           /   7(3)        `9(5)
///           |   |             \
///          /    |              `.
///       (4)8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /          (2) ``''-.,,_  ',
///       |    /                        ``'2-,_s
///       |  4'                       ,.-``
///      |  ,(0)                 _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'` (1)
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// * The order of edge nodes corresponds to **Lin3** nodes.
///
/// # Local IDs of faces
///
/// ```text
///               t           p0 p1 p2 p3 p4 p5
///               |       f:0 [0, 3, 2, 7, 9, 6]
///               3       f:1 [0, 1, 3, 4, 8, 7]
///              /|`.     f:2 [0, 2, 1, 6, 5, 4]
///              ||  `,   f:3 [1, 2, 3, 5, 9, 8]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           `9
///           |   |     [0]     \
///          /    |              `.
///          8    |                ',
///         / [1] |    ,             \
///         |     0. ,' \             `.
///        |     /   \ 3 \ .,6__        `.
///        |    /     \ ,'     ``''-.,,_  ',
///       |    /       '                ``'2-,_s
///       |  4'                       ,.-``
///      |  ,      [2]           _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'`
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Notes
///
/// * The order of face nodes is such that the normals are outward
/// * The order of face nodes corresponds to [super::Tri6] nodes
pub struct Tet10 {}

impl Tet10 {
    pub const GEO_NDIM: usize = 3;
    pub const NNODE: usize = 10;
    pub const NEDGE: usize = 6;
    pub const NFACE: usize = 4;
    pub const EDGE_NNODE: usize = 3;
    pub const FACE_NNODE: usize = 6;
    pub const FACE_NEDGE: usize = 3;

    #[rustfmt::skip]
    pub const EDGE_NODE_IDS: [[usize; Tet10::EDGE_NNODE]; Tet10::NEDGE] = [
        [0, 1, 4],
        [1, 2, 5],
        [2, 0, 6],
        [0, 3, 7],
        [1, 3, 8],
        [2, 3, 9],
    ];

    #[rustfmt::skip]
    pub const FACE_NODE_IDS: [[usize; Tet10::FACE_NNODE]; Tet10::NFACE] = [
        [0, 3, 2, 7, 9, 6],
        [0, 1, 3, 4, 8, 7],
        [0, 2, 1, 6, 5, 4],
        [1, 2, 3, 5, 9, 8],
    ];

    #[rustfmt::skip]
    pub const FACE_EDGE_NODE_IDS: [[[usize; Tet10::EDGE_NNODE]; Tet10::FACE_NEDGE]; Tet10::NFACE] = [
        [[0, 3, 7], [3, 2, 9], [2, 0, 6]],
        [[0, 1, 4], [1, 3, 8], [3, 0, 7]],
        [[0, 2, 6], [2, 1, 5], [1, 0, 4]],
        [[1, 2, 5], [2, 3, 9], [3, 1, 8]],
    ];

    #[rustfmt::skip]
    pub const NODE_REFERENCE_COORDS: [[f64; Tet10::GEO_NDIM]; Tet10::NNODE] = [
        [0.0, 0.0, 0.0], // 0
        [1.0, 0.0, 0.0], // 1
        [0.0, 1.0, 0.0], // 2
        [0.0, 0.0, 1.0], // 3
        [0.5, 0.0, 0.0], // 4
        [0.5, 0.5, 0.0], // 5
        [0.0, 0.5, 0.0], // 6
        [0.0, 0.0, 0.5], // 7
        [0.5, 0.0, 0.5], // 8
        [0.0, 0.5, 0.5], // 9
    ];

    /// Computes the interpolation functions
    ///
    /// # Output
    ///
    /// * `interp` -- interpolation function evaluated at ksi (nnode)
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates with length ≥ geo_ndim
    pub fn calc_interp(interp: &mut Vector, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        let u = 1.0 - r - s - t;

        interp[0] = u * (2.0 * u - 1.0);
        interp[1] = r * (2.0 * r - 1.0);
        interp[2] = s * (2.0 * s - 1.0);
        interp[3] = t * (2.0 * t - 1.0);
        interp[4] = 4.0 * u * r;
        interp[5] = 4.0 * r * s;
        interp[6] = 4.0 * s * u;
        interp[7] = 4.0 * u * t;
        interp[8] = 4.0 * r * t;
        interp[9] = 4.0 * s * t;
    }

    /// Computes the derivatives of interpolation functions with respect to the reference coordinates
    ///
    /// # Output
    ///
    /// * `deriv` -- derivatives of the interpolation function with respect to
    ///   the reference coordinates ksi, evaluated at ksi (nnode,geo_ndim)
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates with length ≥ geo_ndim
    pub fn calc_deriv(deriv: &mut Matrix, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        deriv[0][0] = 4.0 * (r + s + t) - 3.0;
        deriv[1][0] = 4.0 * r - 1.0;
        deriv[2][0] = 0.0;
        deriv[3][0] = 0.0;
        deriv[4][0] = 4.0 - 8.0 * r - 4.0 * s - 4.0 * t;
        deriv[5][0] = 4.0 * s;
        deriv[6][0] = -4.0 * s;
        deriv[7][0] = -4.0 * t;
        deriv[8][0] = 4.0 * t;
        deriv[9][0] = 0.0;

        deriv[0][1] = 4.0 * (r + s + t) - 3.0;
        deriv[1][1] = 0.0;
        deriv[2][1] = 4.0 * s - 1.0;
        deriv[3][1] = 0.0;
        deriv[4][1] = -4.0 * r;
        deriv[5][1] = 4.0 * r;
        deriv[6][1] = 4.0 - 4.0 * r - 8.0 * s - 4.0 * t;
        deriv[7][1] = -4.0 * t;
        deriv[8][1] = 0.0;
        deriv[9][1] = 4.0 * t;

        deriv[0][2] = 4.0 * (r + s + t) - 3.0;
        deriv[1][2] = 0.0;
        deriv[2][2] = 0.0;
        deriv[3][2] = 4.0 * t - 1.0;
        deriv[4][2] = -4.0 * r;
        deriv[5][2] = 0.0;
        deriv[6][2] = -4.0 * s;
        deriv[7][2] = 4.0 - 4.0 * r - 4.0 * s - 8.0 * t;
        deriv[8][2] = 4.0 * r;
        deriv[9][2] = 4.0 * s;
    }
}
<commit_msg>Fix typo in tet10 figure<commit_after>use russell_lab::{Matrix, Vector};

/// Defines a tetrahedron with 10 nodes (quadratic faces)
///
/// ![tet10](https://raw.githubusercontent.com/cpmech/gemlab/main/data/figures/test_draw_shape_tet10.svg)
///
/// # Local IDs of nodes
///
/// ```text
///               t               r    s    t
///               |         p:0 [0.0, 0.0, 0.0]
///               3         p:1 [1.0, 0.0, 0.0]
///              /|`.       p:2 [0.0, 1.0, 0.0]
///              ||  `,     p:3 [0.0, 0.0, 1.0]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           9,
///           |   |             \
///          /    |              `.
///          8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /              ``''-.,,_  ',
///       |    /                        ``-2-,_s
///       |  4'                       ,.-``
///      |  ,                    _,-'`
///      ' /                 ,.'`
///     | /             _5-``      r    s    t
///     '/          ,-'`     p:4 [0.5, 0.0, 0.0]
///    |/      ,.-``         p:5 [0.5, 0.5, 0.0]
///    /  _,-``              p:6 [0.0, 0.5, 0.0]
///   1 '`                   p:7 [0.0, 0.0, 0.5]
///  /                       p:8 [0.5, 0.0, 0.5]
/// r                        p:9 [0.0, 0.5, 0.5]
/// ```
///
/// # Local IDs of edges
///
/// ```text
///               t                    p0  p1 p2
///               |                e:0 [0, 1, 4]
///               3                e:1 [1, 2, 5]
///              /|`.              e:2 [2, 0, 6]
///              ||  `,            e:3 [0, 3, 7]
///             / |    ',          e:4 [1, 3, 8]
///             | |      \         e:5 [2, 3, 9]
///            /  |       `.
///            |  |         `,
///           /   7(3)        `9(5)
///           |   |             \
///          /    |              `.
///       (4)8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /          (2) ``''-.,,_  ',
///       |    /                        ``'2-,_s
///       |  4'                       ,.-``
///      |  ,(0)                 _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'` (1)
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// * The order of edge nodes corresponds to **Lin3** nodes.
///
/// # Local IDs of faces
///
/// ```text
///               t           p0 p1 p2 p3 p4 p5
///               |       f:0 [0, 3, 2, 7, 9, 6]
///               3       f:1 [0, 1, 3, 4, 8, 7]
///              /|`.     f:2 [0, 2, 1, 6, 5, 4]
///              ||  `,   f:3 [1, 2, 3, 5, 9, 8]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           `9
///           |   |     [0]     \
///          /    |              `.
///          8    |                ',
///         / [1] |    ,             \
///         |     0. ,' \             `.
///        |     /   \ 3 \ .,6__        `.
///        |    /     \ ,'     ``''-.,,_  ',
///       |    /       '                ``'2-,_s
///       |  4'                       ,.-``
///      |  ,      [2]           _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'`
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Notes
///
/// * The order of face nodes is such that the normals are outward
/// * The order of face nodes corresponds to [super::Tri6] nodes
pub struct Tet10 {}

impl Tet10 {
    pub const GEO_NDIM: usize = 3;
    pub const NNODE: usize = 10;
    pub const NEDGE: usize = 6;
    pub const NFACE: usize = 4;
    pub const EDGE_NNODE: usize = 3;
    pub const FACE_NNODE: usize = 6;
    pub const FACE_NEDGE: usize = 3;

    #[rustfmt::skip]
    pub const EDGE_NODE_IDS: [[usize; Tet10::EDGE_NNODE]; Tet10::NEDGE] = [
        [0, 1, 4],
        [1, 2, 5],
        [2, 0, 6],
        [0, 3, 7],
        [1, 3, 8],
        [2, 3, 9],
    ];

    #[rustfmt::skip]
    pub const FACE_NODE_IDS: [[usize; Tet10::FACE_NNODE]; Tet10::NFACE] = [
        [0, 3, 2, 7, 9, 6],
        [0, 1, 3, 4, 8, 7],
        [0, 2, 1, 6, 5, 4],
        [1, 2, 3, 5, 9, 8],
    ];

    #[rustfmt::skip]
    pub const FACE_EDGE_NODE_IDS: [[[usize; Tet10::EDGE_NNODE]; Tet10::FACE_NEDGE]; Tet10::NFACE] = [
        [[0, 3, 7], [3, 2, 9], [2, 0, 6]],
        [[0, 1, 4], [1, 3, 8], [3, 0, 7]],
        [[0, 2, 6], [2, 1, 5], [1, 0, 4]],
        [[1, 2, 5], [2, 3, 9], [3, 1, 8]],
    ];

    #[rustfmt::skip]
    pub const NODE_REFERENCE_COORDS: [[f64; Tet10::GEO_NDIM]; Tet10::NNODE] = [
        [0.0, 0.0, 0.0], // 0
        [1.0, 0.0, 0.0], // 1
        [0.0, 1.0, 0.0], // 2
        [0.0, 0.0, 1.0], // 3
        [0.5, 0.0, 0.0], // 4
        [0.5, 0.5, 0.0], // 5
        [0.0, 0.5, 0.0], // 6
        [0.0, 0.0, 0.5], // 7
        [0.5, 0.0, 0.5], // 8
        [0.0, 0.5, 0.5], // 9
    ];

    /// Computes the interpolation functions
    ///
    /// # Output
    ///
    /// * `interp` -- interpolation function evaluated at ksi (nnode)
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates with length ≥ geo_ndim
    pub fn calc_interp(interp: &mut Vector, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        let u = 1.0 - r - s - t;

        interp[0] = u * (2.0 * u - 1.0);
        interp[1] = r * (2.0 * r - 1.0);
        interp[2] = s * (2.0 * s - 1.0);
        interp[3] = t * (2.0 * t - 1.0);
        interp[4] = 4.0 * u * r;
        interp[5] = 4.0 * r * s;
        interp[6] = 4.0 * s * u;
        interp[7] = 4.0 * u * t;
        interp[8] = 4.0 * r * t;
        interp[9] = 4.0 * s * t;
    }

    /// Computes the derivatives of interpolation functions with respect to the reference coordinates
    ///
    /// # Output
    ///
    /// * `deriv` -- derivatives of the interpolation function with respect to
    ///   the reference coordinates ksi, evaluated at ksi (nnode,geo_ndim)
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates with length ≥ geo_ndim
    pub fn calc_deriv(deriv: &mut Matrix, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        deriv[0][0] = 4.0 * (r + s + t) - 3.0;
        deriv[1][0] = 4.0 * r - 1.0;
        deriv[2][0] = 0.0;
        deriv[3][0] = 0.0;
        deriv[4][0] = 4.0 - 8.0 * r - 4.0 * s - 4.0 * t;
        deriv[5][0] = 4.0 * s;
        deriv[6][0] = -4.0 * s;
        deriv[7][0] = -4.0 * t;
        deriv[8][0] = 4.0 * t;
        deriv[9][0] = 0.0;

        deriv[0][1] = 4.0 * (r + s + t) - 3.0;
        deriv[1][1] = 0.0;
        deriv[2][1] = 4.0 * s - 1.0;
        deriv[3][1] = 0.0;
        deriv[4][1] = -4.0 * r;
        deriv[5][1] = 4.0 * r;
        deriv[6][1] = 4.0 - 4.0 * r - 8.0 * s - 4.0 * t;
        deriv[7][1] = -4.0 * t;
        deriv[8][1] = 0.0;
        deriv[9][1] = 4.0 * t;

        deriv[0][2] = 4.0 * (r + s + t) - 3.0;
        deriv[1][2] = 0.0;
        deriv[2][2] = 0.0;
        deriv[3][2] = 4.0 * t - 1.0;
        deriv[4][2] = -4.0 * r;
        deriv[5][2] = 0.0;
        deriv[6][2] = -4.0 * s;
        deriv[7][2] = 4.0 - 4.0 * r - 4.0 * s - 8.0 * t;
        deriv[8][2] = 4.0 * r;
        deriv[9][2] = 4.0 * s;
    }
}
<|endoftext|>


<commit_before>extern crate odbc;
use odbc::*;

#[test]
fn list_tables() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let ds = DataSource::with_parent(&env).unwrap();
    let mut ds = ds.connect("TestDataSource", "", "").unwrap();
    // scope is required (for now) to close statement before disconnecting
    {
        let statement = Statement::with_parent(&mut ds).unwrap();
        let statement = statement.tables().unwrap();
        assert_eq!(statement.num_result_cols().unwrap(), 5);
    }
    ds.disconnect().unwrap();
}

#[test]
fn not_read_only() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap();
    let conn = conn.connect("TestDataSource", "", "").unwrap();

    assert!(!conn.read_only().unwrap());
    conn.disconnect().unwrap();
}

#[test]
fn implicit_disconnect() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap();
    conn.connect("TestDataSource", "", "").unwrap();

    // if there would be no implicit disconnect, all the drops would panic with function sequence
    // error
}

#[test]
fn invalid_connection_string() {

    let expected = if cfg!(target_os = "windows") {
        "State: IM002, Native error: 0, Message: [Microsoft][ODBC Driver Manager] Data source \
            name not found and no default driver specified"
    } else {
        "State: IM002, Native error: 0, Message: [unixODBC][Driver Manager]Data source name not \
            found, and no default driver specified"
    };

    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&environment).unwrap();
    let result = conn.connect_with_connection_string("bla");
    let message = format!("{}", result.err().unwrap());
    assert_eq!(expected, message);
}

#[test]
fn test_connection_string() {

    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&environment).unwrap();
    let conn = conn.connect_with_connection_string("dsn=TestDataSource;Uid=;Pwd=;")
        .unwrap();
    conn.disconnect().unwrap();
}

#[test]
fn test_direct_select() {
    let env = Environment::new().unwrap().set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap().connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    let mut stmt = stmt.exec_direct("SELECT TITLE, YEAR FROM MOVIES ORDER BY YEAR").unwrap();
    assert_eq!(stmt.num_result_cols().unwrap(), 2);

    #[derive(PartialEq)]
    struct Movie {
        title: String,
        year: String,
    }

    let mut actual = Vec::new();
    while let Some(mut cursor) = stmt.fetch().unwrap() {
        actual.push(Movie {
            title: cursor.get_data(1).unwrap().unwrap(),
            year: cursor.get_data(2).unwrap().unwrap(),
        })
    }

    assert!(actual ==
            vec![Movie {
                     title: "2001: A Space Odyssey".to_owned(),
                     year: "1968".to_owned(),
                 },
                 Movie {
                     title: "Jurassic Park".to_owned(),
                     year: "1993".to_owned(),
                 }]);
}

// These tests query the results of catalog functions. These results are only likely to match the
// expectation on the travis.ci build on linux. Therefore we limit compilation and execution of
// these tests to this platform.
#[cfg(unix)]
#[test]
fn list_drivers() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let drivers = environment.drivers()
        .expect("Drivers can be iterated over");
    println!("{:?}", drivers);

    let expected = ["PostgreSQL ANSI", "PostgreSQL Unicode", "SQLite", "SQLite3"];
    assert!(drivers.iter().map(|d| &d.description).eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        driver: "PostgreSQL Unicode".to_owned(),
                    },
                    DataSourceInfo {
                        server_name: "TestDataSource".to_owned(),
                        drive: "SQLite3".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_user_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.user_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        driver: "PostgreSQL Unicode".to_owned(),
                    },
                    DataSourceInfo {
                        server_name: "TestDataSource".to_owned(),
                        driver: "SQLite3".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_system_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.system_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected: [DataSourceInfo; 0] = [];
    assert!(sources.iter().eq(expected.iter()));
}
<commit_msg>add missing 'r'<commit_after>extern crate odbc;
use odbc::*;

#[test]
fn list_tables() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let ds = DataSource::with_parent(&env).unwrap();
    let mut ds = ds.connect("TestDataSource", "", "").unwrap();
    // scope is required (for now) to close statement before disconnecting
    {
        let statement = Statement::with_parent(&mut ds).unwrap();
        let statement = statement.tables().unwrap();
        assert_eq!(statement.num_result_cols().unwrap(), 5);
    }
    ds.disconnect().unwrap();
}

#[test]
fn not_read_only() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap();
    let conn = conn.connect("TestDataSource", "", "").unwrap();

    assert!(!conn.read_only().unwrap());
    conn.disconnect().unwrap();
}

#[test]
fn implicit_disconnect() {

    let env = Environment::new().unwrap();
    let env = env.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap();
    conn.connect("TestDataSource", "", "").unwrap();

    // if there would be no implicit disconnect, all the drops would panic with function sequence
    // error
}

#[test]
fn invalid_connection_string() {

    let expected = if cfg!(target_os = "windows") {
        "State: IM002, Native error: 0, Message: [Microsoft][ODBC Driver Manager] Data source \
            name not found and no default driver specified"
    } else {
        "State: IM002, Native error: 0, Message: [unixODBC][Driver Manager]Data source name not \
            found, and no default driver specified"
    };

    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&environment).unwrap();
    let result = conn.connect_with_connection_string("bla");
    let message = format!("{}", result.err().unwrap());
    assert_eq!(expected, message);
}

#[test]
fn test_connection_string() {

    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&environment).unwrap();
    let conn = conn.connect_with_connection_string("dsn=TestDataSource;Uid=;Pwd=;")
        .unwrap();
    conn.disconnect().unwrap();
}

#[test]
fn test_direct_select() {
    let env = Environment::new().unwrap().set_odbc_version_3().unwrap();
    let conn = DataSource::with_parent(&env).unwrap().connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    let mut stmt = stmt.exec_direct("SELECT TITLE, YEAR FROM MOVIES ORDER BY YEAR").unwrap();
    assert_eq!(stmt.num_result_cols().unwrap(), 2);

    #[derive(PartialEq)]
    struct Movie {
        title: String,
        year: String,
    }

    let mut actual = Vec::new();
    while let Some(mut cursor) = stmt.fetch().unwrap() {
        actual.push(Movie {
                        title: cursor.get_data(1).unwrap().unwrap(),
                        year: cursor.get_data(2).unwrap().unwrap(),
                    })
    }

    assert!(actual ==
            vec![Movie {
                     title: "2001: A Space Odyssey".to_owned(),
                     year: "1968".to_owned(),
                 },
                 Movie {
                     title: "Jurassic Park".to_owned(),
                     year: "1993".to_owned(),
                 }]);
}

// These tests query the results of catalog functions. These results are only likely to match the
// expectation on the travis.ci build on linux. Therefore we limit compilation and execution of
// these tests to this platform.
#[cfg(unix)]
#[test]
fn list_drivers() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let drivers = environment.drivers()
        .expect("Drivers can be iterated over");
    println!("{:?}", drivers);

    let expected = ["PostgreSQL ANSI", "PostgreSQL Unicode", "SQLite", "SQLite3"];
    assert!(drivers.iter().map(|d| &d.description).eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        driver: "PostgreSQL Unicode".to_owned(),
                    },
                    DataSourceInfo {
                        server_name: "TestDataSource".to_owned(),
                        driver: "SQLite3".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_user_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.user_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected = [DataSourceInfo {
                        server_name: "PostgreSQL".to_owned(),
                        driver: "PostgreSQL Unicode".to_owned(),
                    },
                    DataSourceInfo {
                        server_name: "TestDataSource".to_owned(),
                        driver: "SQLite3".to_owned(),
                    }];
    assert!(sources.iter().eq(expected.iter()));
}

#[cfg(unix)]
#[test]
fn list_system_data_sources() {
    let environment = Environment::new().unwrap();
    let environment = environment.set_odbc_version_3().unwrap();
    let sources = environment.system_data_sources()
        .expect("Data sources can be iterated over");
    println!("{:?}", sources);

    let expected: [DataSourceInfo; 0] = [];
    assert!(sources.iter().eq(expected.iter()));
}

<|endoftext|>


<commit_before>#![feature(box_syntax, rustc_private)]

#[allow(plugin_as_library)]
extern crate herbie_lint;
extern crate rustc_front;

use herbie_lint::lisp::{LispExpr, Parser, ParseError};
use herbie_lint::lisp::LispExpr::*;
use rustc_front::hir::BinOp_::*;
use rustc_front::hir::UnOp::*;

pub fn parse(s: &str) -> Result<LispExpr, ParseError> {
    let mut parser = Parser::new();
    parser.parse(s)
}

#[test]
fn test_parser() {
    assert_eq!(parse(""), Err(ParseError::EOE));

    assert_eq!(parse("0."), Ok(Lit(0.)));
    assert_eq!(parse("herbie0"), Ok(Ident(0)));
    assert_eq!(parse("herbie"), Ok(Ident(0)));

    assert_eq!(parse("(+ 0. 0.) foobar"), Err(ParseError::EOE));
    assert_eq!(parse("("), Err(ParseError::EOE));
    assert_eq!(parse("0.eee"), Err(ParseError::Float));

    assert_eq!(parse("(+ 0. herbie1)"), Ok(Binary(BiAdd, box Lit(0.), box Ident(0))));
    assert_eq!(parse("(+ herbie0 herbie1)"), Ok(Binary(BiAdd, box Ident(0), box Ident(1))));

    assert_eq!(parse("+"), Err(ParseError::Unexpected('+')));
    assert_eq!(parse("(+)"), Err(ParseError::Unexpected(')')));
    assert_eq!(parse("(+ 0.)"), Err(ParseError::Arity));
    assert_eq!(parse("(+ 0. 0."), Err(ParseError::Expected(')')));
    assert_eq!(parse("(+ 0. 0. 0.)"), Err(ParseError::Expected(')')));
    assert_eq!(parse("(+ 0. 0. 0."), Err(ParseError::Expected(')')));

    assert_eq!(parse("(- herbie0)"), Ok(Unary(UnNeg, box Ident(0))));
    assert_eq!(parse("(- herbie0 herbie1)"), Ok(Binary(BiSub, box Ident(0), box Ident(1))));

    assert_eq!(parse("-"), Err(ParseError::Unexpected('-')));
    assert_eq!(parse("(-)"), Err(ParseError::Unexpected(')')));
    assert_eq!(parse("(- 0. 0. 0.)"), Err(ParseError::Expected(')')));

    assert_eq!(parse("(cos 1.)"), Ok(Fun("cos".into(), vec![Lit(1.)])));
    assert_eq!(parse("(cos herbie0)"), Ok(Fun("cos".into(), vec![Ident(0)])));
    assert_eq!(parse("(log1p (cos herbie0))"), Ok(Fun("log1p".into(), vec![Fun("cos".into(), vec![Ident(0)])])));

    assert_eq!(parse("(cos)"), Err(ParseError::Arity));
    assert_eq!(parse("(cos"), Err(ParseError::Expected(')')));
    assert_eq!(parse("(cos 1. 2.)"), Err(ParseError::Arity));
    assert_eq!(parse("(cos 1. 2. 3."), Err(ParseError::Expected(')')));

    assert_eq!(parse("(foo 1.)"), Err(ParseError::Ident));
    assert_eq!(parse("(foocos 1.)"), Err(ParseError::Ident));
    assert_eq!(parse("(cosfoocos 1.)"), Err(ParseError::Ident));

    let mut parser = Parser::new();
    assert_eq!(parser.parse("(* (+ (/ herbie0 herbie1) herbie2) herbie1)"), Ok(
        Binary(BiMul,
            box Binary(BiAdd,
                box Binary(BiDiv, box Ident(0), box Ident(1)),
                box Ident(2)
            ),
            box Ident(1)
        )
    ));

    assert_eq!(parser.parse("(+ (* herbie2 herbie1) herbie0)"), Ok(
        Binary(BiAdd,
            box Binary(BiMul, box Ident(2), box Ident(1)),
            box Ident(0)
        )
    ));

    assert_eq!(parse("(+ (* herbie2 herbie1) herbie0)"), Ok(
        Binary(BiAdd,
            box Binary(BiMul, box Ident(0), box Ident(1)),
            box Ident(2)
        )
    ));
}
<commit_msg>Test the to_lisp function<commit_after>#![feature(box_syntax, rustc_private)]

#[allow(plugin_as_library)]
extern crate herbie_lint;
extern crate rustc_front;

use herbie_lint::lisp::{LispExpr, Parser, ParseError};
use herbie_lint::lisp::LispExpr::*;
use rustc_front::hir::BinOp_::*;
use rustc_front::hir::UnOp::*;

pub fn parse(s: &str) -> Result<LispExpr, ParseError> {
    let mut parser = Parser::new();
    parser.parse(s)
}

#[test]
fn test_parser() {
    assert_eq!(parse(""), Err(ParseError::EOE));

    assert_eq!(parse("0."), Ok(Lit(0.)));
    assert_eq!(parse("herbie"), Ok(Ident(0)));
    assert_eq!(parse("(+ 0. herbie1)"), Ok(Binary(BiAdd, box Lit(0.), box Ident(0))));

    let valid = &[
        ("0", Lit(0.)),
        ("herbie0", Ident(0)),
        ("(+ herbie0 herbie1)", Binary(BiAdd, box Ident(0), box Ident(1))),
        ("(- herbie0)", Unary(UnNeg, box Ident(0))),
        ("(- herbie0 herbie1)", Binary(BiSub, box Ident(0), box Ident(1))),
        ("(cos 1)", Fun("cos".into(), vec![Lit(1.)])),
        ("(cos herbie0)", Fun("cos".into(), vec![Ident(0)])),
        ("(log1p (cos herbie0))", Fun("log1p".into(), vec![Fun("cos".into(), vec![Ident(0)])])),
    ];

    for &(s, ref e) in valid {
        assert_eq!(parse(s).as_ref(), Ok(e));
        assert_eq!(s, e.to_lisp("herbie"));
    }

    assert_eq!(parse("(+ 0. 0.) foobar"), Err(ParseError::EOE));
    assert_eq!(parse("("), Err(ParseError::EOE));
    assert_eq!(parse("0.eee"), Err(ParseError::Float));

    assert_eq!(parse("+"), Err(ParseError::Unexpected('+')));
    assert_eq!(parse("(+)"), Err(ParseError::Unexpected(')')));
    assert_eq!(parse("(+ 0.)"), Err(ParseError::Arity));
    assert_eq!(parse("(+ 0. 0."), Err(ParseError::Expected(')')));
    assert_eq!(parse("(+ 0. 0. 0.)"), Err(ParseError::Expected(')')));
    assert_eq!(parse("(+ 0. 0. 0."), Err(ParseError::Expected(')')));

    assert_eq!(parse("-"), Err(ParseError::Unexpected('-')));
    assert_eq!(parse("(-)"), Err(ParseError::Unexpected(')')));
    assert_eq!(parse("(- 0. 0. 0.)"), Err(ParseError::Expected(')')));

    assert_eq!(parse("(cos)"), Err(ParseError::Arity));
    assert_eq!(parse("(cos"), Err(ParseError::Expected(')')));
    assert_eq!(parse("(cos 1. 2.)"), Err(ParseError::Arity));
    assert_eq!(parse("(cos 1. 2. 3."), Err(ParseError::Expected(')')));

    assert_eq!(parse("(foo 1.)"), Err(ParseError::Ident));
    assert_eq!(parse("(foocos 1.)"), Err(ParseError::Ident));
    assert_eq!(parse("(cosfoocos 1.)"), Err(ParseError::Ident));

    let mut parser = Parser::new();
    assert_eq!(parser.parse("(* (+ (/ herbie0 herbie1) herbie2) herbie1)"), Ok(
        Binary(BiMul,
            box Binary(BiAdd,
                box Binary(BiDiv, box Ident(0), box Ident(1)),
                box Ident(2)
            ),
            box Ident(1)
        )
    ));

    assert_eq!(parser.parse("(+ (* herbie2 herbie1) herbie0)"), Ok(
        Binary(BiAdd,
            box Binary(BiMul, box Ident(2), box Ident(1)),
            box Ident(0)
        )
    ));

    assert_eq!(parse("(+ (* herbie2 herbie1) herbie0)"), Ok(
        Binary(BiAdd,
            box Binary(BiMul, box Ident(0), box Ident(1)),
            box Ident(2)
        )
    ));
}
<|endoftext|>


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

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use num::Zero;
use std::num::Num;

/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS.
#[deriving(Clone, PartialEq)]
pub struct SideOffsets2D<T> {
    pub top: T,
    pub right: T,
    pub bottom: T,
    pub left: T,
}

impl<T> SideOffsets2D<T> {
    pub fn new(top: T, right: T, bottom: T, left: T) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: top,
            right: right,
            bottom: bottom,
            left: left,
        }
    }
}

impl<T:Clone> SideOffsets2D<T> {
    pub fn new_all_same(all: T) -> SideOffsets2D<T> {
        SideOffsets2D::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl<T:Num> SideOffsets2D<T> {
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T:Num> Add<SideOffsets2D<T>, SideOffsets2D<T>> for SideOffsets2D<T> {
    fn add(&self, other: &SideOffsets2D<T>) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: self.top + other.top,
            right: self.right + other.right,
            bottom: self.bottom + other.bottom,
            left: self.left + other.left,
        }
    }
}

impl<T: Zero> SideOffsets2D<T> {
    pub fn zero() -> SideOffsets2D<T> {
        SideOffsets2D {
            top: Zero::zero(),
            right: Zero::zero(),
            bottom: Zero::zero(),
            left: Zero::zero(),
        }
    }
}

/// A SIMD enabled version of SideOffsets2D specialized for i32.
#[deriving(Clone, PartialEq, Rand)]
#[simd]
pub struct SideOffsets2DSimdI32 {
    pub top: i32,
    pub bottom: i32,
    pub right: i32,
    pub left: i32,
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32 {
            top: top,
            bottom: bottom,
            right: right,
            left: left,
        }
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn new_all_same(all: i32) -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn horizontal(&self) -> i32 {
        self.left + self.right
    }

    #[inline]
    pub fn vertical(&self) -> i32 {
        self.top + self.bottom
    }
}

impl Add<SideOffsets2DSimdI32, SideOffsets2DSimdI32> for SideOffsets2DSimdI32 {
    #[inline]
    fn add(&self, other: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
        *self + *other // Use SIMD addition
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn zero() -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32 {
            top: 0,
            bottom: 0,
            right: 0,
            left: 0,
        }
    }

    #[cfg(not(target_arch = "x86_64"))]
    #[inline]
    pub fn is_zero(&self) -> bool {
        self.top == 0 && self.right == 0 && self.bottom == 0 && self.left == 0
    }

    #[cfg(target_arch = "x86_64")]
    #[inline]
    pub fn is_zero(&self) -> bool {
        let is_zero: bool;
        unsafe {
            asm! {
                "ptest $1, $1
                 setz $0"
                : "=r"(is_zero)
                : "x"(*self)
                :
                : "intel"
            };
        }
        is_zero
    }
}

#[cfg(test)]
mod tests {
    use std::num::Zero;
    use super::SideOffsets2DSimdI32;

    #[test]
    fn test_is_zero() {
        assert!(SideOffsets2DSimdI32::new_all_same(0).is_zero());
        assert!(!SideOffsets2DSimdI32::new_all_same(1).is_zero());
        assert!(!SideOffsets2DSimdI32::new(1, 0, 0, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 1, 0, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 0, 1, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 0, 0, 1).is_zero());
    }
}

#[cfg(bench)]
mod bench {
    use test::BenchHarness;
    use std::num::Zero;
    use rand::{XorShiftRng, Rng};
    use super::SideOffsets2DSimdI32;

    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "x86_64")]
    #[bench]
    fn bench_naive_is_zero(bh: &mut BenchHarness) {
        fn is_zero(x: &SideOffsets2DSimdI32) -> bool {
            x.top.is_zero() && x.right.is_zero() && x.bottom.is_zero() && x.left.is_zero()
        }
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| is_zero(&rng.gen::<SideOffsets2DSimdI32>()))
    }

    #[bench]
    fn bench_is_zero(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>().is_zero())
    }

    #[bench]
    fn bench_naive_add(bh: &mut BenchHarness) {
        fn add(x: &SideOffsets2DSimdI32, y: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
            SideOffsets2DSimdI32 {
                top: x.top + y.top,
                right: x.right + y.right,
                bottom: x.bottom + y.bottom,
                left: x.left + y.left,
            }
        }
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| add(&rng.gen::<SideOffsets2DSimdI32>(), &rng.gen::<SideOffsets2DSimdI32>()))
    }

    #[bench]
    fn bench_add(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>() + rng.gen::<SideOffsets2DSimdI32>())
    }
}
<commit_msg>Loosen bounds on `horizontal`/`vertical` in `SideOffsets2D`<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use num::Zero;
use std::num::Num;

/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS.
#[deriving(Clone, PartialEq)]
pub struct SideOffsets2D<T> {
    pub top: T,
    pub right: T,
    pub bottom: T,
    pub left: T,
}

impl<T> SideOffsets2D<T> {
    pub fn new(top: T, right: T, bottom: T, left: T) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: top,
            right: right,
            bottom: bottom,
            left: left,
        }
    }
}

impl<T:Clone> SideOffsets2D<T> {
    pub fn new_all_same(all: T) -> SideOffsets2D<T> {
        SideOffsets2D::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl<T> SideOffsets2D<T> where T: Add<T,T> {
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T:Num> Add<SideOffsets2D<T>, SideOffsets2D<T>> for SideOffsets2D<T> {
    fn add(&self, other: &SideOffsets2D<T>) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: self.top + other.top,
            right: self.right + other.right,
            bottom: self.bottom + other.bottom,
            left: self.left + other.left,
        }
    }
}

impl<T: Zero> SideOffsets2D<T> {
    pub fn zero() -> SideOffsets2D<T> {
        SideOffsets2D {
            top: Zero::zero(),
            right: Zero::zero(),
            bottom: Zero::zero(),
            left: Zero::zero(),
        }
    }
}

/// A SIMD enabled version of SideOffsets2D specialized for i32.
#[deriving(Clone, PartialEq, Rand)]
#[simd]
pub struct SideOffsets2DSimdI32 {
    pub top: i32,
    pub bottom: i32,
    pub right: i32,
    pub left: i32,
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32 {
            top: top,
            bottom: bottom,
            right: right,
            left: left,
        }
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn new_all_same(all: i32) -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn horizontal(&self) -> i32 {
        self.left + self.right
    }

    #[inline]
    pub fn vertical(&self) -> i32 {
        self.top + self.bottom
    }
}

impl Add<SideOffsets2DSimdI32, SideOffsets2DSimdI32> for SideOffsets2DSimdI32 {
    #[inline]
    fn add(&self, other: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
        *self + *other // Use SIMD addition
    }
}

impl SideOffsets2DSimdI32 {
    #[inline]
    pub fn zero() -> SideOffsets2DSimdI32 {
        SideOffsets2DSimdI32 {
            top: 0,
            bottom: 0,
            right: 0,
            left: 0,
        }
    }

    #[cfg(not(target_arch = "x86_64"))]
    #[inline]
    pub fn is_zero(&self) -> bool {
        self.top == 0 && self.right == 0 && self.bottom == 0 && self.left == 0
    }

    #[cfg(target_arch = "x86_64")]
    #[inline]
    pub fn is_zero(&self) -> bool {
        let is_zero: bool;
        unsafe {
            asm! {
                "ptest $1, $1
                 setz $0"
                : "=r"(is_zero)
                : "x"(*self)
                :
                : "intel"
            };
        }
        is_zero
    }
}

#[cfg(test)]
mod tests {
    use std::num::Zero;
    use super::SideOffsets2DSimdI32;

    #[test]
    fn test_is_zero() {
        assert!(SideOffsets2DSimdI32::new_all_same(0).is_zero());
        assert!(!SideOffsets2DSimdI32::new_all_same(1).is_zero());
        assert!(!SideOffsets2DSimdI32::new(1, 0, 0, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 1, 0, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 0, 1, 0).is_zero());
        assert!(!SideOffsets2DSimdI32::new(0, 0, 0, 1).is_zero());
    }
}

#[cfg(bench)]
mod bench {
    use test::BenchHarness;
    use std::num::Zero;
    use rand::{XorShiftRng, Rng};
    use super::SideOffsets2DSimdI32;

    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "x86_64")]
    #[bench]
    fn bench_naive_is_zero(bh: &mut BenchHarness) {
        fn is_zero(x: &SideOffsets2DSimdI32) -> bool {
            x.top.is_zero() && x.right.is_zero() && x.bottom.is_zero() && x.left.is_zero()
        }
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| is_zero(&rng.gen::<SideOffsets2DSimdI32>()))
    }

    #[bench]
    fn bench_is_zero(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>().is_zero())
    }

    #[bench]
    fn bench_naive_add(bh: &mut BenchHarness) {
        fn add(x: &SideOffsets2DSimdI32, y: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
            SideOffsets2DSimdI32 {
                top: x.top + y.top,
                right: x.right + y.right,
                bottom: x.bottom + y.bottom,
                left: x.left + y.left,
            }
        }
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| add(&rng.gen::<SideOffsets2DSimdI32>(), &rng.gen::<SideOffsets2DSimdI32>()))
    }

    #[bench]
    fn bench_add(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new().unwrap();
        bh.iter(|| rng.gen::<SideOffsets2DSimdI32>() + rng.gen::<SideOffsets2DSimdI32>())
    }
}
<|endoftext|>


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

use consts::PARAMETER_SIZE;
use platform::device::Device;
use platform::transaction::Transaction;
use std::thread;
use std::time::Duration;
use util::{io_err, OnceCallback};
use u2fprotocol::{u2f_init_device, u2f_is_keyhandle_valid, u2f_register, u2f_sign};

fn is_valid_transport(transports: ::AuthenticatorTransports) -> bool {
    transports.is_empty() || transports.contains(::AuthenticatorTransports::USB)
}

fn find_valid_key_handles<'a, F>(
    app_ids: &'a Vec<::AppId>,
    key_handles: &'a Vec<::KeyHandle>,
    mut is_valid: F,
) -> (&'a ::AppId, Vec<&'a ::KeyHandle>)
where
    F: FnMut(&Vec<u8>, &::KeyHandle) -> bool,
{
    // Try all given app_ids in order.
    for app_id in app_ids {
        // Find all valid key handles for the current app_id.
        let valid_handles = key_handles
            .iter()
            .filter(|key_handle| is_valid(app_id, key_handle))
            .collect::<Vec<_>>();

        // If there's at least one, stop.
        if valid_handles.len() > 0 {
            return (app_id, valid_handles);
        }
    }

    return (&app_ids[0], vec![]);
}

#[derive(Default)]
pub struct StateMachine {
    transaction: Option<Transaction>,
}

impl StateMachine {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn register(
        &mut self,
        flags: ::RegisterFlags,
        timeout: u64,
        challenge: Vec<u8>,
        application: ::AppId,
        key_handles: Vec<::KeyHandle>,
        callback: OnceCallback<::RegisterResult>,
    ) {
        // Abort any prior register/sign calls.
        self.cancel();

        let cbc = callback.clone();

        let transaction = Transaction::new(timeout, cbc.clone(), move |info, alive| {
            // Create a new device.
            let dev = &mut match Device::new(info) {
                Ok(dev) => dev,
                _ => return,
            };

            // Try initializing it.
            if !dev.is_u2f() || !u2f_init_device(dev) {
                return;
            }

            // We currently support none of the authenticator selection
            // criteria because we can't ask tokens whether they do support
            // those features. If flags are set, ignore all tokens for now.
            //
            // Technically, this is a ConstraintError because we shouldn't talk
            // to this authenticator in the first place. But the result is the
            // same anyway.
            if !flags.is_empty() {
                return;
            }

            // Iterate the exclude list and see if there are any matches.
            // Abort the state machine if we found a valid key handle.
            if key_handles.iter().any(|key_handle| {
                is_valid_transport(key_handle.transports)
                    && u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
                        .unwrap_or(false) /* no match on failure */
            }) {
                return;
            }

            while alive() {
                if let Ok(bytes) = u2f_register(dev, &challenge, &application) {
                    callback.call(Ok(bytes));
                    break;
                }

                // Sleep a bit before trying again.
                thread::sleep(Duration::from_millis(100));
            }
        });

        self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
            "couldn't create transaction"
        )))));
    }

    pub fn sign(
        &mut self,
        flags: ::SignFlags,
        timeout: u64,
        challenge: Vec<u8>,
        app_ids: Vec<::AppId>,
        key_handles: Vec<::KeyHandle>,
        callback: OnceCallback<::SignResult>,
    ) {
        // Abort any prior register/sign calls.
        self.cancel();

        let cbc = callback.clone();

        let transaction = Transaction::new(timeout, cbc.clone(), move |info, alive| {
            // Create a new device.
            let dev = &mut match Device::new(info) {
                Ok(dev) => dev,
                _ => return,
            };

            // Try initializing it.
            if !dev.is_u2f() || !u2f_init_device(dev) {
                return;
            }

            // We currently don't support user verification because we can't
            // ask tokens whether they do support that. If the flag is set,
            // ignore all tokens for now.
            //
            // Technically, this is a ConstraintError because we shouldn't talk
            // to this authenticator in the first place. But the result is the
            // same anyway.
            if !flags.is_empty() {
                return;
            }

            // For each appId, try all key handles. If there's at least one
            // valid key handle for an appId, we'll use that appId below.
            let (app_id, valid_handles) =
                find_valid_key_handles(&app_ids, &key_handles, |app_id, key_handle| {
                    u2f_is_keyhandle_valid(dev, &challenge, app_id, &key_handle.credential)
                        .unwrap_or(false) /* no match on failure */
                });

            // Aggregate distinct transports from all given credentials.
            let transports = key_handles
                .iter()
                .fold(::AuthenticatorTransports::empty(), |t, k| {
                    t | k.transports
                });

            // We currently only support USB. If the RP specifies transports
            // and doesn't include USB it's probably lying.
            if !is_valid_transport(transports) {
                return;
            }

            while alive() {
                // If the device matches none of the given key handles
                // then just make it blink with bogus data.
                if valid_handles.is_empty() {
                    let blank = vec![0u8; PARAMETER_SIZE];
                    if let Ok(_) = u2f_register(dev, &blank, &blank) {
                        callback.call(Err(io_err("invalid key")));
                        break;
                    }
                } else {
                    // Otherwise, try to sign.
                    for key_handle in &valid_handles {
                        if let Ok(bytes) = u2f_sign(dev, &challenge, app_id, &key_handle.credential)
                        {
                            callback.call(Ok((
                                app_id.clone(),
                                key_handle.credential.clone(),
                                bytes,
                            )));
                            break;
                        }
                    }
                }

                // Sleep a bit before trying again.
                thread::sleep(Duration::from_millis(100));
            }
        });

        self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
            "couldn't create transaction"
        )))));
    }

    // This blocks.
    pub fn cancel(&mut self) {
        if let Some(mut transaction) = self.transaction.take() {
            transaction.cancel();
        }
    }
}
<commit_msg>Bug 1442557 - [u2f-hid-rs] Keep polling excluded devices when creating credentials r=jcj<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use consts::PARAMETER_SIZE;
use platform::device::Device;
use platform::transaction::Transaction;
use std::thread;
use std::time::Duration;
use util::{io_err, OnceCallback};
use u2fprotocol::{u2f_init_device, u2f_is_keyhandle_valid, u2f_register, u2f_sign};

fn is_valid_transport(transports: ::AuthenticatorTransports) -> bool {
    transports.is_empty() || transports.contains(::AuthenticatorTransports::USB)
}

fn find_valid_key_handles<'a, F>(
    app_ids: &'a Vec<::AppId>,
    key_handles: &'a Vec<::KeyHandle>,
    mut is_valid: F,
) -> (&'a ::AppId, Vec<&'a ::KeyHandle>)
where
    F: FnMut(&Vec<u8>, &::KeyHandle) -> bool,
{
    // Try all given app_ids in order.
    for app_id in app_ids {
        // Find all valid key handles for the current app_id.
        let valid_handles = key_handles
            .iter()
            .filter(|key_handle| is_valid(app_id, key_handle))
            .collect::<Vec<_>>();

        // If there's at least one, stop.
        if valid_handles.len() > 0 {
            return (app_id, valid_handles);
        }
    }

    return (&app_ids[0], vec![]);
}

#[derive(Default)]
pub struct StateMachine {
    transaction: Option<Transaction>,
}

impl StateMachine {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn register(
        &mut self,
        flags: ::RegisterFlags,
        timeout: u64,
        challenge: Vec<u8>,
        application: ::AppId,
        key_handles: Vec<::KeyHandle>,
        callback: OnceCallback<::RegisterResult>,
    ) {
        // Abort any prior register/sign calls.
        self.cancel();

        let cbc = callback.clone();

        let transaction = Transaction::new(timeout, cbc.clone(), move |info, alive| {
            // Create a new device.
            let dev = &mut match Device::new(info) {
                Ok(dev) => dev,
                _ => return,
            };

            // Try initializing it.
            if !dev.is_u2f() || !u2f_init_device(dev) {
                return;
            }

            // We currently support none of the authenticator selection
            // criteria because we can't ask tokens whether they do support
            // those features. If flags are set, ignore all tokens for now.
            //
            // Technically, this is a ConstraintError because we shouldn't talk
            // to this authenticator in the first place. But the result is the
            // same anyway.
            if !flags.is_empty() {
                return;
            }

            // Iterate the exclude list and see if there are any matches.
            // If so, we'll keep polling the device anyway to test for user
            // consent, to be consistent with CTAP2 device behavior.
            let excluded = key_handles.iter().any(|key_handle| {
                is_valid_transport(key_handle.transports)
                    && u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
                        .unwrap_or(false) /* no match on failure */
            });

            while alive() {
                if excluded {
                    let blank = vec![0u8; PARAMETER_SIZE];
                    if let Ok(_) = u2f_register(dev, &blank, &blank) {
                        callback.call(Err(io_err("duplicate registration")));
                        break;
                    }
                } else {
                    if let Ok(bytes) = u2f_register(dev, &challenge, &application) {
                        callback.call(Ok(bytes));
                        break;
                    }
                }

                // Sleep a bit before trying again.
                thread::sleep(Duration::from_millis(100));
            }
        });

        self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
            "couldn't create transaction"
        )))));
    }

    pub fn sign(
        &mut self,
        flags: ::SignFlags,
        timeout: u64,
        challenge: Vec<u8>,
        app_ids: Vec<::AppId>,
        key_handles: Vec<::KeyHandle>,
        callback: OnceCallback<::SignResult>,
    ) {
        // Abort any prior register/sign calls.
        self.cancel();

        let cbc = callback.clone();

        let transaction = Transaction::new(timeout, cbc.clone(), move |info, alive| {
            // Create a new device.
            let dev = &mut match Device::new(info) {
                Ok(dev) => dev,
                _ => return,
            };

            // Try initializing it.
            if !dev.is_u2f() || !u2f_init_device(dev) {
                return;
            }

            // We currently don't support user verification because we can't
            // ask tokens whether they do support that. If the flag is set,
            // ignore all tokens for now.
            //
            // Technically, this is a ConstraintError because we shouldn't talk
            // to this authenticator in the first place. But the result is the
            // same anyway.
            if !flags.is_empty() {
                return;
            }

            // For each appId, try all key handles. If there's at least one
            // valid key handle for an appId, we'll use that appId below.
            let (app_id, valid_handles) =
                find_valid_key_handles(&app_ids, &key_handles, |app_id, key_handle| {
                    u2f_is_keyhandle_valid(dev, &challenge, app_id, &key_handle.credential)
                        .unwrap_or(false) /* no match on failure */
                });

            // Aggregate distinct transports from all given credentials.
            let transports = key_handles
                .iter()
                .fold(::AuthenticatorTransports::empty(), |t, k| {
                    t | k.transports
                });

            // We currently only support USB. If the RP specifies transports
            // and doesn't include USB it's probably lying.
            if !is_valid_transport(transports) {
                return;
            }

            while alive() {
                // If the device matches none of the given key handles
                // then just make it blink with bogus data.
                if valid_handles.is_empty() {
                    let blank = vec![0u8; PARAMETER_SIZE];
                    if let Ok(_) = u2f_register(dev, &blank, &blank) {
                        callback.call(Err(io_err("invalid key")));
                        break;
                    }
                } else {
                    // Otherwise, try to sign.
                    for key_handle in &valid_handles {
                        if let Ok(bytes) = u2f_sign(dev, &challenge, app_id, &key_handle.credential)
                        {
                            callback.call(Ok((
                                app_id.clone(),
                                key_handle.credential.clone(),
                                bytes,
                            )));
                            break;
                        }
                    }
                }

                // Sleep a bit before trying again.
                thread::sleep(Duration::from_millis(100));
            }
        });

        self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
            "couldn't create transaction"
        )))));
    }

    // This blocks.
    pub fn cancel(&mut self) {
        if let Some(mut transaction) = self.transaction.take() {
            transaction.cancel();
        }
    }
}
<|endoftext|>


<commit_before>pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

<commit_msg>FileHeaderSpec, FileHeaderData can derive Debug<commit_after>#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

<|endoftext|>


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

//! Types that facilitate representing `GObject` descendants.

use std::marker::PhantomData;
use std::ptr;
use translate::*;
use types::{self, Type, StaticType};
use ffi;

/// A reference to any GObject descendant.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq, Eq)]
pub struct Ref(*mut ffi::GObject);

impl Ref {
    #[inline]
    fn add_ref(&self) { unsafe { ffi::g_object_ref_sink(self.0 as *mut _); } }

    #[inline]
    fn unref(&self) { unsafe { ffi::g_object_unref(self.0 as *mut _); } }

    /// Transfer: none constructor.
    #[inline]
    pub fn from_glib_none(ptr: *mut ffi::GObject) -> Ref {
        let r = Ref(ptr);
        r.add_ref();
        r
    }

    /// Transfer: full constructor.
    #[inline]
    pub fn from_glib_full(ptr: *mut ffi::GObject) -> Ref {
        Ref(ptr)
    }

    /// Returns a transfer: none raw pointer.
    #[inline]
    pub fn to_glib_none(&self) -> *mut ffi::GObject {
        self.0
    }

    /// Returns a transfer: full raw pointer.
    #[inline]
    pub fn to_glib_full(&self) -> *mut ffi::GObject {
        self.add_ref();
        self.0
    }
}

impl Clone for Ref {
    #[inline]
    fn clone(&self) -> Ref {
        self.add_ref();
        Ref(self.0)
    }
}

impl Drop for Ref {
    #[inline]
    fn drop(&mut self) {
        self.unref();
    }
}

/// A helper type holding a reference to a specific object or interface.
///
/// `T` is the foreign `struct` type corresponding to the object.
pub struct VirtualRef<'a, T> (&'a Ref, PhantomData<T>);

impl<'a, T> VirtualRef<'a, T> {
    #[inline]
    fn new(r: &'a Ref) -> VirtualRef<'a, T> { VirtualRef(r, PhantomData) }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for VirtualRef<'a, T> {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, VirtualRef<'a, T>> {
        Stash(self.0.to_glib_none() as *mut _, self.0)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.0.to_glib_full() as *mut _
    }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for Option<&'a VirtualRef<'a, T>> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a VirtualRef<'a, T>>> {
        if let Some(ref s) = *self {
            Stash(s.0.to_glib_none() as *mut _, Some(s.0))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.0.to_glib_full() as *mut _)
    }
}

/// A wrapper around the `Ref`.
pub trait Wrapper: StaticType {
    /// The foreign `struct` type corresponding to the object.
    type GlibType;
    /// Wraps a `Ref`.
    unsafe fn wrap(r: Ref) -> Self;
    /// Returns a reference to the inner `Ref`.
    fn as_ref(&self) -> &Ref;
    /// Transforms into the inner `Ref`.
    fn unwrap(self) -> Ref;
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for &'a W {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, &'a W> {
        Stash(self.as_ref().to_glib_none() as *mut _, self.as_ref())
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().to_glib_full() as *mut _
    }
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for Option<&'a W> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a W>> {
        if let Some(ref s) = *self {
            Stash(s.as_ref().to_glib_none() as *mut _, Some(s.as_ref()))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.as_ref().to_glib_full() as *mut _)
    }
}

impl <T: Wrapper> FromGlibPtr<*mut <T as Wrapper>::GlibType> for T {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_none(ptr as *mut _))
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_full(ptr as *mut _))
    }
}

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T` and can be `upcast` to a corresponding type.
///
/// `T` always implements `Upcast<T>`.
pub unsafe trait Upcast<T: Wrapper>: Wrapper {
    /// Upcasts to a helper type corresponding to `T`.
    #[inline]
    fn upcast(&self) -> VirtualRef<<T as Wrapper>::GlibType> {
        debug_assert!(types::instance_of::<T>(self.as_ref().to_glib_none() as *const _));
        VirtualRef::<<T as Wrapper>::GlibType>::new(self.as_ref())
    }
}

unsafe impl<T: Wrapper> Upcast<T> for T { }

/// A complement to `Upcast` that allows downcasting.
pub trait Downcast<T> {
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self>;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if the instance doesn't implement `T`.
    fn downcast_unchecked(self) -> T;
}

impl <Super, Sub> Downcast<Sub> for Super
where Super: Wrapper, Sub: Wrapper + Upcast<Super> {
    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        if types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _) {
            unsafe { Ok(Sub::wrap(self.unwrap())) }
        }
        else {
            Err(self)
        }
    }

    #[inline]
    fn downcast_unchecked(self) -> Sub {
        assert!(types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _));
        unsafe { Sub::wrap(self.unwrap()) }
    }
}

#[derive(Clone)]
pub struct Object(Ref);

impl Wrapper for Object {
    type GlibType = ffi::GObject;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object { Object(r) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl StaticType for Object {
    fn static_type() -> Type { Type::BaseObject }
}

pub trait ObjectExt {
}

impl<T: Upcast<Object>> ObjectExt for T {
}
<commit_msg>Add GenericObject for GObject types in glib<commit_after>// Copyright 2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Types that facilitate representing `GObject` descendants.

use std::marker::PhantomData;
use std::ptr;
use translate::*;
use types::{self, Type, StaticType};
use ffi;

/// A reference to any GObject descendant.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq, Eq)]
pub struct Ref(*mut ffi::GObject);

impl Ref {
    #[inline]
    fn add_ref(&self) { unsafe { ffi::g_object_ref_sink(self.0 as *mut _); } }

    #[inline]
    fn unref(&self) { unsafe { ffi::g_object_unref(self.0 as *mut _); } }

    /// Transfer: none constructor.
    #[inline]
    pub fn from_glib_none(ptr: *mut ffi::GObject) -> Ref {
        let r = Ref(ptr);
        r.add_ref();
        r
    }

    /// Transfer: full constructor.
    #[inline]
    pub fn from_glib_full(ptr: *mut ffi::GObject) -> Ref {
        Ref(ptr)
    }

    /// Returns a transfer: none raw pointer.
    #[inline]
    pub fn to_glib_none(&self) -> *mut ffi::GObject {
        self.0
    }

    /// Returns a transfer: full raw pointer.
    #[inline]
    pub fn to_glib_full(&self) -> *mut ffi::GObject {
        self.add_ref();
        self.0
    }
}

impl Clone for Ref {
    #[inline]
    fn clone(&self) -> Ref {
        self.add_ref();
        Ref(self.0)
    }
}

impl Drop for Ref {
    #[inline]
    fn drop(&mut self) {
        self.unref();
    }
}

/// A helper type holding a reference to a specific object or interface.
///
/// `T` is the foreign `struct` type corresponding to the object.
pub struct VirtualRef<'a, T> (&'a Ref, PhantomData<T>);

impl<'a, T> VirtualRef<'a, T> {
    #[inline]
    fn new(r: &'a Ref) -> VirtualRef<'a, T> { VirtualRef(r, PhantomData) }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for VirtualRef<'a, T> {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, VirtualRef<'a, T>> {
        Stash(self.0.to_glib_none() as *mut _, self.0)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.0.to_glib_full() as *mut _
    }
}

impl<'a, T> ToGlibPtr<'a, *mut T> for Option<&'a VirtualRef<'a, T>> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a VirtualRef<'a, T>>> {
        if let Some(ref s) = *self {
            Stash(s.0.to_glib_none() as *mut _, Some(s.0))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.0.to_glib_full() as *mut _)
    }
}

/// A wrapper around the `Ref`.
pub trait Wrapper: StaticType {
    /// The foreign `struct` type corresponding to the object.
    type GlibType;
    /// Wraps a `Ref`.
    unsafe fn wrap(r: Ref) -> Self;
    /// Returns a reference to the inner `Ref`.
    fn as_ref(&self) -> &Ref;
    /// Transforms into the inner `Ref`.
    fn unwrap(self) -> Ref;
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for &'a W {
    type Storage = &'a Ref;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, &'a W> {
        Stash(self.as_ref().to_glib_none() as *mut _, self.as_ref())
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().to_glib_full() as *mut _
    }
}

impl<'a, T, W: Wrapper<GlibType = T>> ToGlibPtr<'a, *mut T> for Option<&'a W> {
    type Storage = Option<&'a Ref>;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut T, Option<&'a W>> {
        if let Some(ref s) = *self {
            Stash(s.as_ref().to_glib_none() as *mut _, Some(s.as_ref()))
        }
        else {
            Stash(ptr::null_mut(), None)
        }
    }

    #[inline]
    fn to_glib_full(&self) -> *mut T {
        self.as_ref().map_or(ptr::null_mut(), |s| s.as_ref().to_glib_full() as *mut _)
    }
}

impl <T: Wrapper> FromGlibPtr<*mut <T as Wrapper>::GlibType> for T {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_none(ptr as *mut _))
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut <T as Wrapper>::GlibType) -> Self {
        assert!(!ptr.is_null());
        debug_assert!(types::instance_of::<T>(ptr as *const _));
        T::wrap(Ref::from_glib_full(ptr as *mut _))
    }
}

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T` and can be `upcast` to a corresponding type.
///
/// `T` always implements `Upcast<T>`.
pub unsafe trait Upcast<T: Wrapper>: Wrapper {
    /// Upcasts to a helper type corresponding to `T`.
    #[inline]
    fn upcast(&self) -> VirtualRef<<T as Wrapper>::GlibType> {
        debug_assert!(types::instance_of::<T>(self.as_ref().to_glib_none() as *const _));
        VirtualRef::<<T as Wrapper>::GlibType>::new(self.as_ref())
    }
}

unsafe impl<T: Wrapper> Upcast<T> for T { }

/// A complement to `Upcast` that allows downcasting.
pub trait Downcast<T> {
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self>;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if the instance doesn't implement `T`.
    fn downcast_unchecked(self) -> T;
}

impl <Super, Sub> Downcast<Sub> for Super
where Super: Wrapper, Sub: Wrapper + Upcast<Super> {
    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        if types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _) {
            unsafe { Ok(Sub::wrap(self.unwrap())) }
        }
        else {
            Err(self)
        }
    }

    #[inline]
    fn downcast_unchecked(self) -> Sub {
        assert!(types::instance_of::<Sub>(self.as_ref().to_glib_none() as *const _));
        unsafe { Sub::wrap(self.unwrap()) }
    }
}

#[derive(Clone)]
pub struct Object(Ref);

impl Wrapper for Object {
    type GlibType = ffi::GObject;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object { Object(r) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl StaticType for Object {
    #[inline]
    fn static_type() -> Type { Type::BaseObject }
}

pub trait ObjectExt {
}

impl<T: Upcast<Object>> ObjectExt for T {
}

/// The crate-local generic type for `GObject` descendants in GLib.
#[derive(Debug)]
pub struct GenericObject<T>(Ref, PhantomData<T>);

impl<T> Wrapper for GenericObject<T> where GenericObject<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> GenericObject<T> { GenericObject(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for GenericObject<T> {
    #[inline]
    fn clone(&self) -> GenericObject<T> {
        GenericObject(self.0.clone(), PhantomData)
    }
}

unsafe impl<T> Upcast<Object> for GenericObject<T> where GenericObject<T>: StaticType { }
<|endoftext|>


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

use client::Client;
use mqtt3::{TopicPath, SubscribeTopic, ToTopicPath};
use error::Result;

// NOTE: split subscription list into concrete & and wild card subscriptions
// all concrete subscription clients could be fetched in O(1)~
pub struct SubscriptionList {
    concrete: HashMap<SubscribeTopic, Vec<Client>>,
    wild: HashMap<SubscribeTopic, Vec<Client>>,
}

impl SubscriptionList {
    pub fn new() -> Self {
        SubscriptionList {
            concrete: HashMap::new(),
            wild: HashMap::new(),
        }
    }

    pub fn add_subscription(&mut self, topic: SubscribeTopic, client: Client) -> Result<()> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;

        if topic_path.wildcards {
            let clients = self.wild.entry(topic).or_insert(Vec::new());
            // add client to a subscription only if it doesn't already exist or
            // else replace the existing one
            if let Some(index) = clients.iter().position(|v| v.id == client.id) {
                clients.insert(index, client);
            } else {
                clients.push(client);
            }
        } else {
            let clients = self.concrete.entry(topic).or_insert(Vec::new());
            // add client to a subscription only if it doesn't already exist or
            // else replace the existing one
            if let Some(index) = clients.iter().position(|v| v.id == client.id) {
                clients.insert(index, client);
            } else {
                clients.push(client);
            }
        }

        Ok(())
    }

    /// Remove a client from a subscription
    pub fn remove_subscription_client(&mut self, topic: SubscribeTopic, id: &str) -> Result<()> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;

        if topic_path.wildcards {
            if let Some(clients) = self.wild.get_mut(&topic) {
                if let Some(index) = clients.iter().position(|v| v.id == id) {
                    clients.remove(index);
                }
            }
        } else {
            if let Some(clients) = self.concrete.get_mut(&topic) {
                if let Some(index) = clients.iter().position(|v| v.id == id) {
                    clients.remove(index);
                }
            }
        }
        Ok(())
    }

    /// Get the list of subscribed clients for a given concrete subscription topic
    pub fn get_subscribed_clients(&mut self, topic: SubscribeTopic) -> Result<Vec<Client>> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;
        // subscription topic should only have concrete topic path
        let _ = topic_path.to_topic_name()?;

        let mut all_clients = vec![];

        // O(1) matches from concrete hashmap
        if let Some(clients) = self.concrete.get(&topic) {
            all_clients.extend(clients.clone());
        }

        for (subscription, clients) in self.wild.iter() {
            let wild_subscription_topic = TopicPath::from_str(subscription.topic_path.clone())?;
            if wild_subscription_topic.is_match(&topic_path) {
                all_clients.extend(clients.clone());
            }
        }

        Ok(all_clients)
    }
}

#[cfg(test)]
mod test {
    use super::SubscriptionList;

}<commit_msg>1. consider qos while matching subscriptions 2. unittests<commit_after>use std::collections::HashMap;

use client::Client;
use mqtt3::{TopicPath, SubscribeTopic, ToTopicPath};
use error::Result;

// NOTE: split subscription list into concrete & and wild card subscriptions
// all concrete subscription clients could be fetched in O(1)~
pub struct SubscriptionList {
    concrete: HashMap<SubscribeTopic, Vec<Client>>,
    wild: HashMap<SubscribeTopic, Vec<Client>>,
}

impl SubscriptionList {
    pub fn new() -> Self {
        SubscriptionList {
            concrete: HashMap::new(),
            wild: HashMap::new(),
        }
    }

    pub fn add_subscription(&mut self, topic: SubscribeTopic, client: Client) -> Result<()> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;

        if topic_path.wildcards {
            let clients = self.wild.entry(topic).or_insert(Vec::new());
            // add client to a subscription only if it doesn't already exist or
            // else replace the existing one
            if let Some(index) = clients.iter().position(|v| v.id == client.id) {
                clients.insert(index, client);
            } else {
                clients.push(client);
            }
        } else {
            let clients = self.concrete.entry(topic).or_insert(Vec::new());
            // add client to a subscription only if it doesn't already exist or
            // else replace the existing one
            if let Some(index) = clients.iter().position(|v| v.id == client.id) {
                clients.insert(index, client);
            } else {
                clients.push(client);
            }
        }

        Ok(())
    }

    /// Remove a client from a subscription
    pub fn remove_subscription_client(&mut self, topic: SubscribeTopic, id: &str) -> Result<()> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;

        if topic_path.wildcards {
            if let Some(clients) = self.wild.get_mut(&topic) {
                if let Some(index) = clients.iter().position(|v| v.id == id) {
                    clients.remove(index);
                }
            }
        } else {
            if let Some(clients) = self.concrete.get_mut(&topic) {
                if let Some(index) = clients.iter().position(|v| v.id == id) {
                    clients.remove(index);
                }
            }
        }
        Ok(())
    }

    /// Get the list of subscribed clients for a given concrete subscription topic
    pub fn get_subscribed_clients(&mut self, topic: SubscribeTopic) -> Result<Vec<Client>> {
        let topic_path = TopicPath::from_str(topic.topic_path.clone())?;
        let qos = topic.qos;

        // subscription topic should only have concrete topic path
        let _ = topic_path.to_topic_name()?;

        let mut all_clients = vec![];

        // O(1) matches from concrete hashmap
        if let Some(clients) = self.concrete.get(&topic) {
            all_clients.extend(clients.clone());
        }

        for (subscription, clients) in self.wild.iter() {
            let wild_subscription_topic = TopicPath::from_str(subscription.topic_path.clone())?;
            let wild_subscription_qos = subscription.qos;

            if wild_subscription_qos == qos && wild_subscription_topic.is_match(&topic_path) {
                all_clients.extend(clients.clone());
            }
        }

        Ok(all_clients)
    }
}

#[cfg(test)]
mod test {
    use futures::sync::mpsc::{self, Receiver};
    use client::Client;
    use super::SubscriptionList;
    use mqtt3::*;

    fn mock_client(id: &str) -> (Client, Receiver<Packet>) {
        let (tx, rx) = mpsc::channel::<Packet>(8);
        (Client::new(id, "127.0.0.1:80".parse().unwrap(), tx), rx)
    }

    #[test]
    fn match_topics_with_wild_card_and_concrete_subscription_clients() {
        let (c1, ..) = mock_client("mock-client-1");
        let (c2, ..) = mock_client("mock-client-2");
        let (c3, ..) = mock_client("mock-client-3");

        let s1 = SubscribeTopic {
            topic_path: "hello/mqtt/rumqttd".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let s2 = SubscribeTopic {
            topic_path: "hello/+/rumqttd".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let s3 = SubscribeTopic {
            topic_path: "hello/#".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let mut sub_list = SubscriptionList::new();
        sub_list.add_subscription(s1, c1).unwrap();
        sub_list.add_subscription(s2, c2).unwrap();
        sub_list.add_subscription(s3, c3).unwrap();

        let s4 = SubscribeTopic {
            topic_path: "hello/mqtt/rumqttd".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let clients = sub_list.get_subscribed_clients(s4).unwrap();

        assert_eq!(clients.len(), 3);

        assert!(clients.iter().any(|e| e.id == "mock-client-1"));
        assert!(clients.iter().any(|e| e.id == "mock-client-2"));
        assert!(clients.iter().any(|e| e.id == "mock-client-3"));
    }

    /// subscription("a/+/c", atmostonce) shouldn't match with ("a/b/c", atleastonce)
    #[test]
    fn dont_match_subscription_with_matching_topic_but_nonmatching_qos(){
        let (c1, ..) = mock_client("mock-client-1");
        let s1 = SubscribeTopic {
            topic_path: "hello/+/rumqttd".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let mut sub_list = SubscriptionList::new();
        sub_list.add_subscription(s1, c1).unwrap();

        let s2 = SubscribeTopic {
            topic_path: "hello/mqtt/rumqttd".to_owned(),
            qos: QoS::AtLeastOnce,
        };

        let clients = sub_list.get_subscribed_clients(s2).unwrap();
        assert_eq!(clients.len(), 0);
    }

    /// subscriptions like 'a/#/c' shouldn't be allowed
    #[test]
    #[should_panic]
    fn dont_allow_subscription_with_multiwildcard_inbetween_topic() {
        let (c1, ..) = mock_client("mock-client-1");
        let s1 = SubscribeTopic {
            topic_path: "hello/#/rumqttd".to_owned(),
            qos: QoS::AtMostOnce,
        };

        let mut sub_list = SubscriptionList::new();
        sub_list.add_subscription(s1, c1).unwrap();
    }

}<|endoftext|>