<commit_before>use diesel::mysql::{Mysql, MysqlConnection};
use diesel::*;
use heck::ToUpperCamelCase;
use std::{borrow::Cow, error::Error};

use super::data_structures::*;
use super::information_schema::DefaultSchema;
use super::table_data::TableName;
use crate::print_schema::ColumnSorting;

diesel::sql_function! {
    #[sql_name = "NULLIF"]
    fn null_if_text(lhs: sql_types::Text, rhs: sql_types::Text) -> sql_types::Nullable<sql_types::Text>
}

pub fn get_table_data<'a>(
    conn: &mut MysqlConnection,
    table: &'a TableName,
    column_sorting: &ColumnSorting,
) -> QueryResult<Vec<ColumnInformation>> {
    use self::information_schema::columns::dsl::*;

    let schema_name = match table.schema {
        Some(ref name) => Cow::Borrowed(name),
        None => Cow::Owned(Mysql::default_schema(conn)?),
    };

    let type_schema = None::<String>.into_sql();
    let query = columns
        .select((
            column_name,
            column_type,
            type_schema,
            __is_nullable,
            // MySQL comments are not nullable and are empty strings if not set
            null_if_text(column_comment, ""),
        ))
        .filter(table_name.eq(&table.sql_name))
        .filter(table_schema.eq(schema_name));
    match column_sorting {
        ColumnSorting::OrdinalPosition => query.order(ordinal_position).load(conn),
        ColumnSorting::Name => query.order(column_name).load(conn),
    }
}

mod information_schema {
    use diesel::prelude::{allow_tables_to_appear_in_same_query, table};

    table! {
        information_schema.tables (table_schema, table_name) {
            table_schema -> VarChar,
            table_name -> VarChar,
            table_comment -> VarChar,
        }
    }

    table! {
        information_schema.table_constraints (constraint_schema, constraint_name) {
            table_schema -> VarChar,
            constraint_schema -> VarChar,
            constraint_name -> VarChar,
            constraint_type -> VarChar,
        }
    }

    table! {
        information_schema.key_column_usage (constraint_schema, constraint_name) {
            constraint_schema -> VarChar,
            constraint_name -> VarChar,
            table_schema -> VarChar,
            table_name -> VarChar,
            column_name -> VarChar,
            referenced_table_schema -> VarChar,
            referenced_table_name -> VarChar,
            referenced_column_name -> VarChar,
        }
    }

    table! {
        information_schema.columns (table_schema, table_name, column_name) {
            table_schema -> VarChar,
            table_name -> VarChar,
            column_name -> VarChar,
            #[sql_name = "is_nullable"]
            __is_nullable -> VarChar,
            ordinal_position -> BigInt,
            udt_name -> VarChar,
            udt_schema -> VarChar,
            column_type -> VarChar,
            column_comment -> VarChar,
        }
    }

    allow_tables_to_appear_in_same_query!(table_constraints, key_column_usage);
}

/// Even though this is using `information_schema`, MySQL needs non-ANSI columns
/// in order to do this.
pub fn load_foreign_key_constraints(
    connection: &mut MysqlConnection,
    schema_name: Option<&str>,
) -> QueryResult<Vec<ForeignKeyConstraint>> {
    use self::information_schema::key_column_usage as kcu;
    use self::information_schema::table_constraints as tc;

    let default_schema = Mysql::default_schema(connection)?;
    let schema_name = match schema_name {
        Some(name) => name,
        None => &default_schema,
    };

    let constraints = tc::table
        .filter(tc::constraint_type.eq("FOREIGN KEY"))
        .filter(tc::table_schema.eq(schema_name))
        .filter(kcu::referenced_column_name.is_not_null())
        .inner_join(
            kcu::table.on(tc::constraint_schema
                .eq(kcu::constraint_schema)
                .and(tc::constraint_name.eq(kcu::constraint_name))),
        )
        .select((
            (kcu::table_name, kcu::table_schema),
            (kcu::referenced_table_name, kcu::referenced_table_schema),
            kcu::column_name,
            kcu::referenced_column_name,
        ))
        .load::<(TableName, TableName, String, _)>(connection)?
        .into_iter()
        .map(
            |(mut child_table, mut parent_table, foreign_key, primary_key)| {
                child_table.strip_schema_if_matches(&default_schema);
                parent_table.strip_schema_if_matches(&default_schema);

                ForeignKeyConstraint {
                    child_table,
                    parent_table,
                    foreign_key: foreign_key.clone(),
                    foreign_key_rust_name: foreign_key,
                    primary_key,
                }
            },
        )
        .collect();
    Ok(constraints)
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let tpe = determine_type_name(&attr.type_name)?;
    let unsigned = determine_unsigned(&attr.type_name);

    Ok(ColumnType {
        schema: None,
        sql_name: tpe.trim().to_lowercase(),
        rust_name: tpe.trim().to_upper_camel_case(),
        is_array: false,
        is_nullable: attr.nullable,
        is_unsigned: unsigned,
    })
}

pub fn get_table_comment(
    conn: &mut MysqlConnection,
    table: &TableName,
) -> QueryResult<Option<String>> {
    use self::information_schema::tables::dsl::*;

    let schema_name = match table.schema {
        Some(ref name) => Cow::Borrowed(name),
        None => Cow::Owned(Mysql::default_schema(conn)?),
    };

    let comment: String = tables
        .select(table_comment)
        .filter(table_name.eq(&table.sql_name))
        .filter(table_schema.eq(schema_name))
        .get_result(conn)?;

    if comment.is_empty() {
        Ok(None)
    } else {
        Ok(Some(comment))
    }
}

fn determine_type_name(
    sql_type_name: &str,
) -> Result<String, Box<dyn Error + Send + Sync + 'static>> {
    let result = if sql_type_name == "tinyint(1)" {
        "bool"
    } else if sql_type_name.starts_with("int") {
        "integer"
    } else if let Some(idx) = sql_type_name.find('(') {
        &sql_type_name[..idx]
    } else {
        sql_type_name
    };

    if determine_unsigned(result) {
        Ok(result
            .to_lowercase()
            .replace("unsigned", "")
            .trim()
            .to_owned())
    } else if result.contains(' ') {
        Err(format!("unrecognized type {:?}", result).into())
    } else {
        Ok(result.to_owned())
    }
}

fn determine_unsigned(sql_type_name: &str) -> bool {
    sql_type_name.to_lowercase().contains("unsigned")
}

#[test]
fn values_which_already_map_to_type_are_returned_unchanged() {
    assert_eq!("text", determine_type_name("text").unwrap());
    assert_eq!("integer", determine_type_name("integer").unwrap());
    assert_eq!("biginteger", determine_type_name("biginteger").unwrap());
}

#[test]
fn trailing_parenthesis_are_stripped() {
    assert_eq!("varchar", determine_type_name("varchar(255)").unwrap());
    assert_eq!("decimal", determine_type_name("decimal(10, 2)").unwrap());
    assert_eq!("float", determine_type_name("float(1)").unwrap());
}

#[test]
fn tinyint_is_bool_if_limit_1() {
    assert_eq!("bool", determine_type_name("tinyint(1)").unwrap());
    assert_eq!("tinyint", determine_type_name("tinyint(2)").unwrap());
}

#[test]
fn int_is_treated_as_integer() {
    assert_eq!("integer", determine_type_name("int").unwrap());
    assert_eq!("integer", determine_type_name("int(11)").unwrap());
}

#[test]
fn unsigned_types_are_supported() {
    assert!(determine_unsigned("float unsigned"));
    assert!(determine_unsigned("UNSIGNED INT"));
    assert!(determine_unsigned("unsigned bigint"));
    assert!(!determine_unsigned("bigint"));
    assert!(!determine_unsigned("FLOAT"));
    assert_eq!("float", determine_type_name("float unsigned").unwrap());
    assert_eq!("int", determine_type_name("UNSIGNED INT").unwrap());
    assert_eq!("bigint", determine_type_name("unsigned bigint").unwrap());
}

#[test]
fn types_with_space_are_not_supported() {
    assert!(determine_type_name("lol wat").is_err());
}

#[cfg(test)]
mod test {
    extern crate dotenvy;

    use self::dotenvy::dotenv;
    use super::*;
    use std::env;

    fn connection() -> MysqlConnection {
        dotenv().ok();

        let connection_url = env::var("MYSQL_DATABASE_URL")
            .or_else(|_| env::var("DATABASE_URL"))
            .expect("DATABASE_URL must be set in order to run tests");
        let mut connection = MysqlConnection::establish(&connection_url).unwrap();
        connection.begin_test_transaction().unwrap();
        connection
    }

