<commit_before>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::io;
use time;
use mysql;
use mysql::{OptsBuilder, Pool, Value};
use mysql::conn::QueryResult;
use std::process;

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

quick_error! {
    #[derive(Debug)]
    enum StoreDataError {
        IOError(error: io::Error) { from() }
        MySQLError(error: mysql::Error) { from() }
        TimeParseError(error: time::ParseError) { from() }
    }
}

fn store_to_db<'a>(db_pool: &Pool, station_folder: &str, data: &StationDataType) -> Result<Option<QueryResult<'a>>, StoreDataError> {
    let datetime_format = "%Y-%m-%d %H:%M:%S";

    match data {
        &StationDataType::SingleData(timestamp_tm, voltage) => {
            let timestamp = try!(timestamp_tm.strftime(&datetime_format));
            let result = try!(db_pool.prep_exec("INSERT INTO battery_data (timestamp, station,
                battery_voltage) VALUES (:timestamp, :station, :battery_voltage)",
                (Value::from(timestamp.to_string()), Value::from(station_folder), Value::from(voltage))));
            return Ok(Some(result));
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            let timestamp = try!(full_data_set.timestamp.strftime(&datetime_format));
            let result = try!(db_pool.prep_exec("INSERT INTO multiple_data (
                    timestamp,
                    station,
                    air_temperature,
                    air_relative_humidity,
                    solar_radiation,
                    soil_water_content,
                    soil_temperature,
                    wind_speed,
                    wind_max,
                    wind_direction,
                    precipitation,
                    air_pressure
                ) VALUES (
                    :timestamp,
                    :station,
                    :air_temperature,
                    :air_relative_humidity,
                    :solar_radiation,
                    :soil_water_content,
                    :soil_temperature,
                    :wind_speed,
                    :wind_max,
                    :wind_direction,
                    :precipitation,
                    :air_pressure
                )", (
                    Value::from(timestamp.to_string()),
                    Value::from(station_folder),
                    Value::from(full_data_set.air_temperature),
                    Value::from(full_data_set.air_relative_humidity),
                    Value::from(full_data_set.solar_radiation),
                    Value::from(full_data_set.soil_water_content),
                    Value::from(full_data_set.soil_temperature),
                    Value::from(full_data_set.wind_speed),
                    Value::from(full_data_set.wind_max),
                    Value::from(full_data_set.wind_direction),
                    Value::from(full_data_set.precipitation),
                    Value::from(full_data_set.air_pressure)
                )));
            return Ok(Some(result));
        }
    }
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        2104 => "2104_Tue".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client<'a>(stream: &mut TcpStream, remote_addr: &SocketAddr,
    db_pool: &Arc<Mutex<Pool>>) -> Result<Option<QueryResult<'a>>, StoreDataError> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let station_folder = port_to_station(local_port);

        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII) ({}): '{}'", &station_folder, str_header);
        info!("Data (ASCII) ({}): '{}'", &station_folder, str_data);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match db_pool.lock() {
                    Ok(db_pool) => {
                        try!(store_to_db(&db_pool, &station_folder, &parsed_data));
                    },
                    Err(e) => info!("Mutex (poison) error (db_pool): {}", e)
                }
            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished");

    Ok(None)
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => {
                info!("Network error: {}", e);
                process::exit(1);
            }
        }
    }

    let mut db_builder = OptsBuilder::new();
    db_builder.ip_or_hostname(Some(config.hostname))
           .db_name(Some(config.db_name))
           .user(Some(config.username))
           .pass(Some(config.password));
    let db_pool = match Pool::new(db_builder) {
        Ok(db_pool) => db_pool,
        Err(e) => {
            info!("Database error: {}", e);
            process::exit(1);
        }
    };

    let db_pool = Arc::new(Mutex::new(db_pool));

    for listener in listeners {
        let cloned_pool = db_pool.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    match handle_client(&mut stream, &addr, &cloned_pool) {
                        Ok(None) => {},
                        Ok(Some(query_result)) => { info!("Database insert successfull: {}, {}",
                            query_result.affected_rows(),  query_result.last_insert_id()) },
                        Err(StoreDataError::MySQLError(db_error)) => { info!("DB Error: {}", db_error) },
                        Err(StoreDataError::IOError(io_error)) => { info!("IO Error: {}", io_error) },
                        Err(StoreDataError::TimeParseError(time_error)) => { info!("Time parse Error: {}", time_error) }
                    }
                }
            }
        });
    }
}

#[cfg(test)]
mod tests {
    use time::{strptime};
    use data_parser::{StationDataType, WeatherStationData};
    use mysql::{Value, Pool, OptsBuilder};
    use chrono::naive::datetime::NaiveDateTime;

    use super::{store_to_db, port_to_station};

    #[test]
    fn test_port_to_station() {
        assert_eq!(port_to_station(2100), "2100_Na");
        assert_eq!(port_to_station(2101), "2101_SG");
        assert_eq!(port_to_station(2102), "2102_PdA");
        assert_eq!(port_to_station(2103), "2103_LC");
        assert_eq!(port_to_station(2104), "2104_Tue");
        assert_eq!(port_to_station(2105), "unknown");
    }

