<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, Debug)]
    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(),
                    })
    }

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

    println!("test_direct_select query result: {:?}", actual);

    assert!(check);
}

// 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()));
}

<commit_msg>remove additional bracket<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, Debug)]
    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(),
                    })
    }

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

    println!("test_direct_select query result: {:?}", actual);

    assert!(check);
}

// 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>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should arrive after a short delay
    thread::sleep(Duration::from_millis(10));
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}
<commit_msg>Improve comments a bit<commit_after>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should arrive after a short delay
    thread::sleep(Duration::from_millis(10));
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe that adds values from the stream to the value in the object
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}
<|endoftext|>


<commit_before>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should arrive after a short delay
    thread::sleep(Duration::from_millis(10));
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe that adds values from the stream to the value in the object
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}

#[test]
fn pipe_through_produces_backpressure() {
    // Create a channel we'll use to send data to the pipe
    let (mut sender, receiver) = mpsc::channel(0);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let mut pipe_out    = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Set the backpressure depth to 3
    pipe_out.set_backpressure_depth(3);

    // Start things running. We never read from this pipe here
    let _pipe_out       = executor::spawn(pipe_out);

    // Send 3 events to the pipe. Wait a bit between them to allow for processing time
    for _x in 0..3 {
        assert!(sender.try_send(1) == Ok(()));
        thread::sleep(Duration::from_millis(5));
    }

    // This will stick in the channel (pipe should not be accepting more input)
    assert!(sender.try_send(2) == Ok(()));
    thread::sleep(Duration::from_millis(5));

    // Channel will push back on this one
    let channel_full = sender.try_send(3);
    assert!(channel_full.is_err());
    assert!(channel_full.unwrap_err().is_full());
}<commit_msg>Add comment<commit_after>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should arrive after a short delay
    thread::sleep(Duration::from_millis(10));
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe that adds values from the stream to the value in the object
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}

#[test]
fn pipe_through_produces_backpressure() {
    // Create a channel we'll use to send data to the pipe
    let (mut sender, receiver) = mpsc::channel(0);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let mut pipe_out    = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Set the backpressure depth to 3
    pipe_out.set_backpressure_depth(3);

    // Start things running. We never read from this pipe here
    let _pipe_out       = executor::spawn(pipe_out);

    // Send 3 events to the pipe. Wait a bit between them to allow for processing time
    for _x in 0..3 {
        assert!(sender.try_send(1) == Ok(()));

        // The wait here allows the message to flow through to the pipe (if we call try_send again before the pipe has a chance to accept the input)
        thread::sleep(Duration::from_millis(5));
    }

    // This will stick in the channel (pipe should not be accepting more input)
    assert!(sender.try_send(2) == Ok(()));
    thread::sleep(Duration::from_millis(5));

    // Channel will push back on this one
    let channel_full = sender.try_send(3);
    assert!(channel_full.is_err());
    assert!(channel_full.unwrap_err().is_full());
}<|endoftext|>


<commit_before>use super::*;
use linked_hash_map::LinkedHashMap;

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`HeadlessGlyphBrushBuilder`](struct.HeadlessGlyphBrushBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{HeadlessGlyphBrushBuilder, Section};
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// let bounds = glyphs.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphBrush::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphBrush::glyphs`](#method.glyphs) calculate the positioned glyphs for a section.
/// This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) the cache has a maximum size and evicts
/// older sections when full, this is because there is no concept of actually drawing the section
/// to imply a section is no longer used.
/// [`HeadlessGlyphBrushBuilder::glyph_positioning_cache_size`](struct.HeadlessGlyphBrushBuilder.html#method.glyph_positioning_cache_size)
/// allows setting the maximum cache size.
pub struct HeadlessGlyphBrush<'font> {
    fonts: HashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: LinkedHashMap<u64, GlyphedSection<'font>>,

    glyph_positioning_cache_size: usize,
}

impl<'font> HeadlessGlyphBrush<'font> {

    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds_custom_layout<'a, S, L>(&mut self, section: S, custom_layout: &L)
        -> Option<Rect<i32>>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);

        for g in self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect{ min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 { x.0 = min.x; }
                if no_match || min.y < y.0 { y.0 = min.y; }
                if no_match || max.x > x.1 { x.1 = max.x; }
                if no_match || max.y > y.1 { y.1 = max.y; }

                no_match = false;
            }
        }

        if no_match { None }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds<'a, S>(&mut self, section: S)
        -> Option<Rect<i32>>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs_custom_layout<'a, 'b, S, L>(&'b mut self, section: S, custom_layout: &L)
        -> PositionedGlyphIter<'b, 'font>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs<'a, 'b, S>(&'b mut self, section: S)
        -> PositionedGlyphIter<'b, 'font>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }

    /// Returns the calculate_glyph_cache key for this sections glyphs
    pub(crate) fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
        where L: GlyphPositioner,
    {
        let section_hash = hash(&(section, layout));

        if self.calculate_glyph_cache.get_refresh(&section_hash).is_none() {
            self.calculate_glyph_cache.insert(section_hash, GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(&self.fonts, section),
                z: section.z,
            });
        }
        else {
            while self.calculate_glyph_cache.len() > self.glyph_positioning_cache_size {
                self.calculate_glyph_cache.pop_front();
            }
        }

        section_hash
    }
}