    #[test]
    fn get_table_data_loads_column_information() {
        let mut connection = connection();

        diesel::sql_query(
            "DROP TABLE IF EXISTS diesel_test.table_1",
        )
        .execute(&mut connection)
        .unwrap();
        // uses VARCHAR(255) as the type because SERIAL returned bigint on most platforms and bigint(20) on MacOS
        diesel::sql_query(
            "CREATE TABLE diesel_test.table_1 \
            (id VARCHAR(255) PRIMARY KEY COMMENT 'column comment') \
            COMMENT 'table comment'",
        )
        .execute(&mut connection)
        .unwrap();
        diesel::sql_query(
            "DROP TABLE IF EXISTS diesel_test.table_2",
        )
        .execute(&mut connection)
        .unwrap();
        diesel::sql_query(
            "CREATE TABLE diesel_test.table_2 (id VARCHAR(255) PRIMARY KEY)",
        )
        .execute(&mut connection)
        .unwrap();

        let table_1 = TableName::new("table_1", "diesel_test");
        let table_2 = TableName::new("table_2", "diesel_test");

        let id_with_comment = ColumnInformation::new(
            "id",
            "varchar(255)",
            None,
            false,
            Some("column comment".to_string()),
        );
        let id_without_comment = ColumnInformation::new("id", "varchar(255)", None, false, None);
        assert_eq!(
            Ok(vec![id_with_comment]),
            get_table_data(&mut connection, &table_1, &ColumnSorting::OrdinalPosition)
        );
        assert_eq!(
            Ok(vec![id_without_comment]),
            get_table_data(&mut connection, &table_2, &ColumnSorting::OrdinalPosition)
        );
    }

    #[test]
    fn gets_table_comment() {
        let mut connection = connection();

        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_1")
            .execute(&mut connection)
            .unwrap();
        diesel::sql_query(
            "CREATE TABLE diesel_test.table_1 (id SERIAL PRIMARY KEY) COMMENT 'table comment'",
        )
        .execute(&mut connection)
        .unwrap();
        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_2")
            .execute(&mut connection)
            .unwrap();
        diesel::sql_query("CREATE TABLE diesel_test.table_2 (id SERIAL PRIMARY KEY)")
            .execute(&mut connection)
            .unwrap();

        let table_1 = TableName::new("table_1", "diesel_test");
        let table_2 = TableName::new("table_2", "diesel_test");
        assert_eq!(
            Ok(Some("table comment".to_string())),
            get_table_comment(&mut connection, &table_1)
        );
        assert_eq!(Ok(None), get_table_comment(&mut connection, &table_2));
    }
}
<commit_msg>Fix formatting<commit_after>use diesel::mysql::{Mysql, MysqlConnection};
use diesel::*;
use heck::ToUpperCamelCase;
use std::{borrow::Cow, error::Error};

use super::data_structures::*;
use super::information_schema::DefaultSchema;
use super::table_data::TableName;
use crate::print_schema::ColumnSorting;

diesel::sql_function! {
    #[sql_name = "NULLIF"]
    fn null_if_text(lhs: sql_types::Text, rhs: sql_types::Text) -> sql_types::Nullable<sql_types::Text>
}

pub fn get_table_data<'a>(
    conn: &mut MysqlConnection,
    table: &'a TableName,
    column_sorting: &ColumnSorting,
) -> QueryResult<Vec<ColumnInformation>> {
    use self::information_schema::columns::dsl::*;

    let schema_name = match table.schema {
        Some(ref name) => Cow::Borrowed(name),
        None => Cow::Owned(Mysql::default_schema(conn)?),
    };

    let type_schema = None::<String>.into_sql();
    let query = columns
        .select((
            column_name,
            column_type,
            type_schema,
            __is_nullable,
            // MySQL comments are not nullable and are empty strings if not set
            null_if_text(column_comment, ""),
        ))
        .filter(table_name.eq(&table.sql_name))
        .filter(table_schema.eq(schema_name));
    match column_sorting {
        ColumnSorting::OrdinalPosition => query.order(ordinal_position).load(conn),
        ColumnSorting::Name => query.order(column_name).load(conn),
    }
}

mod information_schema {
    use diesel::prelude::{allow_tables_to_appear_in_same_query, table};

    table! {
        information_schema.tables (table_schema, table_name) {
            table_schema -> VarChar,
            table_name -> VarChar,
            table_comment -> VarChar,
        }
    }

    table! {
        information_schema.table_constraints (constraint_schema, constraint_name) {
            table_schema -> VarChar,
            constraint_schema -> VarChar,
            constraint_name -> VarChar,
            constraint_type -> VarChar,
        }
    }

    table! {
        information_schema.key_column_usage (constraint_schema, constraint_name) {
            constraint_schema -> VarChar,
            constraint_name -> VarChar,
            table_schema -> VarChar,
            table_name -> VarChar,
            column_name -> VarChar,
            referenced_table_schema -> VarChar,
            referenced_table_name -> VarChar,
            referenced_column_name -> VarChar,
        }
    }

    table! {
        information_schema.columns (table_schema, table_name, column_name) {
            table_schema -> VarChar,
            table_name -> VarChar,
            column_name -> VarChar,
            #[sql_name = "is_nullable"]
            __is_nullable -> VarChar,
            ordinal_position -> BigInt,
            udt_name -> VarChar,
            udt_schema -> VarChar,
            column_type -> VarChar,
            column_comment -> VarChar,
        }
    }

    allow_tables_to_appear_in_same_query!(table_constraints, key_column_usage);
}

/// Even though this is using `information_schema`, MySQL needs non-ANSI columns
/// in order to do this.
pub fn load_foreign_key_constraints(
    connection: &mut MysqlConnection,
    schema_name: Option<&str>,
) -> QueryResult<Vec<ForeignKeyConstraint>> {
    use self::information_schema::key_column_usage as kcu;
    use self::information_schema::table_constraints as tc;

    let default_schema = Mysql::default_schema(connection)?;
    let schema_name = match schema_name {
        Some(name) => name,
        None => &default_schema,
    };

    let constraints = tc::table
        .filter(tc::constraint_type.eq("FOREIGN KEY"))
        .filter(tc::table_schema.eq(schema_name))
        .filter(kcu::referenced_column_name.is_not_null())
        .inner_join(
            kcu::table.on(tc::constraint_schema
                .eq(kcu::constraint_schema)
                .and(tc::constraint_name.eq(kcu::constraint_name))),
        )
        .select((
            (kcu::table_name, kcu::table_schema),
            (kcu::referenced_table_name, kcu::referenced_table_schema),
            kcu::column_name,
            kcu::referenced_column_name,
        ))
        .load::<(TableName, TableName, String, _)>(connection)?
        .into_iter()
        .map(
            |(mut child_table, mut parent_table, foreign_key, primary_key)| {
                child_table.strip_schema_if_matches(&default_schema);
                parent_table.strip_schema_if_matches(&default_schema);

                ForeignKeyConstraint {
                    child_table,
                    parent_table,
                    foreign_key: foreign_key.clone(),
                    foreign_key_rust_name: foreign_key,
                    primary_key,
                }
            },
        )
        .collect();
    Ok(constraints)
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let tpe = determine_type_name(&attr.type_name)?;
    let unsigned = determine_unsigned(&attr.type_name);

    Ok(ColumnType {
        schema: None,
        sql_name: tpe.trim().to_lowercase(),
        rust_name: tpe.trim().to_upper_camel_case(),
        is_array: false,
        is_nullable: attr.nullable,
        is_unsigned: unsigned,
    })
}

pub fn get_table_comment(
    conn: &mut MysqlConnection,
    table: &TableName,
) -> QueryResult<Option<String>> {
    use self::information_schema::tables::dsl::*;

    let schema_name = match table.schema {
        Some(ref name) => Cow::Borrowed(name),
        None => Cow::Owned(Mysql::default_schema(conn)?),
    };

    let comment: String = tables
        .select(table_comment)
        .filter(table_name.eq(&table.sql_name))
        .filter(table_schema.eq(schema_name))
        .get_result(conn)?;

    if comment.is_empty() {
        Ok(None)
    } else {
        Ok(Some(comment))
    }
}

fn determine_type_name(
    sql_type_name: &str,
) -> Result<String, Box<dyn Error + Send + Sync + 'static>> {
    let result = if sql_type_name == "tinyint(1)" {
        "bool"
    } else if sql_type_name.starts_with("int") {
        "integer"
    } else if let Some(idx) = sql_type_name.find('(') {
        &sql_type_name[..idx]
    } else {
        sql_type_name
    };

    if determine_unsigned(result) {
        Ok(result
            .to_lowercase()
            .replace("unsigned", "")
            .trim()
            .to_owned())
    } else if result.contains(' ') {
        Err(format!("unrecognized type {:?}", result).into())
    } else {
        Ok(result.to_owned())
    }
}

fn determine_unsigned(sql_type_name: &str) -> bool {
    sql_type_name.to_lowercase().contains("unsigned")
}