    #[test]
    fn test_store_to_db1() {
        let mut db_builder = OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = Pool::new(db_builder).unwrap();

        let query_result = store_to_db(&pool, "test1", &StationDataType::SingleData(strptime("2016-06-12 12:13:14",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73));
        let query_result = query_result.unwrap().unwrap();
        let affected_rows = query_result.affected_rows();
        assert_eq!(affected_rows, 1);
        let last_insert_id = query_result.last_insert_id();

        let select_result = pool.prep_exec("select * from battery_data where id=(:id)", (Value::from(last_insert_id),)).unwrap();
        for opt_item in select_result {
            let mut row_item = opt_item.unwrap();
            assert_eq!(row_item.len(), 4);
            let row_id: u64 = row_item.get(0).unwrap();
            assert_eq!(row_id, last_insert_id);
            let row_timestamp: NaiveDateTime = row_item.get(1).unwrap();
            assert_eq!(row_timestamp, NaiveDateTime::parse_from_str("2016-06-12 12:13:14", "%Y-%m-%d %H:%M:%S").unwrap());
            let row_station: String = row_item.get(2).unwrap();
            assert_eq!(row_station, "test1");
            let row_voltage: f64 = row_item.get(3).unwrap();
            assert_eq!(row_voltage, 12.73);
        }

        let delete_result = pool.prep_exec("delete from battery_data where station='test1'", ()).unwrap();
        assert_eq!(delete_result.affected_rows(), 1);
    }

    #[test]
    fn test_store_to_db2() {
        let mut db_builder = OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = Pool::new(db_builder).unwrap();

        let query_result = store_to_db(&pool, "test2", &StationDataType::MultipleData(WeatherStationData{
            timestamp: strptime("2016-06-15 15:16:17", "%Y-%m-%d %H:%M:%S").unwrap(),
            air_temperature: 18.15,
            air_relative_humidity: 65.31,
            solar_radiation: 620.4,
            soil_water_content: 0.056,
            soil_temperature: 16.25,
            wind_speed: 4.713,
            wind_max: 9.5,
            wind_direction: 257.9,
            precipitation: 1.232,
            air_pressure: 981.4
        }));
        let query_result = query_result.unwrap().unwrap();
        let affected_rows = query_result.affected_rows();
        assert_eq!(affected_rows, 1);
        let last_insert_id = query_result.last_insert_id();

        let select_result = pool.prep_exec("select * from multiple_data where id=(:id)", (Value::from(last_insert_id),)).unwrap();
        for opt_item in select_result {
            let mut row_item = opt_item.unwrap();
            assert_eq!(row_item.len(), 13);
            let row_id: u64 = row_item.get(0).unwrap();
            assert_eq!(row_id, last_insert_id);
            let row_timestamp: NaiveDateTime = row_item.get(1).unwrap();
            assert_eq!(row_timestamp, NaiveDateTime::parse_from_str("2016-06-15 15:16:17", "%Y-%m-%d %H:%M:%S").unwrap());
            let row_station: String = row_item.get(2).unwrap();
            assert_eq!(row_station, "test2");
            let row_air_temperature: f64 = row_item.get(3).unwrap();
            assert_eq!(row_air_temperature, 18.15);
            let row_air_relative_humidity: f64 = row_item.get(4).unwrap();
            assert_eq!(row_air_relative_humidity, 65.31);
            let row_solar_radiation: f64 = row_item.get(5).unwrap();
            assert_eq!(row_solar_radiation, 620.4 );
            let row_soil_water_content: f64 = row_item.get(6).unwrap();
            assert_eq!(row_soil_water_content, 0.056);
            let row_soil_temperature: f64 = row_item.get(7).unwrap();
            assert_eq!(row_soil_temperature, 16.25);
            let row_wind_speed: f64 = row_item.get(8).unwrap();
            assert_eq!(row_wind_speed, 4.713);
            let row_wind_max: f64 = row_item.get(9).unwrap();
            assert_eq!(row_wind_max, 9.5);
            let row_wind_direction: f64 = row_item.get(10).unwrap();
            assert_eq!(row_wind_direction, 257.9);
            let row_precipitation: f64 = row_item.get(11).unwrap();
            assert_eq!(row_precipitation, 1.232);
            let row_air_pressure: f64 = row_item.get(12).unwrap();
            assert_eq!(row_air_pressure, 981.4);
        }

        let delete_result = pool.prep_exec("delete from multiple_data where station='test2'", ()).unwrap();
        assert_eq!(delete_result.affected_rows(), 1);
    }

}
<commit_msg>fix wrong station name<commit_after>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::io;
use time;
use mysql;
use mysql::{OptsBuilder, Pool, Value};
use mysql::conn::QueryResult;
use std::process;

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

quick_error! {
    #[derive(Debug)]
    enum StoreDataError {
        IOError(error: io::Error) { from() }
        MySQLError(error: mysql::Error) { from() }
        TimeParseError(error: time::ParseError) { from() }
    }
}

fn store_to_db<'a>(db_pool: &Pool, station_name: &str, data: &StationDataType) -> Result<Option<QueryResult<'a>>, StoreDataError> {
    let datetime_format = "%Y-%m-%d %H:%M:%S";

    match data {
        &StationDataType::SingleData(timestamp_tm, voltage) => {
            let timestamp = try!(timestamp_tm.strftime(&datetime_format));
            let result = try!(db_pool.prep_exec("INSERT INTO battery_data (timestamp, station,
                battery_voltage) VALUES (:timestamp, :station, :battery_voltage)",
                (Value::from(timestamp.to_string()), Value::from(station_name), Value::from(voltage))));
            return Ok(Some(result));
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            let timestamp = try!(full_data_set.timestamp.strftime(&datetime_format));
            let result = try!(db_pool.prep_exec("INSERT INTO multiple_data (
                    timestamp,
                    station,
                    air_temperature,
                    air_relative_humidity,
                    solar_radiation,
                    soil_water_content,
                    soil_temperature,
                    wind_speed,
                    wind_max,
                    wind_direction,
                    precipitation,
                    air_pressure
                ) VALUES (
                    :timestamp,
                    :station,
                    :air_temperature,
                    :air_relative_humidity,
                    :solar_radiation,
                    :soil_water_content,
                    :soil_temperature,
                    :wind_speed,
                    :wind_max,
                    :wind_direction,
                    :precipitation,
                    :air_pressure
                )", (
                    Value::from(timestamp.to_string()),
                    Value::from(station_name),
                    Value::from(full_data_set.air_temperature),
                    Value::from(full_data_set.air_relative_humidity),
                    Value::from(full_data_set.solar_radiation),
                    Value::from(full_data_set.soil_water_content),
                    Value::from(full_data_set.soil_temperature),
                    Value::from(full_data_set.wind_speed),
                    Value::from(full_data_set.wind_max),
                    Value::from(full_data_set.wind_direction),
                    Value::from(full_data_set.precipitation),
                    Value::from(full_data_set.air_pressure)
                )));
            return Ok(Some(result));
        }
    }
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "Nahuelbuta".to_string(),
        2101 => "Santa_Gracia".to_string(),
        2102 => "Pan_de_Azucar".to_string(),
        2103 => "La_Campana".to_string(),
        2104 => "Wanne_Tuebingen".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client<'a>(stream: &mut TcpStream, remote_addr: &SocketAddr,
    db_pool: &Arc<Mutex<Pool>>) -> Result<Option<QueryResult<'a>>, StoreDataError> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let station_name = port_to_station(local_port);

        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII) ({}): '{}'", &station_name, str_header);
        info!("Data (ASCII) ({}): '{}'", &station_name, str_data);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match db_pool.lock() {
                    Ok(db_pool) => {
                        try!(store_to_db(&db_pool, &station_name, &parsed_data));
                    },
                    Err(e) => info!("Mutex (poison) error (db_pool): {}", e)
                }
            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished");

    Ok(None)
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => {
                info!("Network error: {}", e);
                process::exit(1);
            }
        }
    }

    let mut db_builder = OptsBuilder::new();
    db_builder.ip_or_hostname(Some(config.hostname))
           .db_name(Some(config.db_name))
           .user(Some(config.username))
           .pass(Some(config.password));
    let db_pool = match Pool::new(db_builder) {
        Ok(db_pool) => db_pool,
        Err(e) => {
            info!("Database error: {}", e);
            process::exit(1);
        }
    };

    let db_pool = Arc::new(Mutex::new(db_pool));

    for listener in listeners {
        let cloned_pool = db_pool.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    match handle_client(&mut stream, &addr, &cloned_pool) {
                        Ok(None) => {},
                        Ok(Some(query_result)) => { info!("Database insert successfull: {}, {}",
                            query_result.affected_rows(),  query_result.last_insert_id()) },
                        Err(StoreDataError::MySQLError(db_error)) => { info!("DB Error: {}", db_error) },
                        Err(StoreDataError::IOError(io_error)) => { info!("IO Error: {}", io_error) },
                        Err(StoreDataError::TimeParseError(time_error)) => { info!("Time parse Error: {}", time_error) }
                    }
                }
            }
        });
    }
}