/// Builder for a [`HeadlessGlyphBrush`](struct.HeadlessGlyphBrush.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::HeadlessGlyphBrushBuilder;
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct HeadlessGlyphBrushBuilder<'a> {
    font_data: Vec<Font<'a>>,
    glyph_positioning_cache_size: usize,
}

impl<'a> HeadlessGlyphBrushBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(font(font_0_data).unwrap())
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
            glyph_positioning_cache_size: 50,
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data.push(font(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Sets the max number of unique sections to cache positioning data. After processing
    /// over this amount of sections oldest section positioning data will be evicted from the cache.
    ///
    /// Defaults to 50
    pub fn glyph_positioning_cache_size(mut self, entries: usize) -> Self {
        self.glyph_positioning_cache_size = entries;
        self
    }

    /// Builds a `HeadlessGlyphBrush`
    pub fn build(self) -> HeadlessGlyphBrush<'a> {
        let fonts = self.font_data.into_iter().enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        let cache = LinkedHashMap::with_capacity(self.glyph_positioning_cache_size + 1);

        HeadlessGlyphBrush {
            fonts,
            calculate_glyph_cache: cache,
            glyph_positioning_cache_size: self.glyph_positioning_cache_size,
        }
    }
}
<commit_msg>Tweak cache_glyphs visibility<commit_after>use super::*;
use linked_hash_map::LinkedHashMap;

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`HeadlessGlyphBrushBuilder`](struct.HeadlessGlyphBrushBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{HeadlessGlyphBrushBuilder, Section};
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// let bounds = glyphs.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphBrush::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphBrush::glyphs`](#method.glyphs) calculate the positioned glyphs for a section.
/// This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) the cache has a maximum size and evicts
/// older sections when full, this is because there is no concept of actually drawing the section
/// to imply a section is no longer used.
/// [`HeadlessGlyphBrushBuilder::glyph_positioning_cache_size`](struct.HeadlessGlyphBrushBuilder.html#method.glyph_positioning_cache_size)
/// allows setting the maximum cache size.
pub struct HeadlessGlyphBrush<'font> {
    fonts: HashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: LinkedHashMap<u64, GlyphedSection<'font>>,

    glyph_positioning_cache_size: usize,
}

impl<'font> HeadlessGlyphBrush<'font> {

    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds_custom_layout<'a, S, L>(&mut self, section: S, custom_layout: &L)
        -> Option<Rect<i32>>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);

        for g in self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect{ min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 { x.0 = min.x; }
                if no_match || min.y < y.0 { y.0 = min.y; }
                if no_match || max.x > x.1 { x.1 = max.x; }
                if no_match || max.y > y.1 { y.1 = max.y; }

                no_match = false;
            }
        }

        if no_match { None }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds<'a, S>(&mut self, section: S)
        -> Option<Rect<i32>>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs_custom_layout<'a, 'b, S, L>(&'b mut self, section: S, custom_layout: &L)
        -> PositionedGlyphIter<'b, 'font>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs<'a, 'b, S>(&'b mut self, section: S)
        -> PositionedGlyphIter<'b, 'font>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }

    /// Returns the calculate_glyph_cache key for this sections glyphs
    fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
        where L: GlyphPositioner,
    {
        let section_hash = hash(&(section, layout));

        if self.calculate_glyph_cache.get_refresh(&section_hash).is_none() {
            self.calculate_glyph_cache.insert(section_hash, GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(&self.fonts, section),
                z: section.z,
            });
        }
        else {
            while self.calculate_glyph_cache.len() > self.glyph_positioning_cache_size {
                self.calculate_glyph_cache.pop_front();
            }
        }

        section_hash
    }
}

/// Builder for a [`HeadlessGlyphBrush`](struct.HeadlessGlyphBrush.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::HeadlessGlyphBrushBuilder;
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct HeadlessGlyphBrushBuilder<'a> {
    font_data: Vec<Font<'a>>,
    glyph_positioning_cache_size: usize,
}

impl<'a> HeadlessGlyphBrushBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(font(font_0_data).unwrap())
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
            glyph_positioning_cache_size: 50,
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data.push(font(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Sets the max number of unique sections to cache positioning data. After processing
    /// over this amount of sections oldest section positioning data will be evicted from the cache.
    ///
    /// Defaults to 50
    pub fn glyph_positioning_cache_size(mut self, entries: usize) -> Self {
        self.glyph_positioning_cache_size = entries;
        self
    }

    /// Builds a `HeadlessGlyphBrush`
    pub fn build(self) -> HeadlessGlyphBrush<'a> {
        let fonts = self.font_data.into_iter().enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        let cache = LinkedHashMap::with_capacity(self.glyph_positioning_cache_size + 1);

        HeadlessGlyphBrush {
            fonts,
            calculate_glyph_cache: cache,
            glyph_positioning_cache_size: self.glyph_positioning_cache_size,
        }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;
use EqPair;

/// Stores a higher order point for homotopy spaces.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum HPoint<T = usize> {
    /// A point.
    Point(T),
    /// A path between two higher order points.
    Path(Box<(HPoint<T>, HPoint<T>)>),
}

impl<T> HPoint<T> {
    /// Gets the homotopy level of a higher order point for homotopy spaces.
    pub fn level(&self) -> usize {
        use HPoint::*;

        match self {
            Point(_) => 0,
            Path(ab) => ab.0.level().max(ab.1.level()) + 1,
        }
    }
}

/// A discrete space that models undirected homotopy paths
/// at a specified homotopy level.
///
/// A homotopy level is a space that connects pieces of
/// lower homotopy levels.
/// Homotopy level 0 consists of the space of the pieces themselves.
///
/// Dimension is `(<homotopy level>, <number of pieces>)`,
/// position is `HPoint`.
///
/// Uses `EqPair` internally to include loop spaces.
pub struct Homotopy<T = Data>(PhantomData<T>);

impl<T> Construct for Homotopy<T> {
    fn new() -> Homotopy<T> {Homotopy(PhantomData)}
}

impl Count<(usize, usize)> for Homotopy<Data> {
    type N = usize;
    fn count(&self, &(level, n): &(usize, usize)) -> usize {
        let s: EqPair = Construct::new();
        let mut count = n;
        for _ in 0..level {
            count = s.count(&count);
        }
        count
    }
}

impl Count<(usize, BigUint)> for Homotopy<Data> {
    type N = BigUint;
    fn count(&self, (level, n): &(usize, BigUint)) -> BigUint {
        let s: EqPair = Construct::new();
        let mut count = n.clone();
        for _ in 0..*level {
            count = s.count(&count);
        }
        count
    }
}

impl<T, U> Count<(usize, U)> for Homotopy<Of<T>>
    where
        T: Construct + Count<U>,
        Homotopy: Count<(usize, <T as Count<U>>::N), N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, (level, dim): &(usize, U)) -> Self::N {
        let of: T = Construct::new();
        let data: Homotopy<Data> = Construct::new();
        data.count(&(*level, of.count(dim)))
    }
}

impl Zero<(usize, usize), HPoint> for Homotopy<Data> {
    fn zero(&self, &(level, n): &(usize, usize)) -> HPoint {
        use HPoint::*;

        match level {
            0 => Point(0),
            _ => Path(Box::new((self.zero(&(level-1, n)), self.zero(&(level-1, n))))),
        }
    }
}

impl<T, U, V>
Zero<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + Zero<U, V>, U: Clone
{
    fn zero(&self, &(level, ref dim): &(usize, U)) -> HPoint<V> {
        use HPoint::*;

        match level {
            0 => {
                let of: T = Construct::new();
                Point(of.zero(&dim))
            }
            _ => Path(Box::new((self.zero(&(level-1, dim.clone())),
                                self.zero(&(level-1, dim.clone()))))),
        }
    }
}

impl ToIndex<(usize, usize), HPoint>
for Homotopy<Data> {
    fn to_index(&self, &(level, n): &(usize, usize), pos: &HPoint) -> usize {
        use HPoint::*;

        match pos {
            Point(x) => *x,
            Path(ab) => {
                let count = self.count(&(level, n));
                let a = self.to_index(&(level-1, n), &ab.0);
                let b = self.to_index(&(level-1, n), &ab.1);
                let min = a.min(b);
                let max = a.max(b);
                let s: EqPair = Construct::new();
                s.to_index(&count, &(min, max))
            }
        }
    }
}

impl<T, U, V>
ToIndex<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>, U: Clone
{
    fn to_index(
        &self,
        dim: &(usize, U),
        pos: &HPoint<V>
    ) -> usize {
        use HPoint::*;

        match pos {
            Point(x) => {
                let of: T = Construct::new();
                of.to_index(&dim.1, x)
            }
            Path(ab) => {
                let count = self.count(dim);
                let dim_n = (dim.0-1, dim.1.clone());
                let a = self.to_index(&dim_n, &ab.0);
                let b = self.to_index(&dim_n, &ab.1);
                let min = a.min(b);
                let max = a.max(b);
                let s: EqPair = Construct::new();
                s.to_index(&count, &(min, max))
            }
        }
    }
}

impl ToPos<(usize, usize), HPoint> for Homotopy<Data> {
    fn to_pos(&self, &(level, n): &(usize, usize), index: usize, pos: &mut HPoint) {
        use HPoint::*;

        match level {
            0 => {
                *pos = Point(index);
                return;
            }
            1 => {
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&n, index, &mut ab);
                *pos = Path(Box::new((Point(ab.0), Point(ab.1))));
                return;
            }
            _ => {
                let count = self.count(&(level, n));
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&count, index, &mut ab);
                let mut a = Point(0);
                let mut b = Point(0);
                self.to_pos(&(level - 1, n), ab.0, &mut a);
                self.to_pos(&(level - 1, n), ab.1, &mut b);
                *pos = Path(Box::new((a, b)));
                return;
            }
        }
    }
}

