<commit_before>use crate::schema::TestBackend;
use diesel::*;

#[test]
fn test_debug_count_output() {
    use crate::schema::users::dsl::*;
    let sql = debug_query::<TestBackend, _>(&users.count()).to_string();
    if cfg!(feature = "postgres") {
        assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
    } else {
        assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
    }
}

#[test]
fn test_debug_output() {
    use crate::schema::users::dsl::*;
    let command = update(users.filter(id.eq(1))).set(name.eq("new_name"));
    let sql = debug_query::<TestBackend, _>(&command).to_string();
    if cfg!(feature = "postgres") {
        assert_eq!(
            sql,
            r#"UPDATE "users" SET "name" = $1 WHERE "users"."id" = $2 -- binds: ["new_name", 1]"#
        )
    } else {
        assert_eq!(
            sql,
            r#"UPDATE `users` SET `name` = ? WHERE `users`.`id` = ? -- binds: ["new_name", 1]"#
        )
    }
}

#[test]
fn test_debug_batch_insert() {
    // This test ensures that we've implemented `debug_query` for batch insert
    // on sqlite
    // This requires a separate impl because it's more than one sql statement that
    // is executed

    use crate::schema::users::dsl::*;

    let values = vec![
        (name.eq("Sean"), hair_color.eq(Some("black"))),
        (name.eq("Tess"), hair_color.eq(None::<&str>)),
    ];
    let borrowed_command = insert_into(users).values(&values);
    let borrowed_sql_display = debug_query::<TestBackend, _>(&borrowed_command).to_string();
    let borrowed_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&borrowed_command));

    let owned_command = insert_into(users).values(values);
    let owned_sql_display = debug_query::<TestBackend, _>(&owned_command).to_string();
    let owned_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&owned_command));

    if cfg!(feature = "postgres") {
        assert_eq!(
            borrowed_sql_display,
            r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: "INSERT INTO \"users\" (\"name\", \"hair_color\") VALUES ($1, $2), ($3, $4)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: "INSERT INTO \"users\" (\"name\", \"hair_color\") VALUES ($1, $2), ($3, $4)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );
    } else if cfg!(feature = "sqlite") {
        assert_eq!(
            borrowed_sql_display,
            r#"BEGIN;
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
COMMIT;
"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"BEGIN;
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
COMMIT;
"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
        );
    } else {
        assert_eq!(
            borrowed_sql_display,
            r#"INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );
    }
}

#[test]
#[cfg(feature = "postgres")]
fn test_upsert() {
    // this test ensures we get the right debug string for upserts
    use crate::schema::users::dsl::*;

    let values = vec![
        (name.eq("Sean"), hair_color.eq(Some("black"))),
        (name.eq("Tess"), hair_color.eq(None::<&str>)),
    ];

    let upsert_command = insert_into(users)
        .values(values)
        .on_conflict(hair_color)
        .filter_target(hair_color.eq(Some("black")))
        .do_nothing();
    let upsert_sql_display = debug_query::<TestBackend, _>(&upsert_command).to_string();

    assert_eq!(
        upsert_sql_display,
        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE "users"."hair_color" = $5 DO NOTHING -- binds: ["Sean", Some("black"), "Tess", None, Some("black")]"#
    );
}
<commit_msg>comment out failing test<commit_after>use crate::schema::TestBackend;
use diesel::*;

#[test]
fn test_debug_count_output() {
    use crate::schema::users::dsl::*;
    let sql = debug_query::<TestBackend, _>(&users.count()).to_string();
    if cfg!(feature = "postgres") {
        assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
    } else {
        assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
    }
}

#[test]
fn test_debug_output() {
    use crate::schema::users::dsl::*;
    let command = update(users.filter(id.eq(1))).set(name.eq("new_name"));
    let sql = debug_query::<TestBackend, _>(&command).to_string();
    if cfg!(feature = "postgres") {
        assert_eq!(
            sql,
            r#"UPDATE "users" SET "name" = $1 WHERE "users"."id" = $2 -- binds: ["new_name", 1]"#
        )
    } else {
        assert_eq!(
            sql,
            r#"UPDATE `users` SET `name` = ? WHERE `users`.`id` = ? -- binds: ["new_name", 1]"#
        )
    }
}

#[test]
fn test_debug_batch_insert() {
    // This test ensures that we've implemented `debug_query` for batch insert
    // on sqlite
    // This requires a separate impl because it's more than one sql statement that
    // is executed

    use crate::schema::users::dsl::*;

    let values = vec![
        (name.eq("Sean"), hair_color.eq(Some("black"))),
        (name.eq("Tess"), hair_color.eq(None::<&str>)),
    ];
    let borrowed_command = insert_into(users).values(&values);
    let borrowed_sql_display = debug_query::<TestBackend, _>(&borrowed_command).to_string();
    let borrowed_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&borrowed_command));

    let owned_command = insert_into(users).values(values);
    let owned_sql_display = debug_query::<TestBackend, _>(&owned_command).to_string();
    let owned_sql_debug = format!("{:?}", debug_query::<TestBackend, _>(&owned_command));

    if cfg!(feature = "postgres") {
        assert_eq!(
            borrowed_sql_display,
            r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: "INSERT INTO \"users\" (\"name\", \"hair_color\") VALUES ($1, $2), ($3, $4)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: "INSERT INTO \"users\" (\"name\", \"hair_color\") VALUES ($1, $2), ($3, $4)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );
    } else if cfg!(feature = "sqlite") {
        assert_eq!(
            borrowed_sql_display,
            r#"BEGIN;
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
COMMIT;
"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"BEGIN;
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Sean", Some("black")]
INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: ["Tess", None]
COMMIT;
"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: ["BEGIN", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Sean\", Some(\"black\")]", "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?) -- binds: [\"Tess\", None]", "COMMIT"], binds: [] }"#
        );
    } else {
        assert_eq!(
            borrowed_sql_display,
            r#"INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            borrowed_sql_debug,
            r#"Query { sql: "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );

        assert_eq!(
            owned_sql_display,
            r#"INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?) -- binds: ["Sean", Some("black"), "Tess", None]"#
        );
        assert_eq!(
            owned_sql_debug,
            r#"Query { sql: "INSERT INTO `users` (`name`, `hair_color`) VALUES (?, ?), (?, ?)", binds: ["Sean", Some("black"), "Tess", None] }"#
        );
    }
}

#[test]
#[cfg(feature = "postgres")]
fn test_upsert() {
    // this test ensures we get the right debug string for upserts
    use crate::schema::users::dsl::*;

    let values = vec![
        (name.eq("Sean"), hair_color.eq(Some("black"))),
        (name.eq("Tess"), hair_color.eq(None::<&str>)),
    ];

    let upsert_command_single_where = insert_into(users)
        .values(values)
        .on_conflict(hair_color)
        .filter_target(hair_color.eq(Some("black")))
        .do_nothing();
    let upsert_single_where_sql_display =
        debug_query::<TestBackend, _>(&upsert_command_single_where).to_string();

    assert_eq!(
        upsert_single_where_sql_display,
        r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE "users"."hair_color" = $5 DO NOTHING -- binds: ["Sean", Some("black"), "Tess", None, Some("black")]"#
    );

    // let upsert_command_second_where = insert_into(users)
    //     .values(values)
    //     .on_conflict(hair_color)
    //     .filter_target(name.eq(Some("Sean")))
    //     .filter_target(hair_color.eq(Some("black")))
    //     .do_nothing();

    // let upsert_second_where_sql_display =
    //     debug_query::<TestBackend, _>(&upsert_command_second_where).to_string();

    // assert_eq!(
    //     upsert_second_where_sql_display,
    //     r#"INSERT INTO "users" ("name", "hair_color") VALUES ($1, $2), ($3, $4) ON CONFLICT ("hair_color") WHERE "users"."hair_color" = $5 and WHERE "users"."name" = $6 DO NOTHING -- binds: ["Sean", Some("black"), "Tess", None, Some("black"), Some("Sean")]"#
    // );
}
<|endoftext|>