#[cfg(test)]
mod tests {
    use time::{strptime};
    use data_parser::{StationDataType, WeatherStationData};
    use mysql::{Value, Pool, OptsBuilder};
    use chrono::naive::datetime::NaiveDateTime;

    use super::{store_to_db, port_to_station};

    #[test]
    fn test_port_to_station() {
        assert_eq!(port_to_station(2100), "Nahuelbuta");
        assert_eq!(port_to_station(2101), "Santa_Gracia");
        assert_eq!(port_to_station(2102), "Pan_de_Azucar");
        assert_eq!(port_to_station(2103), "La_Campana");
        assert_eq!(port_to_station(2104), "Wanne_Tuebingen");
        assert_eq!(port_to_station(2105), "unknown");
    }

    #[test]
    fn test_store_to_db1() {
        let mut db_builder = OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = Pool::new(db_builder).unwrap();

        let query_result = store_to_db(&pool, "test1", &StationDataType::SingleData(strptime("2016-06-12 12:13:14",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73));
        let query_result = query_result.unwrap().unwrap();
        let affected_rows = query_result.affected_rows();
        assert_eq!(affected_rows, 1);
        let last_insert_id = query_result.last_insert_id();

        let select_result = pool.prep_exec("select * from battery_data where id=(:id)", (Value::from(last_insert_id),)).unwrap();
        for opt_item in select_result {
            let mut row_item = opt_item.unwrap();
            assert_eq!(row_item.len(), 4);
            let row_id: u64 = row_item.get(0).unwrap();
            assert_eq!(row_id, last_insert_id);
            let row_timestamp: NaiveDateTime = row_item.get(1).unwrap();
            assert_eq!(row_timestamp, NaiveDateTime::parse_from_str("2016-06-12 12:13:14", "%Y-%m-%d %H:%M:%S").unwrap());
            let row_station: String = row_item.get(2).unwrap();
            assert_eq!(row_station, "test1");
            let row_voltage: f64 = row_item.get(3).unwrap();
            assert_eq!(row_voltage, 12.73);
        }

        let delete_result = pool.prep_exec("delete from battery_data where station='test1'", ()).unwrap();
        assert_eq!(delete_result.affected_rows(), 1);
    }

    #[test]
    fn test_store_to_db2() {
        let mut db_builder = OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = Pool::new(db_builder).unwrap();

        let query_result = store_to_db(&pool, "test2", &StationDataType::MultipleData(WeatherStationData{
            timestamp: strptime("2016-06-15 15:16:17", "%Y-%m-%d %H:%M:%S").unwrap(),
            air_temperature: 18.15,
            air_relative_humidity: 65.31,
            solar_radiation: 620.4,
            soil_water_content: 0.056,
            soil_temperature: 16.25,
            wind_speed: 4.713,
            wind_max: 9.5,
            wind_direction: 257.9,
            precipitation: 1.232,
            air_pressure: 981.4
        }));
        let query_result = query_result.unwrap().unwrap();
        let affected_rows = query_result.affected_rows();
        assert_eq!(affected_rows, 1);
        let last_insert_id = query_result.last_insert_id();

        let select_result = pool.prep_exec("select * from multiple_data where id=(:id)", (Value::from(last_insert_id),)).unwrap();
        for opt_item in select_result {
            let mut row_item = opt_item.unwrap();
            assert_eq!(row_item.len(), 13);
            let row_id: u64 = row_item.get(0).unwrap();
            assert_eq!(row_id, last_insert_id);
            let row_timestamp: NaiveDateTime = row_item.get(1).unwrap();
            assert_eq!(row_timestamp, NaiveDateTime::parse_from_str("2016-06-15 15:16:17", "%Y-%m-%d %H:%M:%S").unwrap());
            let row_station: String = row_item.get(2).unwrap();
            assert_eq!(row_station, "test2");
            let row_air_temperature: f64 = row_item.get(3).unwrap();
            assert_eq!(row_air_temperature, 18.15);
            let row_air_relative_humidity: f64 = row_item.get(4).unwrap();
            assert_eq!(row_air_relative_humidity, 65.31);
            let row_solar_radiation: f64 = row_item.get(5).unwrap();
            assert_eq!(row_solar_radiation, 620.4 );
            let row_soil_water_content: f64 = row_item.get(6).unwrap();
            assert_eq!(row_soil_water_content, 0.056);
            let row_soil_temperature: f64 = row_item.get(7).unwrap();
            assert_eq!(row_soil_temperature, 16.25);
            let row_wind_speed: f64 = row_item.get(8).unwrap();
            assert_eq!(row_wind_speed, 4.713);
            let row_wind_max: f64 = row_item.get(9).unwrap();
            assert_eq!(row_wind_max, 9.5);
            let row_wind_direction: f64 = row_item.get(10).unwrap();
            assert_eq!(row_wind_direction, 257.9);
            let row_precipitation: f64 = row_item.get(11).unwrap();
            assert_eq!(row_precipitation, 1.232);
            let row_air_pressure: f64 = row_item.get(12).unwrap();
            assert_eq!(row_air_pressure, 981.4);
        }

        let delete_result = pool.prep_exec("delete from multiple_data where station='test2'", ()).unwrap();
        assert_eq!(delete_result.affected_rows(), 1);
    }

}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * 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.
 */

use slog::{debug, o, Logger};

/// Server is the UDP server main implementation
pub struct Server {
    log: Logger,
}

impl Server {
    pub fn new(log: Logger) -> Self {
        let log = log.new(o!("source" => "Server"));

        debug!(log, "Started");
        return Server { log };
    }
}
<commit_msg>Nicer<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * 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.
 */

use slog::{debug, o, Logger};
use std::any::type_name;

/// Server is the UDP server main implementation
pub struct Server {
    log: Logger,
}

impl Server {
    pub fn new(log: Logger) -> Self {
        let log = log.new(o!("source" => "server::Server"));

        debug!(log, "Started");
        return Server { log };
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Chris Liebert

extern crate libc;

use std::ffi::CStr;
use std::fs::File;
use std::io::Error;
use std::io::prelude::*;
use std::num::ParseIntError;

use glium;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;

#[cfg(feature = "sqlite")]
use glium::Version;

#[cfg(feature = "sqlite")]
use dbloader::{DBLoader, DBLoaderError};

/// A representation for a GPU program
///
/// Shader programs contain the source for a vertex and fragment shader
/// in addition to a name
///
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Shader {
    pub name: String,
    pub vertex_source: String,
    pub fragment_source: String,
}

#[derive(Debug)]
pub enum ShaderError {
    IoError(Error),
    ProgramChooserCreationError(glium::program::ProgramChooserCreationError),
    ProgramCreationError(glium::ProgramCreationError),
    InvalidGLSLVersionStringError(ParseIntError),
    UnsupportedGLSLVersionError(Error),
}

impl Shader {
    /// Create a default shader with hardcoded source
    ///
    pub fn default(display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        Shader::from_source(r#"
#version 150

 // Input data
 in vec3 position;
 in vec3 normal;
 in vec2 texcoord;

// Uniforms
uniform mat4 projection;
uniform mat4 modelview;

uniform mat4 model;

uniform vec3 light_position_worldspace;

// Output data
out vec3 out_position;
out vec3 out_normal;
out vec2 out_texcoord;
out vec3 camera_direction;
out vec3 light_direction;
out vec3 light_position;

void main() {
	mat4 mvp = projection * modelview * model;
	out_position = (mvp * vec4(position, 1.0)).xyz;
	camera_direction = normalize(vec3(0, 0, 0) - out_position);
	light_direction = vec3(0,-1, 0);
	light_position = light_position_worldspace;
	gl_Position = mvp * vec4(position, 1.0);
	out_normal = ( mvp * vec4(normal, 0)).xyz;
	out_texcoord = texcoord;
}

     "#, r#"

#version 150
precision mediump float;

// Interpolated values from the vertex shaders
in vec3 out_position;
in vec3 out_normal;
in vec2 out_texcoord;
in vec3 camera_direction;
in vec3 light_direction;

// Ouput data
out vec3 color;

// Values that stay constant for the whole mesh.
uniform sampler2D diffuse_texture;

uniform vec3 ambient;
uniform vec3 diffuse;
uniform vec3 specular;
uniform vec3 light_position;

void main(){
	vec3 light_color = vec3(1,1,1);
	float light_power = 3.8f;

	// Material properties
	vec3 diffuseColor = vec3(0.3, 0.3, 0.3) * ( diffuse + texture(diffuse_texture, out_texcoord).rgb );

	vec3 ambientColor = ambient + vec3(0.3, 0.3, 0.3) * diffuseColor;
	vec3 specularColor = specular;

	// Distance to the light
	float distance = length(light_position - out_position);
	// Normal of the computed fragment, in camera space
	vec3 n = normalize(out_normal);
	// Direction of the light (from the fragment to the light)
	vec3 l = normalize(light_direction);
	float cosTheta = clamp(dot(n, l), 0.0, 1.0);
	vec3 E = normalize(camera_direction);
	vec3 R = reflect(-l, n);
	float cosAlpha = clamp(dot(E, R), 0.0, 1.0);

	color =
		// Ambient : simulates indirect lighting
		ambientColor +
		// Diffuse : "color" of the object
		diffuseColor * light_color * light_power * cosTheta / (distance * distance) +
		// Specular : reflective highlight, like a mirror
		specularColor * light_color * light_power * pow(cosAlpha, 5.0) / (distance * distance);
}

"#,
		&display)
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that contains the shader and shader_version tables in SQLite
    ///
	#[cfg(feature = "sqlite")]
    #[allow(unused_assignments)]
    pub fn from_dbloader(shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        use glium::Version;
        let supported_glsl_version: Version = display.get_supported_glsl_version();
        let api: glium::Api = supported_glsl_version.0;
        let major_version : u8 = supported_glsl_version.1;
        let minor_version : u8 = supported_glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
                glium::Api::Gl => {
                    use_gles = false;
                },
                glium::Api::GlEs => {
                    use_gles = true;
                    glsl_version_string.push_str(" es");
                },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) => return Err(ShaderError::InvalidGLSLVersionStringError(e)),
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        let program: Program = match use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        };

        // Shader compilation no longer required
        display.release_shader_compiler();
        return Ok(program);
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that has a specific shader version
    ///
	#[cfg(feature = "sqlite")]
    pub fn from_dbloader_with_version(shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        if !display.is_glsl_version_supported(&glsl_version) {
            return Err(ShaderError::UnsupportedGLSLVersionError(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version")));
        }

        let api: glium::Api = glsl_version.0;
        let major_version : u8 = glsl_version.1;
        let minor_version : u8 = glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut _use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
            glium::Api::Gl => {
                _use_gles = false;
            },
            glium::Api::GlEs => {
                _use_gles = true;
                glsl_version_string.push_str(" es");
            },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) =>  {
                // This is not likely to happen
                panic!("Unable to parse supported glsl version string: {}", e);
            },
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        Ok(match _use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        })
    }

    /// Create a `glium::program::Program` object from vertex and fragment file sources
    ///
    pub fn from_file(vertex: &str, fragment: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let mut vf = try!(
        	File::open(vertex).map_err(ShaderError::IoError)
        );
        let mut vertex_source = String::new();
        try!(
        	vf.read_to_string(&mut vertex_source).map_err(ShaderError::IoError)
        );
        let mut ff = try!(
        	File::open(fragment).map_err(ShaderError::IoError)
        );
        let mut fragment_source = String::new();
        try!(
        	ff.read_to_string(&mut fragment_source).map_err(ShaderError::IoError)
        );
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }

    /// Create a `glium::program::Program` object from vertex and fragment sources
    ///
    pub fn from_source(vertex_source: &str, fragment_source: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }
}

/// `extern Shader shader_default(Display display);`
///
#[no_mangle]
pub extern "C" fn shader_default(display: &GlutinFacade)
                                        -> Box<glium::program::Program> {
    match Shader::default(display) {
        Ok(s) => Box::new(s),
        Err(e) => panic!("Unable to load default shader: {:?}", e),
    }
}

/// `extern void free_shader(Shader shader);`
///
#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(shader_name_cstr: *const libc::c_char,
                                            dbloader: &DBLoader,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = Shader::from_dbloader(&shader_name, dbloader, display).unwrap();
        return Box::new(shader_program);
    }
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(_shader_name_cstr: *const libc::c_char,
                                            _dbloader: *const libc::c_void,
                                            _display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    panic!("The SQLite feature is not enabled");
}

/// `extern Shader get_shader_from_source(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn get_shader_from_source(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> Box<glium::program::Program> {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        let shader_program = match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) => s,
	        Err(e) => panic!("Unable to create shader program: {:?}", e),
        };
        return Box::new(shader_program);
    }
}