#[test]
fn values_which_already_map_to_type_are_returned_unchanged() {
    assert_eq!("text", determine_type_name("text").unwrap());
    assert_eq!("integer", determine_type_name("integer").unwrap());
    assert_eq!("biginteger", determine_type_name("biginteger").unwrap());
}

#[test]
fn trailing_parenthesis_are_stripped() {
    assert_eq!("varchar", determine_type_name("varchar(255)").unwrap());
    assert_eq!("decimal", determine_type_name("decimal(10, 2)").unwrap());
    assert_eq!("float", determine_type_name("float(1)").unwrap());
}

#[test]
fn tinyint_is_bool_if_limit_1() {
    assert_eq!("bool", determine_type_name("tinyint(1)").unwrap());
    assert_eq!("tinyint", determine_type_name("tinyint(2)").unwrap());
}

#[test]
fn int_is_treated_as_integer() {
    assert_eq!("integer", determine_type_name("int").unwrap());
    assert_eq!("integer", determine_type_name("int(11)").unwrap());
}

#[test]
fn unsigned_types_are_supported() {
    assert!(determine_unsigned("float unsigned"));
    assert!(determine_unsigned("UNSIGNED INT"));
    assert!(determine_unsigned("unsigned bigint"));
    assert!(!determine_unsigned("bigint"));
    assert!(!determine_unsigned("FLOAT"));
    assert_eq!("float", determine_type_name("float unsigned").unwrap());
    assert_eq!("int", determine_type_name("UNSIGNED INT").unwrap());
    assert_eq!("bigint", determine_type_name("unsigned bigint").unwrap());
}

#[test]
fn types_with_space_are_not_supported() {
    assert!(determine_type_name("lol wat").is_err());
}

#[cfg(test)]
mod test {
    extern crate dotenvy;

    use self::dotenvy::dotenv;
    use super::*;
    use std::env;

    fn connection() -> MysqlConnection {
        dotenv().ok();

        let connection_url = env::var("MYSQL_DATABASE_URL")
            .or_else(|_| env::var("DATABASE_URL"))
            .expect("DATABASE_URL must be set in order to run tests");
        let mut connection = MysqlConnection::establish(&connection_url).unwrap();
        connection.begin_test_transaction().unwrap();
        connection
    }

    #[test]
    fn get_table_data_loads_column_information() {
        let mut connection = connection();

        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_1")
            .execute(&mut connection)
            .unwrap();
        // uses VARCHAR(255) as the type because SERIAL returned bigint on most platforms and bigint(20) on MacOS
        diesel::sql_query(
            "CREATE TABLE diesel_test.table_1 \
            (id VARCHAR(255) PRIMARY KEY COMMENT 'column comment') \
            COMMENT 'table comment'",
        )
        .execute(&mut connection)
        .unwrap();
        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_2")
            .execute(&mut connection)
            .unwrap();
        diesel::sql_query("CREATE TABLE diesel_test.table_2 (id VARCHAR(255) PRIMARY KEY)")
            .execute(&mut connection)
            .unwrap();

        let table_1 = TableName::new("table_1", "diesel_test");
        let table_2 = TableName::new("table_2", "diesel_test");

        let id_with_comment = ColumnInformation::new(
            "id",
            "varchar(255)",
            None,
            false,
            Some("column comment".to_string()),
        );
        let id_without_comment = ColumnInformation::new("id", "varchar(255)", None, false, None);
        assert_eq!(
            Ok(vec![id_with_comment]),
            get_table_data(&mut connection, &table_1, &ColumnSorting::OrdinalPosition)
        );
        assert_eq!(
            Ok(vec![id_without_comment]),
            get_table_data(&mut connection, &table_2, &ColumnSorting::OrdinalPosition)
        );
    }

    #[test]
    fn gets_table_comment() {
        let mut connection = connection();

        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_1")
            .execute(&mut connection)
            .unwrap();
        diesel::sql_query(
            "CREATE TABLE diesel_test.table_1 (id SERIAL PRIMARY KEY) COMMENT 'table comment'",
        )
        .execute(&mut connection)
        .unwrap();
        diesel::sql_query("DROP TABLE IF EXISTS diesel_test.table_2")
            .execute(&mut connection)
            .unwrap();
        diesel::sql_query("CREATE TABLE diesel_test.table_2 (id SERIAL PRIMARY KEY)")
            .execute(&mut connection)
            .unwrap();

        let table_1 = TableName::new("table_1", "diesel_test");
        let table_2 = TableName::new("table_2", "diesel_test");
        assert_eq!(
            Ok(Some("table comment".to_string())),
            get_table_comment(&mut connection, &table_1)
        );
        assert_eq!(Ok(None), get_table_comment(&mut connection, &table_2));
    }
}
<|endoftext|>


<commit_before>#[crate_id="quadtree#0.0.1"];
#[crate_type = "lib"];

#[desc = "A basic quadtree library."];
#[license = "MIT"];

pub mod geometry;
pub mod quadtree;<commit_msg>Bump version to 0.1.0<commit_after>#[crate_id="quadtree#0.1.0"];
#[crate_type = "lib"];

#[desc = "A basic quadtree library."];
#[license = "MIT"];

pub mod geometry;
pub mod quadtree;
<|endoftext|>


<commit_before>use super::{Open, Sink};
extern crate cpal;
use std::io;
use std::thread;
use std::collections::VecDeque;

pub struct CpalSink {
    event_loop: cpal::EventLoop,
    buffer: mut VecDeque<i16>,
    stream_id: Option<cpal::StreamId>,
}

impl Open for CpalSink {
    fn open(device: Option<String>) -> CpalSink {
        info!("Using cpal sink");

        if device.is_some() {
            // N.B. This is perfectly possible to support.
            // TODO: First need to enable listing of devices.
                // Remember to filter to those which support Stereo 16bit 44100Hz
            // TODO: Choose cpal sink by name.
            panic!("cpal sink does not support specifying a device name");
        }

        let event_loop = cpal::EventLoop::new();

        CpalSink {
            // Allow an (arbitrary) 2 second buffer before resizing.
            buffer: VecDeque::with_capacity(44100 * 2 * 2),
            event_loop: event_loop,
        }
    }
}

impl Sink for CpalSink {
    fn start(&mut self) -> io::Result<()> {

        if self.stream_id.is_none() {

            let device = cpal::default_output_device().expect("no output device available");
            // TODO: Support more formats.
            let format = cpal::Format(2, 44100, cpal::SampleFormat::I16);

            self.stream_id = self.event_loop.build_output_stream(&device, &format)?;

            self.event_loop.play_stream(self.stream_id.clone());
        }

        if self.thread.is_none() {
            let event_loop = self.event_loop;
            let source  = self.buffer;
            thread::spawn(move |event_loop, source| {
                event_loop.run(move |_stream_id, mut stream_data| {
                    match data {
                        cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => {
                            let sl = source.len();
                            if (sl > buffer.len()) {
                                sl = buffer.len();
                            }
                            // let u: Vec<_> = source.drain(..sl).collect();
                            // buffer[..s1].copy_from_slice(u[..s1]);

                            for (sample, data) in buffer.iter_mut().zip(source.drain(..sl)) {
                                *sample = data;
                            }
                        },
                        _ => (),
                    }
                });
            })
        }

        Ok(())
    }

    fn stop(&mut self) -> io::Result<()> {
        if !self.stream_id.is_none() {
            self.event_loop.destroy_stream(self.stream_id);
            self.stream_id = None;
            self.buffer.clear();
        }
        Ok(())
    }

    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        // self.0.as_mut().unwrap().write_interleaved(&data).unwrap();
        // self.buffer.reserve(data.len()); // Unneccessary?
        // self.buffer.extend_from_slice(data);
        self.buffer.extend(data);
        Ok(())
    }
}
<commit_msg>cpal backend builds. Panics building output stream on my system.<commit_after>use super::{Open, Sink};
extern crate cpal;
use std::io;
use std::thread;
use std::sync::mpsc::{sync_channel, SyncSender};

pub struct CpalSink {
    // event_loop: cpal::EventLoop,
    send: SyncSender<i16>,
}

impl Open for CpalSink {
    fn open(device: Option<String>) -> CpalSink {
        info!("Using cpal sink");

        // buffer for samples from librespot (~10ms)
        let (tx, rx) = sync_channel::<i16>(2 * 1024 * 4);
        let event_loop = cpal::EventLoop::new();

        if device.is_some() {
            // N.B. This is perfectly possible to support.
            // TODO: First need to enable listing of devices.
                // Remember to filter to those which support Stereo 16bit 44100Hz
            // TODO: Choose cpal sink by name.
            panic!("cpal sink does not support specifying a device name");
        }
        let cpal_device = cpal::default_output_device().expect("no output device available");
        // TODO: Support more formats? Surely cpal will handle that.
        let format = cpal::Format{channels: 2, sample_rate: cpal::SampleRate(44100), data_type: cpal::SampleFormat::I16};

        let stream_id = event_loop.build_output_stream(&cpal_device, &format).expect("could not build output stream");
        event_loop.play_stream(stream_id);

        thread::spawn(move |/*event_loop, rx*/| {
            event_loop.run(move |_stream_id, stream_data| {
                match stream_data {
                    cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => {
                        for (sample, recv) in buffer.iter_mut().zip(rx.try_iter()) {
                            *sample = recv;
                        }
                    },
                    _ => (),
                }
            });
        });

        CpalSink {
            send: tx,
            // event_loop: event_loop,
        }
    }
}