<commit_before>mod js_obj;
mod js_type;

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

// `undefined`
pub struct JsUndef;
// `null`
pub struct JsNull;
// `bool`
pub struct JsBool(bool);
// `number`
pub struct JsNum(f64);
// `symbol`
pub struct JsSym(String);
// `array`
pub type JsArr<JsT> = Vec<Box<JsT>>;

// `string`
pub struct JsStr {
    text: String,
}

impl JsStr {
    const MAX_STR_LEN: u64 = 9007199254740991; // 2^53 - 1

    fn new(s: &str) -> JsStr {
        assert!((s.len() as u64) < JsStr::MAX_STR_LEN);
        JsStr { text: s.to_string(), }
    }
}

<commit_msg>Add JsTrait impls & fix pub visibility on js_primitive types<commit_after>use std::string::String;
use std::vec::Vec;
use js_types::js_type::{JsTrait, JsT};

// `undefined`
pub struct JsUndef;
impl JsTrait for JsUndef {}

// `null`
pub struct JsNull;
impl JsTrait for JsNull {}

// `bool`
pub struct JsBool(pub bool);
impl JsTrait for JsBool {}

// `number`
pub struct JsNum(pub f64);
impl JsTrait for JsNum {}

// `symbol`
pub struct JsSym(pub String);
impl JsTrait for JsSym {}

// `array`
pub type JsArr<T> = Vec<T>;
impl<T> JsTrait for JsArr<T> {}

// `string`
pub struct JsStr {
    text: String,
}

impl JsStr {
    const MAX_STR_LEN: u64 = 9007199254740991; // 2^53 - 1

    pub fn new(s: &str) -> JsStr {
        assert!((s.len() as u64) < JsStr::MAX_STR_LEN);
        JsStr { text: s.to_string(), }
    }
}

impl JsTrait for JsStr {}

<|endoftext|>


<commit_before>use std::io;
use byteorder::{ReadBytesExt, WriteBytesExt, NetworkEndian};
use super::super::{ReadFrom, WriteTo, ReadError};

/// ts: i64 | id: u16
#[derive(Debug)]
pub struct EntryAdded {
    timestamp: i64,
    id: u16,
}

impl EntryAdded {
    pub fn new(timestamp: i64, id: u16) -> Self {
        EntryAdded { timestamp, id }
    }

    pub fn timestamp(&self) -> i64 {
        self.timestamp
    }

    pub fn id(&self) -> u16 {
        self.id
    }
}

impl ReadFrom for EntryAdded {
    fn read_from<R: io::Read>(source: &mut R) -> Result<Self, ReadError> {
        let timestamp = source.read_i64::<NetworkEndian>()?;
        let id = source.read_u16::<NetworkEndian>()?;

        Ok(EntryAdded::new(timestamp, id))
    }
}

impl WriteTo for EntryAdded {
    fn write_to<W: io::Write>(&self, target: &mut W) -> io::Result<()> {
        target.write_i64::<NetworkEndian>(self.timestamp)?;
        target.write_u16::<NetworkEndian>(self.id)?;

        Ok(())
    }
}

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

    #[test]
    fn test_write() {
        let msg = Message::EntryAdded(EntryAdded::new(12345, 23));
        let mut vec = Vec::<u8>::new();

        assert!(msg.write_to(&mut vec).is_ok());

        assert_eq!(
            vec![
                /* cmd */ 4,
                /* ts  */ 0, 0, 0, 0, 0, 0, 48, 57,
                /* id  */ 0, 23,
            ],
            vec
        );
    }

    #[test]
    fn test_read() {
        let mut vec: Vec<u8> = vec![
            /* ts  */ 0, 0, 0, 0, 0, 0, 48, 57,
            /* id  */ 0, 23,
        ];

        let msg = EntryAdded::read_from(&mut vec.as_mut_slice().as_ref()).unwrap();

        assert_eq!(12345, msg.timestamp());
        assert_eq!(23, msg.id());
    }
}<commit_msg>Fix tests<commit_after>use std::io;
use byteorder::{ReadBytesExt, WriteBytesExt, NetworkEndian};
use super::super::{ReadFrom, WriteTo, ReadError};

/// ts: i64 | id: u16
#[derive(Debug)]
pub struct EntryAdded {
    timestamp: i64,
    id: u16,
}

impl EntryAdded {
    pub fn new(timestamp: i64, id: u16) -> Self {
        EntryAdded { timestamp, id }
    }

    pub fn timestamp(&self) -> i64 {
        self.timestamp
    }

    pub fn id(&self) -> u16 {
        self.id
    }
}

impl ReadFrom for EntryAdded {
    fn read_from<R: io::Read>(source: &mut R) -> Result<Self, ReadError> {
        let timestamp = source.read_i64::<NetworkEndian>()?;
        let id = source.read_u16::<NetworkEndian>()?;

        Ok(EntryAdded::new(timestamp, id))
    }
}

impl WriteTo for EntryAdded {
    fn write_to<W: io::Write>(&self, target: &mut W) -> io::Result<()> {
        target.write_i64::<NetworkEndian>(self.timestamp)?;
        target.write_u16::<NetworkEndian>(self.id)?;

        Ok(())
    }
}

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

    #[test]
    fn test_write() {
        let msg = EntryAdded::new(12345, 23);
        let mut vec = Vec::<u8>::new();

        assert!(msg.write_to(&mut vec).is_ok());

        assert_eq!(
            vec![
                /* ts  */ 0, 0, 0, 0, 0, 0, 48, 57,
                /* id  */ 0, 23,
            ],
            vec
        );
    }

    #[test]
    fn test_read() {
        let mut vec: Vec<u8> = vec![
            /* ts  */ 0, 0, 0, 0, 0, 0, 48, 57,
            /* id  */ 0, 23,
        ];

        let msg = EntryAdded::read_from(&mut vec.as_mut_slice().as_ref()).unwrap();

        assert_eq!(12345, msg.timestamp());
        assert_eq!(23, msg.id());
    }
}<|endoftext|>


<commit_before>//! Platform-independent platform abstraction
//!
//! This is the platform-independent portion of the standard library's
//! platform abstraction layer, whereas `std::sys` is the
//! platform-specific portion.
//!
//! The relationship between `std::sys_common`, `std::sys` and the
//! rest of `std` is complex, with dependencies going in all
//! directions: `std` depending on `sys_common`, `sys_common`
//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
//! Ideally `sys_common` would be split into two and the dependencies
//! between them all would form a dag, facilitating the extraction of
//! `std::sys` from the standard library.

#![allow(missing_docs)]
#![allow(missing_debug_implementations)]

use crate::sync::Once;
use crate::sys;

macro_rules! rtabort {
    ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
}

macro_rules! rtassert {
    ($e:expr) => {
        if !$e {
            rtabort!(concat!("assertion failed: ", stringify!($e)));
        }
    };
}

#[allow(unused_macros)] // not used on all platforms
macro_rules! rtunwrap {
    ($ok:ident, $e:expr) => {
        match $e {
            $ok(v) => v,
            ref err => {
                let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
                rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
            }
        }
    };
}