/// `extern Shader is_shader_source_valid(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn shader_source_is_valid(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> bool {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) =>  {
	            drop(s);
	            true
	        },
	        Err(_e) => {
	        	false
	        },
        }
    }
}<commit_msg>Switched default shader to version 110<commit_after>// Copyright (C) 2016 Chris Liebert

extern crate libc;

use std::ffi::CStr;
use std::fs::File;
use std::io::Error;
use std::io::prelude::*;
use std::num::ParseIntError;

use glium;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;

#[cfg(feature = "sqlite")]
use glium::Version;

#[cfg(feature = "sqlite")]
use dbloader::{DBLoader, DBLoaderError};

/// A representation for a GPU program
///
/// Shader programs contain the source for a vertex and fragment shader
/// in addition to a name
///
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Shader {
    pub name: String,
    pub vertex_source: String,
    pub fragment_source: String,
}

#[derive(Debug)]
pub enum ShaderError {
    IoError(Error),
    ProgramChooserCreationError(glium::program::ProgramChooserCreationError),
    ProgramCreationError(glium::ProgramCreationError),
    InvalidGLSLVersionStringError(ParseIntError),
    UnsupportedGLSLVersionError(Error),
}

impl Shader {
    /// Create a default shader with hardcoded source
    ///
    pub fn default(display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        Shader::from_source(r#"
#version 110

// Input data
vec3 position;
vec3 normal;
vec2 texcoord;

// Uniforms
uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 model;
uniform vec3 light_position_worldspace;

// Output data
vec3 out_position;
vec3 out_normal;
vec2 out_texcoord;
vec3 camera_direction;
vec3 light_direction;
vec3 light_position;

 void main() {
	mat4 mvp = projection * modelview * model;
	out_position = (mvp * vec4(position, 1.0)).xyz;
	camera_direction = normalize(vec3(0, 0, 0) - out_position);
	light_direction = vec3(0,-1, 0);
	light_position = light_position_worldspace;
	gl_Position = mvp * vec4(position, 1.0);
	out_normal = ( mvp * vec4(normal, 0)).xyz;
	out_texcoord = texcoord;
 }
     "#, r#"
#version 110

// Interpolated values from the vertex shaders
vec3 out_position;
vec3 out_normal;
vec2 out_texcoord;
vec3 camera_direction;
vec3 light_direction;

// Ouput data
vec3 color;

// Values that stay constant for the whole mesh.
uniform sampler2D diffuse_texture;

uniform vec3 ambient;
uniform vec3 diffuse;
uniform vec3 specular;
uniform vec3 light_position;

void main(){
	vec3 light_color = vec3(1,1,1);
	float light_power = 3.8;

	// Material properties
	vec4 diffuseColor4 = vec4(0.3, 0.3, 0.3, 1.0) * ( vec4(diffuse, 1.0) + texture2D(diffuse_texture, out_texcoord));
	vec3 diffuseColor =  vec3( diffuseColor4[0], diffuseColor4[1], diffuseColor4[2]);

	vec3 ambientColor = ambient + vec3(0.3, 0.3, 0.3) * diffuseColor;
	vec3 specularColor = specular;

	// Distance to the light
	float distance = length(light_position - out_position);
	// Normal of the computed fragment, in camera space
	vec3 n = normalize(out_normal);
	// Direction of the light (from the fragment to the light)
	vec3 l = normalize(light_direction);
	float cosTheta = clamp(dot(n, l), 0.0, 1.0);
	vec3 E = normalize(camera_direction);
	vec3 R = reflect(-l, n);
	float cosAlpha = clamp(dot(E, R), 0.0, 1.0);

	color =
		// Ambient : simulates indirect lighting
		ambientColor +
		// Diffuse : "color" of the object
		diffuseColor * light_color * light_power * cosTheta / (distance * distance) +
		// Specular : reflective highlight, like a mirror
		specularColor * light_color * light_power * pow(cosAlpha, 5.0) / (distance * distance);
}
"#,
		&display)
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that contains the shader and shader_version tables in SQLite
    ///
	#[cfg(feature = "sqlite")]
    #[allow(unused_assignments)]
    pub fn from_dbloader(shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        use glium::Version;
        let supported_glsl_version: Version = display.get_supported_glsl_version();
        let api: glium::Api = supported_glsl_version.0;
        let major_version : u8 = supported_glsl_version.1;
        let minor_version : u8 = supported_glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
                glium::Api::Gl => {
                    use_gles = false;
                },
                glium::Api::GlEs => {
                    use_gles = true;
                    glsl_version_string.push_str(" es");
                },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) => return Err(ShaderError::InvalidGLSLVersionStringError(e)),
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        let program: Program = match use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        };