impl<T, U, V>
ToPos<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V> + Zero<U, V>, U: Clone
{
    fn to_pos(
        &self,
        &(level, ref dim): &(usize, U),
        index: usize,
        pos: &mut HPoint<V>
    ) {
        use HPoint::*;

        match level {
            0 => {
                let of: T = Construct::new();
                let mut of_pos = of.zero(dim);
                of.to_pos(dim, index, &mut of_pos);
                *pos = Point(of_pos);
                return;
            }
            1 => {
                let of: T = Construct::new();
                let s: EqPair<Of<T>> = Construct::new();
                let mut ab = (of.zero(dim), of.zero(dim));
                s.to_pos(&dim, index, &mut ab);
                *pos = Path(Box::new((Point(ab.0), Point(ab.1))));
                return;
            }
            _ => {
                let of: T = Construct::new();
                let count = self.count(&(level, dim.clone()));
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&count, index, &mut ab);
                let mut a = Point(of.zero(dim));
                let mut b = Point(of.zero(dim));
                self.to_pos(&(level - 1, dim.clone()), ab.0, &mut a);
                self.to_pos(&(level - 1, dim.clone()), ab.1, &mut b);
                *pos = Path(Box::new((a, b)));
                return;
            }
        }
    }
}
<commit_msg>Impl `Zero<(BigUint, BigUint), HPoint<BigUint>>` for `Homotopy`<commit_after>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;
use EqPair;

/// Stores a higher order point for homotopy spaces.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum HPoint<T = usize> {
    /// A point.
    Point(T),
    /// A path between two higher order points.
    Path(Box<(HPoint<T>, HPoint<T>)>),
}

impl<T> HPoint<T> {
    /// Gets the homotopy level of a higher order point for homotopy spaces.
    pub fn level(&self) -> usize {
        use HPoint::*;

        match self {
            Point(_) => 0,
            Path(ab) => ab.0.level().max(ab.1.level()) + 1,
        }
    }
}

/// A discrete space that models undirected homotopy paths
/// at a specified homotopy level.
///
/// A homotopy level is a space that connects pieces of
/// lower homotopy levels.
/// Homotopy level 0 consists of the space of the pieces themselves.
///
/// Dimension is `(<homotopy level>, <number of pieces>)`,
/// position is `HPoint`.
///
/// Uses `EqPair` internally to include loop spaces.
pub struct Homotopy<T = Data>(PhantomData<T>);

impl<T> Construct for Homotopy<T> {
    fn new() -> Homotopy<T> {Homotopy(PhantomData)}
}

impl Count<(usize, usize)> for Homotopy<Data> {
    type N = usize;
    fn count(&self, &(level, n): &(usize, usize)) -> usize {
        let s: EqPair = Construct::new();
        let mut count = n;
        for _ in 0..level {
            count = s.count(&count);
        }
        count
    }
}

impl Count<(usize, BigUint)> for Homotopy<Data> {
    type N = BigUint;
    fn count(&self, (level, n): &(usize, BigUint)) -> BigUint {
        let s: EqPair = Construct::new();
        let mut count = n.clone();
        for _ in 0..*level {
            count = s.count(&count);
        }
        count
    }
}

impl<T, U> Count<(usize, U)> for Homotopy<Of<T>>
    where
        T: Construct + Count<U>,
        Homotopy: Count<(usize, <T as Count<U>>::N), N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, (level, dim): &(usize, U)) -> Self::N {
        let of: T = Construct::new();
        let data: Homotopy<Data> = Construct::new();
        data.count(&(*level, of.count(dim)))
    }
}

impl Zero<(usize, usize), HPoint> for Homotopy<Data> {
    fn zero(&self, &(level, n): &(usize, usize)) -> HPoint {
        use HPoint::*;

        match level {
            0 => Point(0),
            _ => Path(Box::new((self.zero(&(level-1, n)), self.zero(&(level-1, n))))),
        }
    }
}

impl Zero<(usize, BigUint), HPoint<BigUint>> for Homotopy<Data> {
    fn zero(&self, (level, n): &(usize, BigUint)) -> HPoint<BigUint> {
        use HPoint::*;

        match *level {
            0 => Point(0usize.into()),
            _ => Path(Box::new((self.zero(&(level-1, n.clone())), self.zero(&(level-1, n.clone()))))),
        }
    }
}

impl<T, U, V>
Zero<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + Zero<U, V>, U: Clone
{
    fn zero(&self, &(level, ref dim): &(usize, U)) -> HPoint<V> {
        use HPoint::*;

        match level {
            0 => {
                let of: T = Construct::new();
                Point(of.zero(&dim))
            }
            _ => Path(Box::new((self.zero(&(level-1, dim.clone())),
                                self.zero(&(level-1, dim.clone()))))),
        }
    }
}