pub mod alloc;
pub mod at_exit_imp;
pub mod backtrace;
pub mod bytestring;
pub mod condvar;
pub mod fs;
pub mod io;
pub mod mutex;
#[cfg(any(doc, // see `mod os`, docs are generated for multiple platforms
          unix,
          target_os = "redox",
          target_os = "cloudabi",
          target_os = "hermit",
          target_arch = "wasm32",
          feature = "restricted-std",
          all(target_vendor = "fortanix", target_env = "sgx")))]
pub mod os_str_bytes;
pub mod poison;
pub mod process;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod util;
pub mod wtf8;

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "cloudabi",
                 target_os = "l4re",
                 target_os = "hermit",
                 feature = "restricted-std",
                 all(target_arch = "wasm32", not(target_os = "emscripten")),
                 all(target_vendor = "fortanix", target_env = "sgx")))] {
        pub use crate::sys::net;
    } else {
        pub mod net;
    }
}

// common error constructors

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInner<Inner: ?Sized> {
    fn as_inner(&self) -> &Inner;
}

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInnerMut<Inner: ?Sized> {
    fn as_inner_mut(&mut self) -> &mut Inner;
}

/// A trait for extracting representations from std types
#[doc(hidden)]
pub trait IntoInner<Inner> {
    fn into_inner(self) -> Inner;
}

/// A trait for creating std types from internal representations
#[doc(hidden)]
pub trait FromInner<Inner> {
    fn from_inner(inner: Inner) -> Self;
}

/// Enqueues a procedure to run when the main thread exits.
///
/// Currently these closures are only run once the main *Rust* thread exits.
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
/// infinitely so. Eventually a handler registration will be forced to fail.
///
/// Returns `Ok` if the handler was successfully registered, meaning that the
/// closure will be run once the main thread exits. Returns `Err` to indicate
/// that the closure could not be registered, meaning that it is not scheduled
/// to be run.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
    if at_exit_imp::push(Box::new(f)) { Ok(()) } else { Err(()) }
}

/// One-time runtime cleanup.
pub fn cleanup() {
    static CLEANUP: Once = Once::new();
    CLEANUP.call_once(|| unsafe {
        sys::args::cleanup();
        sys::stack_overflow::cleanup();
        at_exit_imp::cleanup();
    });
}

// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
#[allow(dead_code)] // not used on all platforms
pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
    let q = value / denom;
    let r = value % denom;
    // Decompose value as (value/denom*denom + value%denom),
    // substitute into (value*numer)/denom and simplify.
    // r < denom, so (denom*numer) is the upper bound of (r*numer)
    q * numer + r * numer / denom
}

#[test]
fn test_muldiv() {
    assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
}
<commit_msg>Simplify os_str_bytes cfg expression.<commit_after>//! Platform-independent platform abstraction
//!
//! This is the platform-independent portion of the standard library's
//! platform abstraction layer, whereas `std::sys` is the
//! platform-specific portion.
//!
//! The relationship between `std::sys_common`, `std::sys` and the
//! rest of `std` is complex, with dependencies going in all
//! directions: `std` depending on `sys_common`, `sys_common`
//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
//! Ideally `sys_common` would be split into two and the dependencies
//! between them all would form a dag, facilitating the extraction of
//! `std::sys` from the standard library.

#![allow(missing_docs)]
#![allow(missing_debug_implementations)]

use crate::sync::Once;
use crate::sys;

macro_rules! rtabort {
    ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
}

macro_rules! rtassert {
    ($e:expr) => {
        if !$e {
            rtabort!(concat!("assertion failed: ", stringify!($e)));
        }
    };
}

#[allow(unused_macros)] // not used on all platforms
macro_rules! rtunwrap {
    ($ok:ident, $e:expr) => {
        match $e {
            $ok(v) => v,
            ref err => {
                let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
                rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
            }
        }
    };
}

pub mod alloc;
pub mod at_exit_imp;
pub mod backtrace;
pub mod bytestring;
pub mod condvar;
pub mod fs;
pub mod io;
pub mod mutex;
// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
// when generating documentation.
#[cfg(any(doc, not(windows)))]
pub mod os_str_bytes;
pub mod poison;
pub mod process;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod util;
pub mod wtf8;

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "cloudabi",
                 target_os = "l4re",
                 target_os = "hermit",
                 feature = "restricted-std",
                 all(target_arch = "wasm32", not(target_os = "emscripten")),
                 all(target_vendor = "fortanix", target_env = "sgx")))] {
        pub use crate::sys::net;
    } else {
        pub mod net;
    }
}

// common error constructors

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInner<Inner: ?Sized> {
    fn as_inner(&self) -> &Inner;
}

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInnerMut<Inner: ?Sized> {
    fn as_inner_mut(&mut self) -> &mut Inner;
}

/// A trait for extracting representations from std types
#[doc(hidden)]
pub trait IntoInner<Inner> {
    fn into_inner(self) -> Inner;
}

/// A trait for creating std types from internal representations
#[doc(hidden)]
pub trait FromInner<Inner> {
    fn from_inner(inner: Inner) -> Self;
}

/// Enqueues a procedure to run when the main thread exits.
///
/// Currently these closures are only run once the main *Rust* thread exits.
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
/// infinitely so. Eventually a handler registration will be forced to fail.
///
/// Returns `Ok` if the handler was successfully registered, meaning that the
/// closure will be run once the main thread exits. Returns `Err` to indicate
/// that the closure could not be registered, meaning that it is not scheduled
/// to be run.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
    if at_exit_imp::push(Box::new(f)) { Ok(()) } else { Err(()) }
}

/// One-time runtime cleanup.
pub fn cleanup() {
    static CLEANUP: Once = Once::new();
    CLEANUP.call_once(|| unsafe {
        sys::args::cleanup();
        sys::stack_overflow::cleanup();
        at_exit_imp::cleanup();
    });
}

// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
#[allow(dead_code)] // not used on all platforms
pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
    let q = value / denom;
    let r = value % denom;
    // Decompose value as (value/denom*denom + value%denom),
    // substitute into (value*numer)/denom and simplify.
    // r < denom, so (denom*numer) is the upper bound of (r*numer)
    q * numer + r * numer / denom
}

#[test]
fn test_muldiv() {
    assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
}
<|endoftext|>


<commit_before>//! The default matrix data storage allocator.
//!
//! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.

use std::cmp;
use std::mem;
use std::ops::Mul;
use std::ptr;

#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec;

use generic_array::ArrayLength;
use typenum::Prod;

use crate::base::allocator::{Allocator, Reallocator};
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{Dim, DimName};
use crate::base::array_storage::ArrayStorage;
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage;
use crate::base::storage::{Storage, StorageMut};
use crate::base::Scalar;

/*
 *
 * Allocator.
 *
 */
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
/// matrices respectively.
pub struct DefaultAllocator;

// Static - Static
impl<N, R, C> Allocator<N, R, C> for DefaultAllocator
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Buffer = ArrayStorage<N, R, C>;

    #[inline]
    unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
        mem::MaybeUninit::uninit().assume_init()
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: R,
        ncols: C,
        iter: I,
    ) -> Self::Buffer
    {
        let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols) };
        let mut count = 0;

        for (res, e) in res.iter_mut().zip(iter.into_iter()) {
            *res = e;
            count += 1;
        }

        assert!(
            count == nrows.value() * ncols.value(),
            "Matrix init. from iterator: iterator not long enough."
        );

        res
    }
}

// Dynamic - Static
// Dynamic - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
    type Buffer = VecStorage<N, Dynamic, C>;

    #[inline]
    unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer {
        let mut res = Vec::new();
        let length = nrows.value() * ncols.value();
        res.reserve_exact(length);
        res.set_len(length);

        VecStorage::new(nrows, ncols, res)
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: Dynamic,
        ncols: C,
        iter: I,
    ) -> Self::Buffer
    {
        let it = iter.into_iter();
        let res: Vec<N> = it.collect();
        assert!(res.len() == nrows.value() * ncols.value(),
                "Allocation from iterator error: the iterator did not yield the correct number of elements.");

        VecStorage::new(nrows, ncols, res)
    }
}