        // Shader compilation no longer required
        display.release_shader_compiler();
        return Ok(program);
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that has a specific shader version
    ///
	#[cfg(feature = "sqlite")]
    pub fn from_dbloader_with_version(shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        if !display.is_glsl_version_supported(&glsl_version) {
            return Err(ShaderError::UnsupportedGLSLVersionError(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version")));
        }

        let api: glium::Api = glsl_version.0;
        let major_version : u8 = glsl_version.1;
        let minor_version : u8 = glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut _use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
            glium::Api::Gl => {
                _use_gles = false;
            },
            glium::Api::GlEs => {
                _use_gles = true;
                glsl_version_string.push_str(" es");
            },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) =>  {
                // This is not likely to happen
                panic!("Unable to parse supported glsl version string: {}", e);
            },
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        Ok(match _use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        })
    }

    /// Create a `glium::program::Program` object from vertex and fragment file sources
    ///
    pub fn from_file(vertex: &str, fragment: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let mut vf = try!(
        	File::open(vertex).map_err(ShaderError::IoError)
        );
        let mut vertex_source = String::new();
        try!(
        	vf.read_to_string(&mut vertex_source).map_err(ShaderError::IoError)
        );
        let mut ff = try!(
        	File::open(fragment).map_err(ShaderError::IoError)
        );
        let mut fragment_source = String::new();
        try!(
        	ff.read_to_string(&mut fragment_source).map_err(ShaderError::IoError)
        );
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }

    /// Create a `glium::program::Program` object from vertex and fragment sources
    ///
    pub fn from_source(vertex_source: &str, fragment_source: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }
}

/// `extern Shader shader_default(Display display);`
///
#[no_mangle]
pub extern "C" fn shader_default(display: &GlutinFacade)
                                        -> Box<glium::program::Program> {
    match Shader::default(display) {
        Ok(s) => Box::new(s),
        Err(e) => panic!("Unable to load default shader: {:?}", e),
    }
}

/// `extern void free_shader(Shader shader);`
///
#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(shader_name_cstr: *const libc::c_char,
                                            dbloader: &DBLoader,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = Shader::from_dbloader(&shader_name, dbloader, display).unwrap();
        return Box::new(shader_program);
    }
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(_shader_name_cstr: *const libc::c_char,
                                            _dbloader: *const libc::c_void,
                                            _display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    panic!("The SQLite feature is not enabled");
}

/// `extern Shader get_shader_from_source(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn get_shader_from_source(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> Box<glium::program::Program> {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        let shader_program = match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) => s,
	        Err(e) => panic!("Unable to create shader program: {:?}", e),
        };
        return Box::new(shader_program);
    }
}