impl Sink for CpalSink {
    fn start(&mut self) -> io::Result<()> {
        Ok(())
    }

    fn stop(&mut self) -> io::Result<()> {
        Ok(())
    }

    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        for s in data.iter() {
            let res = self.send.send(*s);
            if res.is_err() {
                error!("jackaudio: cannot write to channel");
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use backend::Backend;
use expression::coerce::Coerce;
use expression::{AsExpression, Expression};
use query_builder::*;
use result::QueryResult;
use sql_types::*;

/// Represents the SQL `CURRENT_TIMESTAMP` constant. This is equivalent to the
/// `NOW()` function on backends that support it.
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, QueryId, NonAggregate)]
pub struct now;

impl Expression for now {
    type SqlType = Timestamp;
}

impl<DB: Backend> QueryFragment<DB> for now {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("CURRENT_TIMESTAMP");
        Ok(())
    }
}

impl_selectable_expression!(now);

operator_allowed!(now, Add, add);
operator_allowed!(now, Sub, sub);
sql_function! {
    /// Represents the SQL `DATE` function. The argument should be a Timestamp
    /// expression, and the return value will be an expression of type Date.

    /// # Examples

    /// ```ignore
    /// # #[macro_use] extern crate diesel;
    /// # extern crate chrono;
    /// # include!(\"../../doctest_setup.rs\");
    /// # use diesel::dsl::*;
    /// #
    /// # fn main() {
    /// #     let connection = establish_connection();
    /// let today: chrono::NaiveDate = diesel::select(date(now)).first(&connection).unwrap();
    /// # }
    /// ```
    fn date(expr: Timestamp) -> Date;
}

impl AsExpression<Nullable<Timestamp>> for now {
    type Expression = Coerce<now, Nullable<Timestamp>>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}

#[cfg(feature = "postgres")]
impl AsExpression<Timestamptz> for now {
    type Expression = Coerce<now, Timestamptz>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}

#[cfg(feature = "postgres")]
impl AsExpression<Nullable<Timestamptz>> for now {
    type Expression = Coerce<now, Nullable<Timestamptz>>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}
<commit_msg>Fix a rustdoc issue with nightly<commit_after>use backend::Backend;
use expression::coerce::Coerce;
use expression::{AsExpression, Expression};
use query_builder::*;
use result::QueryResult;
use sql_types::*;

/// Represents the SQL `CURRENT_TIMESTAMP` constant. This is equivalent to the
/// `NOW()` function on backends that support it.
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, QueryId, NonAggregate)]
pub struct now;

impl Expression for now {
    type SqlType = Timestamp;
}

impl<DB: Backend> QueryFragment<DB> for now {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("CURRENT_TIMESTAMP");
        Ok(())
    }
}

impl_selectable_expression!(now);

operator_allowed!(now, Add, add);
operator_allowed!(now, Sub, sub);
sql_function! {
    /// Represents the SQL `DATE` function. The argument should be a Timestamp
    /// expression, and the return value will be an expression of type Date.

    /// # Examples

    /// ```ignore
    /// # #[macro_use] extern crate diesel;
    /// # extern crate chrono;
    /// # include!("../../doctest_setup.rs");
    /// # use diesel::dsl::*;
    /// #
    /// # fn main() {
    /// #     let connection = establish_connection();
    /// let today: chrono::NaiveDate = diesel::select(date(now)).first(&connection).unwrap();
    /// # }
    /// ```
    fn date(expr: Timestamp) -> Date;
}

impl AsExpression<Nullable<Timestamp>> for now {
    type Expression = Coerce<now, Nullable<Timestamp>>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}

#[cfg(feature = "postgres")]
impl AsExpression<Timestamptz> for now {
    type Expression = Coerce<now, Timestamptz>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}

#[cfg(feature = "postgres")]
impl AsExpression<Nullable<Timestamptz>> for now {
    type Expression = Coerce<now, Nullable<Timestamptz>>;

    fn as_expression(self) -> Self::Expression {
        Coerce::new(self)
    }
}
<|endoftext|>


<commit_before>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// errors.rs
//   definitions for ThecaError, a catch-all for converting various
//   lib errors.

use core::fmt;
use core::error::Error;
use docopt;
use time::{ParseError};
use std::error::{FromError};
use crypto::symmetriccipher::SymmetricCipherError;
use std::old_io::{IoError};
use std::string::FromUtf8Error;
use rustc_serialize::json::EncoderError;

pub use self::ErrorKind::{
    InternalIoError,
    GenericError
};

pub enum ErrorKind {
    InternalIoError(IoError),
    GenericError
}

pub struct ThecaError {
    pub kind: ErrorKind,
    pub desc: String,
    pub detail: Option<String>
}

macro_rules! specific_fail {
    ($short:expr) => {
        return Err(::std::error::FromError::from_error(
            ThecaError {
                kind: GenericError,
                desc: $short,
                detail: None
            }
        ))
    }
}

macro_rules! specific_fail_str {
    ($s:expr) => {
        return specific_fail!($s.to_string())
    }
}

macro_rules! try_errno {
    ($e:expr) => {
        {
            if $e != 0 {
                return Err(::std::error::FromError::from_error(IoError::from_errno(errno() as usize, true)));
            }
        }
    }
}

impl FromError<EncoderError> for ThecaError {
    fn from_error(err: EncoderError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.description().to_string(),
            detail: None
        }
    }
}

impl FromError<IoError> for ThecaError {
    fn from_error(err: IoError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.desc.to_string(),
            detail: err.detail
        }
    }
}

impl FromError<(ErrorKind, &'static str)> for ThecaError {
    fn from_error((kind, desc): (ErrorKind, &'static str)) -> ThecaError {
        ThecaError { kind: kind, desc: desc.to_string(), detail: None }
    }
}

impl FromError<ParseError> for ThecaError {
    fn from_error(err: ParseError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("\ntime parsing error: {}", err),
            detail: None
        }
    }
}

impl FromError<FromUtf8Error> for ThecaError {
    fn from_error(err: FromUtf8Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("\nerror parsing utf-8, is profile encrypted?\n({})", err),
            detail: None
        }
    }
}

impl FromError<SymmetricCipherError> for ThecaError {
    fn from_error(_: SymmetricCipherError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\ninvalid encryption key".to_string(),
            detail: None
        }
    }
}

impl FromError<docopt::Error> for ThecaError {
    fn from_error(err: docopt::Error) -> ThecaError {
        ThecaError { kind: GenericError, desc: err.to_string(), detail: None }
    }
}

impl FromError<fmt::Error> for ThecaError {
    fn from_error(_: fmt::Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\nformatting error".to_string(),
            detail: None
        }
    }
}
<commit_msg>line styling<commit_after>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// errors.rs
//   definitions for ThecaError, a catch-all for converting various
//   lib errors.

use core::fmt;
use core::error::Error;
use docopt;
use time::{ParseError};
use std::error::{FromError};
use crypto::symmetriccipher::SymmetricCipherError;
use std::old_io::{IoError};
use std::string::FromUtf8Error;
use rustc_serialize::json::EncoderError;

pub use self::ErrorKind::{
    InternalIoError,
    GenericError
};

pub enum ErrorKind {
    InternalIoError(IoError),
    GenericError
}

pub struct ThecaError {
    pub kind: ErrorKind,
    pub desc: String,
    pub detail: Option<String>
}

macro_rules! specific_fail {
    ($short:expr) => {
        return Err(::std::error::FromError::from_error(
            ThecaError {
                kind: GenericError,
                desc: $short,
                detail: None
            }
        ))
    }
}

macro_rules! specific_fail_str {
    ($s:expr) => {
        return specific_fail!($s.to_string())
    }
}

macro_rules! try_errno {
    ($e:expr) => {
        {
            if $e != 0 {
                return Err(
                    ::std::error::FromError::from_error(
                        IoError::from_errno(
                            errno() as usize,
                            true
                        )
                    )
                );
            }
        }
    }
}

impl FromError<EncoderError> for ThecaError {
    fn from_error(err: EncoderError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.description().to_string(),
            detail: None
        }
    }
}

impl FromError<IoError> for ThecaError {
    fn from_error(err: IoError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.desc.to_string(),
            detail: err.detail
        }
    }
}