// Static - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
    type Buffer = VecStorage<N, R, Dynamic>;

    #[inline]
    unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer {
        let mut res = Vec::new();
        let length = nrows.value() * ncols.value();
        res.reserve_exact(length);
        res.set_len(length);

        VecStorage::new(nrows, ncols, res)
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: R,
        ncols: Dynamic,
        iter: I,
    ) -> Self::Buffer
    {
        let it = iter.into_iter();
        let res: Vec<N> = it.collect();
        assert!(res.len() == nrows.value() * ncols.value(),
                "Allocation from iterator error: the iterator did not yield the correct number of elements.");

        VecStorage::new(nrows, ncols, res)
    }
}

/*
 *
 * Reallocator.
 *
 */
// Anything -> Static × Static
impl<N: Scalar, RFrom, CFrom, RTo, CTo> Reallocator<N, RFrom, CFrom, RTo, CTo> for DefaultAllocator
where
    RFrom: Dim,
    CFrom: Dim,
    RTo: DimName,
    CTo: DimName,
    Self: Allocator<N, RFrom, CFrom>,
    RTo::Value: Mul<CTo::Value>,
    Prod<RTo::Value, CTo::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: CTo,
        buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer,
    ) -> ArrayStorage<N, RTo, CTo>
    {
        let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// Static × Static -> Dynamic × Any
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom, CFrom, CTo> Reallocator<N, RFrom, CFrom, Dynamic, CTo> for DefaultAllocator
where
    RFrom: DimName,
    CFrom: DimName,
    CTo: Dim,
    RFrom::Value: Mul<CFrom::Value>,
    Prod<RFrom::Value, CFrom::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: ArrayStorage<N, RFrom, CFrom>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// Static × Static -> Static × Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom, CFrom, RTo> Reallocator<N, RFrom, CFrom, RTo, Dynamic> for DefaultAllocator
where
    RFrom: DimName,
    CFrom: DimName,
    RTo: DimName,
    RFrom::Value: Mul<CFrom::Value>,
    Prod<RFrom::Value, CFrom::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: ArrayStorage<N, RFrom, CFrom>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// All conversion from a dynamic buffer to a dynamic buffer.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, CFrom: Dim, CTo: Dim> Reallocator<N, Dynamic, CFrom, Dynamic, CTo>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: VecStorage<N, Dynamic, CFrom>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, CFrom: Dim, RTo: DimName> Reallocator<N, Dynamic, CFrom, RTo, Dynamic>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: VecStorage<N, Dynamic, CFrom>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom: DimName, CTo: Dim> Reallocator<N, RFrom, Dynamic, Dynamic, CTo>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: VecStorage<N, RFrom, Dynamic>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom: DimName, RTo: DimName> Reallocator<N, RFrom, Dynamic, RTo, Dynamic>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: VecStorage<N, RFrom, Dynamic>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}
<commit_msg>Be more specific on what is happening here<commit_after>//! The default matrix data storage allocator.
//!
//! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.

use std::cmp;
use std::mem;
use std::ops::Mul;
use std::ptr;

#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec;

use generic_array::ArrayLength;
use typenum::Prod;

use crate::base::allocator::{Allocator, Reallocator};
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{Dim, DimName};
use crate::base::array_storage::ArrayStorage;
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage;
use crate::base::storage::{Storage, StorageMut};
use crate::base::Scalar;

/*
 *
 * Allocator.
 *
 */
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
/// matrices respectively.
pub struct DefaultAllocator;

// Static - Static
impl<N, R, C> Allocator<N, R, C> for DefaultAllocator
where
    N: Scalar,
    R: DimName,
    C: DimName,
    R::Value: Mul<C::Value>,
    Prod<R::Value, C::Value>: ArrayLength<N>,
{
    type Buffer = ArrayStorage<N, R, C>;

    #[inline]
    unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
        mem::MaybeUninit::<Self::Buffer>::uninit().assume_init()
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: R,
        ncols: C,
        iter: I,
    ) -> Self::Buffer
    {
        let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols) };
        let mut count = 0;

        for (res, e) in res.iter_mut().zip(iter.into_iter()) {
            *res = e;
            count += 1;
        }

        assert!(
            count == nrows.value() * ncols.value(),
            "Matrix init. from iterator: iterator not long enough."
        );

        res
    }
}

// Dynamic - Static
// Dynamic - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
    type Buffer = VecStorage<N, Dynamic, C>;

    #[inline]
    unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer {
        let mut res = Vec::new();
        let length = nrows.value() * ncols.value();
        res.reserve_exact(length);
        res.set_len(length);

        VecStorage::new(nrows, ncols, res)
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: Dynamic,
        ncols: C,
        iter: I,
    ) -> Self::Buffer
    {
        let it = iter.into_iter();
        let res: Vec<N> = it.collect();
        assert!(res.len() == nrows.value() * ncols.value(),
                "Allocation from iterator error: the iterator did not yield the correct number of elements.");

        VecStorage::new(nrows, ncols, res)
    }
}

// Static - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
    type Buffer = VecStorage<N, R, Dynamic>;

    #[inline]
    unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer {
        let mut res = Vec::new();
        let length = nrows.value() * ncols.value();
        res.reserve_exact(length);
        res.set_len(length);

        VecStorage::new(nrows, ncols, res)
    }

    #[inline]
    fn allocate_from_iterator<I: IntoIterator<Item = N>>(
        nrows: R,
        ncols: Dynamic,
        iter: I,
    ) -> Self::Buffer
    {
        let it = iter.into_iter();
        let res: Vec<N> = it.collect();
        assert!(res.len() == nrows.value() * ncols.value(),
                "Allocation from iterator error: the iterator did not yield the correct number of elements.");

        VecStorage::new(nrows, ncols, res)
    }
}

/*
 *
 * Reallocator.
 *
 */
// Anything -> Static × Static
impl<N: Scalar, RFrom, CFrom, RTo, CTo> Reallocator<N, RFrom, CFrom, RTo, CTo> for DefaultAllocator
where
    RFrom: Dim,
    CFrom: Dim,
    RTo: DimName,
    CTo: DimName,
    Self: Allocator<N, RFrom, CFrom>,
    RTo::Value: Mul<CTo::Value>,
    Prod<RTo::Value, CTo::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: CTo,
        buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer,
    ) -> ArrayStorage<N, RTo, CTo>
    {
        let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// Static × Static -> Dynamic × Any
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom, CFrom, CTo> Reallocator<N, RFrom, CFrom, Dynamic, CTo> for DefaultAllocator
where
    RFrom: DimName,
    CFrom: DimName,
    CTo: Dim,
    RFrom::Value: Mul<CFrom::Value>,
    Prod<RFrom::Value, CFrom::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: ArrayStorage<N, RFrom, CFrom>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// Static × Static -> Static × Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom, CFrom, RTo> Reallocator<N, RFrom, CFrom, RTo, Dynamic> for DefaultAllocator
where
    RFrom: DimName,
    CFrom: DimName,
    RTo: DimName,
    RFrom::Value: Mul<CFrom::Value>,
    Prod<RFrom::Value, CFrom::Value>: ArrayLength<N>,
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: ArrayStorage<N, RFrom, CFrom>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto);

        let (rfrom, cfrom) = buf.shape();

        let len_from = rfrom.value() * cfrom.value();
        let len_to = rto.value() * cto.value();
        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));

        res
    }
}