/// `extern Shader is_shader_source_valid(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn shader_source_is_valid(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> bool {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) =>  {
	            drop(s);
	            true
	        },
	        Err(_e) => {
	        	false
	        },
        }
    }
}<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::Ref;
use std::sync::mpsc;
use std::fmt;
use types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `sample_with` methods. They update lazily when someone reads them.
#[derive(Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
enum SigValue<T>
{
    /// A signal with constant value.
    ///
    /// We store the value in a Rc to provide Clone support without a `T: Clone` bound.
    Constant(Rc<T>),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is mainly produced by stream methods or mapping other signals.
    Shared(Rc<SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant<V: Into<Rc<T>>>(val: V) -> Self
    {
        Signal(Constant(val.into()))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Sample by reference.
    ///
    /// This is meant to be the most efficient way when cloning is undesirable,
    /// but it requires a callback to prevent outliving internal borrows.
    pub fn sample_with<F, R>(&self, cb: F) -> R
        where F: FnOnce(MaybeOwned<T>) -> R
    {
        match self.0
        {
            Constant(ref val) => cb(MaybeOwned::Borrowed(val)),
            Dynamic(ref f) => cb(MaybeOwned::Owned(f())),
            Shared(ref s) => { s.update(); cb(MaybeOwned::Borrowed(&s.sample())) },
            Nested(ref f) => f().sample_with(cb),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Sample by value.
    ///
    /// This will clone the content of the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => (**val).clone(),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().clone() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<T>) -> R + 'static,
        R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || this.sample_with(&f))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<T>, MaybeOwned<S>) -> R + 'static,
        S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| this.sample_with(|a| f(a, b)))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => (**sig).clone(),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().clone() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T> From<Rc<T>> for Signal<T>
{
    /// Creates a constant signal from T (avoids re-wrapping the Rc).
    #[inline]
    fn from(val: Rc<T>) -> Self
    {
        Signal(Constant(val))
    }
}

// the derive impl adds a `T: Clone` we don't want
impl<T> Clone for Signal<T>
{
    /// Creates a copy of this signal that references the same value.
    fn clone(&self) -> Self
    {
        Signal(match self.0
        {
            Constant(ref val) => Constant(val.clone()),
            Dynamic(ref rf) => Dynamic(rf.clone()),
            Shared(ref rs) => Shared(rs.clone()),
            Nested(ref rf) => Nested(rf.clone()),
        })
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SignalShared@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        self.sample_with(|val| fmt::Display::fmt(&*val, f))
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.storage.borrow()
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<P>) -> T + 'static
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Borrowed(&self.source.sample()));
            self.storage.set_local(res);
        }
        self.storage.borrow()
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.update();
        self.storage.inc_local();
        self.storage.borrow()
    }
}

/// Helper for using `Signal::sample_with` with multiple signals.
///
/// Called as: `sample_with!(s1, s2, ...; f)` where:
///
/// - `s1: Signal<S1>, s2: Signal<S2>, ...` are N input signals
/// - `f(MaybeOwned<S1>, MaybeOwned<S2>, ...) -> R` is a function that takes N arguments
///
/// or as: `sample_with!(s1, s2, ... => |v1, v2, ...| expr)` where:
///
/// - `v1: MaybeOwned<S1>, v2: MaybeOwned<S2>, ...` are N variable names
/// - `expr` is an expresion using those variables
#[macro_export]
macro_rules! sample_with
{
    (@impl $f:expr ; ; $($var:ident)+) => ( $f($($var),+) );

    (@impl $f:expr ; $sig:expr, $($tail:expr,)* ; $($var:ident)*) => (
        $crate::Signal::sample_with(&$sig, |a| sample_with!(@impl $f; $($tail,)*; $($var)* a))
    );

    (@named ; ; $e:expr) => ($e);

    (@named $sig:expr, $($stail:expr,)* ; $var:ident $($vtail:ident)* ; $e:expr) => (
        $crate::Signal::sample_with(&$sig, |$var| sample_with!(@named $($stail,)*; $($vtail)*; $e))
    );

    ($($sig:expr),+ ; $f:expr) => ( sample_with!(@impl $f; $($sig,)+;) );

    ($($sig:expr),+ => | $($var:ident),+ | $e:expr) => ( sample_with!(@named $($sig,)+; $($var)+; $e));
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
        signal.sample_with(|val| assert_eq!(*val, 42));
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);
        signal.sample_with(|val| assert_eq!(*val, t));

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn sample_with_macro()
    {
        let s1 = Signal::constant(30);
        let s2 = Signal::from_fn(|| 12);
        let s3 = Signal::from_storage(Rc::new(SharedImpl::new(45, ())));

        let a = 55;
        let res = sample_with!(s1, s2, s3 => |x, y, z| *x + *y + *z + a);
        assert_eq!(res, 142);

        let f = |a: MaybeOwned<i32>, b: MaybeOwned<i32>, c: MaybeOwned<i32>| *a + *b + *c;
        let res = sample_with!(s1, s2, s3; f);
        assert_eq!(res, 87);
    }
}
<commit_msg>simplified clone on reference calls<commit_after>use std::rc::Rc;
use std::cell::Ref;
use std::sync::mpsc;
use std::fmt;
use types::{MaybeOwned, Storage, SharedSignal, SharedImpl};
use stream::Stream;

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `sample_with` methods. They update lazily when someone reads them.
#[derive(Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
enum SigValue<T>
{
    /// A signal with constant value.
    ///
    /// We store the value in a Rc to provide Clone support without a `T: Clone` bound.
    Constant(Rc<T>),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Rc<Fn() -> T>),
    /// A signal that contains shared data.
    ///
    /// This is mainly produced by stream methods or mapping other signals.
    Shared(Rc<SharedSignal<T>>),
    /// A signal that contains a signal, and allows sampling the inner signal directly.
    ///
    /// This is produced by `Signal::switch`
    Nested(Rc<Fn() -> Signal<T>>),
}