impl FromError<(ErrorKind, &'static str)> for ThecaError {
    fn from_error((kind, desc): (ErrorKind, &'static str)) -> ThecaError {
        ThecaError { kind: kind, desc: desc.to_string(), detail: None }
    }
}

impl FromError<ParseError> for ThecaError {
    fn from_error(err: ParseError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("\ntime parsing error: {}", err),
            detail: None
        }
    }
}

impl FromError<FromUtf8Error> for ThecaError {
    fn from_error(err: FromUtf8Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!(
                "\nerror parsing utf-8, is profile encrypted?\n({})",
                err
            ),
            detail: None
        }
    }
}

impl FromError<SymmetricCipherError> for ThecaError {
    fn from_error(_: SymmetricCipherError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\ninvalid encryption key".to_string(),
            detail: None
        }
    }
}

impl FromError<docopt::Error> for ThecaError {
    fn from_error(err: docopt::Error) -> ThecaError {
        ThecaError { kind: GenericError, desc: err.to_string(), detail: None }
    }
}

impl FromError<fmt::Error> for ThecaError {
    fn from_error(_: fmt::Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\nformatting error".to_string(),
            detail: None
        }
    }
}
<|endoftext|>


<commit_before>use anyhow::{Context, Result};
use async_std::io::{Read, Write};
use async_std::net::{TcpListener, TcpStream};
use async_std::os::unix::net::{UnixListener, UnixStream};
use async_trait::async_trait;

pub trait GenericSocket: Read + Write + Unpin + Send + Sync {}
pub type SocketBox = Box<dyn GenericSocket>;

#[async_trait]
pub trait GenericListener: Sync + Send {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>>;
}

#[async_trait]
impl GenericListener for TcpListener {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>> {
        let (socket, _) = self.accept().await?;
        Ok(Box::new(socket))
    }
}

#[async_trait]
impl GenericListener for UnixListener {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>> {
        let (socket, _) = self.accept().await?;
        Ok(Box::new(socket))
    }
}

impl GenericSocket for TcpStream {}
impl GenericSocket for UnixStream {}

pub async fn get_client(
    unix_socket_path: Option<String>,
    port: Option<String>,
) -> Result<Box<dyn GenericSocket>> {
    if let Some(socket_path) = unix_socket_path {
        let stream = UnixStream::connect(socket_path).await?;
        return Ok(Box::new(stream));
    }

    // Don't allow anything else than loopback until we have proper crypto
    // let address = format!("{}:{}", address, port);
    let address = format!("127.0.0.1:{}", port.unwrap());

    // Connect to socket
    let socket = TcpStream::connect(&address)
        .await
        .context("Failed to connect to the daemon. Did you start it?")?;

    Ok(Box::new(socket))
}

pub async fn get_listener(
    unix_socket_path: Option<String>,
    port: Option<String>,
) -> Result<Box<dyn GenericListener>> {
    if let Some(socket_path) = unix_socket_path {
        return Ok(Box::new(UnixListener::bind(socket_path).await?));
    }

    let port = port.unwrap();
    let address = format!("127.0.0.1:{}", port);
    Ok(Box::new(TcpListener::bind(address).await?))
}
<commit_msg>Remove old socket on daemon startup<commit_after>use std::path::PathBuf;

use anyhow::{bail, Context, Result};
use async_std::io::{Read, Write};
use async_std::net::{TcpListener, TcpStream};
use async_std::os::unix::net::{UnixListener, UnixStream};
use async_trait::async_trait;

pub trait GenericSocket: Read + Write + Unpin + Send + Sync {}
pub type SocketBox = Box<dyn GenericSocket>;

#[async_trait]
pub trait GenericListener: Sync + Send {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>>;
}

#[async_trait]
impl GenericListener for TcpListener {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>> {
        let (socket, _) = self.accept().await?;
        Ok(Box::new(socket))
    }
}

#[async_trait]
impl GenericListener for UnixListener {
    async fn accept<'a>(&'a self) -> Result<Box<dyn GenericSocket>> {
        let (socket, _) = self.accept().await?;
        Ok(Box::new(socket))
    }
}

impl GenericSocket for TcpStream {}
impl GenericSocket for UnixStream {}

/// Get a new stream for the client.
/// This can either be a UnixStream or a TCPStream,
/// which depends on the parameters.
pub async fn get_client(
    unix_socket_path: Option<String>,
    port: Option<String>,
) -> Result<Box<dyn GenericSocket>> {
    if let Some(socket_path) = unix_socket_path {
        let stream = UnixStream::connect(socket_path).await?;
        return Ok(Box::new(stream));
    }

    // Don't allow anything else than loopback until we have proper crypto
    // let address = format!("{}:{}", address, port);
    let address = format!("127.0.0.1:{}", port.unwrap());

    // Connect to socket
    let socket = TcpStream::connect(&address)
        .await
        .context("Failed to connect to the daemon. Did you start it?")?;

    Ok(Box::new(socket))
}

/// Get a new listener for the daemon.
/// This can either be a UnixListener or a TCPlistener,
/// which depends on the parameters.
pub async fn get_listener(
    unix_socket_path: Option<String>,
    port: Option<String>,
) -> Result<Box<dyn GenericListener>> {
    if let Some(socket_path) = unix_socket_path {
        // Check, if the socket already exists
        // In case it does, we have to check, if it's an active socket.
        // If it is, we have to throw an error, because another daemon is already running.
        // Otherwise, we can simply remove it.
        if PathBuf::from(&socket_path).exists() {
            if get_client(Some(socket_path.clone()), None).await.is_ok() {
                bail!(
                    "There seems to be an active pueue daemon.\n\
                      If you're sure there isn't, please remove the socket by hand \
                      inside the pueue_directory."
                );
            }

            std::fs::remove_file(&socket_path)?;
        }

        return Ok(Box::new(UnixListener::bind(socket_path).await?));
    }

    let port = port.unwrap();
    let address = format!("127.0.0.1:{}", port);
    Ok(Box::new(TcpListener::bind(address).await?))
}
<|endoftext|>


<commit_before>//! Determine which URLs are allowed for loading.

use std::fmt;
use std::io;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use url::Url;

use crate::error::AllowedUrlError;

/// Currently only contains the base URL.
///
/// The plan is to add:
/// base_only:    Only allow to load content from the same base URL. By default
//                this restriction is enabled and requires to provide base_url.
/// include_xml:  Allows to use xi:include with XML. Enabled by default.
/// include_text: Allows to use xi:include with text. Enabled by default.
/// local_only:   Only allow to load content from the local filesystem.
///               Enabled by default.
#[derive(Clone)]
pub struct UrlResolver {
    /// Base URL; all relative references will be resolved with respect to this.
    pub base_url: Option<Url>,
}

impl UrlResolver {
    /// Creates a `UrlResolver` with defaults, and sets the `base_url`.
    pub fn new(base_url: Option<Url>) -> Self {
        UrlResolver { base_url }
    }

    pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, AllowedUrlError> {
        let url = Url::options()
            .base_url(self.base_url.as_ref())
            .parse(href)
            .map_err(AllowedUrlError::UrlParseError)?;

        // Allow loads of data: from any location
        if url.scheme() == "data" {
            return Ok(AllowedUrl(url));
        }

        // All other sources require a base url
        if self.base_url.is_none() {
            return Err(AllowedUrlError::BaseRequired);
        }

        let base_url = self.base_url.as_ref().unwrap();

        // Deny loads from differing URI schemes
        if url.scheme() != base_url.scheme() {
            return Err(AllowedUrlError::DifferentUriSchemes);
        }

        // resource: is allowed to load anything from other resources
        if url.scheme() == "resource" {
            return Ok(AllowedUrl(url));
        }

        // Non-file: isn't allowed to load anything
        if url.scheme() != "file" {
            return Err(AllowedUrlError::DisallowedScheme);
        }

        // We have two file: URIs.  Now canonicalize them (remove .. and symlinks, etc.)
        // and see if the directories match

        let url_path = url
            .to_file_path()
            .map_err(|_| AllowedUrlError::InvalidPath)?;
        let base_path = base_url
            .to_file_path()
            .map_err(|_| AllowedUrlError::InvalidPath)?;

        let base_parent = base_path.parent();
        if base_parent.is_none() {
            return Err(AllowedUrlError::BaseIsRoot);
        }

        let base_parent = base_parent.unwrap();

        let url_canon =
            canonicalize(&url_path).map_err(|_| AllowedUrlError::CanonicalizationError)?;
        let parent_canon =
            canonicalize(&base_parent).map_err(|_| AllowedUrlError::CanonicalizationError)?;

        if url_canon.starts_with(parent_canon) {
            Ok(AllowedUrl(url))
        } else {
            Err(AllowedUrlError::NotSiblingOrChildOfBaseFile)
        }
    }
}