// All conversion from a dynamic buffer to a dynamic buffer.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, CFrom: Dim, CTo: Dim> Reallocator<N, Dynamic, CFrom, Dynamic, CTo>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: VecStorage<N, Dynamic, CFrom>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, CFrom: Dim, RTo: DimName> Reallocator<N, Dynamic, CFrom, RTo, Dynamic>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: VecStorage<N, Dynamic, CFrom>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom: DimName, CTo: Dim> Reallocator<N, RFrom, Dynamic, Dynamic, CTo>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: Dynamic,
        cto: CTo,
        buf: VecStorage<N, RFrom, Dynamic>,
    ) -> VecStorage<N, Dynamic, CTo>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, RFrom: DimName, RTo: DimName> Reallocator<N, RFrom, Dynamic, RTo, Dynamic>
    for DefaultAllocator
{
    #[inline]
    unsafe fn reallocate_copy(
        rto: RTo,
        cto: Dynamic,
        buf: VecStorage<N, RFrom, Dynamic>,
    ) -> VecStorage<N, RTo, Dynamic>
    {
        let new_buf = buf.resize(rto.value() * cto.value());
        VecStorage::new(rto, cto, new_buf)
    }
}
<|endoftext|>


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

use syntax::{ast, ast_util, codemap, visit};
use syntax::ast::Public;
use syntax::attr::AttrMetaMethods;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty::expr_ty;
use rustc::middle::{ty, def};
use rustc::middle::typeck::astconv::AstConv;
use rustc::util::ppaux::Repr;

declare_lint!(TRANSMUTE_TYPE_LINT, Allow,
              "Warn and report types being transmuted")
declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects")
declare_lint!(PRIVATIZE, Deny,
              "Allows to enforce private fields for struct definitions")

/// Lint for auditing transmutes
///
/// This lint (off by default, enable with `-W transmute-type-lint`) warns about all the transmutes
/// being used, along with the types they transmute to/from.
pub struct TransmutePass;

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]` values are used correctly.
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a GC pass.
pub struct UnrootedPass;

/// Lint for keeping DOM fields private
///
/// This lint (disable with `-A privatize`/`#[allow(privatize)]`) ensures all types marked with `#[privatize]` have no private fields
pub struct PrivatizePass;