impl ToIndex<(usize, usize), HPoint>
for Homotopy<Data> {
    fn to_index(&self, &(level, n): &(usize, usize), pos: &HPoint) -> usize {
        use HPoint::*;

        match pos {
            Point(x) => *x,
            Path(ab) => {
                let count = self.count(&(level, n));
                let a = self.to_index(&(level-1, n), &ab.0);
                let b = self.to_index(&(level-1, n), &ab.1);
                let min = a.min(b);
                let max = a.max(b);
                let s: EqPair = Construct::new();
                s.to_index(&count, &(min, max))
            }
        }
    }
}

impl<T, U, V>
ToIndex<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>, U: Clone
{
    fn to_index(
        &self,
        dim: &(usize, U),
        pos: &HPoint<V>
    ) -> usize {
        use HPoint::*;

        match pos {
            Point(x) => {
                let of: T = Construct::new();
                of.to_index(&dim.1, x)
            }
            Path(ab) => {
                let count = self.count(dim);
                let dim_n = (dim.0-1, dim.1.clone());
                let a = self.to_index(&dim_n, &ab.0);
                let b = self.to_index(&dim_n, &ab.1);
                let min = a.min(b);
                let max = a.max(b);
                let s: EqPair = Construct::new();
                s.to_index(&count, &(min, max))
            }
        }
    }
}

impl ToPos<(usize, usize), HPoint> for Homotopy<Data> {
    fn to_pos(&self, &(level, n): &(usize, usize), index: usize, pos: &mut HPoint) {
        use HPoint::*;

        match level {
            0 => {
                *pos = Point(index);
                return;
            }
            1 => {
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&n, index, &mut ab);
                *pos = Path(Box::new((Point(ab.0), Point(ab.1))));
                return;
            }
            _ => {
                let count = self.count(&(level, n));
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&count, index, &mut ab);
                let mut a = Point(0);
                let mut b = Point(0);
                self.to_pos(&(level - 1, n), ab.0, &mut a);
                self.to_pos(&(level - 1, n), ab.1, &mut b);
                *pos = Path(Box::new((a, b)));
                return;
            }
        }
    }
}