/// Wrapper for URLs which are allowed to be loaded
///
/// SVG files can reference other files (PNG/JPEG images, other SVGs,
/// CSS files, etc.).  This object is constructed by checking whether
/// a specified `href` (a possibly-relative filename, for example)
/// should be allowed to be loaded, given the base URL of the SVG
/// being loaded.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AllowedUrl(Url);

impl Deref for AllowedUrl {
    type Target = Url;

    fn deref(&self) -> &Url {
        &self.0
    }
}

impl fmt::Display for AllowedUrl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

// For tests, we don't want to touch the filesystem.  In that case,
// assume that we are being passed canonical file names.
#[cfg(not(test))]
fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf, io::Error> {
    path.as_ref().canonicalize()
}
#[cfg(test)]
fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf, io::Error> {
    Ok(path.as_ref().to_path_buf())
}

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

    #[test]
    fn disallows_relative_file_with_no_base_file() {
        let url_resolver = UrlResolver::new(None);
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::UrlParseError(
                url::ParseError::RelativeUrlWithoutBase
            ))
        ));
    }

    #[test]
    fn disallows_different_schemes() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse("http://example.com/malicious.svg").unwrap(),
        ));
        assert!(matches!(
            url_resolver.resolve_href("file:///etc/passwd"),
            Err(AllowedUrlError::DifferentUriSchemes)
        ));
    }

    fn make_file_uri(p: &str) -> String {
        if cfg!(windows) {
            format!("file:///c:{}", p)
        } else {
            format!("file://{}", p)
        }
    }

    #[test]
    fn disallows_base_is_root() {
        let url_resolver = UrlResolver::new(Some(Url::parse(&make_file_uri("/")).unwrap()));
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::BaseIsRoot)
        ));
    }

    #[test]
    fn disallows_non_file_scheme() {
        let url_resolver = UrlResolver::new(Some(Url::parse("http://foo.bar/baz.svg").unwrap()));
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::DisallowedScheme)
        ));
    }

    #[test]
    fn allows_data_url_with_no_base_file() {
        let url_resolver = UrlResolver::new(None);
        assert_eq!(
            url_resolver
                .resolve_href("data:image/jpeg;base64,xxyyzz")
                .unwrap()
                .as_ref(),
            "data:image/jpeg;base64,xxyyzz",
        );
    }

    #[test]
    fn allows_relative() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver.resolve_href("foo.svg").unwrap();
        let expected = make_file_uri("/example/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn allows_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver
            .resolve_href(&make_file_uri("/example/foo.svg"))
            .unwrap();
        let expected = make_file_uri("/example/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn allows_child_of_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver
            .resolve_href(&make_file_uri("/example/subdir/foo.svg"))
            .unwrap();
        let expected = make_file_uri("/example/subdir/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn disallows_non_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        assert!(matches!(
            url_resolver.resolve_href(&make_file_uri("/etc/passwd")),
            Err(AllowedUrlError::NotSiblingOrChildOfBaseFile)
        ));
    }

    #[cfg(windows)]
    #[test]
    fn invalid_url_from_test_suite() {
        // let resolver = UrlResolver::new(Some(Url::parse("file:///c:/foo.svg").expect("initial url")));
        let resolver = UrlResolver::new(None);
        match resolver.resolve_href("file://invalid.css") {
            Ok(_) => println!("yay!"),
            Err(e) => println!("err: {}", e),
        }
    }

}
<commit_msg>It works without a base URL!  So write down the requirements.<commit_after>//! Determine which URLs are allowed for loading.

use std::fmt;
use std::io;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use url::Url;

use crate::error::AllowedUrlError;

/// Currently only contains the base URL.
///
/// The plan is to add:
/// base_only:    Only allow to load content from the same base URL. By default
//                this restriction is enabled and requires to provide base_url.
/// include_xml:  Allows to use xi:include with XML. Enabled by default.
/// include_text: Allows to use xi:include with text. Enabled by default.
/// local_only:   Only allow to load content from the local filesystem.
///               Enabled by default.
#[derive(Clone)]
pub struct UrlResolver {
    /// Base URL; all relative references will be resolved with respect to this.
    pub base_url: Option<Url>,
}

impl UrlResolver {
    /// Creates a `UrlResolver` with defaults, and sets the `base_url`.
    pub fn new(base_url: Option<Url>) -> Self {
        UrlResolver { base_url }
    }

    pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, AllowedUrlError> {
        let url = Url::options()
            .base_url(self.base_url.as_ref())
            .parse(href)
            .map_err(AllowedUrlError::UrlParseError)?;

        // Allow loads of data: from any location
        if url.scheme() == "data" {
            return Ok(AllowedUrl(url));
        }

        // All other sources require a base url
        if self.base_url.is_none() {
            return Err(AllowedUrlError::BaseRequired);
        }

        let base_url = self.base_url.as_ref().unwrap();

        // Deny loads from differing URI schemes
        if url.scheme() != base_url.scheme() {
            return Err(AllowedUrlError::DifferentUriSchemes);
        }

        // resource: is allowed to load anything from other resources
        if url.scheme() == "resource" {
            return Ok(AllowedUrl(url));
        }

        // Non-file: isn't allowed to load anything
        if url.scheme() != "file" {
            return Err(AllowedUrlError::DisallowedScheme);
        }

        // We have two file: URIs.  Now canonicalize them (remove .. and symlinks, etc.)
        // and see if the directories match

        let url_path = url
            .to_file_path()
            .map_err(|_| AllowedUrlError::InvalidPath)?;
        let base_path = base_url
            .to_file_path()
            .map_err(|_| AllowedUrlError::InvalidPath)?;

        let base_parent = base_path.parent();
        if base_parent.is_none() {
            return Err(AllowedUrlError::BaseIsRoot);
        }

        let base_parent = base_parent.unwrap();

        let url_canon =
            canonicalize(&url_path).map_err(|_| AllowedUrlError::CanonicalizationError)?;
        let parent_canon =
            canonicalize(&base_parent).map_err(|_| AllowedUrlError::CanonicalizationError)?;

        if url_canon.starts_with(parent_canon) {
            Ok(AllowedUrl(url))
        } else {
            Err(AllowedUrlError::NotSiblingOrChildOfBaseFile)
        }
    }
}

/// Wrapper for URLs which are allowed to be loaded
///
/// SVG files can reference other files (PNG/JPEG images, other SVGs,
/// CSS files, etc.).  This object is constructed by checking whether
/// a specified `href` (a possibly-relative filename, for example)
/// should be allowed to be loaded, given the base URL of the SVG
/// being loaded.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AllowedUrl(Url);

impl Deref for AllowedUrl {
    type Target = Url;

    fn deref(&self) -> &Url {
        &self.0
    }
}

impl fmt::Display for AllowedUrl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

// For tests, we don't want to touch the filesystem.  In that case,
// assume that we are being passed canonical file names.
#[cfg(not(test))]
fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf, io::Error> {
    path.as_ref().canonicalize()
}
#[cfg(test)]
fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf, io::Error> {
    Ok(path.as_ref().to_path_buf())
}

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

    #[test]
    fn disallows_relative_file_with_no_base_file() {
        let url_resolver = UrlResolver::new(None);
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::UrlParseError(
                url::ParseError::RelativeUrlWithoutBase
            ))
        ));
    }

    #[test]
    fn disallows_different_schemes() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse("http://example.com/malicious.svg").unwrap(),
        ));
        assert!(matches!(
            url_resolver.resolve_href("file:///etc/passwd"),
            Err(AllowedUrlError::DifferentUriSchemes)
        ));
    }

    fn make_file_uri(p: &str) -> String {
        if cfg!(windows) {
            format!("file:///c:{}", p)
        } else {
            format!("file://{}", p)
        }
    }

    #[test]
    fn disallows_base_is_root() {
        let url_resolver = UrlResolver::new(Some(Url::parse(&make_file_uri("/")).unwrap()));
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::BaseIsRoot)
        ));
    }

    #[test]
    fn disallows_non_file_scheme() {
        let url_resolver = UrlResolver::new(Some(Url::parse("http://foo.bar/baz.svg").unwrap()));
        assert!(matches!(
            url_resolver.resolve_href("foo.svg"),
            Err(AllowedUrlError::DisallowedScheme)
        ));
    }

    #[test]
    fn allows_data_url_with_no_base_file() {
        let url_resolver = UrlResolver::new(None);
        assert_eq!(
            url_resolver
                .resolve_href("data:image/jpeg;base64,xxyyzz")
                .unwrap()
                .as_ref(),
            "data:image/jpeg;base64,xxyyzz",
        );
    }

    #[test]
    fn allows_relative() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver.resolve_href("foo.svg").unwrap();
        let expected = make_file_uri("/example/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn allows_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver
            .resolve_href(&make_file_uri("/example/foo.svg"))
            .unwrap();
        let expected = make_file_uri("/example/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn allows_child_of_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        let resolved = url_resolver
            .resolve_href(&make_file_uri("/example/subdir/foo.svg"))
            .unwrap();
        let expected = make_file_uri("/example/subdir/foo.svg");
        assert_eq!(resolved.as_ref(), expected);
    }

    #[test]
    fn disallows_non_sibling() {
        let url_resolver = UrlResolver::new(Some(
            Url::parse(&make_file_uri("/example/bar.svg")).unwrap(),
        ));
        assert!(matches!(
            url_resolver.resolve_href(&make_file_uri("/etc/passwd")),
            Err(AllowedUrlError::NotSiblingOrChildOfBaseFile)
        ));
    }

    #[cfg(windows)]
    #[test]
    fn invalid_url_from_test_suite() {
        // This is required for Url to panic.
        let resolver = UrlResolver::new(Some(Url::parse("file:///c:/foo.svg").expect("initial url")));
        // With this, it doesn't panic:
        //   let resolver = UrlResolver::new(None);
        match resolver.resolve_href("file://invalid.css") {
            Ok(_) => println!("yay!"),
            Err(e) => println!("err: {}", e),
        }
    }

}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::hash::Hash;