impl LintPass for TransmutePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TRANSMUTE_TYPE_LINT)
    }

    fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) {
        match ex.node {
            ast::ExprCall(ref expr, ref args) => {
                match expr.node {
                    ast::ExprPath(ref path) => {
                        if path.segments.last()
                                        .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute")
                           && args.len() == 1 {
                            let tcx = cx.tcx();
                            cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span,
                                         format!("Transmute from {} to {} detected",
                                                 expr_ty(tcx, ex).repr(tcx),
                                                 expr_ty(tcx, &**args.get(0)).repr(tcx)
                                        ).as_slice());
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

// Checks if a type has the #[must_root] annotation.
// Unwraps pointers as well
// TODO (#3874, sort of): unwrap other types like Vec/Option/HashMap/etc
fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) {
    match ty.node {
        ast::TyBox(ref t) | ast::TyUniq(ref t) |
        ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) |
        ast::TyPtr(ast::MutTy { ty: ref t, ..}) | ast::TyRptr(_, ast::MutTy { ty: ref t, ..}) => lint_unrooted_ty(cx, &**t, warning),
        ast::TyPath(_, _, id) => {
                match cx.tcx.def_map.borrow().get_copy(&id) {
                    def::DefTy(def_id, _) => {
                        if ty::has_attr(cx.tcx, def_id, "must_root") {
                            cx.span_lint(UNROOTED_MUST_ROOT, ty.span, warning);
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
    };
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if cx.tcx.map.expect_item(id).attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                lint_unrooted_ty(cx, &*field.node.ty,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate");
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        lint_unrooted_ty(cx, &*ty.ty,
                                         "Type must be rooted, use #[must_root] on the enum definition to propagate")
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, _id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _) |
            visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => {
                return;
            }
            _ => ()
        }
        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    lint_unrooted_ty(cx, &*arg.ty,
                                     "Type must be rooted")
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let`
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        // Catch the let binding
        let expr = match s.node {
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                        Some(ref e) => &**e,
                        _ => return
                },
                _ => return
            },
            _ => return
        };

        let t = expr_ty(cx.tcx, &*expr);
        match ty::get(t).sty {
            ty::ty_struct(did, _) |
            ty::ty_enum(did, _) => {
                if ty::has_attr(cx.tcx, did, "must_root") {
                    cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                 format!("Expression of type {} must be rooted", t.repr(cx.tcx)).as_slice());
                }
            }
            _ => {}
        }
    }
}

impl LintPass for PrivatizePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRIVATIZE)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if ty::has_attr(cx.tcx, ast_util::local_def(id), "privatize") {
            for field in def.fields.iter() {
                match field.node {
                    ast::StructField_ { kind: ast::NamedField(ident, visibility), .. } if visibility == Public => {
                        cx.span_lint(PRIVATIZE, field.span,
                                     format!("Field {} is public where only private fields are allowed", ident.name).as_slice());
                    }
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>Catch all types of local bindings in check_stmt<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::{ast, ast_util, codemap, visit};
use syntax::ast::Public;
use syntax::attr::AttrMetaMethods;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty::expr_ty;
use rustc::middle::{ty, def};
use rustc::middle::typeck::astconv::AstConv;
use rustc::util::ppaux::Repr;

declare_lint!(TRANSMUTE_TYPE_LINT, Allow,
              "Warn and report types being transmuted")
declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects")
declare_lint!(PRIVATIZE, Deny,
              "Allows to enforce private fields for struct definitions")

/// Lint for auditing transmutes
///
/// This lint (off by default, enable with `-W transmute-type-lint`) warns about all the transmutes
/// being used, along with the types they transmute to/from.
pub struct TransmutePass;

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]` values are used correctly.
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a GC pass.
pub struct UnrootedPass;

/// Lint for keeping DOM fields private
///
/// This lint (disable with `-A privatize`/`#[allow(privatize)]`) ensures all types marked with `#[privatize]` have no private fields
pub struct PrivatizePass;

impl LintPass for TransmutePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TRANSMUTE_TYPE_LINT)
    }

    fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) {
        match ex.node {
            ast::ExprCall(ref expr, ref args) => {
                match expr.node {
                    ast::ExprPath(ref path) => {
                        if path.segments.last()
                                        .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute")
                           && args.len() == 1 {
                            let tcx = cx.tcx();
                            cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span,
                                         format!("Transmute from {} to {} detected",
                                                 expr_ty(tcx, ex).repr(tcx),
                                                 expr_ty(tcx, &**args.get(0)).repr(tcx)
                                        ).as_slice());
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

// Checks if a type has the #[must_root] annotation.
// Unwraps pointers as well
// TODO (#3874, sort of): unwrap other types like Vec/Option/HashMap/etc
fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) {
    match ty.node {
        ast::TyBox(ref t) | ast::TyUniq(ref t) |
        ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) |
        ast::TyPtr(ast::MutTy { ty: ref t, ..}) | ast::TyRptr(_, ast::MutTy { ty: ref t, ..}) => lint_unrooted_ty(cx, &**t, warning),
        ast::TyPath(_, _, id) => {
                match cx.tcx.def_map.borrow().get_copy(&id) {
                    def::DefTy(def_id, _) => {
                        if ty::has_attr(cx.tcx, def_id, "must_root") {
                            cx.span_lint(UNROOTED_MUST_ROOT, ty.span, warning);
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
    };
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if cx.tcx.map.expect_item(id).attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                lint_unrooted_ty(cx, &*field.node.ty,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate");
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        lint_unrooted_ty(cx, &*ty.ty,
                                         "Type must be rooted, use #[must_root] on the enum definition to propagate")
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, _id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _) |
            visit::FkMethod(i, _, _) if i.as_str() == "new" || i.as_str() == "new_inherited" => {
                return;
            }
            _ => ()
        }
        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    lint_unrooted_ty(cx, &*arg.ty,
                                     "Type must be rooted")
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant `
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _) |
                // For loops allow you to bind a return value locally
                ast::ExprForLoop(_, ref e, _, _) => &**e,
                // XXXManishearth look into `if let` once it lands in our rustc
                _ => return
            },
            _ => return
        };

        let t = expr_ty(cx.tcx, &*expr);
        match ty::get(t).sty {
            ty::ty_struct(did, _) |
            ty::ty_enum(did, _) => {
                if ty::has_attr(cx.tcx, did, "must_root") {
                    cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                 format!("Expression of type {} must be rooted", t.repr(cx.tcx)).as_slice());
                }
            }
            _ => {}
        }
    }
}

impl LintPass for PrivatizePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRIVATIZE)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef, _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        if ty::has_attr(cx.tcx, ast_util::local_def(id), "privatize") {
            for field in def.fields.iter() {
                match field.node {
                    ast::StructField_ { kind: ast::NamedField(ident, visibility), .. } if visibility == Public => {
                        cx.span_lint(PRIVATIZE, field.span,
                                     format!("Field {} is public where only private fields are allowed", ident.name).as_slice());
                    }
                    _ => {}
                }
            }
        }
    }
}
<|endoftext|>


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

use std;
use fips;
use git;
use cli::clone::CloneClapOptions;
use types::{DeliveryResult, ExitCode};
use errors::DeliveryError;
use errors::Kind::{MissingSshPubKey, CloneFailed, ProjectNotFound, UnauthorizedAction};
use utils::say::{say, sayln};
use utils::cwd;
use utils::path_ext;
use http::APIClient;
use user::User;
use command::Command;
use config::Config;

pub struct CloneCommand<'n> {
    pub options: &'n CloneClapOptions<'n>,
    pub config: &'n Config,
}

impl<'n> Command for CloneCommand<'n> {
    fn setup(&self, child_processes: &mut Vec<std::process::Child>) -> DeliveryResult<()> {
        try!(fips::setup_and_start_stunnel_if_fips_mode(&self.config, child_processes));
        Ok(())
    }

    fn run(&self) -> DeliveryResult<ExitCode> {
        sayln("green", "Chef Delivery");
        say("white", "Cloning ");
        let delivery_url = try!(self.config.delivery_git_ssh_url());
        let project_root = cwd().join(self.options.project);
        let clone_url = if self.options.git_url.is_empty() {
            delivery_url.clone()
        } else {
            String::from(self.options.git_url)
        };

        say("yellow", &clone_url);
        say("white", " to ");
        sayln("magenta", &format!("{}", self.options.project));

        // Verify if the destination path already exist.
        if path_ext::is_dir(&project_root) {
            let msg  = format!("The destination path '{}' already exists.",
                               project_root.to_str().unwrap());
            return Err(DeliveryError::throw(CloneFailed, Some(msg)))
        }

        if let Some(e) = git::clone(self.options.project, &clone_url).err() {
            debug!("Raw Clone Error: {:?}", e);
            sayln("red", &format!("Unable to clone project '{}'", self.options.project));
            sayln("yellow", "Analyzing reason of failure...");

            // Verify that the user is well configured
            let user = User::load(&self.config, None)?;
            if !user.verify_pub_key() {
                let link = self.config.users_url()?;
                let msg  = format!("The configured user '{}' does not have an ssh_pub_key.\
                            \nPlease login to the Automate server and configure your key \
                            at:\n\t{}", self.config.user()?, link);
                return Err(DeliveryError::throw(MissingSshPubKey, Some(msg)))
            }

            // Does the project exist?
            let o = self.config.organization()?;
            let p = self.options.project;
            if !APIClient::from_config(&self.config)?.project_exists(&o, p) {
                let msg = format!("You can find the list of available projects \
                                  at:\n\t{}", self.config.projects_url()?);
                return Err(
                    DeliveryError::throw(ProjectNotFound(p.to_string()), Some(msg))
                )
            }

            // Is the user powerful enough to perform this action?
            if let Some(ref d) = e.detail {
                if d.find("Unauthorized action").is_some() {
                let link = self.config.users_url()?;
                let msg = format!("Contact an administrator to grant you with appropriate \
                           permissions at the following url:\n\t{}", link);
                    return Err(DeliveryError::throw(UnauthorizedAction, Some(msg)))
                }
            }

            // We dont know what's the problem, throw the normal error
            return Err(e)
        }

        try!(git::create_or_update_delivery_remote(&delivery_url,
                                                   &project_root));
        Ok(0)
    }
}
<commit_msg>reword message when analyzing a clone failure<commit_after>//
// Copyright:: Copyright (c) 2016 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std;
use fips;
use git;
use cli::clone::CloneClapOptions;
use types::{DeliveryResult, ExitCode};
use errors::DeliveryError;
use errors::Kind::{MissingSshPubKey, CloneFailed, ProjectNotFound, UnauthorizedAction};
use utils::say::{say, sayln};
use utils::cwd;
use utils::path_ext;
use http::APIClient;
use user::User;
use command::Command;
use config::Config;

pub struct CloneCommand<'n> {
    pub options: &'n CloneClapOptions<'n>,
    pub config: &'n Config,
}

impl<'n> Command for CloneCommand<'n> {
    fn setup(&self, child_processes: &mut Vec<std::process::Child>) -> DeliveryResult<()> {
        try!(fips::setup_and_start_stunnel_if_fips_mode(&self.config, child_processes));
        Ok(())
    }

    fn run(&self) -> DeliveryResult<ExitCode> {
        sayln("green", "Chef Delivery");
        say("white", "Cloning ");
        let delivery_url = try!(self.config.delivery_git_ssh_url());
        let project_root = cwd().join(self.options.project);
        let clone_url = if self.options.git_url.is_empty() {
            delivery_url.clone()
        } else {
            String::from(self.options.git_url)
        };

        say("yellow", &clone_url);
        say("white", " to ");
        sayln("magenta", &format!("{}", self.options.project));

        // Verify if the destination path already exist.
        if path_ext::is_dir(&project_root) {
            let msg  = format!("The destination path '{}' already exists.",
                               project_root.to_str().unwrap());
            return Err(DeliveryError::throw(CloneFailed, Some(msg)))
        }

        if let Some(e) = git::clone(self.options.project, &clone_url).err() {
            debug!("Raw Clone Error: {:?}", e);
            sayln("red", &format!("Unable to clone project '{}'", self.options.project));
            sayln("yellow", "Analyzing error:");

            // Verify that the user is well configured
            let user = User::load(&self.config, None)?;
            if !user.verify_pub_key() {
                let link = self.config.users_url()?;
                let msg  = format!("The configured user '{}' does not have an ssh_pub_key.\
                            \nPlease login to the Automate server and configure your key \
                            at:\n\t{}", self.config.user()?, link);
                return Err(DeliveryError::throw(MissingSshPubKey, Some(msg)))
            }

            // Does the project exist?
            let o = self.config.organization()?;
            let p = self.options.project;
            if !APIClient::from_config(&self.config)?.project_exists(&o, p) {
                let msg = format!("You can find the list of available projects \
                                  at:\n\t{}", self.config.projects_url()?);
                return Err(
                    DeliveryError::throw(ProjectNotFound(p.to_string()), Some(msg))
                )
            }

            // Is the user powerful enough to perform this action?
            if let Some(ref d) = e.detail {
                if d.find("Unauthorized action").is_some() {
                let link = self.config.users_url()?;
                let msg = format!("Contact an administrator to grant you with appropriate \
                           permissions at the following url:\n\t{}", link);
                    return Err(DeliveryError::throw(UnauthorizedAction, Some(msg)))
                }
            }

            // We dont know what's the problem, throw the normal error
            return Err(e)
        }

        try!(git::create_or_update_delivery_remote(&delivery_url,
                                                   &project_root));
        Ok(0)
    }
}
<|endoftext|>


<commit_before>

#[allow(dead_code)]
pub fn fibonacci(i: u64) -> u64  {
    match i {
        0 => 0,
        1 => 1,
        n => fibonacci(n-2) + fibonacci(n-1)
    }
}

#[allow(dead_code)]
pub fn sum_of_even_fibonacci_up_to(n: u64) -> u64 {
    let mut sum = 0;
    let mut i = 0;
    let mut fib: u64 = 0;
    while fib <= n {
        if fib % 2 == 0 {
            sum = sum+fib;
        }
        fib = fibonacci(i);
        i = i+1;
    }
    sum
}

#[allow(dead_code)]
pub fn sum_of_even_fibonacci_up_to_fun(n: u64) -> u64 {
    let series = (0..).map(|i| fibonacci(i)).filter(|f| f % 2 == 0).take_while(|f| f <= &n);
    series.fold(0, |sum, n| sum + n)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn first() {
        assert_eq!(fibonacci(0), 0);
    }

    #[test]
    fn second() {
        assert_eq!(fibonacci(1), 1);
    }

    #[test]
    fn remote() {
        assert_eq!(fibonacci(12), 144);
    }

    #[test]
    fn sum_up_to_ten() {
        assert_eq!(sum_of_even_fibonacci_up_to(10), 10);
    }

    #[test]
    fn sum_up_to_four_million() {
        assert_eq!(sum_of_even_fibonacci_up_to(4000000),4613732 );
    }

    #[test]
    fn sum_up_to_four_million_fun() {
        assert_eq!(sum_of_even_fibonacci_up_to_fun(4000000),4613732 );
    }
}

<commit_msg>clarified<commit_after>

#[allow(dead_code)]
pub fn fibonacci(i: u64) -> u64 {
    match i {
        0 => 0,
        1 => 1,
        n => fibonacci(n - 2) + fibonacci(n - 1),
    }
}

#[allow(dead_code)]
pub fn sum_of_even_fibonacci_up_to(n: u64) -> u64 {
    let mut sum = 0;
    let mut i = 0;
    let mut fib = 0;
    while fib <= n {
        if fib % 2 == 0 {
            sum = sum + fib;
        }
        fib = fibonacci(i);
        i = i + 1;
    }
    sum
}

#[allow(dead_code)]
pub fn sum_of_even_fibonacci_up_to_fun(threshold: u64) -> u64 {
    let integrals = 0..;
    let fibonacci = integrals.map(|i| fibonacci(i));
    let even = fibonacci.filter(|f| f % 2 == 0);
    let up_to = even.take_while(|f| f <= &threshold);
    up_to.fold(0, |sum, n| sum + n)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn first() {
        assert_eq!(fibonacci(0), 0);
    }

    #[test]
    fn second() {
        assert_eq!(fibonacci(1), 1);
    }

    #[test]
    fn remote() {
        assert_eq!(fibonacci(12), 144);
    }

    #[test]
    fn sum_up_to_ten() {
        assert_eq!(sum_of_even_fibonacci_up_to(10), 10);
    }

    #[test]
    fn sum_up_to_four_million() {
        assert_eq!(sum_of_even_fibonacci_up_to(4000000), 4613732);
    }

    #[test]
    fn sum_up_to_four_million_fun() {
        assert_eq!(sum_of_even_fibonacci_up_to_fun(4000000), 4613732);
    }
}
<|endoftext|>


<commit_before>use rustc_data_structures::vec_map::VecMap;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;

use super::RegionInferenceContext;

impl<'tcx> RegionInferenceContext<'tcx> {
    /// Resolve any opaque types that were encountered while borrow checking
    /// this item. This is then used to get the type in the `type_of` query.
    ///
    /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
    /// This is lowered to give HIR something like
    ///
    /// type f<'a>::_Return<'_a> = impl Sized + '_a;
    /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
    ///
    /// When checking the return type record the type from the return and the
    /// type used in the return value. In this case they might be `_Return<'1>`
    /// and `&'2 i32` respectively.
    ///
    /// Once we to this method, we have completed region inference and want to
    /// call `infer_opaque_definition_from_instantiation` to get the inferred
    /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
    /// compares lifetimes directly, so we need to map the inference variables
    /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
    ///
    /// First we map all the lifetimes in the concrete type to an equal
    /// universal region that occurs in the concrete type's substs, in this case
    /// this would result in `&'1 i32`. We only consider regions in the substs
    /// in case there is an equal region that does not. For example, this should
    /// be allowed:
    /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
    ///
    /// Then we map the regions in both the type and the subst to their
    /// `external_name` giving `concrete_type = &'a i32`,
    /// `substs = ['static, 'a]`. This will then allow
    /// `infer_opaque_definition_from_instantiation` to determine that
    /// `_Return<'_a> = &'_a i32`.
    ///
    /// There's a slight complication around closures. Given
    /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
    /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
    /// ignored by type checking so ends up being inferred to an empty region.
    /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
    /// which has no `external_name` in which case we use `'empty` as the
    /// region to pass to `infer_opaque_definition_from_instantiation`.
    #[instrument(skip(self, infcx))]
    pub(in crate::borrow_check) fn infer_opaque_types(
        &self,
        infcx: &InferCtxt<'_, 'tcx>,
        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
        span: Span,
    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
        opaque_ty_decls
            .into_iter()
            .map(|(opaque_type_key, concrete_type)| {
                let substs = opaque_type_key.substs;
                debug!(?concrete_type, ?substs);

                let mut subst_regions = vec![self.universal_regions.fr_static];
                let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
                    let vid = self.universal_regions.to_region_vid(region);
                    subst_regions.push(vid);
                    self.definitions[vid].external_name.unwrap_or_else(|| {
                        infcx
                            .tcx
                            .sess
                            .delay_span_bug(span, "opaque type with non-universal region substs");
                        infcx.tcx.lifetimes.re_static
                    })
                });

                subst_regions.sort();
                subst_regions.dedup();

                let universal_concrete_type =
                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
                        ty::ReVar(vid) => subst_regions
                            .iter()
                            .find(|ur_vid| self.eval_equal(vid, **ur_vid))
                            .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
                            .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
                        ty::ReLateBound(..) => region,
                        ty::ReStatic => region,
                        _ => {
                            infcx.tcx.sess.delay_span_bug(
                                span,
                                &format!("unexpected concrete region in borrowck: {:?}", region),
                            );
                            region
                        }
                    });

                debug!(?universal_concrete_type, ?universal_substs);

                let opaque_type_key =
                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
                let remapped_type = infcx.infer_opaque_definition_from_instantiation(
                    opaque_type_key,
                    universal_concrete_type,
                    span,
                );
                (opaque_type_key, remapped_type)
            })
            .collect()
    }

    /// Map the regions in the type to named regions. This is similar to what
    /// `infer_opaque_types` does, but can infer any universal region, not only
    /// ones from the substs for the opaque type. It also doesn't double check
    /// that the regions produced are in fact equal to the named region they are
    /// replaced with. This is fine because this function is only to improve the
    /// region names in error messages.
    pub(in crate::borrow_check) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        tcx.fold_regions(ty, &mut false, |region, _| match *region {
            ty::ReVar(vid) => {
                // Find something that we can name
                let upper_bound = self.approx_universal_upper_bound(vid);
                self.definitions[upper_bound].external_name.unwrap_or(region)
            }
            _ => region,
        })
    }
}
<commit_msg>Auto merge of #88533 - oli-obk:tait_🧊, r=spastorino<commit_after>use rustc_data_structures::vec_map::VecMap;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;

use super::RegionInferenceContext;

impl<'tcx> RegionInferenceContext<'tcx> {
    /// Resolve any opaque types that were encountered while borrow checking
    /// this item. This is then used to get the type in the `type_of` query.
    ///
    /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
    /// This is lowered to give HIR something like
    ///
    /// type f<'a>::_Return<'_a> = impl Sized + '_a;
    /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
    ///
    /// When checking the return type record the type from the return and the
    /// type used in the return value. In this case they might be `_Return<'1>`
    /// and `&'2 i32` respectively.
    ///
    /// Once we to this method, we have completed region inference and want to
    /// call `infer_opaque_definition_from_instantiation` to get the inferred
    /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
    /// compares lifetimes directly, so we need to map the inference variables
    /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
    ///
    /// First we map all the lifetimes in the concrete type to an equal
    /// universal region that occurs in the concrete type's substs, in this case
    /// this would result in `&'1 i32`. We only consider regions in the substs
    /// in case there is an equal region that does not. For example, this should
    /// be allowed:
    /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
    ///
    /// Then we map the regions in both the type and the subst to their
    /// `external_name` giving `concrete_type = &'a i32`,
    /// `substs = ['static, 'a]`. This will then allow
    /// `infer_opaque_definition_from_instantiation` to determine that
    /// `_Return<'_a> = &'_a i32`.
    ///
    /// There's a slight complication around closures. Given
    /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
    /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
    /// ignored by type checking so ends up being inferred to an empty region.
    /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
    /// which has no `external_name` in which case we use `'empty` as the
    /// region to pass to `infer_opaque_definition_from_instantiation`.
    #[instrument(skip(self, infcx))]
    pub(in crate::borrow_check) fn infer_opaque_types(
        &self,
        infcx: &InferCtxt<'_, 'tcx>,
        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
        span: Span,
    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
        opaque_ty_decls
            .into_iter()
            .map(|(opaque_type_key, concrete_type)| {
                let substs = opaque_type_key.substs;
                debug!(?concrete_type, ?substs);

                let mut subst_regions = vec![self.universal_regions.fr_static];
                let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
                    let vid = self.universal_regions.to_region_vid(region);
                    subst_regions.push(vid);
                    self.definitions[vid].external_name.unwrap_or_else(|| {
                        infcx
                            .tcx
                            .sess
                            .delay_span_bug(span, "opaque type with non-universal region substs");
                        infcx.tcx.lifetimes.re_static
                    })
                });

                subst_regions.sort();
                subst_regions.dedup();

                let universal_concrete_type =
                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
                        ty::ReVar(vid) => subst_regions
                            .iter()
                            .find(|ur_vid| self.eval_equal(vid, **ur_vid))
                            .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
                            .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
                        _ => region,
                    });

                debug!(?universal_concrete_type, ?universal_substs);

                let opaque_type_key =
                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
                let remapped_type = infcx.infer_opaque_definition_from_instantiation(
                    opaque_type_key,
                    universal_concrete_type,
                    span,
                );
                (opaque_type_key, remapped_type)
            })
            .collect()
    }

    /// Map the regions in the type to named regions. This is similar to what
    /// `infer_opaque_types` does, but can infer any universal region, not only
    /// ones from the substs for the opaque type. It also doesn't double check
    /// that the regions produced are in fact equal to the named region they are
    /// replaced with. This is fine because this function is only to improve the
    /// region names in error messages.
    pub(in crate::borrow_check) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        tcx.fold_regions(ty, &mut false, |region, _| match *region {
            ty::ReVar(vid) => {
                // Find something that we can name
                let upper_bound = self.approx_universal_upper_bound(vid);
                self.definitions[upper_bound].external_name.unwrap_or(region)
            }
            _ => region,
        })
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
tag!(lsb       "[".as_bytes());
tag!(rsb       "]".as_bytes());
tag!(equal     "=".as_bytes());

take_until_and_leave!(category_bytes "]".as_bytes());
fn category_name(input: &[u8]) -> IResult<&[u8], &str> {
  category_bytes(input).map_res(str::from_utf8)
}

take_until!(not_equal      "=".as_bytes());
take_until_either_and_leave!(value_bytes "\n;".as_bytes());

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  value_bytes(input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

o!(comment_body     <&[u8], &[u8]>       semicolon ~ [ not_line_ending]);
o!(comment          <&[u8], ()>          comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment    <&[u8], &[u8]>       comment_body);
o!(category         <&[u8], &str>        lsb ~ [ category_name ] ~ rsb ~ opt_multispace);
opt!(opt_multispace <&[u8], &[u8]>       multispace);
opt!(opt_space      <&[u8], &[u8]>       space);

chain!(key_value    <&[u8],(&str,&str)>,
    key: parameter_parser ~
         opt_space        ~
         equal            ~
         opt_space        ~
    val: value_parser     ~
         opt_space        ~
         opt_comment      ~
         opt_multispace   ,
    ||{(key, val)}
);

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,
    category: category            ~
    keys: keys_and_values_wrapper ,
    move ||{(category, keys)}
);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_value_test() {
  let ini_file1 = "value
key =";
  let end = "
key =";

  let res = value_parser(ini_file1.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?})", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(end.as_bytes(),  "value"));

  let ini_file2 = "value;blah
key =";
  let end2 = ";blah
key =";

  let res2 = value_parser(ini_file2.as_bytes());
  println!("{:?}", res2);
  match res2 {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res2, Done(end2.as_bytes(),  "value"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<commit_msg>Adapt the INI parser to optional parsing in chain<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
tag!(lsb       "[".as_bytes());
tag!(rsb       "]".as_bytes());
tag!(equal     "=".as_bytes());

take_until_and_leave!(category_bytes "]".as_bytes());
fn category_name(input: &[u8]) -> IResult<&[u8], &str> {
  category_bytes(input).map_res(str::from_utf8)
}

take_until!(not_equal      "=".as_bytes());
take_until_either_and_leave!(value_bytes "\n;".as_bytes());

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  value_bytes(input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

o!(comment_body     <&[u8], &[u8]>       semicolon ~ [ not_line_ending ]);
o!(comment          <&[u8], ()>          comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment    <&[u8], &[u8]>       comment_body);

chain!(category     <&[u8], &str>,
          lsb             ~
    name: category_name   ~
          rsb             ~
          multispace?     ,
    ||{ name }
);
chain!(key_value    <&[u8],(&str,&str)>,
    key: parameter_parser ~
         space?           ~
         equal            ~
         space?           ~
    val: value_parser     ~
         space?           ~
         comment_body?    ~
         multispace?      ,
    ||{(key, val)}
);

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,
    category: category            ~
    keys: keys_and_values_wrapper ,
    move ||{(category, keys)}
);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_value_test() {
  let ini_file1 = "value
key =";
  let end = "
key =";

  let res = value_parser(ini_file1.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?})", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(end.as_bytes(),  "value"));

  let ini_file2 = "value;blah
key =";
  let end2 = ";blah
key =";

  let res2 = value_parser(ini_file2.as_bytes());
  println!("{:?}", res2);
  match res2 {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res2, Done(end2.as_bytes(),  "value"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<|endoftext|>