impl<T, U, V>
ToPos<(usize, U), HPoint<V>> for Homotopy<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V> + Zero<U, V>, U: Clone
{
    fn to_pos(
        &self,
        &(level, ref dim): &(usize, U),
        index: usize,
        pos: &mut HPoint<V>
    ) {
        use HPoint::*;

        match level {
            0 => {
                let of: T = Construct::new();
                let mut of_pos = of.zero(dim);
                of.to_pos(dim, index, &mut of_pos);
                *pos = Point(of_pos);
                return;
            }
            1 => {
                let of: T = Construct::new();
                let s: EqPair<Of<T>> = Construct::new();
                let mut ab = (of.zero(dim), of.zero(dim));
                s.to_pos(&dim, index, &mut ab);
                *pos = Path(Box::new((Point(ab.0), Point(ab.1))));
                return;
            }
            _ => {
                let of: T = Construct::new();
                let count = self.count(&(level, dim.clone()));
                let s: EqPair = Construct::new();
                let mut ab = (0, 0);
                s.to_pos(&count, index, &mut ab);
                let mut a = Point(of.zero(dim));
                let mut b = Point(of.zero(dim));
                self.to_pos(&(level - 1, dim.clone()), ab.0, &mut a);
                self.to_pos(&(level - 1, dim.clone()), ab.1, &mut b);
                *pos = Path(Box::new((a, b)));
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::RwLock;

use capture;
use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    Sys_VID_FlipScreen: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,
    VideoMode_IsWindowed: Function<unsafe extern "C" fn() -> c_int>,

    window_rect: Option<*mut RECT>,
    s_BackBufferFBO: Option<*mut FBO_Container_t>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct RECT {
    left: c_int,
    right: c_int,
    top: c_int,
    bottom: c_int,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct FBO_Container_t {
    s_hBackBufferFBO: GLuint,
    s_hBackBufferCB: GLuint,
    s_hBackBufferDB: GLuint,
    s_hBackBufferTex: GLuint,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    encode::initialize();

    // Initialize the capturing.
    capture::initialize();

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::ReadPixels::is_loaded() {
        panic!("could not load glReadPixels()");
    }
    gl::PixelStorei::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::PixelStorei::is_loaded() {
        panic!("could not load glPixelStorei()");
    }
}

/// Flips the screen.
#[export_name = "_Z18Sys_VID_FlipScreenv"]
pub unsafe extern "C" fn Sys_VID_FlipScreen() {
    if capture::is_capturing() {
        let (w, h) = get_resolution();
        let mut buf = capture::get_buffer((w, h));

        // Our buffer expects 1-byte alignment.
        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

        // Get the pixels!
        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGB, gl::UNSIGNED_BYTE,
                       buf.data.as_mut_ptr() as _);

        capture::capture(buf);
    }

    real!(Sys_VID_FlipScreen)();

    // TODO: check if we're called from SCR_UpdateScreen().

    // println!("s_BackBufferFBO: {:?}", *POINTERS.read().unwrap().s_BackBufferFBO.unwrap());
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, Sys_VID_FlipScreen, "_Z18Sys_VID_FlipScreenv");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");
        find!(pointers, hw, VideoMode_IsWindowed, "VideoMode_IsWindowed");

        pointers.window_rect = Some(hw.sym("window_rect")
                .chain_err(|| "couldn't find window_rect")? as _);
        pointers.s_BackBufferFBO = Some(hw.sym("s_BackBufferFBO")
                .chain_err(|| "couldn't find s_BackBufferFBO")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width;
    let mut height;

    if real!(VideoMode_IsWindowed)() != 0 {
        let window_rect = *POINTERS.read().unwrap().window_rect.unwrap();
        width = window_rect.right - window_rect.left;
        height = window_rect.bottom - window_rect.top;
    } else {
        width = mem::uninitialized();
        height = mem::uninitialized();
        real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());
    }

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<commit_msg>Remove unused variable<commit_after>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::RwLock;

use capture;
use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    Sys_VID_FlipScreen: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,
    VideoMode_IsWindowed: Function<unsafe extern "C" fn() -> c_int>,

    window_rect: Option<*mut RECT>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct RECT {
    left: c_int,
    right: c_int,
    top: c_int,
    bottom: c_int,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    encode::initialize();

    // Initialize the capturing.
    capture::initialize();

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::ReadPixels::is_loaded() {
        panic!("could not load glReadPixels()");
    }
    gl::PixelStorei::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::PixelStorei::is_loaded() {
        panic!("could not load glPixelStorei()");
    }
}

/// Flips the screen.
#[export_name = "_Z18Sys_VID_FlipScreenv"]
pub unsafe extern "C" fn Sys_VID_FlipScreen() {
    if capture::is_capturing() {
        let (w, h) = get_resolution();
        let mut buf = capture::get_buffer((w, h));

        // Our buffer expects 1-byte alignment.
        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

        // Get the pixels!
        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGB, gl::UNSIGNED_BYTE,
                       buf.data.as_mut_ptr() as _);

        capture::capture(buf);
    }

    real!(Sys_VID_FlipScreen)();

    // TODO: check if we're called from SCR_UpdateScreen().
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, Sys_VID_FlipScreen, "_Z18Sys_VID_FlipScreenv");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");
        find!(pointers, hw, VideoMode_IsWindowed, "VideoMode_IsWindowed");

        pointers.window_rect = Some(hw.sym("window_rect")
                .chain_err(|| "couldn't find window_rect")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width;
    let mut height;

    if real!(VideoMode_IsWindowed)() != 0 {
        let window_rect = *POINTERS.read().unwrap().window_rect.unwrap();
        width = window_rect.right - window_rect.left;
        height = window_rect.bottom - window_rect.top;
    } else {
        width = mem::uninitialized();
        height = mem::uninitialized();
        real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());
    }

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<|endoftext|>


<commit_before>#[crate_id = "http#0.1-pre"];

#[comment = "Rust HTTP server"];
#[license = "MIT/ASL2"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

#[doc(html_root_url = "http://www.rust-ci.org/chris-morgan/rust-http/doc/")];

#[deny(non_camel_case_types)];
//#[deny(missing_doc)];

#[feature(macro_rules)];
#[macro_escape];

extern crate extra;
extern crate time;
extern crate collections;

pub mod buffer;
pub mod client;
pub mod common;
pub mod connecter;
pub mod server;
pub mod method;
pub mod headers;
pub mod rfc2616;
#[path = "generated/status.rs"]
pub mod status;  // Getting an error? It's generated; use ``make`` or see the ``Makefile``

/// TODO: submit upstream
#[cfg(test)]
pub mod memstream;
<commit_msg>logging macros are moved out to the separate crate `log`.<commit_after>#[crate_id = "http#0.1-pre"];

#[comment = "Rust HTTP server"];
#[license = "MIT/ASL2"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

#[doc(html_root_url = "http://www.rust-ci.org/chris-morgan/rust-http/doc/")];

#[deny(non_camel_case_types)];
//#[deny(missing_doc)];

#[feature(macro_rules)];
#[feature(phase)];
#[macro_escape];

#[phase(syntax, link)] extern crate log;
extern crate extra;
extern crate time;
extern crate collections;

pub mod buffer;
pub mod client;
pub mod common;
pub mod connecter;
pub mod server;
pub mod method;
pub mod headers;
pub mod rfc2616;
#[path = "generated/status.rs"]
pub mod status;  // Getting an error? It's generated; use ``make`` or see the ``Makefile``

/// TODO: submit upstream
#[cfg(test)]
pub mod memstream;
<|endoftext|>


<commit_before>// Copyright 2016 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Base code for authentication.

use std::error::Error;
use std::fmt;
use std::io;

use hyper::{Client, Url};
use hyper::Error as HttpClientError;
use hyper::client::IntoUrl;
use hyper::error::ParseError;
use hyper::status::StatusCode;
use time::PreciseTime;

/// Authentication token.
#[derive(Clone)]
pub struct AuthToken {
    /// Token contents.
    pub token: String,
    /// Expiration time (if any).
    pub expires_at: Option<PreciseTime>
}

header! { (AuthTokenHeader, "X-Auth-Token") => [String] }
header! { (SubjectTokenHeader, "X-Subject-Token") => [String] }

/// Error from an authentication call.
#[derive(Debug)]
pub enum AuthError {
    /// Insufficient credentials passed to make authentication request.
    InsufficientCredentials(&'static str),
    /// Requested service endpoint was not found.
    EndpointNotFound,
    /// Authentication rejected (invalid credentials or token).
    Unauthorized,
    /// Generic HTTP error (not covered by EndpointNotFound and Unauthorized).
    HttpError(StatusCode, Option<String>),
    /// Protocol-level error reported by underlying HTTP library.
    ProtocolError(HttpClientError)
}

/// Trait for any authentication method.
pub trait AuthMethod {
    /// Verify authentication and generate an auth token.
    ///
    /// May cache a token while it is still valid.
    fn get_token(&mut self, client: &Client) -> Result<AuthToken, AuthError>;
    /// Get a URL for the request service.
    fn get_endpoint(&mut self, service_type: &str, client: &Client)
        -> Result<Url, AuthError>;
}

/// Authentication method that provides no authentication (uses a fake token).
pub struct NoAuth {
    endpoint: Url
}

impl NoAuth {
    /// Create a new fake authentication method using a fixed endpoint.
    pub fn new<U>(endpoint: U) -> Result<NoAuth, ParseError> where U: IntoUrl {
        let url = try!(endpoint.into_url());
        Ok(NoAuth {
            endpoint: url
        })
    }
}

impl AuthMethod for NoAuth {
    /// Return a fake token for compliance with the protocol.
    fn get_token(&mut self, _client: &Client) -> Result<AuthToken, AuthError> {
        Ok(AuthToken {
            token: String::from("no-auth"),
            expires_at: None
        })
    }

    /// Get a predefined endpoint for all service types
    fn get_endpoint(&mut self, _service_type: &str, _client: &Client)
            -> Result<Url, AuthError> {
        Ok(self.endpoint.clone())
    }
}

impl fmt::Display for AuthError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AuthError::InsufficientCredentials(msg) =>
                write!(f, "Insufficient credentials provided: {}", msg),
            AuthError::EndpointNotFound =>
                write!(f, "Requested endpoint was not found"),
            AuthError::Unauthorized =>
                write!(f, "Authentication failed"),
            AuthError::HttpError(status, ref maybe_msg) =>
                match *maybe_msg {
                    Some(ref msg) =>
                        write!(f, "HTTP error {}: {}", status, msg),
                    None =>
                        write!(f, "HTTP error {}", status),
                },
            AuthError::ProtocolError(ref e) => fmt::Display::fmt(e, f)
        }
    }
}

impl Error for AuthError {
    fn description(&self) -> &str {
        match *self {
            AuthError::InsufficientCredentials(..) =>
                "Insufficient credentials provided",
            AuthError::EndpointNotFound => "Requested endpoint was not found",
            AuthError::Unauthorized => "Authentication failed",
            AuthError::HttpError(..) => "HTTP error",
            AuthError::ProtocolError(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            AuthError::ProtocolError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<HttpClientError> for AuthError {
    fn from(value: HttpClientError) -> AuthError {
        AuthError::ProtocolError(value)
    }
}

impl From<io::Error> for AuthError {
    fn from(value: io::Error) -> AuthError {
        AuthError::ProtocolError(HttpClientError::Io(value))
    }
}

#[cfg(test)]
pub mod test {
    use hyper;

    use super::{AuthMethod, NoAuth};

    #[test]
    fn test_noauth_new() {
        let a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let e = a.endpoint;
        assert_eq!(e.scheme(), "http");
        assert_eq!(e.host_str().unwrap(), "127.0.0.1");
        assert_eq!(e.port().unwrap(), 8080u16);
        assert_eq!(e.path(), "/v1");
    }

    #[test]
    fn test_noauth_new_fail() {
        NoAuth::new("foo bar").err().unwrap();
    }

    #[test]
    fn test_noauth_get_token() {
        let mut a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let tok = a.get_token(&hyper::Client::new()).unwrap();
        assert_eq!(&tok.token, "no-auth");
        assert!(tok.expires_at.is_none());
    }

    #[test]
    fn test_noauth_get_endpoint() {
        let mut a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let e = a.get_endpoint("foobar", &hyper::Client::new()).unwrap();
        assert_eq!(e.scheme(), "http");
        assert_eq!(e.host_str().unwrap(), "127.0.0.1");
        assert_eq!(e.port().unwrap(), 8080u16);
        assert_eq!(e.path(), "/v1");
    }
}
<commit_msg>Authentication: require Clone and Send for auth methods<commit_after>// Copyright 2016 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Base code for authentication.

use std::error::Error;
use std::fmt;
use std::io;

use hyper::{Client, Url};
use hyper::Error as HttpClientError;
use hyper::client::IntoUrl;
use hyper::error::ParseError;
use hyper::status::StatusCode;
use time::PreciseTime;

/// Authentication token.
#[derive(Clone)]
pub struct AuthToken {
    /// Token contents.
    pub token: String,
    /// Expiration time (if any).
    pub expires_at: Option<PreciseTime>
}

header! { (AuthTokenHeader, "X-Auth-Token") => [String] }
header! { (SubjectTokenHeader, "X-Subject-Token") => [String] }

/// Error from an authentication call.
#[derive(Debug)]
pub enum AuthError {
    /// Insufficient credentials passed to make authentication request.
    InsufficientCredentials(&'static str),
    /// Requested service endpoint was not found.
    EndpointNotFound,
    /// Authentication rejected (invalid credentials or token).
    Unauthorized,
    /// Generic HTTP error (not covered by EndpointNotFound and Unauthorized).
    HttpError(StatusCode, Option<String>),
    /// Protocol-level error reported by underlying HTTP library.
    ProtocolError(HttpClientError)
}

/// Trait for any authentication method.
pub trait AuthMethod: Clone + Send {
    /// Verify authentication and generate an auth token.
    ///
    /// May cache a token while it is still valid.
    fn get_token(&mut self, client: &Client) -> Result<AuthToken, AuthError>;
    /// Get a URL for the request service.
    fn get_endpoint(&mut self, service_type: &str, client: &Client)
        -> Result<Url, AuthError>;
}

/// Authentication method that provides no authentication (uses a fake token).
#[derive(Clone)]
pub struct NoAuth {
    endpoint: Url
}

impl NoAuth {
    /// Create a new fake authentication method using a fixed endpoint.
    pub fn new<U>(endpoint: U) -> Result<NoAuth, ParseError> where U: IntoUrl {
        let url = try!(endpoint.into_url());
        Ok(NoAuth {
            endpoint: url
        })
    }
}

impl AuthMethod for NoAuth {
    /// Return a fake token for compliance with the protocol.
    fn get_token(&mut self, _client: &Client) -> Result<AuthToken, AuthError> {
        Ok(AuthToken {
            token: String::from("no-auth"),
            expires_at: None
        })
    }

    /// Get a predefined endpoint for all service types
    fn get_endpoint(&mut self, _service_type: &str, _client: &Client)
            -> Result<Url, AuthError> {
        Ok(self.endpoint.clone())
    }
}

impl fmt::Display for AuthError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AuthError::InsufficientCredentials(msg) =>
                write!(f, "Insufficient credentials provided: {}", msg),
            AuthError::EndpointNotFound =>
                write!(f, "Requested endpoint was not found"),
            AuthError::Unauthorized =>
                write!(f, "Authentication failed"),
            AuthError::HttpError(status, ref maybe_msg) =>
                match *maybe_msg {
                    Some(ref msg) =>
                        write!(f, "HTTP error {}: {}", status, msg),
                    None =>
                        write!(f, "HTTP error {}", status),
                },
            AuthError::ProtocolError(ref e) => fmt::Display::fmt(e, f)
        }
    }
}

impl Error for AuthError {
    fn description(&self) -> &str {
        match *self {
            AuthError::InsufficientCredentials(..) =>
                "Insufficient credentials provided",
            AuthError::EndpointNotFound => "Requested endpoint was not found",
            AuthError::Unauthorized => "Authentication failed",
            AuthError::HttpError(..) => "HTTP error",
            AuthError::ProtocolError(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            AuthError::ProtocolError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<HttpClientError> for AuthError {
    fn from(value: HttpClientError) -> AuthError {
        AuthError::ProtocolError(value)
    }
}

impl From<io::Error> for AuthError {
    fn from(value: io::Error) -> AuthError {
        AuthError::ProtocolError(HttpClientError::Io(value))
    }
}

#[cfg(test)]
pub mod test {
    use hyper;

    use super::{AuthMethod, NoAuth};

    #[test]
    fn test_noauth_new() {
        let a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let e = a.endpoint;
        assert_eq!(e.scheme(), "http");
        assert_eq!(e.host_str().unwrap(), "127.0.0.1");
        assert_eq!(e.port().unwrap(), 8080u16);
        assert_eq!(e.path(), "/v1");
    }

    #[test]
    fn test_noauth_new_fail() {
        NoAuth::new("foo bar").err().unwrap();
    }

    #[test]
    fn test_noauth_get_token() {
        let mut a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let tok = a.get_token(&hyper::Client::new()).unwrap();
        assert_eq!(&tok.token, "no-auth");
        assert!(tok.expires_at.is_none());
    }

    #[test]
    fn test_noauth_get_endpoint() {
        let mut a = NoAuth::new("http://127.0.0.1:8080/v1").unwrap();
        let e = a.get_endpoint("foobar", &hyper::Client::new()).unwrap();
        assert_eq!(e.scheme(), "http");
        assert_eq!(e.host_str().unwrap(), "127.0.0.1");
        assert_eq!(e.port().unwrap(), 8080u16);
        assert_eq!(e.path(), "/v1");
    }
}
<|endoftext|>