pub struct AnySet<T: Copy + Hash + Eq> {
    inner: HashSet<T>,
    any: Option<T>,
}

impl<T: Copy + Hash + Eq> AnySet<T> {
    pub fn new() -> Self {
        AnySet {
            inner: HashSet::new(),
            any: None,
        }
    }

    pub fn any(&self) -> Option<T> {
        self.any
    }

    pub fn insert(&mut self, value: T) {
        self.inner.insert(value);
        self.any = Some(value);
    }

    pub fn remove(&mut self, value: T) {
        self.inner.remove(&value);
        if self.inner.is_empty() {
            self.any = None;
        }
    }
}
<commit_msg>Corrected bug in AnySet implementation<commit_after>use std::collections::HashSet;
use std::hash::Hash;

pub struct AnySet<T: Copy + Hash + Eq> {
    inner: HashSet<T>,
    any: Option<T>,
}

impl<T: Copy + Hash + Eq> AnySet<T> {
    pub fn new() -> Self {
        AnySet {
            inner: HashSet::new(),
            any: None,
        }
    }

    pub fn any(&self) -> Option<T> {
        self.any
    }

    pub fn insert(&mut self, value: T) {
        if self.inner.is_empty() {
            self.any = Some(value);
        }
        self.inner.insert(value);
    }

    pub fn remove(&mut self, value: T) {
        self.inner.remove(&value);
        self.any = self.inner.iter().next().map(|r| *r);
    }
}
<|endoftext|>


<commit_before>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let mut opts = opts();
        opts.skip_if_exists = true;
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() > 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.is_in_progress() {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<commit_msg>rebuild existing crates if they appear on the queue<commit_after>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() > 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.is_in_progress() {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(passert_macros)]

extern crate passert;

#[cfg(test)]
use std::cmp;
#[cfg(test)]
use std::ascii::AsciiExt;

#[test]
fn literal_true() {
    passert!(true);
}

#[test]
#[should_panic(expected = "Assertion failed: false")]
fn literal_false() {
    passert!(false);
}

#[test]
fn binding_true() {
    let t = true;
    passert!(t);
}

#[test]
#[should_panic(expected = "Assertion failed: f")]
fn binding_false() {
    let f = false;
    passert!(f);
}

#[test]
fn unary_expression_true() {
    let f = false;
    passert!(!f);
}

#[test]
#[should_panic(expected = "Assertion failed: !t")]
fn unary_expression_false() {
    let t = true;
    passert!(!t);
}

#[test]
fn binary_expression_true() {
    let a = 3;
    let b = -8;
    passert!(a + 2 + 3 == -b);
}

#[test]
#[should_panic(expected = "Assertion failed: a + 2 + 3 == -b")]
fn binary_expression_false() {
    let a = 3;
    let b = 4;
    passert!(a + 2 + 3 == -b);
}

#[test]
fn macro_expression_true() {
    passert!(format!("{}{}", "foo", "bar") == "foobar");
}

#[test]
#[should_panic(expected = "format!(\"{}{}\", \"foo\", \"bar\") == \"fizzbuzz\"")]
fn macro_expression_false() {
    passert!(format!("{}{}", "foo", "bar") == "fizzbuzz");
}

#[test]
fn paren_expression_true() {
    let a = 3;
    let b = -8;
    passert!((a + 2) + 3 == -b);
}

#[test]
#[should_panic(expected = "Assertion failed: (a + 2) + 3 == -b")]
fn paren_expression_false() {
    let a = 3;
    let b = 4;
    passert!((a + 2) + 3 == -b);
}

#[test]
fn call_expression_true() {
    let a = 1;
    let b = 2;
    passert!(cmp::max(a, b) == 2);
}

#[test]
#[should_panic(expected = "Assertion failed: cmp::max(a, b) == 3")]
fn call_expression_false() {
    let a = 1;
    let b = 2;
    passert!(cmp::max(a, b) == 3);
}

#[test]
fn method_call_expression_true() {
    let str = "foo";
    passert!(str.to_ascii_uppercase() == "FOO");
}

#[test]
#[should_panic(expected = "Assertion failed: str.to_ascii_uppercase() == \"BAR\"")]
fn method_call_expression_false() {
    let str = "foo";
    passert!(str.to_ascii_uppercase() == "BAR");
}
<commit_msg>test(macros): add test to verify macro hygiene<commit_after>#![feature(plugin)]
#![plugin(passert_macros)]

extern crate passert;

#[cfg(test)]
use std::cmp;
#[cfg(test)]
use std::ascii::AsciiExt;

#[test]
fn literal_true() {
    passert!(true);
}

#[test]
#[should_panic(expected = "Assertion failed: false")]
fn literal_false() {
    passert!(false);
}

#[test]
fn binding_true() {
    let t = true;
    passert!(t);
}

#[test]
#[should_panic(expected = "Assertion failed: f")]
fn binding_false() {
    let f = false;
    passert!(f);
}

#[test]
fn unary_expression_true() {
    let f = false;
    passert!(!f);
}

#[test]
#[should_panic(expected = "Assertion failed: !t")]
fn unary_expression_false() {
    let t = true;
    passert!(!t);
}

#[test]
fn binary_expression_true() {
    let a = 3;
    let b = -8;
    passert!(a + 2 + 3 == -b);
}

#[test]
#[should_panic(expected = "Assertion failed: a + 2 + 3 == -b")]
fn binary_expression_false() {
    let a = 3;
    let b = 4;
    passert!(a + 2 + 3 == -b);
}

#[test]
fn macro_expression_true() {
    passert!(format!("{}{}", "foo", "bar") == "foobar");
}

#[test]
#[should_panic(expected = "format!(\"{}{}\", \"foo\", \"bar\") == \"fizzbuzz\"")]
fn macro_expression_false() {
    passert!(format!("{}{}", "foo", "bar") == "fizzbuzz");
}

#[test]
fn paren_expression_true() {
    let a = 3;
    let b = -8;
    passert!((a + 2) + 3 == -b);
}

#[test]
#[should_panic(expected = "Assertion failed: (a + 2) + 3 == -b")]
fn paren_expression_false() {
    let a = 3;
    let b = 4;
    passert!((a + 2) + 3 == -b);
}

#[test]
fn call_expression_true() {
    let a = 1;
    let b = 2;
    passert!(cmp::max(a, b) == 2);
}

#[test]
#[should_panic(expected = "Assertion failed: cmp::max(a, b) == 3")]
fn call_expression_false() {
    let a = 1;
    let b = 2;
    passert!(cmp::max(a, b) == 3);
}

#[test]
fn method_call_expression_true() {
    let str = "foo";
    passert!(str.to_ascii_uppercase() == "FOO");
}

#[test]
#[should_panic(expected = "Assertion failed: str.to_ascii_uppercase() == \"BAR\"")]
fn method_call_expression_false() {
    let str = "foo";
    passert!(str.to_ascii_uppercase() == "BAR");
}

#[test]
fn hygiene() {
    let a = 42;
    // Verify that this temp_0 is used, not the new binding inside the block
    let temp_0 = 43;
    passert!(a + 1 == temp_0);
}
<|endoftext|>


<commit_before>extern crate pest;

use std::io::{self, Write};
use std::rc::Rc;

use pest::inputs::{Input, Position, StringInput};
use pest::iterators::Pairs;
use pest::{Error, Parser, ParserState, state};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Rule {
    expr,
    paren,
    paren_end
}

struct ParenParser;

impl Parser<Rule> for ParenParser {
    fn parse<I: Input>(rule: Rule, input: Rc<I>) -> Result<Pairs<Rule, I>, Error<Rule, I>> {
        fn expr<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.sequence(move |state| {
                pos.sequence(|p| {
                    p.repeat(|p| {
                        paren(p, state)
                    }).and_then(|p| {
                        p.at_end()
                    })
                })
            })
        }

        fn paren<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.rule(Rule::paren, pos, |state, pos| {
                state.sequence(move |state| {
                    pos.sequence(|p| {
                        p.match_string("(").and_then(|p| {
                            p.optional(|p| {
                                state.sequence(move |state| {
                                    p.sequence(|p| {
                                        state.lookahead(true, move |_| {
                                            p.lookahead(true, |p| {
                                                p.match_string("(")
                                            })
                                        }).and_then(|p| {
                                            p.repeat(|p| {
                                                paren(p, state)
                                            })
                                        })
                                    })
                                })
                            })
                        }).and_then(|p| {
                            state.rule(Rule::paren_end, p, |state, pos| {
                                pos.match_string(")")
                            })
                        })
                    })
                })
            })
        }

        state(input, move |mut state, pos| {
            match rule {
                Rule::expr => expr(pos, &mut state),
                Rule::paren => paren(pos, &mut state),
                _ => unreachable!()
            }
        })
    }
}