impl<T> Signal<T>
{
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub fn constant<V: Into<Rc<T>>>(val: V) -> Self
    {
        Signal(Constant(val.into()))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
        where F: Fn() -> T + 'static
    {
        Signal(Dynamic(Rc::new(f)))
    }

    /// Creates a new shared signal.
    pub(crate) fn shared<S>(storage: S) -> Self
        where S: SharedSignal<T> + 'static
    {
        Signal(Shared(Rc::new(storage)))
    }

    /// Checks if the signal has changed since the last time it was sampled.
    pub fn has_changed(&self) -> bool
    {
        match self.0 {
            Constant(_) => false,
            Dynamic(_) | Nested(_) => true,
            Shared(ref s) => { s.update(); s.has_changed() },
        }
    }

    /// Sample by reference.
    ///
    /// This is meant to be the most efficient way when cloning is undesirable,
    /// but it requires a callback to prevent outliving internal borrows.
    pub fn sample_with<F, R>(&self, cb: F) -> R
        where F: FnOnce(MaybeOwned<T>) -> R
    {
        match self.0
        {
            Constant(ref val) => cb(MaybeOwned::Borrowed(val)),
            Dynamic(ref f) => cb(MaybeOwned::Owned(f())),
            Shared(ref s) => { s.update(); cb(MaybeOwned::Borrowed(&s.sample())) },
            Nested(ref f) => f().sample_with(cb),
        }
    }
}

impl<T: Clone> Signal<T>
{
    /// Sample by value.
    ///
    /// This will clone the content of the signal.
    pub fn sample(&self) -> T
    {
        match self.0
        {
            Constant(ref val) => T::clone(val),
            Dynamic(ref f) => f(),
            Shared(ref s) => { s.update(); s.sample().clone() },
            Nested(ref f) => f().sample(),
        }
    }
}

impl<T: 'static> Signal<T>
{
    /// Maps a signal with the provided function.
    ///
    /// The closure is called only when the parent signal changes.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
        where F: Fn(MaybeOwned<T>) -> R + 'static,
        R: 'static
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => {
                Signal::constant(f(MaybeOwned::Borrowed(val)))
            }
            // shared signal: apply f only when the parent signal has changed
            Shared(ref sig) => Signal::shared(SharedImpl{
                storage: Storage::inherit(sig.storage()),
                source: sig.clone(),
                f,
            }),
            // dynamic/nested signal: apply f unconditionally
            Dynamic(_) | Nested(_) => {
                let this = self.clone();
                Signal::from_fn(move || this.sample_with(&f))
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
        where F: Fn(MaybeOwned<T>, MaybeOwned<S>) -> R + 'static,
        S: 'static, R: 'static
    {
        let this = self.clone();
        trigger.map(move |b| this.sample_with(|a| f(a, b)))
    }

    /// Creates a signal from a shared value.
    pub(crate) fn from_storage<P: 'static>(storage: Rc<SharedImpl<T, P, ()>>) -> Self
    {
        Signal(Shared(storage))
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using non-blocking operations) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
        where F: Fn(T, V) -> T + 'static,
        V: 'static
    {
        Signal::shared(SharedImpl{
            storage: Storage::new(initial),
            source: rx,
            f,
        })
    }
}

impl<T: 'static> Signal<Signal<T>>
{
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T>
    {
        match self.0
        {
            // constant signal: just extract the inner signal
            Constant(ref sig) => Signal::clone(sig),
            // dynamic signal: re-label as nested
            Dynamic(ref f) => Signal(Nested(f.clone())),
            // shared signal: sample to extract the inner signal
            Shared(ref sig_) => {
                let sig = sig_.clone();
                Signal(Nested(Rc::new(move || { sig.update(); sig.sample().clone() })))
            }
            // nested signal: remove one layer
            Nested(ref f_) => {
                let f = f_.clone();
                Signal(Nested(Rc::new(move || f().sample())))
            }
        }
    }
}

impl<T: Default> Default for Signal<T>
{
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self
    {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T>
{
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self
    {
        Signal::constant(val)
    }
}

impl<T> From<Rc<T>> for Signal<T>
{
    /// Creates a constant signal from T (avoids re-wrapping the Rc).
    #[inline]
    fn from(val: Rc<T>) -> Self
    {
        Signal(Constant(val))
    }
}

// the derive impl adds a `T: Clone` we don't want
impl<T> Clone for Signal<T>
{
    /// Creates a copy of this signal that references the same value.
    fn clone(&self) -> Self
    {
        Signal(match self.0
        {
            Constant(ref val) => Constant(val.clone()),
            Dynamic(ref rf) => Dynamic(rf.clone()),
            Shared(ref rs) => Shared(rs.clone()),
            Nested(ref rf) => Nested(rf.clone()),
        })
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
            Shared(ref rs) => write!(f, "Shared(SignalShared@{:p})", rs),
            Nested(ref rf) => write!(f, "Nested(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Signal<T>
{
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        self.sample_with(|val| fmt::Display::fmt(&*val, f))
    }
}

// A signal that contains only storage.

impl<T, S> SharedImpl<T, S, ()>
{
    pub fn new(initial: T, source: S) -> Self
    {
        SharedImpl{
            storage: Storage::new(initial),
            source,
            f: (),
        }
    }
}

impl<T, S> SharedSignal<T> for SharedImpl<T, S, ()>
{
    fn update(&self) {}

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.storage.borrow()
    }
}

// A signal that maps a parent shared signal.

impl<T, P, F> SharedSignal<T> for SharedImpl<T, Rc<SharedSignal<P>>, F>
    where F: Fn(MaybeOwned<P>) -> T + 'static
{
    fn update(&self)
    {
        self.source.update()
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        if self.has_changed()
        {
            let res = (self.f)(MaybeOwned::Borrowed(&self.source.sample()));
            self.storage.set_local(res);
        }
        self.storage.borrow()
    }
}

// A signal that folds a channel.

impl<T, S, F> SharedSignal<T> for SharedImpl<T, mpsc::Receiver<S>, F>
    where F: Fn(T, S) -> T + 'static,
{
    fn update(&self)
    {
        if let Ok(first) = self.source.try_recv()
        {
            let acc = (self.f)(self.storage.take(), first);
            let new = self.source.try_iter().fold(acc, &self.f);
            self.storage.set(new);
        }
    }

    fn has_changed(&self) -> bool
    {
        self.storage.must_update()
    }

    fn storage(&self) -> &Storage<T>
    {
        &self.storage
    }

    fn sample(&self) -> Ref<T>
    {
        self.update();
        self.storage.inc_local();
        self.storage.borrow()
    }
}

/// Helper for using `Signal::sample_with` with multiple signals.
///
/// Called as: `sample_with!(s1, s2, ...; f)` where:
///
/// - `s1: Signal<S1>, s2: Signal<S2>, ...` are N input signals
/// - `f(MaybeOwned<S1>, MaybeOwned<S2>, ...) -> R` is a function that takes N arguments
///
/// or as: `sample_with!(s1, s2, ... => |v1, v2, ...| expr)` where:
///
/// - `v1: MaybeOwned<S1>, v2: MaybeOwned<S2>, ...` are N variable names
/// - `expr` is an expresion using those variables
#[macro_export]
macro_rules! sample_with
{
    (@impl $f:expr ; ; $($var:ident)+) => ( $f($($var),+) );

    (@impl $f:expr ; $sig:expr, $($tail:expr,)* ; $($var:ident)*) => (
        $crate::Signal::sample_with(&$sig, |a| sample_with!(@impl $f; $($tail,)*; $($var)* a))
    );

    (@named ; ; $e:expr) => ($e);

    (@named $sig:expr, $($stail:expr,)* ; $var:ident $($vtail:ident)* ; $e:expr) => (
        $crate::Signal::sample_with(&$sig, |$var| sample_with!(@named $($stail,)*; $($vtail)*; $e))
    );

    ($($sig:expr),+ ; $f:expr) => ( sample_with!(@impl $f; $($sig,)+;) );

    ($($sig:expr),+ => | $($var:ident),+ | $e:expr) => ( sample_with!(@named $($sig,)+; $($var)+; $e));
}

#[cfg(test)]
mod tests
{
    use super::*;
    use std::rc::Rc;
    use std::cell::Cell;
    use std::time::Instant;

    #[test]
    fn signal_basic()
    {
        let signal = Signal::constant(42);
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
        signal.sample_with(|val| assert_eq!(*val, 42));
    }

    #[test]
    fn signal_shared()
    {
        let st = Rc::new(SharedImpl::new(1, ()));
        let signal = Signal::from_storage(st.clone());
        let double = signal.map(|a| *a * 2);

        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        st.set(42);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
    }

    #[test]
    fn signal_dynamic()
    {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);
        signal.sample_with(|val| assert_eq!(*val, t));

        let n = Rc::new(Cell::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || cloned.get());
        let double = signal.map(|a| *a * 2);
        let plusone = double.map(|a| *a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        n.set(13);
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn sample_with_macro()
    {
        let s1 = Signal::constant(30);
        let s2 = Signal::from_fn(|| 12);
        let s3 = Signal::from_storage(Rc::new(SharedImpl::new(45, ())));

        let a = 55;
        let res = sample_with!(s1, s2, s3 => |x, y, z| *x + *y + *z + a);
        assert_eq!(res, 142);

        let f = |a: MaybeOwned<i32>, b: MaybeOwned<i32>, c: MaybeOwned<i32>| *a + *b + *c;
        let res = sample_with!(s1, s2, s3; f);
        assert_eq!(res, 87);
    }
}
<|endoftext|>


<commit_before>use std::{cmp, iter, slice};
use {Expression, Length};
use iterators::SwitchIter;

#[derive(Copy, Clone)]
pub struct Constant<T>(pub T);

impl<'a, T: 'a + Send + Clone> Expression for Constant<T> {
    type Element = T;
    type Values = iter::Repeat<T>;

    fn length(&self) -> Length {
        Length::Infinite
    }

    fn values(self) -> Self::Values {
        iter::repeat(self.0)
    }

    fn split(self) -> (Self, Self) {
        (self.clone(), self)
    }
}

#[derive(Copy, Clone)]
pub struct Value<T>(pub T);

impl<'a, T: 'a + Sync + Send + Clone> Expression for Value<&'a [T]> {
    type Element = T;
    type Values = iter::Cloned<slice::Iter<'a, T>>;

    fn length(&self) -> Length {
        Length::Finite(self.0.len())
    }

    fn values(self) -> Self::Values {
        self.0.iter().cloned()
    }

    fn split(self) -> (Self, Self) {
        let (lo, hi) = self.0.split_at(self.0.len() / 2);
        (Value(lo), Value(hi))
    }
}

impl<'a, T: 'a + Sync + Send + Clone> Expression for &'a [T] {
    type Element = T;
    type Values = iter::Cloned<slice::Iter<'a, T>>;

    fn length(&self) -> Length {
        Length::Finite((*self).len())
    }

    fn values(self) -> Self::Values {
        self.iter().cloned()
    }

    fn split(self) -> (Self, Self) {
        self.split_at(self.len() / 2)
    }
}

pub struct Switch<B, T, E>(B, T, E);
pub fn make_switch<B, T, E>(b: B, t: T, e: E) -> Switch<B, T, E>
    where B: Expression<Element = bool>,
          T: Expression,
          E: Expression<Element = T::Element>,
{
    Switch(b, t, e)
}

impl<B, T, E> Expression for Switch<B, T, E>
    // this should be, like, "bool"-like or something
    where B: Expression<Element = bool>,
          T: Expression,
          E: Expression<Element = T::Element>,
{
    type Element = T::Element;
    type Values = SwitchIter<B::Values, T::Values, E::Values>;

    fn length(&self) -> Length {
        let len_b = self.0.length();
        let len_t = self.1.length();
        let len_e = self.2.length();
        debug_assert!(len_b.compatible(len_t) && len_b.compatible(len_e) && len_t.compatible(len_e));
        cmp::min(cmp::min(len_b, len_t), len_e)
    }

    fn values(self) -> Self::Values {
        SwitchIter::new(self.0.values(), self.1.values(), self.2.values())
    }

    fn split(self) -> (Self, Self) {
        let (b1, b2) = self.0.split();
        let (t1, t2) = self.1.split();
        let (e1, e2) = self.2.split();

        (Switch(b1, t1, e1), Switch(b2, t2, e2))
    }
}
<commit_msg>Make &mut [T] an expression.<commit_after>use std::{cmp, iter, slice};
use {Expression, Length};
use iterators::SwitchIter;

#[derive(Copy, Clone)]
pub struct Constant<T>(pub T);

impl<'a, T: 'a + Send + Clone> Expression for Constant<T> {
    type Element = T;
    type Values = iter::Repeat<T>;

    fn length(&self) -> Length {
        Length::Infinite
    }

    fn values(self) -> Self::Values {
        iter::repeat(self.0)
    }

    fn split(self) -> (Self, Self) {
        (self.clone(), self)
    }
}

#[derive(Copy, Clone)]
pub struct Value<T>(pub T);

impl<'a, T: 'a + Sync + Send + Clone> Expression for Value<&'a [T]> {
    type Element = T;
    type Values = iter::Cloned<slice::Iter<'a, T>>;

    fn length(&self) -> Length {
        Length::Finite(self.0.len())
    }

    fn values(self) -> Self::Values {
        self.0.iter().cloned()
    }

    fn split(self) -> (Self, Self) {
        let (lo, hi) = self.0.split_at(self.0.len() / 2);
        (Value(lo), Value(hi))
    }
}

impl<'a, T: 'a + Sync + Send + Clone> Expression for &'a [T] {
    type Element = T;
    type Values = iter::Cloned<slice::Iter<'a, T>>;