#[derive(Debug)]
struct Paren(Vec<Paren>);

fn expr<I: Input>(pairs: Pairs<Rule, I>) -> Vec<Paren> {
    pairs.filter(|p| p.rule() == Rule::paren).map(|p| Paren(expr(p.consume()))).collect()
}

fn main() {
    loop {
        let mut line = String::new();

        print!("> ");
        io::stdout().flush().unwrap();

        io::stdin().read_line(&mut line).unwrap();
        line.pop();

        let input = Rc::new(StringInput::new(line));

        match ParenParser::parse(Rule::expr, input) {
            Ok(pairs) => println!("{:?}", expr(pairs)),
            Err(e) => println!("\n{}", e)
        };
    }
}
<commit_msg>Fixed warning.<commit_after>extern crate pest;

use std::io::{self, Write};
use std::rc::Rc;

use pest::inputs::{Input, Position, StringInput};
use pest::iterators::Pairs;
use pest::{Error, Parser, ParserState, state};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Rule {
    expr,
    paren,
    paren_end
}

struct ParenParser;

impl Parser<Rule> for ParenParser {
    fn parse<I: Input>(rule: Rule, input: Rc<I>) -> Result<Pairs<Rule, I>, Error<Rule, I>> {
        fn expr<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.sequence(move |state| {
                pos.sequence(|p| {
                    p.repeat(|p| {
                        paren(p, state)
                    }).and_then(|p| {
                        p.at_end()
                    })
                })
            })
        }

        fn paren<I: Input>(
            pos: Position<I>,
            state: &mut ParserState<Rule, I>
        ) -> Result<Position<I>, Position<I>> {
            state.rule(Rule::paren, pos, |state, pos| {
                state.sequence(move |state| {
                    pos.sequence(|p| {
                        p.match_string("(").and_then(|p| {
                            p.optional(|p| {
                                state.sequence(move |state| {
                                    p.sequence(|p| {
                                        state.lookahead(true, move |_| {
                                            p.lookahead(true, |p| {
                                                p.match_string("(")
                                            })
                                        }).and_then(|p| {
                                            p.repeat(|p| {
                                                paren(p, state)
                                            })
                                        })
                                    })
                                })
                            })
                        }).and_then(|p| {
                            state.rule(Rule::paren_end, p, |_, pos| {
                                pos.match_string(")")
                            })
                        })
                    })
                })
            })
        }

        state(input, move |mut state, pos| {
            match rule {
                Rule::expr => expr(pos, &mut state),
                Rule::paren => paren(pos, &mut state),
                _ => unreachable!()
            }
        })
    }
}

#[derive(Debug)]
struct Paren(Vec<Paren>);

fn expr<I: Input>(pairs: Pairs<Rule, I>) -> Vec<Paren> {
    pairs.filter(|p| p.rule() == Rule::paren).map(|p| Paren(expr(p.consume()))).collect()
}

fn main() {
    loop {
        let mut line = String::new();

        print!("> ");
        io::stdout().flush().unwrap();

        io::stdin().read_line(&mut line).unwrap();
        line.pop();

        let input = Rc::new(StringInput::new(line));

        match ParenParser::parse(Rule::expr, input) {
            Ok(pairs) => println!("{:?}", expr(pairs)),
            Err(e) => println!("\n{}", e)
        };
    }
}
<|endoftext|>


<commit_before>// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs

#![feature(no_core, unboxed_closures, start, lang_items, box_syntax)]
#![no_core]
#![allow(dead_code)]

extern crate mini_core;

use mini_core::*;

#[link(name = "c")]
extern "C" {
    fn puts(s: *const u8);
}

unsafe extern "C" fn my_puts(s: *const u8) {
    puts(s);
}

// TODO remove when jit supports linking rlibs
#[cfg(jit)]
fn panic<T>(_: T) { loop {} }

#[lang = "termination"]
trait Termination {
    fn report(self) -> i32;
}

impl Termination for () {
    fn report(self) -> i32 {
        unsafe {
            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
            *NUM_REF as i32
        }
    }
}

trait SomeTrait {
    fn object_safe(&self);
}

impl SomeTrait for &'static str {
    fn object_safe(&self) {
        unsafe {
            puts(*self as *const str as *const u8);
        }
    }
}

#[lang = "start"]
fn start<T: Termination + 'static>(
    main: fn() -> T,
    _argc: isize,
    _argv: *const *const u8,
) -> isize {
    main().report() as isize
}

static mut NUM: u8 = 6 * 7;
static NUM_REF: &'static u8 = unsafe { &NUM };

fn main() {
    unsafe {
        let hello: &[u8] = b"Hello\0" as &[u8; 6];
        let ptr: *const u8 = hello as *const [u8] as *const u8;
        puts(ptr);

        // TODO remove when jit supports linking rlibs
        #[cfg(not(jit))]
        {
            let world = box "World!\0";
            puts(*world as *const str as *const u8);
        }

        if intrinsics::size_of_val(hello) as u8 != 6 {
            panic(&("", "", 0, 0));
        };

        let chars = &['C', 'h', 'a', 'r', 's'];
        let chars = chars as &[char];
        if intrinsics::size_of_val(chars) as u8 != 4 * 5 {
            panic(&("", "", 0, 0));
        }

        let a: &dyn SomeTrait = &"abc\0";
        a.object_safe();

        if intrinsics::size_of_val(a) as u8 != 16 {
            panic(&("", "", 0, 0));
        }
    }
}
<commit_msg>Rustfmt<commit_after>// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs

#![feature(no_core, unboxed_closures, start, lang_items, box_syntax)]
#![no_core]
#![allow(dead_code)]

extern crate mini_core;

use mini_core::*;

#[link(name = "c")]
extern "C" {
    fn puts(s: *const u8);
}

unsafe extern "C" fn my_puts(s: *const u8) {
    puts(s);
}

// TODO remove when jit supports linking rlibs
#[cfg(jit)]
fn panic<T>(_: T) {
    loop {}
}

#[lang = "termination"]
trait Termination {
    fn report(self) -> i32;
}

impl Termination for () {
    fn report(self) -> i32 {
        unsafe {
            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
            *NUM_REF as i32
        }
    }
}

trait SomeTrait {
    fn object_safe(&self);
}

impl SomeTrait for &'static str {
    fn object_safe(&self) {
        unsafe {
            puts(*self as *const str as *const u8);
        }
    }
}

#[lang = "start"]
fn start<T: Termination + 'static>(
    main: fn() -> T,
    _argc: isize,
    _argv: *const *const u8,
) -> isize {
    main().report() as isize
}

static mut NUM: u8 = 6 * 7;
static NUM_REF: &'static u8 = unsafe { &NUM };

fn main() {
    unsafe {
        let hello: &[u8] = b"Hello\0" as &[u8; 6];
        let ptr: *const u8 = hello as *const [u8] as *const u8;
        puts(ptr);

        // TODO remove when jit supports linking rlibs
        #[cfg(not(jit))]
        {
            let world = box "World!\0";
            puts(*world as *const str as *const u8);
        }

        if intrinsics::size_of_val(hello) as u8 != 6 {
            panic(&("", "", 0, 0));
        };

        let chars = &['C', 'h', 'a', 'r', 's'];
        let chars = chars as &[char];
        if intrinsics::size_of_val(chars) as u8 != 4 * 5 {
            panic(&("", "", 0, 0));
        }

        let a: &dyn SomeTrait = &"abc\0";
        a.object_safe();

        if intrinsics::size_of_val(a) as u8 != 16 {
            panic(&("", "", 0, 0));
        }
    }
}
<|endoftext|>