    fn length(&self) -> Length {
        Length::Finite((*self).len())
    }

    fn values(self) -> Self::Values {
        self.iter().cloned()
    }

    fn split(self) -> (Self, Self) {
        self.split_at(self.len() / 2)
    }
}

impl<'a, T: 'a + Send> Expression for &'a mut [T] {
    type Element = &'a mut T;
    type Values = slice::IterMut<'a, T>;

    fn length(&self) -> Length {
        Length::Finite((**self).len())
    }

    fn values(self) -> Self::Values {
        self.iter_mut()
    }

    fn split(self) -> (Self, Self) {
        let len = (*self).len();
        self.split_at_mut(len / 2)
    }
}

pub struct Switch<B, T, E>(B, T, E);
pub fn make_switch<B, T, E>(b: B, t: T, e: E) -> Switch<B, T, E>
    where B: Expression<Element = bool>,
          T: Expression,
          E: Expression<Element = T::Element>,
{
    Switch(b, t, e)
}

impl<B, T, E> Expression for Switch<B, T, E>
    // this should be, like, "bool"-like or something
    where B: Expression<Element = bool>,
          T: Expression,
          E: Expression<Element = T::Element>,
{
    type Element = T::Element;
    type Values = SwitchIter<B::Values, T::Values, E::Values>;

    fn length(&self) -> Length {
        let len_b = self.0.length();
        let len_t = self.1.length();
        let len_e = self.2.length();
        debug_assert!(len_b.compatible(len_t) && len_b.compatible(len_e) && len_t.compatible(len_e));
        cmp::min(cmp::min(len_b, len_t), len_e)
    }

    fn values(self) -> Self::Values {
        SwitchIter::new(self.0.values(), self.1.values(), self.2.values())
    }

    fn split(self) -> (Self, Self) {
        let (b1, b2) = self.0.split();
        let (t1, t2) = self.1.split();
        let (e1, e2) = self.2.split();

        (Switch(b1, t1, e1), Switch(b2, t2, e2))
    }
}
<|endoftext|>