<commit_before>///! Busy handler (when the database is locked)
use std::convert::TryInto;
use std::mem;
use std::os::raw::{c_int, c_void};
use std::panic::catch_unwind;
use std::ptr;
use std::time::Duration;

use crate::ffi;
use crate::{Connection, InnerConnection, Result};

impl Connection {
    /// Set a busy handler that sleeps for a specified amount of time when a
    /// table is locked. The handler will sleep multiple times until at
    /// least "ms" milliseconds of sleeping have accumulated.
    ///
    /// Calling this routine with an argument equal to zero turns off all busy
    /// handlers.
    ///
    /// There can only be a single busy handler for a particular database
    /// connection at any given moment. If another busy handler was defined
    /// (using [`busy_handler`](Connection::busy_handler)) prior to calling this routine, that other
    /// busy handler is cleared.
    pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
        let ms: i32 = timeout
            .as_secs()
            .checked_mul(1000)
            .and_then(|t| t.checked_add(timeout.subsec_millis().into()))
            .and_then(|t| t.try_into().ok())
            .expect("too big");
        self.db.borrow_mut().busy_timeout(ms)
    }

    /// Register a callback to handle `SQLITE_BUSY` errors.
    ///
    /// If the busy callback is `None`, then `SQLITE_BUSY is returned
    /// immediately upon encountering the lock.` The argument to the busy
    /// handler callback is the number of times that the
    /// busy handler has been invoked previously for the
    /// same locking event. If the busy callback returns `false`, then no
    /// additional attempts are made to access the
    /// database and `SQLITE_BUSY` is returned to the
    /// application. If the callback returns `true`, then another attempt
    /// is made to access the database and the cycle repeats.
    ///
    /// There can only be a single busy handler defined for each database
    /// connection. Setting a new busy handler clears any previously set
    /// handler. Note that calling [`busy_timeout()`](Connection::busy_timeout) or evaluating `PRAGMA
    /// busy_timeout=N` will change the busy handler and thus
    /// clear any previously set busy handler.
    pub fn busy_handler(&self, callback: Option<fn(i32) -> bool>) -> Result<()> {
        unsafe extern "C" fn busy_handler_callback(p_arg: *mut c_void, count: c_int) -> c_int {
            let handler_fn: fn(i32) -> bool = mem::transmute(p_arg);
            if let Ok(true) = catch_unwind(|| handler_fn(count)) {
                1
            } else {
                0
            }
        }
        let mut c = self.db.borrow_mut();
        let r = match callback {
            Some(f) => unsafe {
                ffi::sqlite3_busy_handler(c.db(), Some(busy_handler_callback), f as *mut c_void)
            },
            None => unsafe { ffi::sqlite3_busy_handler(c.db(), None, ptr::null_mut()) },
        };
        c.decode_result(r)
    }
}

impl InnerConnection {
    #[inline]
    fn busy_timeout(&mut self, timeout: c_int) -> Result<()> {
        let r = unsafe { ffi::sqlite3_busy_timeout(self.db, timeout) };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::mpsc::sync_channel;
    use std::thread;
    use std::time::Duration;

    use crate::{Connection, Error, ErrorCode, Result, TransactionBehavior};

    #[test]
    fn test_default_busy() -> Result<()> {
        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let mut db1 = Connection::open(&path)?;
        let tx1 = db1.transaction_with_behavior(TransactionBehavior::Exclusive)?;
        let db2 = Connection::open(&path)?;
        let r: Result<()> = db2.query_row("PRAGMA schema_version", [], |_| unreachable!());
        match r.unwrap_err() {
            Error::SqliteFailure(err, _) => {
                assert_eq!(err.code, ErrorCode::DatabaseBusy);
            }
            err => panic!("Unexpected error {}", err),
        }
        tx1.rollback()
    }

    #[test]
    #[ignore] // FIXME: unstable
    fn test_busy_timeout() {
        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let db2 = Connection::open(&path).unwrap();
        db2.busy_timeout(Duration::from_secs(1)).unwrap();

        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db1 = Connection::open(&path).unwrap();
            let tx1 = db1
                .transaction_with_behavior(TransactionBehavior::Exclusive)
                .unwrap();
            rx.send(1).unwrap();
            thread::sleep(Duration::from_millis(100));
            tx1.rollback().unwrap();
        });

        assert_eq!(tx.recv().unwrap(), 1);
        let _ = db2
            .query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
            .expect("unexpected error");

        child.join().unwrap();
    }

    #[test]
    #[ignore] // FIXME: unstable
    fn test_busy_handler() {
        static CALLED: AtomicBool = AtomicBool::new(false);
        fn busy_handler(_: i32) -> bool {
            CALLED.store(true, Ordering::Relaxed);
            thread::sleep(Duration::from_millis(100));
            true
        }

        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let db2 = Connection::open(&path).unwrap();
        db2.busy_handler(Some(busy_handler)).unwrap();

        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db1 = Connection::open(&path).unwrap();
            let tx1 = db1
                .transaction_with_behavior(TransactionBehavior::Exclusive)
                .unwrap();
            rx.send(1).unwrap();
            thread::sleep(Duration::from_millis(100));
            tx1.rollback().unwrap();
        });

        assert_eq!(tx.recv().unwrap(), 1);
        let _ = db2
            .query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
            .expect("unexpected error");
        assert_eq!(CALLED.load(Ordering::Relaxed), true);

        child.join().unwrap();
    }
}
<commit_msg>[docs] Fix over-long monospacing of `SQLITE_BUSY`<commit_after>///! Busy handler (when the database is locked)
use std::convert::TryInto;
use std::mem;
use std::os::raw::{c_int, c_void};
use std::panic::catch_unwind;
use std::ptr;
use std::time::Duration;

use crate::ffi;
use crate::{Connection, InnerConnection, Result};

impl Connection {
    /// Set a busy handler that sleeps for a specified amount of time when a
    /// table is locked. The handler will sleep multiple times until at
    /// least "ms" milliseconds of sleeping have accumulated.
    ///
    /// Calling this routine with an argument equal to zero turns off all busy
    /// handlers.
    ///
    /// There can only be a single busy handler for a particular database
    /// connection at any given moment. If another busy handler was defined
    /// (using [`busy_handler`](Connection::busy_handler)) prior to calling this routine, that other
    /// busy handler is cleared.
    pub fn busy_timeout(&self, timeout: Duration) -> Result<()> {
        let ms: i32 = timeout
            .as_secs()
            .checked_mul(1000)
            .and_then(|t| t.checked_add(timeout.subsec_millis().into()))
            .and_then(|t| t.try_into().ok())
            .expect("too big");
        self.db.borrow_mut().busy_timeout(ms)
    }

    /// Register a callback to handle `SQLITE_BUSY` errors.
    ///
    /// If the busy callback is `None`, then `SQLITE_BUSY` is returned
    /// immediately upon encountering the lock. The argument to the busy
    /// handler callback is the number of times that the
    /// busy handler has been invoked previously for the
    /// same locking event. If the busy callback returns `false`, then no
    /// additional attempts are made to access the
    /// database and `SQLITE_BUSY` is returned to the
    /// application. If the callback returns `true`, then another attempt
    /// is made to access the database and the cycle repeats.
    ///
    /// There can only be a single busy handler defined for each database
    /// connection. Setting a new busy handler clears any previously set
    /// handler. Note that calling [`busy_timeout()`](Connection::busy_timeout) or evaluating `PRAGMA
    /// busy_timeout=N` will change the busy handler and thus
    /// clear any previously set busy handler.
    pub fn busy_handler(&self, callback: Option<fn(i32) -> bool>) -> Result<()> {
        unsafe extern "C" fn busy_handler_callback(p_arg: *mut c_void, count: c_int) -> c_int {
            let handler_fn: fn(i32) -> bool = mem::transmute(p_arg);
            if let Ok(true) = catch_unwind(|| handler_fn(count)) {
                1
            } else {
                0
            }
        }
        let mut c = self.db.borrow_mut();
        let r = match callback {
            Some(f) => unsafe {
                ffi::sqlite3_busy_handler(c.db(), Some(busy_handler_callback), f as *mut c_void)
            },
            None => unsafe { ffi::sqlite3_busy_handler(c.db(), None, ptr::null_mut()) },
        };
        c.decode_result(r)
    }
}

impl InnerConnection {
    #[inline]
    fn busy_timeout(&mut self, timeout: c_int) -> Result<()> {
        let r = unsafe { ffi::sqlite3_busy_timeout(self.db, timeout) };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::mpsc::sync_channel;
    use std::thread;
    use std::time::Duration;

    use crate::{Connection, Error, ErrorCode, Result, TransactionBehavior};

    #[test]
    fn test_default_busy() -> Result<()> {
        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let mut db1 = Connection::open(&path)?;
        let tx1 = db1.transaction_with_behavior(TransactionBehavior::Exclusive)?;
        let db2 = Connection::open(&path)?;
        let r: Result<()> = db2.query_row("PRAGMA schema_version", [], |_| unreachable!());
        match r.unwrap_err() {
            Error::SqliteFailure(err, _) => {
                assert_eq!(err.code, ErrorCode::DatabaseBusy);
            }
            err => panic!("Unexpected error {}", err),
        }
        tx1.rollback()
    }

    #[test]
    #[ignore] // FIXME: unstable
    fn test_busy_timeout() {
        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let db2 = Connection::open(&path).unwrap();
        db2.busy_timeout(Duration::from_secs(1)).unwrap();

        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db1 = Connection::open(&path).unwrap();
            let tx1 = db1
                .transaction_with_behavior(TransactionBehavior::Exclusive)
                .unwrap();
            rx.send(1).unwrap();
            thread::sleep(Duration::from_millis(100));
            tx1.rollback().unwrap();
        });

        assert_eq!(tx.recv().unwrap(), 1);
        let _ = db2
            .query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
            .expect("unexpected error");

        child.join().unwrap();
    }

    #[test]
    #[ignore] // FIXME: unstable
    fn test_busy_handler() {
        static CALLED: AtomicBool = AtomicBool::new(false);
        fn busy_handler(_: i32) -> bool {
            CALLED.store(true, Ordering::Relaxed);
            thread::sleep(Duration::from_millis(100));
            true
        }

        let temp_dir = tempfile::tempdir().unwrap();
        let path = temp_dir.path().join("test.db3");

        let db2 = Connection::open(&path).unwrap();
        db2.busy_handler(Some(busy_handler)).unwrap();

        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db1 = Connection::open(&path).unwrap();
            let tx1 = db1
                .transaction_with_behavior(TransactionBehavior::Exclusive)
                .unwrap();
            rx.send(1).unwrap();
            thread::sleep(Duration::from_millis(100));
            tx1.rollback().unwrap();
        });

        assert_eq!(tx.recv().unwrap(), 1);
        let _ = db2
            .query_row("PRAGMA schema_version", [], |row| row.get::<_, i32>(0))
            .expect("unexpected error");
        assert_eq!(CALLED.load(Ordering::Relaxed), true);

        child.join().unwrap();
    }
}
<|endoftext|>


<commit_before><commit_msg>crav1e: lib: Add return types to color properties functions<commit_after><|endoftext|>


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

//! Date and Time Functions — calendrical calculations and miscellaneous time stuff

use libc::{c_int, c_uint};
use ffi;
use std;
use super::translate::ToGlibPtr;

/// Simply a replacement for time_t. It has been deprecated since it is not equivalent to time_t on 64-bit platforms with a 64-bit time_t.
/// Unrelated to GTimer.
///
/// Note that GTime is defined to always be a 32-bit integer, unlike time_t which may be 64-bit on some systems. Therefore, GTime will
/// overflow in the year 2038, and you cannot use the address of a GTime variable as argument to the UNIX time() function.
pub type Time = i32;

/// Integer representing a year; G_DATE_BAD_YEAR is the invalid value. The year must be 1 or higher; negative (BC) years are not allowed.
/// The year is represented with four digits.
pub type Year = u16;
/// Integer representing a day of the month; between 1 and 31. G_DATE_BAD_DAY represents an invalid day of the month.
pub type Day = u8;

/// Enumeration representing a month; values are G_DATE_JANUARY, G_DATE_FEBRUARY, etc. G_DATE_BAD_MONTH is the invalid value.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Month {
    /// invalid value
    BadMonth,
    /// january
    January,
    /// february
    February,
    /// march
    March,
    /// april
    April,
    /// may
    May,
    /// june
    June,
    /// july
    July,
    /// august
    August,
    /// september
    September,
    /// october
    October,
    /// november
    November,
    /// december
    December
}

/// Enumeration representing a day of the week; G_DATE_MONDAY, G_DATE_TUESDAY, etc. G_DATE_BAD_WEEKDAY is an invalid weekday.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Weekday {
    /// invalid value
    BadWeekday,
    /// monday
    Monday,
    /// tuesday
    Tuesday,
    /// wednesday
    Wednesday,
    /// thrusday
    Thursday,
    /// friday
    Friday,
    /// saturday
    Saturday,
    /// sunday
    Sunday
}

pub struct Date {
    pointer: *mut ffi::GDate
}

impl Date {
    pub fn new() -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new() };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_dmy(day: Day, month: Month, year: Year) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_dmy(day as c_int, month as c_int, year) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_julian(julian_day: u32) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_julian(julian_day) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        unsafe { ffi::g_date_clear(self.pointer, 1) }
    }

    pub fn set_day(&mut self, day: Day) {
        unsafe { ffi::g_date_set_day(self.pointer, day as c_int) }
    }

    pub fn set_month(&mut self, month: Month) {
        unsafe { ffi::g_date_set_month(self.pointer, month as c_int) }
    }

    pub fn set_year(&mut self, year: Year) {
        unsafe { ffi::g_date_set_year(self.pointer, year) }
    }

    pub fn set_dmy(&mut self, day: Day, month: Month, year: Year) {
        unsafe { ffi::g_date_set_dmy(self.pointer, day as c_int, month as c_int, year) }
    }

    pub fn set_julian(&mut self, julian: u32) {
        unsafe { ffi::g_date_set_julian(self.pointer, julian) }
    }

    pub fn set_time_t(&mut self, timet: i64) {
        unsafe { ffi::g_date_set_time_t(self.pointer, timet) }
    }

    pub fn set_time_val(&mut self, timeval: &mut TimeVal) {
        unsafe { ffi::g_date_set_time_val(self.pointer, std::mem::transmute(timeval)) }
    }

    pub fn set_parse(&mut self, str_: &str) {
        unsafe { ffi::g_date_set_parse(self.pointer, str_.to_glib_none().0) }
    }

    pub fn add_days(&mut self, days: usize) {
        unsafe { ffi::g_date_add_days(self.pointer, days as c_uint) }
    }

    pub fn subtract_days(&mut self, days: usize) {
        unsafe { ffi::g_date_subtract_days(self.pointer, days as c_uint) }
    }

    pub fn add_months(&mut self, months: usize) {
        unsafe { ffi::g_date_add_months(self.pointer, months as c_uint) }
    }

    pub fn subtract_months(&mut self, months: usize) {
        unsafe { ffi::g_date_subtract_months(self.pointer, months as c_uint) }
    }

    pub fn add_years(&mut self, years: usize) {
        unsafe { ffi::g_date_add_years(self.pointer, years as c_uint) }
    }

    pub fn subtract_years(&mut self, years: usize) {
        unsafe { ffi::g_date_subtract_years(self.pointer, years as c_uint) }
    }

    pub fn between(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_between(self.pointer, other.pointer) as isize }
    }

    pub fn compare(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_compare(self.pointer, other.pointer) as isize   }
    }

    pub fn clamp(&mut self, min_date: &Date, max_date: &Date) {
        unsafe { ffi::g_date_clamp(self.pointer, min_date.pointer, max_date.pointer) }
    }

    pub fn order(&mut self, other: &mut Date) {
        unsafe { ffi::g_date_order(self.pointer, other.pointer) }
    }

    pub fn get_day(&self) -> Day {
        unsafe { ffi::g_date_get_day(self.pointer) }
    }

    pub fn get_month(&self) -> Month {
        unsafe { std::mem::transmute(ffi::g_date_get_month(self.pointer)) }
    }

    pub fn get_year(&self) -> Year {
        unsafe { ffi::g_date_get_year(self.pointer) }
    }

    pub fn get_julian(&self) -> u32 {
        unsafe { ffi::g_date_get_julian(self.pointer) }
    }

    pub fn get_weekday(&self) -> Weekday {
        unsafe { std::mem::transmute(ffi::g_date_get_weekday(self.pointer)) }
    }

    pub fn get_day_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_day_of_year(self.pointer) }
    }

    pub fn is_first_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_first_of_month(self.pointer)) }
    }

    pub fn is_last_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_last_of_month(self.pointer)) }
    }

    pub fn get_monday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_monday_week_of_year(self.pointer) }
    }

    pub fn get_sunday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_sunday_week_of_year(self.pointer) }
    }

    pub fn get_iso8601_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_iso8601_week_of_year(self.pointer) }
    }

    /*pub fn strftime(&self, s: &mut String, format: &str) -> u32 {
        unsafe { ffi::g_date_strftime(self.pointer) }
    }*/

    pub fn is_valid(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_valid(self.pointer)) }
    }
}

impl Drop for Date {
    fn drop(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::g_date_free(self.pointer); }
            self.pointer = std::ptr::null_mut();
        }
    }
}

/// Represents a precise time, with seconds and microseconds. Similar to the struct timeval returned by the gettimeofday() UNIX
/// system call.
///
/// GLib is attempting to unify around the use of 64bit integers to represent microsecond-precision time. As such, this type
/// will be removed from a future version of GLib.
#[repr(C)]
pub struct TimeVal {
    /// seconds
    pub tv_sec: i32,
    /// microseconds
    pub tv_usec: i32
}

impl TimeVal {
    pub fn add(&mut self, microseconds: u64) {
        unsafe { ffi::g_time_val_add(std::mem::transmute(self), microseconds) }
    }

    pub fn from_iso8601(&mut self, iso_date: &str) {
        unsafe { ffi::g_time_val_from_iso8601(iso_date.to_glib_none().0, std::mem::transmute(self)) }
    }

    pub fn to_iso8601(&mut self) -> Option<String> {
        unsafe { ::translate::from_glib_none(ffi::g_time_val_to_iso8601(std::mem::transmute(self))) }
    }
}

pub fn get_current_time() -> TimeVal {
    let mut t = TimeVal {
        tv_sec: 0,
        tv_usec: 0
    };

    unsafe { ffi::g_get_current_time(std::mem::transmute(&mut t)) };
    t
}

pub fn usleep(microseconds: u64) {
    unsafe { ffi::g_usleep(microseconds) }
}

pub fn get_monotonic_time() -> i64 {
    unsafe { ffi::g_get_monotonic_time() }
}

pub fn get_real_time() -> i64 {
    unsafe { ffi::g_get_real_time() }
}

pub fn get_days_in_month(month: Month, year: Year) -> u8 {
    unsafe { ffi::g_date_get_days_in_month(month as c_int, year) }
}

pub fn is_leap_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_is_leap_year(year)) }
}

pub fn get_monday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_monday_weeks_in_year(year) }
}

pub fn get_sunday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_sunday_weeks_in_year(year) }
}

pub fn is_valid_day(day: Day) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_day(day as c_int)) }
}

pub fn is_valid_month(month: Month) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_month(month as c_int)) }
}

pub fn is_valid_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_year(year)) }
}

pub fn is_valid_dmy(day: Day, month: Month, year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_dmy(day as c_int, month as c_int, year)) }
}

pub fn is_valid_julian(julian: u32) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_julian(julian)) }
}

pub fn is_valid_weekday(day: Weekday) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_weekday(day as c_int)) }
}
<commit_msg>Fix the 32-bit build by truncating the microseconds value<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Date and Time Functions — calendrical calculations and miscellaneous time stuff

use libc::{c_int, c_uint, c_ulong};
use ffi;
use std;
use super::translate::ToGlibPtr;

/// Simply a replacement for time_t. It has been deprecated since it is not equivalent to time_t on 64-bit platforms with a 64-bit time_t.
/// Unrelated to GTimer.
///
/// Note that GTime is defined to always be a 32-bit integer, unlike time_t which may be 64-bit on some systems. Therefore, GTime will
/// overflow in the year 2038, and you cannot use the address of a GTime variable as argument to the UNIX time() function.
pub type Time = i32;

/// Integer representing a year; G_DATE_BAD_YEAR is the invalid value. The year must be 1 or higher; negative (BC) years are not allowed.
/// The year is represented with four digits.
pub type Year = u16;
/// Integer representing a day of the month; between 1 and 31. G_DATE_BAD_DAY represents an invalid day of the month.
pub type Day = u8;

/// Enumeration representing a month; values are G_DATE_JANUARY, G_DATE_FEBRUARY, etc. G_DATE_BAD_MONTH is the invalid value.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Month {
    /// invalid value
    BadMonth,
    /// january
    January,
    /// february
    February,
    /// march
    March,
    /// april
    April,
    /// may
    May,
    /// june
    June,
    /// july
    July,
    /// august
    August,
    /// september
    September,
    /// october
    October,
    /// november
    November,
    /// december
    December
}

/// Enumeration representing a day of the week; G_DATE_MONDAY, G_DATE_TUESDAY, etc. G_DATE_BAD_WEEKDAY is an invalid weekday.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Weekday {
    /// invalid value
    BadWeekday,
    /// monday
    Monday,
    /// tuesday
    Tuesday,
    /// wednesday
    Wednesday,
    /// thrusday
    Thursday,
    /// friday
    Friday,
    /// saturday
    Saturday,
    /// sunday
    Sunday
}

pub struct Date {
    pointer: *mut ffi::GDate
}

impl Date {
    pub fn new() -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new() };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_dmy(day: Day, month: Month, year: Year) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_dmy(day as c_int, month as c_int, year) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_julian(julian_day: u32) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_julian(julian_day) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        unsafe { ffi::g_date_clear(self.pointer, 1) }
    }

    pub fn set_day(&mut self, day: Day) {
        unsafe { ffi::g_date_set_day(self.pointer, day as c_int) }
    }

    pub fn set_month(&mut self, month: Month) {
        unsafe { ffi::g_date_set_month(self.pointer, month as c_int) }
    }

    pub fn set_year(&mut self, year: Year) {
        unsafe { ffi::g_date_set_year(self.pointer, year) }
    }

    pub fn set_dmy(&mut self, day: Day, month: Month, year: Year) {
        unsafe { ffi::g_date_set_dmy(self.pointer, day as c_int, month as c_int, year) }
    }

    pub fn set_julian(&mut self, julian: u32) {
        unsafe { ffi::g_date_set_julian(self.pointer, julian) }
    }

    pub fn set_time_t(&mut self, timet: i64) {
        unsafe { ffi::g_date_set_time_t(self.pointer, timet) }
    }

    pub fn set_time_val(&mut self, timeval: &mut TimeVal) {
        unsafe { ffi::g_date_set_time_val(self.pointer, std::mem::transmute(timeval)) }
    }

    pub fn set_parse(&mut self, str_: &str) {
        unsafe { ffi::g_date_set_parse(self.pointer, str_.to_glib_none().0) }
    }

    pub fn add_days(&mut self, days: usize) {
        unsafe { ffi::g_date_add_days(self.pointer, days as c_uint) }
    }

    pub fn subtract_days(&mut self, days: usize) {
        unsafe { ffi::g_date_subtract_days(self.pointer, days as c_uint) }
    }

    pub fn add_months(&mut self, months: usize) {
        unsafe { ffi::g_date_add_months(self.pointer, months as c_uint) }
    }

    pub fn subtract_months(&mut self, months: usize) {
        unsafe { ffi::g_date_subtract_months(self.pointer, months as c_uint) }
    }

    pub fn add_years(&mut self, years: usize) {
        unsafe { ffi::g_date_add_years(self.pointer, years as c_uint) }
    }

    pub fn subtract_years(&mut self, years: usize) {
        unsafe { ffi::g_date_subtract_years(self.pointer, years as c_uint) }
    }

    pub fn between(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_between(self.pointer, other.pointer) as isize }
    }

    pub fn compare(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_compare(self.pointer, other.pointer) as isize   }
    }

    pub fn clamp(&mut self, min_date: &Date, max_date: &Date) {
        unsafe { ffi::g_date_clamp(self.pointer, min_date.pointer, max_date.pointer) }
    }

    pub fn order(&mut self, other: &mut Date) {
        unsafe { ffi::g_date_order(self.pointer, other.pointer) }
    }

    pub fn get_day(&self) -> Day {
        unsafe { ffi::g_date_get_day(self.pointer) }
    }

    pub fn get_month(&self) -> Month {
        unsafe { std::mem::transmute(ffi::g_date_get_month(self.pointer)) }
    }

    pub fn get_year(&self) -> Year {
        unsafe { ffi::g_date_get_year(self.pointer) }
    }

    pub fn get_julian(&self) -> u32 {
        unsafe { ffi::g_date_get_julian(self.pointer) }
    }

    pub fn get_weekday(&self) -> Weekday {
        unsafe { std::mem::transmute(ffi::g_date_get_weekday(self.pointer)) }
    }

    pub fn get_day_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_day_of_year(self.pointer) }
    }

    pub fn is_first_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_first_of_month(self.pointer)) }
    }

    pub fn is_last_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_last_of_month(self.pointer)) }
    }

    pub fn get_monday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_monday_week_of_year(self.pointer) }
    }

    pub fn get_sunday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_sunday_week_of_year(self.pointer) }
    }

    pub fn get_iso8601_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_iso8601_week_of_year(self.pointer) }
    }

    /*pub fn strftime(&self, s: &mut String, format: &str) -> u32 {
        unsafe { ffi::g_date_strftime(self.pointer) }
    }*/

    pub fn is_valid(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_valid(self.pointer)) }
    }
}

impl Drop for Date {
    fn drop(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::g_date_free(self.pointer); }
            self.pointer = std::ptr::null_mut();
        }
    }
}

/// Represents a precise time, with seconds and microseconds. Similar to the struct timeval returned by the gettimeofday() UNIX
/// system call.
///
/// GLib is attempting to unify around the use of 64bit integers to represent microsecond-precision time. As such, this type
/// will be removed from a future version of GLib.
#[repr(C)]
pub struct TimeVal {
    /// seconds
    pub tv_sec: i32,
    /// microseconds
    pub tv_usec: i32
}

impl TimeVal {
    pub fn add(&mut self, microseconds: u64) {
        unsafe { ffi::g_time_val_add(std::mem::transmute(self), microseconds as c_ulong) }
    }

    pub fn from_iso8601(&mut self, iso_date: &str) {
        unsafe { ffi::g_time_val_from_iso8601(iso_date.to_glib_none().0, std::mem::transmute(self)) }
    }

    pub fn to_iso8601(&mut self) -> Option<String> {
        unsafe { ::translate::from_glib_none(ffi::g_time_val_to_iso8601(std::mem::transmute(self))) }
    }
}

pub fn get_current_time() -> TimeVal {
    let mut t = TimeVal {
        tv_sec: 0,
        tv_usec: 0
    };

    unsafe { ffi::g_get_current_time(std::mem::transmute(&mut t)) };
    t
}

pub fn usleep(microseconds: u64) {
    unsafe { ffi::g_usleep(microseconds as c_ulong) }
}

pub fn get_monotonic_time() -> i64 {
    unsafe { ffi::g_get_monotonic_time() }
}

pub fn get_real_time() -> i64 {
    unsafe { ffi::g_get_real_time() }
}

pub fn get_days_in_month(month: Month, year: Year) -> u8 {
    unsafe { ffi::g_date_get_days_in_month(month as c_int, year) }
}

pub fn is_leap_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_is_leap_year(year)) }
}

pub fn get_monday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_monday_weeks_in_year(year) }
}

pub fn get_sunday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_sunday_weeks_in_year(year) }
}

pub fn is_valid_day(day: Day) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_day(day as c_int)) }
}

pub fn is_valid_month(month: Month) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_month(month as c_int)) }
}

pub fn is_valid_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_year(year)) }
}

pub fn is_valid_dmy(day: Day, month: Month, year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_dmy(day as c_int, month as c_int, year)) }
}

pub fn is_valid_julian(julian: u32) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_julian(julian)) }
}

pub fn is_valid_weekday(day: Weekday) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_weekday(day as c_int)) }
}
<|endoftext|>


<commit_before>#[link(name = "tnetstring",
       vers = "0.3",
       uuid = "ce93b70c-c22a-45fa-97a7-66ab97009005")];
#[crate_type = "lib"];

/// Rust TNetStrings serialization library.

use std::f64;
use std::hashmap::HashMap;
use std::io::Decorator;
use std::io::mem::{MemWriter, BufReader};
use std::num::strconv;
use std::str;

/// Represents a TNetString value.
pub enum TNetString {
    Str(~[u8]),
    Int(int),
    Float(f64),
    Bool(bool),
    Null,
    Map(Map),
    Vec(~[TNetString]),
}

pub type Map = ~HashMap<~[u8], TNetString>;

/// Serializes a TNetString value into a `Writer`.
pub fn to_writer(writer: &mut Writer, tnetstring: &TNetString) {
    fn write_str(wr: &mut Writer, s: &[u8]) {
        write!(wr, "{}:", s.len());
        wr.write(s);
        write!(wr, ",");
    }

    match *tnetstring {
        Str(ref s) => {
            write_str(writer, *s);
        }
        Int(i) => {
            let s = i.to_str();
            write!(writer, "{}:{}\\#", s.len(), s);
        }
        Float(f) => {
            let s = f64::to_str_digits(f, 6u);
            write!(writer, "{}:{}^", s.len(), s);
        }
        Bool(b) => {
            let s = b.to_str();
            write!(writer, "{}:{}!", s.len(), s);
        }
        Map(ref m) => {
            let mut wr = MemWriter::new();
            for (key, value) in m.iter() {
                write_str(&mut wr as &mut Writer, *key);
                to_writer(&mut wr as &mut Writer, value);
            }
            let payload = wr.inner();
            write!(writer, "{}:", payload.len());
            writer.write(payload);
            write!(writer, "\\}");
        }
        Vec(ref v) => {
            let mut wr = MemWriter::new();
            for e in v.iter() {
                to_writer(&mut wr as &mut Writer, e)
            }
            let payload = wr.inner();
            write!(writer, "{}:", payload.len());
            writer.write(payload);
            write!(writer, "]");
        }
        Null => {
            write!(writer, "0:~");
        }
    }
}

/// Serializes a TNetString value into a byte string.
pub fn to_bytes(tnetstring: &TNetString) -> ~[u8] {
    let mut wr = MemWriter::new();
    to_writer(&mut wr as &mut Writer, tnetstring);
    wr.inner()
}

/// Serializes a TNetString value into a string.
impl ToStr for TNetString {
    fn to_str(&self) -> ~str {
        str::from_utf8_owned(to_bytes(self))
    }
}

/// Deserializes a `TNetString` value from a `Reader`.
pub fn from_reader<R: Reader + Buffer>(rdr: &mut R) -> Option<TNetString> {
    let mut ch = match rdr.read_byte() {
        Some(ch) => ch,
        None => { return None; }
    };
    let mut len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if ch < '0' as u8 || ch > '9' as u8 {
        fail!("Not a TNetString: invalid or missing length prefix");
    } else if ch == '0' as u8 {
        ch = match rdr.read_byte() {
            Some(ch) => ch,
            None => {
                fail!("Not a TNetString: invalid or missing length prefix");
            }
        };
    } else {
        loop {
            len = (10u * len) + ((ch as uint) - ('0' as uint));

            ch = match rdr.read_byte() {
                Some(ch) => ch,
                None => {
                    fail!("Not a TNetString: invalid or missing length prefix");
                }
            };

            if ch < '0' as u8 || ch > '9' as u8 {
                break;
            }
        }
    }

    // Validate end-of-length-prefix marker.
    if ch != ':' as u8 {
        fail!("Not a TNetString: missing length prefix");
    }

    // Read the data plus terminating type tag.
    let payload = rdr.read_bytes(len);

    if payload.len() != len {
        fail!("Not a TNetString: invalid length prefix");
    }

    let ch = match rdr.read_char() {
        Some(ch) => ch,
        None => {
            fail!("Not a TNetString: missing type tag");
        }
    };

    match ch {
        '#' => {
            let v = strconv::from_str_bytes_common(payload, 10, true, false, false,
                                                   strconv::ExpNone, false, false);
            v.and_then(|v| Some(Int(v)))
        }
        '}' => Some(Map(parse_map(payload))),
        ']' => Some(Vec(parse_vec(payload))),
        '!' => {
            str::from_utf8_owned_opt(payload)
                .and_then(|s| FromStr::from_str(s))
                .and_then(|v| Some(Bool(v)))
        }
        '^' => {
            let v = strconv::from_str_bytes_common(payload, 10u, true, true, true,
                                                   strconv::ExpDec, false, false);
            v.and_then(|v| Some(Float(v)))
        }
        '~' => {
            assert!(payload.is_empty());
            Some(Null)
        }
        ',' => {
            Some(Str(payload))
        }
        ch => {
            fail!(format!("Invalid payload type: {}", ch))
        }
    }
}

fn parse_vec(data: &[u8]) -> ~[TNetString] {
    if data.is_empty() { return ~[]; }

    let mut result = ~[];
    let mut rdr = BufReader::new(data);

    loop {
        match from_reader(&mut rdr) {
            Some(value) => { result.push(value); }
            None => { return result; }
        }
    }
}

fn parse_pair<R: Reader + Buffer>(rdr: &mut R) -> Option<(~[u8], TNetString)> {
    match from_reader(rdr) {
        Some(Str(key)) => {
            match from_reader(rdr) {
                Some(value) => Some((key, value)),
                None => fail!("invalid TNetString"),
            }
        }
        Some(_) => fail!("Keys can only be strings."),
        None => None,
    }
}

fn parse_map(data: &[u8]) -> ~HashMap<~[u8], TNetString> {
    let mut result = ~HashMap::new();
    let mut rdr = BufReader::new(data);

    loop {
        match parse_pair(&mut rdr) {
            Some((key, value)) => { result.insert(key, value); }
            None => { return result; }
        }
    }
}

/// Deserializes a TNetString value from a byte string.
pub fn from_bytes<'a>(data: &'a [u8]) -> (Option<TNetString>, BufReader<'a>) {
    let mut rdr = BufReader::new(data);
    let tnetstring = from_reader(&mut rdr);
    (tnetstring, rdr)
}

/// Deserializes a TNetString value from a string.
pub fn from_str<'a>(data: &'a str) -> (Option<TNetString>, BufReader<'a>) {
    from_bytes(data.as_bytes())
}

/// Test the equality between two TNetString values
impl Eq for TNetString {
    fn eq(&self, other: &TNetString) -> bool {
        match (self, other) {
            (&Str(ref s0), &Str(ref s1)) => s0 == s1,
            (&Int(i0), &Int(i1)) => i0 == i1,
            (&Float(f0), &Float(f1)) => f0 == f1,
            (&Bool(b0), &Bool(b1)) => b0 == b1,
            (&Null, &Null) => true,
            (&Map(ref d0), &Map(ref d1)) => {
                if d0.len() == d1.len() {
                    for (k0, v0) in d0.iter() {
                        // XXX send_map::linear::LinearMap has find_ref, but
                        // that method is not available for HashMap.
                        let result = match d1.find(k0) {
                            Some(v1) => v0 == v1,
                            None => false,
                        };
                        if !result { return false; }
                    }
                    true
                } else {
                    false
                }
            }
            (&Vec(ref v0), &Vec(ref v1)) => {
                v0.eq(v1)
            },
            _ => false
        }
    }

    fn ne(&self, other: &TNetString) -> bool { !self.eq(other) }
}
<commit_msg>Update to rust 0.9-pre (a5fa1d)<commit_after>#[crate_id = "tnetstring#0.3"];

/// Rust TNetStrings serialization library.

use std::f64;
use std::hashmap::HashMap;
use std::io::Decorator;
use std::io::mem::{MemWriter, BufReader};
use std::num::strconv;
use std::str;

/// Represents a TNetString value.
pub enum TNetString {
    Str(~[u8]),
    Int(int),
    Float(f64),
    Bool(bool),
    Null,
    Map(Map),
    Vec(~[TNetString]),
}

pub type Map = ~HashMap<~[u8], TNetString>;

/// Serializes a TNetString value into a `Writer`.
pub fn to_writer(writer: &mut Writer, tnetstring: &TNetString) {
    fn write_str(wr: &mut Writer, s: &[u8]) {
        write!(wr, "{}:", s.len());
        wr.write(s);
        write!(wr, ",");
    }

    match *tnetstring {
        Str(ref s) => {
            write_str(writer, *s);
        }
        Int(i) => {
            let s = i.to_str();
            write!(writer, "{}:{}\\#", s.len(), s);
        }
        Float(f) => {
            let s = f64::to_str_digits(f, 6u);
            write!(writer, "{}:{}^", s.len(), s);
        }
        Bool(b) => {
            let s = b.to_str();
            write!(writer, "{}:{}!", s.len(), s);
        }
        Map(ref m) => {
            let mut wr = MemWriter::new();
            for (key, value) in m.iter() {
                write_str(&mut wr as &mut Writer, *key);
                to_writer(&mut wr as &mut Writer, value);
            }
            let payload = wr.inner();
            write!(writer, "{}:", payload.len());
            writer.write(payload);
            write!(writer, "\\}");
        }
        Vec(ref v) => {
            let mut wr = MemWriter::new();
            for e in v.iter() {
                to_writer(&mut wr as &mut Writer, e)
            }
            let payload = wr.inner();
            write!(writer, "{}:", payload.len());
            writer.write(payload);
            write!(writer, "]");
        }
        Null => {
            write!(writer, "0:~");
        }
    }
}

/// Serializes a TNetString value into a byte string.
pub fn to_bytes(tnetstring: &TNetString) -> ~[u8] {
    let mut wr = MemWriter::new();
    to_writer(&mut wr as &mut Writer, tnetstring);
    wr.inner()
}

/// Serializes a TNetString value into a string.
impl ToStr for TNetString {
    fn to_str(&self) -> ~str {
        str::from_utf8_owned(to_bytes(self))
    }
}

/// Deserializes a `TNetString` value from a `Reader`.
pub fn from_reader<R: Reader + Buffer>(rdr: &mut R) -> Option<TNetString> {
    let mut ch = match rdr.read_byte() {
        Some(ch) => ch,
        None => { return None; }
    };
    let mut len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if ch < '0' as u8 || ch > '9' as u8 {
        fail!("Not a TNetString: invalid or missing length prefix");
    } else if ch == '0' as u8 {
        ch = match rdr.read_byte() {
            Some(ch) => ch,
            None => {
                fail!("Not a TNetString: invalid or missing length prefix");
            }
        };
    } else {
        loop {
            len = (10u * len) + ((ch as uint) - ('0' as uint));

            ch = match rdr.read_byte() {
                Some(ch) => ch,
                None => {
                    fail!("Not a TNetString: invalid or missing length prefix");
                }
            };

            if ch < '0' as u8 || ch > '9' as u8 {
                break;
            }
        }
    }

    // Validate end-of-length-prefix marker.
    if ch != ':' as u8 {
        fail!("Not a TNetString: missing length prefix");
    }

    // Read the data plus terminating type tag.
    let payload = rdr.read_bytes(len);

    if payload.len() != len {
        fail!("Not a TNetString: invalid length prefix");
    }

    let ch = match rdr.read_char() {
        Some(ch) => ch,
        None => {
            fail!("Not a TNetString: missing type tag");
        }
    };

    match ch {
        '#' => {
            let v = strconv::from_str_bytes_common(payload, 10, true, false, false,
                                                   strconv::ExpNone, false, false);
            v.and_then(|v| Some(Int(v)))
        }
        '}' => Some(Map(parse_map(payload))),
        ']' => Some(Vec(parse_vec(payload))),
        '!' => {
            str::from_utf8_owned_opt(payload)
                .and_then(|s| FromStr::from_str(s))
                .and_then(|v| Some(Bool(v)))
        }
        '^' => {
            let v = strconv::from_str_bytes_common(payload, 10u, true, true, true,
                                                   strconv::ExpDec, false, false);
            v.and_then(|v| Some(Float(v)))
        }
        '~' => {
            assert!(payload.is_empty());
            Some(Null)
        }
        ',' => {
            Some(Str(payload))
        }
        ch => {
            fail!(format!("Invalid payload type: {}", ch))
        }
    }
}

fn parse_vec(data: &[u8]) -> ~[TNetString] {
    if data.is_empty() { return ~[]; }

    let mut result = ~[];
    let mut rdr = BufReader::new(data);

    loop {
        match from_reader(&mut rdr) {
            Some(value) => { result.push(value); }
            None => { return result; }
        }
    }
}

fn parse_pair<R: Reader + Buffer>(rdr: &mut R) -> Option<(~[u8], TNetString)> {
    match from_reader(rdr) {
        Some(Str(key)) => {
            match from_reader(rdr) {
                Some(value) => Some((key, value)),
                None => fail!("invalid TNetString"),
            }
        }
        Some(_) => fail!("Keys can only be strings."),
        None => None,
    }
}

fn parse_map(data: &[u8]) -> ~HashMap<~[u8], TNetString> {
    let mut result = ~HashMap::new();
    let mut rdr = BufReader::new(data);

    loop {
        match parse_pair(&mut rdr) {
            Some((key, value)) => { result.insert(key, value); }
            None => { return result; }
        }
    }
}

/// Deserializes a TNetString value from a byte string.
pub fn from_bytes<'a>(data: &'a [u8]) -> (Option<TNetString>, BufReader<'a>) {
    let mut rdr = BufReader::new(data);
    let tnetstring = from_reader(&mut rdr);
    (tnetstring, rdr)
}

/// Deserializes a TNetString value from a string.
pub fn from_str<'a>(data: &'a str) -> (Option<TNetString>, BufReader<'a>) {
    from_bytes(data.as_bytes())
}

/// Test the equality between two TNetString values
impl Eq for TNetString {
    fn eq(&self, other: &TNetString) -> bool {
        match (self, other) {
            (&Str(ref s0), &Str(ref s1)) => s0 == s1,
            (&Int(i0), &Int(i1)) => i0 == i1,
            (&Float(f0), &Float(f1)) => f0 == f1,
            (&Bool(b0), &Bool(b1)) => b0 == b1,
            (&Null, &Null) => true,
            (&Map(ref d0), &Map(ref d1)) => {
                if d0.len() == d1.len() {
                    for (k0, v0) in d0.iter() {
                        // XXX send_map::linear::LinearMap has find_ref, but
                        // that method is not available for HashMap.
                        let result = match d1.find(k0) {
                            Some(v1) => v0 == v1,
                            None => false,
                        };
                        if !result { return false; }
                    }
                    true
                } else {
                    false
                }
            }
            (&Vec(ref v0), &Vec(ref v1)) => {
                v0.eq(v1)
            },
            _ => false
        }
    }

    fn ne(&self, other: &TNetString) -> bool { !self.eq(other) }
}
<|endoftext|>


<commit_before>//! Train a dictionary from various sources.
//!
//! A dictionary can help improve the compression of small files.
//! The dictionary must be present during decompression,
//! but can be shared accross multiple "similar" files.
//!
//! Creating a dictionary using the `zstd` C library,
//! using the `zstd` command-line interface, using this library,
//! or using the `train` binary provided, should give the same result,
//! and are therefore completely compatible.
//!
//! To use, see [`Encoder::with_dictionary`] or [`Decoder::with_dictionary`].
//!
//! [`Encoder::with_dictionary`]: ../struct.Encoder.html#method.with_dictionary
//! [`Decoder::with_dictionary`]: ../struct.Decoder.html#method.with_dictionary

use ll;
use ::parse_code;

use std::io::{self, Read};
use std::path;
use std::fs;

/// Train a dictionary from a big continuous chunk of data.
///
/// This is the most efficient way to train a dictionary,
/// since this is directly fed into `zstd`.
pub fn from_continuous(sample_data: &[u8], sample_sizes: &[usize],
                       max_size: usize)
                       -> io::Result<Vec<u8>> {
    // Complain if the lengths don't add up to the entire data.
    if sample_sizes.iter().sum::<usize>() != sample_data.len() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "sample sizes don't add up".to_string()));
    }

    let mut result = Vec::with_capacity(max_size);
    unsafe {
        let code = ll::ZDICT_trainFromBuffer(result.as_mut_ptr(),
                                             result.capacity(),
                                             sample_data.as_ptr(),
                                             sample_sizes.as_ptr(),
                                             sample_sizes.len());
        let written = try!(parse_code(code));
        result.set_len(written);
    }
    Ok(result)
}

/// Train a dictionary from multiple samples.
///
/// The samples will internaly be copied to a single continuous buffer,
/// so make sure you have enough memory available.
///
/// If you need to stretch your system's limits,
/// [`from_continuous`] directly uses the given slice.
///
/// [`from_continuous`]: ./fn.from_continuous.html
pub fn from_samples<S: AsRef<[u8]>>(samples: &[S], max_size: usize)
                                    -> io::Result<Vec<u8>> {
    // Copy every sample to a big chunk of memory
    let data: Vec<_> = samples.iter()
        .flat_map(|s| s.as_ref())
        .cloned()
        .collect();
    let sizes: Vec<_> = samples.iter().map(|s| s.as_ref().len()).collect();

    from_continuous(&data, &sizes, max_size)
}

/// Train a dict from a list of files.
pub fn from_files<I, P>(filenames: I, max_size: usize) -> io::Result<Vec<u8>>
    where P: AsRef<path::Path>,
          I: IntoIterator<Item = P>
{
    let mut buffer = Vec::new();
    let mut sizes = Vec::new();

    for filename in filenames {
        let mut file = try!(fs::File::open(filename));
        let len = try!(file.read_to_end(&mut buffer));
        sizes.push(len);
    }

    from_continuous(&buffer, &sizes, max_size)
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::io;

    #[test]
    fn test_dict_training() {
        // Train a dictionary
        let paths: Vec<_> = fs::read_dir("src")
            .unwrap()
            .map(|entry| entry.unwrap())
            .map(|entry| entry.path())
            .filter(|path| path.to_str().unwrap().ends_with(".rs"))
            .collect();

        let dict = super::from_files(&paths, 4000).unwrap();

        for path in paths {
            let mut buffer = Vec::new();
            let mut file = fs::File::open(path).unwrap();
            io::copy(&mut file,
                     &mut ::stream::Encoder::with_dictionary(&mut buffer,
                                                             1,
                                                             &dict)
                         .unwrap()
                         .auto_finish())
                .unwrap();

        }
    }
}
<commit_msg>Add dictionary test<commit_after>//! Train a dictionary from various sources.
//!
//! A dictionary can help improve the compression of small files.
//! The dictionary must be present during decompression,
//! but can be shared accross multiple "similar" files.
//!
//! Creating a dictionary using the `zstd` C library,
//! using the `zstd` command-line interface, using this library,
//! or using the `train` binary provided, should give the same result,
//! and are therefore completely compatible.
//!
//! To use, see [`Encoder::with_dictionary`] or [`Decoder::with_dictionary`].
//!
//! [`Encoder::with_dictionary`]: ../struct.Encoder.html#method.with_dictionary
//! [`Decoder::with_dictionary`]: ../struct.Decoder.html#method.with_dictionary

use ll;
use ::parse_code;

use std::io::{self, Read};
use std::path;
use std::fs;

/// Train a dictionary from a big continuous chunk of data.
///
/// This is the most efficient way to train a dictionary,
/// since this is directly fed into `zstd`.
pub fn from_continuous(sample_data: &[u8], sample_sizes: &[usize],
                       max_size: usize)
                       -> io::Result<Vec<u8>> {
    // Complain if the lengths don't add up to the entire data.
    if sample_sizes.iter().sum::<usize>() != sample_data.len() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "sample sizes don't add up".to_string()));
    }

    let mut result = Vec::with_capacity(max_size);
    unsafe {
        let code = ll::ZDICT_trainFromBuffer(result.as_mut_ptr(),
                                             result.capacity(),
                                             sample_data.as_ptr(),
                                             sample_sizes.as_ptr(),
                                             sample_sizes.len());
        let written = try!(parse_code(code));
        result.set_len(written);
    }
    Ok(result)
}

/// Train a dictionary from multiple samples.
///
/// The samples will internaly be copied to a single continuous buffer,
/// so make sure you have enough memory available.
///
/// If you need to stretch your system's limits,
/// [`from_continuous`] directly uses the given slice.
///
/// [`from_continuous`]: ./fn.from_continuous.html
pub fn from_samples<S: AsRef<[u8]>>(samples: &[S], max_size: usize)
                                    -> io::Result<Vec<u8>> {
    // Copy every sample to a big chunk of memory
    let data: Vec<_> = samples.iter()
        .flat_map(|s| s.as_ref())
        .cloned()
        .collect();
    let sizes: Vec<_> = samples.iter().map(|s| s.as_ref().len()).collect();

    from_continuous(&data, &sizes, max_size)
}

/// Train a dict from a list of files.
pub fn from_files<I, P>(filenames: I, max_size: usize) -> io::Result<Vec<u8>>
    where P: AsRef<path::Path>,
          I: IntoIterator<Item = P>
{
    let mut buffer = Vec::new();
    let mut sizes = Vec::new();

    for filename in filenames {
        let mut file = try!(fs::File::open(filename));
        let len = try!(file.read_to_end(&mut buffer));
        sizes.push(len);
    }

    from_continuous(&buffer, &sizes, max_size)
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::io;
    use std::io::Read;

    #[test]
    fn test_dict_training() {
        // Train a dictionary
        let paths: Vec<_> = fs::read_dir("src")
            .unwrap()
            .map(|entry| entry.unwrap())
            .map(|entry| entry.path())
            .filter(|path| path.to_str().unwrap().ends_with(".rs"))
            .collect();

        let dict = super::from_files(&paths, 4000).unwrap();

        for path in paths {
            let mut buffer = Vec::new();
            let mut file = fs::File::open(path).unwrap();
            let mut content = Vec::new();
            file.read_to_end(&mut content).unwrap();
            io::copy(&mut &content[..],
                     &mut ::stream::Encoder::with_dictionary(&mut buffer,
                                                             1,
                                                             &dict)
                         .unwrap()
                         .auto_finish())
                .unwrap();

            let mut result = Vec::new();
            io::copy(&mut ::stream::Decoder::with_dictionary(&buffer[..],
                                                             &dict[..])
                         .unwrap(),
                     &mut result)
                .unwrap();

            assert_eq!(&content, &result);
        }
    }
}
<|endoftext|>


<commit_before>use funcs::*;
use env::*;
use atom::*;
use errors::*;
use errors::Error::*;
use std::fmt::{Write};
use std::string::*;

#[allow(dead_code)]
fn print_list(list: &[Atom]) -> String {
    let mut s = String::new();
    write!(&mut s,"[").unwrap();

    if let Some(first) = list.first() {
        write!(&mut s, "{}", first).unwrap();
        for i in list.iter().skip(1) {
            write!(&mut s, " {}", i).unwrap();
        }
    }
    write!(&mut s, "]").unwrap();
    s
}

fn eval_procedure(p: &Procedure, args: &[Atom], env: &mut Env) ->  AtomResult {
    env.apply(&p.params, args);

    let res = p.body.iter()
        .map(|node| eval(&node, env))
        .last().unwrap_or(Err(InvalidArguments));

    env.pop();

    res
}

fn eval_macro(p: &Procedure, args: &[Atom], env: &mut Env) -> AtomResult {
    env.apply(&p.params, args);

    let res = p.body.iter()
        .map(|node| eval(&node, env))
        .last().unwrap_or(Err(InvalidArguments));

    env.pop();

    res
}

fn define(args: &[Atom], env: &mut Env) -> AtomResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }

    if let Atom::Symbol(ref key) = args[0] {
        let value = try!(eval(&args[1], env));
        env.set(key.clone(), value);
        Ok(Atom::Nil)
    } else {
        Err(Error::InvalidArguments)
    }
}

fn quote(list: &[Atom]) -> AtomResult {
    println!("quote is returning {}", print_list(list));
    list.first().map(|atom| atom.clone()).ok_or(InvalidArguments)
}

fn collect_body(l: &[Atom]) -> Vec<Atom> {
    l.iter().skip(2).map(|x| x.clone()).collect()
}

fn macroexpand(_: &[Atom], _: &Env) -> AtomResult {
    Err(NotImplemented)
}

fn do_form(list: &[Atom], env: &mut Env) -> AtomResult {
    list.iter()
        .map(|node| eval(node, env))
        .last().unwrap_or(Err(InvalidArguments))
}

fn make_proc(list: &[Atom]) -> AtomResult {
    if let Atom::List(ref p) = list[1] {
        Ok(Atom::Function(Function::Proc(Procedure{ params: p.clone(),
                                                    body: collect_body(list)})))
    } else {
        Err(InvalidArguments)
    }
}

fn macro_form(args: &[Atom], env: &mut Env) -> AtomResult {
    if args.len() < 3 {
        return Err(InvalidArguments)
    }

    let name = match args[0] {
        Atom::Symbol(name) => name,
        _ => return Err(InvalidArguments)
    };
    let params = match args[1] {
        Atom::List(ref list) => {
            list.iter().map(|n| n.clone()).collect()
        },
        _ => return Err(InvalidArguments)
    };

    let body = args[2..].iter().map(|n| n.clone()).collect();

    env.set(name, Atom::Function(Function::Macro(Procedure{ params: params, body: body})));

    Ok(Atom::Symbol(name))
}

fn if_form(list: &[Atom], env: &mut Env) -> AtomResult {
    if list.len() < 2 {
        Err(InvalidArguments)
    } else {
        eval(&list[0], env)
            .and_then(|p| {
                let truthy = match p {
                    Atom::Boolean(b) => b,
                    Atom::Nil => false,
                    _ => true
                };
                if truthy {
                    eval(&list[1], env)
                } else if list.len() > 2 {
                    eval(&list[2], env)
                } else {
                    Ok(Atom::Boolean(false))
                }
            })
    }
}

fn eval_special_forms(f: Form, list: &[Atom], env: &mut Env) -> AtomResult {
    use atom::Form::*;
    match f {
        Def => {
            define(&list[1..], env)
        },
        Do => {
            do_form(&list[1..], env)
        },
        Macro => {
            macro_form(&list[1..], env)
        }
        Fn => {
            make_proc(&list)
        },
        Quote => {
            quote(&list[1..])
        },
        If => {
            if_form(&list[1..], env)
        },
        MacroExpand => {
            macroexpand(&list[1..], env)
        },
        _ => Err(InvalidArguments)
    }
}

pub fn eval_node(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    match *node {
        Atom::Symbol(sym) => {
            match env.get(sym.as_ref()) {
                Some(v) => Ok(v),
                None => Ok(Atom::Nil)
            }
        },
        Atom::List(ref list) => {
            Ok(Atom::List(try!(list.iter().map(|n| eval(&n, env)).collect())))
        },
        _ => Ok(node.clone())
    }
}

fn macro_expand(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    match *node {
        Atom::List(ref list) => {
            match list[0] {
                Atom::Symbol(ref sym) => {
                    if let Some(Atom::Function(Function::Macro(ref m))) = env.get(sym.as_ref()) {
                        return macro_expand(&try!(eval_macro(m, &list[1..], env)), env)
                    }
                },
                Atom::Function(Function::Macro(ref m)) => {
                    return macro_expand(&try!(eval_macro(m, &list[1..], env)), env)
                }
                _ => ()
            }
        },
        _ => ()
    }

    Ok(node.clone())
}

pub fn eval(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    println!("eval: {}", node);

    let pre_list = match *node {
        Atom::List(ref list) => list,
        _ => return eval_node(node, env)
    };

    if pre_list.is_empty() {
        return Ok(Atom::Nil)
    }

    let expanded_node = try!(macro_expand(node, env));
    let mut list = match expanded_node {
        Atom::List(l) => l,
        _ => return Ok(expanded_node)
    };

    match list[0] {
        Atom::Symbol(_) | Atom::List(_) => {
            list[0] = try!(eval(&list[0], env));
            return eval(&Atom::List(list), env)
        },
        _ => ()
    }

    match list[0] {
        Atom::Form(f) => {
            return eval_special_forms(f, &list, env)
        },
        Atom::Function(ref func) => {
            let args: Vec<Atom> = try!(list.iter().skip(1).map(|n| eval(&n, env)).collect());
            match *func {
                Function::Proc(ref p) => {
                    return eval_procedure(p, &args, env)
                },
                Function::Native(native) => {
                    return eval_native(native, &args, env)
                },
                _ => {
                    panic!("no macros here!")
                }
            }
        },
        _ => return Err(Error::NotAFunction)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::*;
    use atom::*;
    use env::Env;

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut Env::new()).unwrap();

        assert_eq!(Atom::from(true), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut Env::new()).unwrap();

        assert_eq!(Atom::Boolean(false), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Atom::Boolean(true), x);
    }

    fn tassert(v: &str) {
        assert_eq!(Atom::Boolean(true), teval(v));
    }

    fn trefute(v: &str) {
        assert_eq!(Atom::Boolean(false), teval(v));
    }

    #[test]
    fn comparisons() {
        tassert("(= 1 1 1 1)");
        trefute("(= 1 0 1 1)");
        tassert("(< 1 5 10)");
        trefute("(< 5 1 20)");
        tassert("(<= 1 1 1 5)");
        trefute("(<= 5 2 1 5)");
        tassert("(> 5 3 2 1)");
        trefute("(> 5 3 2 10)");
        tassert("(>= 5 5 5 3)");
        trefute("(>= 5 5 5 10)");
    }
    use number::Number;

    fn num(i: i64) -> Atom {
        Atom::Number(Number::Integer(i))
    }

    #[test]
    fn adds() {
        assert_eq!(num(5), teval("(+ 2 3)"));
        assert_eq!(num(25), teval("(+ 5 5 5 5 5)"));
    }

    #[test]
    fn subs() {
        assert_eq!(num(0), teval("(- 5 5)"));
        assert_eq!(num(5), teval("(- 20 10 5)"));
    }

    #[test]
    fn muls() {
        assert_eq!(num(0), teval("(* 5 5 5 0)"));
        assert_eq!(num(5), teval("(* 1 5)"));
        assert_eq!(num(-5), teval("(* -1 5)"));
    }

    fn teval(s: &str) -> Atom {
        let mut env = Env::new();
        tokenize(s)
            .and_then(|n| eval(&n, &mut env)).unwrap()
    }

    fn teval_env(s: &str, env: &mut Env) -> AtomResult {
        tokenize(s).and_then(|n| {
            eval(&n, env)
        })
    }

    #[test]
    fn symbol_resolving() {
        let mut env = Env::new();

        teval_env("(def foo 5)", &mut env).unwrap();

        assert_eq!(num(0), teval_env("(- foo 5)", &mut env).unwrap());
    }

    #[test]
    fn no_def_func() {
        assert_eq!(teval("3"), teval("((fn (a b) (+ a b)) 1 2)"));
    }

    #[test]
    fn first_and_rest() {
        assert_eq!(num(0), teval("(first '(0 1 2))"));
        assert_eq!(teval("'(1 2)"), teval("(rest '(0 1 2))"));
    }

    #[test]
    fn simple_func() {
        let mut env = Env::new();
        let _ = eval(&tokenize("(def f (fn (r b) (+ r b)))").unwrap(), &mut env).unwrap();
        let res = eval(&tokenize("(f 2 3)").unwrap(), &mut env).unwrap();

        assert_eq!(num(5), res);
    }

    #[test]
    fn quote_func() {
        assert_eq!(teval("'(1 2)"), teval("(quote (1 2))"));
        assert_eq!(teval("'a"), teval("(quote a)"));
    }

    #[test]
    fn do_func() {
        assert_eq!(teval("4"), teval("(do (+ 1 2) (+ 2 2))"));
    }

    #[test]
    fn splice_macro() {
        let mut env = Env::new();

        teval_env("(defmacro foo (& a) `(list ~@a))", &mut env).unwrap();

        let r = teval_env("(foo 1 2)", &mut env).unwrap();

        assert_eq!(teval("'(1 2)"), r);
        //assert_eq!(teval("'(1 2)"), teval_env("(foo '(1 2))", &mut env).unwrap());
    }

    #[test]
    fn back_tick_simple_list() {
        assert_eq!(teval("'(1 2)"), teval("`(1 2)"));
    }
    // #[test]
    //  fn simple_macro() {
    //      let mut env = Env::new();
    //      teval_env("(defmacro m () '(+ 3 5))", &mut env).unwrap();
    //      assert_eq!(teval("'(+ 3 5)"), teval_env("(macroexpand '(m))", &mut env).unwrap());

    //      teval_env("(def mm (macro () (+ 3 5)))", &mut env).unwrap();
    //      assert_eq!(teval("8"), teval_env("(macroexpand '(mm))", &mut env).unwrap());

    //      assert_eq!(teval("8"), teval_env("(m)", &mut env).unwrap());
    //      assert_eq!(teval("8"), teval_env("(mm)", &mut env).unwrap());

    #[test]
    fn back_tick_subst() {
        assert_eq!(teval("'(1 3)"), teval("`(1 ~@(+ 1 2))"));
    }

    #[test]
    fn more_complex_macro() {
        let mut env = Env::new();
        teval_env("(defmacro unless (p a b) `(if (not ~p) ~a ~b))", &mut env).unwrap();
        assert_eq!(teval("3"), teval_env("(unless false 3 5)", &mut env).unwrap());
    }

    #[test]
    fn recursive_fibonacci() {
        let mut env = Env::new();
        teval_env("(def fibonacci (fn (n) (if (<= n 2) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))))", &mut env).unwrap();

        assert_eq!(teval("1"), teval_env("(fibonacci 0)", &mut env).unwrap());
        assert_eq!(teval("2"), teval_env("(fibonacci 3)", &mut env).unwrap());
        assert_eq!(teval("55"), teval_env("(fibonacci 10)", &mut env).unwrap());
    }

    #[test]
    #[should_panic]
    fn numbers_arent_functions() {
        teval("(1 1)");
    }
}
<commit_msg>quasi quoting<commit_after>use funcs::*;
use env::*;
use atom::*;
use errors::*;
use errors::Error::*;
use std::fmt::{Write};
use std::string::*;

#[allow(dead_code)]
fn print_list(list: &[Atom]) -> String {
    let mut s = String::new();
    write!(&mut s,"[").unwrap();

    if let Some(first) = list.first() {
        write!(&mut s, "{}", first).unwrap();
        for i in list.iter().skip(1) {
            write!(&mut s, " {}", i).unwrap();
        }
    }
    write!(&mut s, "]").unwrap();
    s
}

fn eval_procedure(p: &Procedure, args: &[Atom], env: &mut Env) ->  AtomResult {
    env.apply(&p.params, args);

    let res = p.body.iter()
        .map(|node| eval(&node, env))
        .last().unwrap_or(Err(InvalidArguments));

    env.pop();

    res
}

fn eval_macro(p: &Procedure, args: &[Atom], env: &mut Env) -> AtomResult {
    env.apply(&p.params, args);

    let res = p.body.iter()
        .map(|node| eval(&node, env))
        .last().unwrap_or(Err(InvalidArguments));

    env.pop();

    res
}

fn define(args: &[Atom], env: &mut Env) -> AtomResult {
    if args.len() != 2 {
        return Err(Error::InvalidArguments);
    }

    if let Atom::Symbol(ref key) = args[0] {
        let value = try!(eval(&args[1], env));
        env.set(key.clone(), value);
        Ok(Atom::Nil)
    } else {
        Err(Error::InvalidArguments)
    }
}

fn quote(list: &[Atom]) -> AtomResult {
    println!("quote is returning {}", print_list(list));
    list.first().map(|atom| atom.clone()).ok_or(InvalidArguments)
}

fn collect_body(l: &[Atom]) -> Vec<Atom> {
    l.iter().skip(2).map(|x| x.clone()).collect()
}

fn macroexpand(_: &[Atom], _: &Env) -> AtomResult {
    Err(NotImplemented)
}

fn do_form(list: &[Atom], env: &mut Env) -> AtomResult {
    list.iter()
        .map(|node| eval(node, env))
        .last().unwrap_or(Err(InvalidArguments))
}

fn make_proc(list: &[Atom]) -> AtomResult {
    if let Atom::List(ref p) = list[1] {
        Ok(Atom::Function(Function::Proc(Procedure{ params: p.clone(),
                                                    body: collect_body(list)})))
    } else {
        Err(InvalidArguments)
    }
}

fn macro_form(args: &[Atom], env: &mut Env) -> AtomResult {
    if args.len() < 3 {
        return Err(InvalidArguments)
    }

    let name = match args[0] {
        Atom::Symbol(name) => name,
        _ => return Err(InvalidArguments)
    };
    let params = match args[1] {
        Atom::List(ref list) => {
            list.iter().map(|n| n.clone()).collect()
        },
        _ => return Err(InvalidArguments)
    };

    let body = args[2..].iter().map(|n| n.clone()).collect();

    env.set(name, Atom::Function(Function::Macro(Procedure{ params: params, body: body})));

    Ok(Atom::Symbol(name))
}

fn if_form(list: &[Atom], env: &mut Env) -> AtomResult {
    if list.len() < 2 {
        Err(InvalidArguments)
    } else {
        eval(&list[0], env)
            .and_then(|p| {
                let truthy = match p {
                    Atom::Boolean(b) => b,
                    Atom::Nil => false,
                    _ => true
                };
                if truthy {
                    eval(&list[1], env)
                } else if list.len() > 2 {
                    eval(&list[2], env)
                } else {
                    Ok(Atom::Boolean(false))
                }
            })
    }
}

fn expand_quasiquote(node: &Atom, env: &mut Env) -> AtomResult {
    if !node.is_pair() {
        return Ok(Atom::List(vec![Atom::Form(Form::Quote), node.clone()]))
    }

    match *node {
        Atom::List(ref list) => {
            match list[0] {
                Atom::Form(Form::Unquote) => {
                    return Ok(list[1].clone())
                },
                _ => ()
            }

            if list[0].is_pair() {
                match list[0] {
                    Atom::List(ref sublist) => {
                        match sublist[0] {
                            Atom::Form(Form::Splice) => {
                                let append = Atom::Function(Function::Native(Native::Append));
                                let rest = list[1..].iter().map(|n| n.clone()).collect();
                                return Ok(Atom::List(vec![append, sublist[1].clone(),
                                                          Atom::List(rest)]))
                            },
                            _ => ()
                        }
                    },
                    _ => ()
                }
            }

            let rest = list[1..].iter().map(|n| n.clone()).collect();
            return Ok(Atom::List(vec![Atom::Function(Function::Native(Native::Cons)),
                                      try!(expand_quasiquote(&list[0], env)),
                                      try!(expand_quasiquote(&Atom::List(rest), env))]))
        },
        _ => unreachable!()
    }
}

fn eval_special_forms(f: Form, list: &[Atom], env: &mut Env) -> AtomResult {
    use atom::Form::*;
    match f {
        Def => {
            define(&list[1..], env)
        },
        Do => {
            do_form(&list[1..], env)
        },
        Macro => {
            macro_form(&list[1..], env)
        }
        Fn => {
            make_proc(&list)
        },
        QuasiQuote => {
            expand_quasiquote(&list[1], env)
                .and_then(|n| eval(&n, env))
        },
        Quote => {
            quote(&list[1..])
        },
        If => {
            if_form(&list[1..], env)
        },
        MacroExpand => {
            macroexpand(&list[1..], env)
        },
        _ => Err(InvalidArguments)
    }
}

pub fn eval_node(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    match *node {
        Atom::Symbol(sym) => {
            match env.get(sym.as_ref()) {
                Some(v) => Ok(v),
                None => Ok(Atom::Nil)
            }
        },
        Atom::List(ref list) => {
            Ok(Atom::List(try!(list.iter().map(|n| eval(&n, env)).collect())))
        },
        _ => Ok(node.clone())
    }
}

fn macro_expand(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    match *node {
        Atom::List(ref list) => {
            match list[0] {
                Atom::Symbol(ref sym) => {
                    if let Some(Atom::Function(Function::Macro(ref m))) = env.get(sym.as_ref()) {
                        return macro_expand(&try!(eval_macro(m, &list[1..], env)), env)
                    }
                },
                Atom::Function(Function::Macro(ref m)) => {
                    return macro_expand(&try!(eval_macro(m, &list[1..], env)), env)
                }
                _ => ()
            }
        },
        _ => ()
    }

    Ok(node.clone())
}

pub fn eval(node: &Atom, env: &mut Env) -> Result<Atom, Error> {
    println!("eval: {}", node);

    let pre_list = match *node {
        Atom::List(ref list) => list,
        _ => return eval_node(node, env)
    };

    if pre_list.is_empty() {
        return Ok(Atom::Nil)
    }

    let expanded_node = try!(macro_expand(node, env));
    let mut list = match expanded_node {
        Atom::List(l) => l,
        _ => return Ok(expanded_node)
    };

    match list[0] {
        Atom::Symbol(_) | Atom::List(_) => {
            list[0] = try!(eval(&list[0], env));
            return eval(&Atom::List(list), env)
        },
        _ => ()
    }

    match list[0] {
        Atom::Form(f) => {
            return eval_special_forms(f, &list, env)
        },
        Atom::Function(ref func) => {
            let args: Vec<Atom> = try!(list.iter().skip(1).map(|n| eval(&n, env)).collect());
            match *func {
                Function::Proc(ref p) => {
                    return eval_procedure(p, &args, env)
                },
                Function::Native(native) => {
                    return eval_native(native, &args, env)
                },
                _ => {
                    panic!("no macros here!")
                }
            }
        },
        _ => return Err(Error::NotAFunction)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::*;
    use atom::*;
    use env::Env;

    #[test]
    fn if_special_form() {
        let x = eval(&tokenize("(if (= 1 1) true false)").unwrap(), &mut Env::new()).unwrap();

        assert_eq!(Atom::from(true), x);
    }

    #[test]
    fn if_special_form_false() {
        let x = eval(&tokenize("(if (= 1 2) true false)").unwrap(), &mut Env::new()).unwrap();

        assert_eq!(Atom::Boolean(false), x);
    }

    #[test]
    fn if_no_else() {
        let x = teval("(if (= 1 1) true)");

        assert_eq!(Atom::Boolean(true), x);
    }

    fn tassert(v: &str) {
        assert_eq!(Atom::Boolean(true), teval(v));
    }

    fn trefute(v: &str) {
        assert_eq!(Atom::Boolean(false), teval(v));
    }

    #[test]
    fn comparisons() {
        tassert("(= 1 1 1 1)");
        trefute("(= 1 0 1 1)");
        tassert("(< 1 5 10)");
        trefute("(< 5 1 20)");
        tassert("(<= 1 1 1 5)");
        trefute("(<= 5 2 1 5)");
        tassert("(> 5 3 2 1)");
        trefute("(> 5 3 2 10)");
        tassert("(>= 5 5 5 3)");
        trefute("(>= 5 5 5 10)");
    }
    use number::Number;

    fn num(i: i64) -> Atom {
        Atom::Number(Number::Integer(i))
    }

    #[test]
    fn adds() {
        assert_eq!(num(5), teval("(+ 2 3)"));
        assert_eq!(num(25), teval("(+ 5 5 5 5 5)"));
    }

    #[test]
    fn subs() {
        assert_eq!(num(0), teval("(- 5 5)"));
        assert_eq!(num(5), teval("(- 20 10 5)"));
    }

    #[test]
    fn muls() {
        assert_eq!(num(0), teval("(* 5 5 5 0)"));
        assert_eq!(num(5), teval("(* 1 5)"));
        assert_eq!(num(-5), teval("(* -1 5)"));
    }

    fn teval(s: &str) -> Atom {
        let mut env = Env::new();
        tokenize(s)
            .and_then(|n| eval(&n, &mut env)).unwrap()
    }

    fn teval_env(s: &str, env: &mut Env) -> AtomResult {
        tokenize(s).and_then(|n| {
            eval(&n, env)
        })
    }

    #[test]
    fn symbol_resolving() {
        let mut env = Env::new();

        teval_env("(def foo 5)", &mut env).unwrap();

        assert_eq!(num(0), teval_env("(- foo 5)", &mut env).unwrap());
    }

    #[test]
    fn no_def_func() {
        assert_eq!(teval("3"), teval("((fn (a b) (+ a b)) 1 2)"));
    }

    #[test]
    fn first_and_rest() {
        assert_eq!(num(0), teval("(first '(0 1 2))"));
        assert_eq!(teval("'(1 2)"), teval("(rest '(0 1 2))"));
    }

    #[test]
    fn simple_func() {
        let mut env = Env::new();
        let _ = eval(&tokenize("(def f (fn (r b) (+ r b)))").unwrap(), &mut env).unwrap();
        let res = eval(&tokenize("(f 2 3)").unwrap(), &mut env).unwrap();

        assert_eq!(num(5), res);
    }

    #[test]
    fn quote_func() {
        assert_eq!(teval("'(1 2)"), teval("(quote (1 2))"));
        assert_eq!(teval("'a"), teval("(quote a)"));
    }

    #[test]
    fn do_func() {
        assert_eq!(teval("4"), teval("(do (+ 1 2) (+ 2 2))"));
    }

    #[test]
    fn splice_macro() {
        let mut env = Env::new();

        teval_env("(defmacro foo (& a) `(list ~@a))", &mut env).unwrap();

        let r = teval_env("(foo 1 2)", &mut env).unwrap();

        assert_eq!(teval("'(1 2)"), r);
        //assert_eq!(teval("'(1 2)"), teval_env("(foo '(1 2))", &mut env).unwrap());
    }

    #[test]
    fn back_tick_simple_list() {
        assert_eq!(teval("'(1 2)"), teval("`(1 2)"));
    }
    // #[test]
    //  fn simple_macro() {
    //      let mut env = Env::new();
    //      teval_env("(defmacro m () '(+ 3 5))", &mut env).unwrap();
    //      assert_eq!(teval("'(+ 3 5)"), teval_env("(macroexpand '(m))", &mut env).unwrap());

    //      teval_env("(def mm (macro () (+ 3 5)))", &mut env).unwrap();
    //      assert_eq!(teval("8"), teval_env("(macroexpand '(mm))", &mut env).unwrap());

    //      assert_eq!(teval("8"), teval_env("(m)", &mut env).unwrap());
    //      assert_eq!(teval("8"), teval_env("(mm)", &mut env).unwrap());

    #[test]
    fn back_tick_subst() {
        assert_eq!(teval("'(1 3)"), teval("`(1 ~@(+ 1 2))"));
    }

    #[test]
    fn more_complex_macro() {
        let mut env = Env::new();
        teval_env("(defmacro unless (p a b) `(if (not ~p) ~a ~b))", &mut env).unwrap();
        assert_eq!(teval("3"), teval_env("(unless false 3 5)", &mut env).unwrap());
    }

    #[test]
    fn recursive_fibonacci() {
        let mut env = Env::new();
        teval_env("(def fibonacci (fn (n) (if (<= n 2) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))))", &mut env).unwrap();

        assert_eq!(teval("1"), teval_env("(fibonacci 0)", &mut env).unwrap());
        assert_eq!(teval("2"), teval_env("(fibonacci 3)", &mut env).unwrap());
        assert_eq!(teval("55"), teval_env("(fibonacci 10)", &mut env).unwrap());
    }

    #[test]
    #[should_panic]
    fn numbers_arent_functions() {
        teval("(1 1)");
    }
}
<|endoftext|>


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

use quote::{Tokens, ToTokens};
use syn::{Body, Field, Variant, VariantData, MacroInput, Ty};
use utils::{number_idents, get_field_types};

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
pub fn expand(input: &MacroInput, _: &str) -> Tokens {
    match input.body {
        Body::Struct(VariantData::Tuple(ref fields)) => tuple_from(input, fields),
        Body::Struct(VariantData::Struct(ref fields)) => struct_from(input, fields),
        Body::Enum(ref variants) => enum_from(input, variants),
        _ => panic!("Only tuple structs and enums can derive From"),
    }
}

pub fn from_impl<T: ToTokens>(input: &MacroInput, fields: &Vec<Field>, body: T) -> Tokens {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let input_type = &input.ident;
    let original_types = &get_field_types(fields);
    quote!{
        impl#impl_generics ::std::convert::From<(#(#original_types),*)> for #input_type#ty_generics #where_clause {
            fn from(original: (#(#original_types),*)) -> #input_type#ty_generics {
                #body
            }
        }
    }
}

fn tuple_from(input: &MacroInput, fields: &Vec<Field>) -> Tokens {
    let input_type = &input.ident;
    let body = tuple_body(input_type, fields);
    from_impl(input, fields, body)
}

fn tuple_body<T: ToTokens>(return_type: T, fields: &Vec<Field>) -> Tokens {
    if fields.len() == 1 {
        quote!(#return_type(original))
    } else {
        let field_names = &number_idents(fields.len());
        quote!(#return_type(#(original.#field_names),*))
    }
}

fn struct_from(input: &MacroInput, fields: &Vec<Field>) -> Tokens {
    let input_type = &input.ident;
    let body = struct_body(input_type, fields);
    from_impl(input, fields, body)
}

fn struct_body<T: ToTokens>(return_type: T, fields: &Vec<Field>) -> Tokens {
    if fields.len() == 1 {
        let field_name = &fields[0].ident;
        quote!(#return_type{#field_name: original})
    } else {
        let argument_field_names = &number_idents(fields.len());
        let field_names: &Vec<_> = &fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
        quote!(#return_type{#(#field_names: original.#argument_field_names),*})
    }
}

fn enum_from(input: &MacroInput, variants: &Vec<Variant>) -> Tokens {
    let mut type_signature_counts = HashMap::new();
    let input_type = &input.ident;

    for variant in variants {
        match variant.data {
            VariantData::Tuple(ref fields) |
            VariantData::Struct(ref fields) => {
                let original_types = get_field_types(fields);
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            _ => {}
        }
    }

    let mut tokens = Tokens::new();

    for variant in variants.iter() {
        match variant.data {

            VariantData::Tuple(ref fields) => {
                let original_types = get_field_types(fields);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = tuple_body(quote!(#input_type::#variant_ident), fields);
                    tokens.append(&from_impl(input, fields, body).to_string());
                }
            }

            VariantData::Struct(ref fields) => {
                let original_types = get_field_types(fields);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), fields);
                    tokens.append(&from_impl(input, fields, body).to_string());
                }
            }
            _ => {}
        }
    }
    tokens
}
<commit_msg>Fix error message<commit_after>use std::collections::HashMap;

use quote::{Tokens, ToTokens};
use syn::{Body, Field, Variant, VariantData, MacroInput, Ty};
use utils::{number_idents, get_field_types};

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
pub fn expand(input: &MacroInput, _: &str) -> Tokens {
    match input.body {
        Body::Struct(VariantData::Tuple(ref fields)) => tuple_from(input, fields),
        Body::Struct(VariantData::Struct(ref fields)) => struct_from(input, fields),
        Body::Enum(ref variants) => enum_from(input, variants),
        _ => panic!("Only structs and enums can derive From"),
    }
}

pub fn from_impl<T: ToTokens>(input: &MacroInput, fields: &Vec<Field>, body: T) -> Tokens {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let input_type = &input.ident;
    let original_types = &get_field_types(fields);
    quote!{
        impl#impl_generics ::std::convert::From<(#(#original_types),*)> for #input_type#ty_generics #where_clause {
            fn from(original: (#(#original_types),*)) -> #input_type#ty_generics {
                #body
            }
        }
    }
}

fn tuple_from(input: &MacroInput, fields: &Vec<Field>) -> Tokens {
    let input_type = &input.ident;
    let body = tuple_body(input_type, fields);
    from_impl(input, fields, body)
}

fn tuple_body<T: ToTokens>(return_type: T, fields: &Vec<Field>) -> Tokens {
    if fields.len() == 1 {
        quote!(#return_type(original))
    } else {
        let field_names = &number_idents(fields.len());
        quote!(#return_type(#(original.#field_names),*))
    }
}

fn struct_from(input: &MacroInput, fields: &Vec<Field>) -> Tokens {
    let input_type = &input.ident;
    let body = struct_body(input_type, fields);
    from_impl(input, fields, body)
}

fn struct_body<T: ToTokens>(return_type: T, fields: &Vec<Field>) -> Tokens {
    if fields.len() == 1 {
        let field_name = &fields[0].ident;
        quote!(#return_type{#field_name: original})
    } else {
        let argument_field_names = &number_idents(fields.len());
        let field_names: &Vec<_> = &fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
        quote!(#return_type{#(#field_names: original.#argument_field_names),*})
    }
}

fn enum_from(input: &MacroInput, variants: &Vec<Variant>) -> Tokens {
    let mut type_signature_counts = HashMap::new();
    let input_type = &input.ident;

    for variant in variants {
        match variant.data {
            VariantData::Tuple(ref fields) |
            VariantData::Struct(ref fields) => {
                let original_types = get_field_types(fields);
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            _ => {}
        }
    }

    let mut tokens = Tokens::new();

    for variant in variants.iter() {
        match variant.data {

            VariantData::Tuple(ref fields) => {
                let original_types = get_field_types(fields);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = tuple_body(quote!(#input_type::#variant_ident), fields);
                    tokens.append(&from_impl(input, fields, body).to_string());
                }
            }

            VariantData::Struct(ref fields) => {
                let original_types = get_field_types(fields);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), fields);
                    tokens.append(&from_impl(input, fields, body).to_string());
                }
            }
            _ => {}
        }
    }
    tokens
}
<|endoftext|>


<commit_before>extern crate cairo;
extern crate gtk;

use std::f64::consts::PI;

use gtk::prelude::*;
use gtk::DrawingArea;

use cairo::Context;

use std::io::prelude::*;
use std::io::{BufReader, SeekFrom};
use std::fs::File;

pub struct MainWindow {
    win : gtk::Window,
}

impl MainWindow {
    pub fn new() -> MainWindow {
        let window = gtk::Window::new(gtk::WindowType::Toplevel);
        window.set_title("Dust, Gearonix software");
        window.set_border_width(10);
        window.set_position(gtk::WindowPosition::Center);
        window.set_default_size(350, 70);
        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let drawing_area = Box::new(DrawingArea::new)();

        drawing_area.connect_draw( |_, cr| {

            let f = File::open("/home/thany/1.png").unwrap();
            let mut reader = BufReader::new(f);
            let pngsize = reader.seek(SeekFrom::End(0)).unwrap() as usize;
            reader.seek(SeekFrom::Start(0));
            let mut data = Box::new(Vec::<u8>::new)();
            data.resize(pngsize, 0u8);
            let len = reader.read(&mut data).unwrap();

            println!("First line is {} bytes long", len);

            cr.set_dash(&[3., 2., 1.], 1.);
            assert_eq!(cr.get_dash(), (vec![3., 2., 1.], 1.));

            cr.scale(500f64, 500f64);

            cr.set_source_rgb(250.0/255.0, 224.0/255.0, 55.0/255.0);
            cr.paint();

            cr.set_line_width(0.05);

            // border
            cr.set_source_rgb(0.3, 0.3, 0.3);
            cr.rectangle(0.0, 0.0, 1.0, 1.0);
            cr.stroke();

            cr.set_line_width(0.03);

            // draw circle
            cr.arc(0.5, 0.5, 0.4, 0.0, PI * 2.);
            cr.stroke();

            // mouth
            let mouth_top = 0.68;
            let mouth_width = 0.38;

            let mouth_dx = 0.10;
            let mouth_dy = 0.10;

            cr.move_to( 0.50 - mouth_width/2.0, mouth_top);
            cr.curve_to(0.50 - mouth_dx,        mouth_top + mouth_dy,
                         0.50 + mouth_dx,        mouth_top + mouth_dy,
                         0.50 + mouth_width/2.0, mouth_top);

            println!("Extents: {:?}", cr.fill_extents());

            cr.stroke();

            let eye_y = 0.38;
            let eye_dx = 0.15;
            cr.arc(0.5 - eye_dx, eye_y, 0.05, 0.0, PI * 2.);
            cr.fill();

            cr.arc(0.5 + eye_dx, eye_y, 0.05, 0.0, PI * 2.);
            cr.fill();

            Inhibit(false)
        });
        window.add(&drawing_area);

        MainWindow { win: window }
    }

    pub fn show(&self) {
        self.win.show_all();
    }
}
<commit_msg>some changes.<commit_after>extern crate cairo;
extern crate gtk;

use std::f64::consts::PI;

use gtk::prelude::*;
use gtk::DrawingArea;

use cairo::Context;

use std::io::prelude::*;
use std::io::{BufReader, SeekFrom};
use std::fs::File;

pub struct MainWindow {
    win : gtk::Window,
}

impl MainWindow {
    pub fn new() -> MainWindow {
        let window = gtk::Window::new(gtk::WindowType::Toplevel);
        window.set_title("Dust, Gearonix software");
        window.set_border_width(10);
        window.set_position(gtk::WindowPosition::Center);
        window.set_default_size(350, 70);
        window.connect_delete_event(|_, _| {
            gtk::main_quit();
            Inhibit(false)
        });

        let drawing_area = Box::new(DrawingArea::new)();

        drawing_area.connect_draw( |_, cr| {

            let f = File::open("/home/thany/1.png").unwrap();
            let mut reader = BufReader::new(f);
            let pngsize = reader.seek(SeekFrom::End(0)).unwrap() as usize;
            reader.seek(SeekFrom::Start(0));
            let mut data = Box::new(Vec::<u8>::new)();
            data.resize(pngsize, 0u8);
            let len = reader.read(&mut data).unwrap();

            println!("First line is {} bytes long", len);

            cr.set_dash(&[3., 2., 1.], 1.);
            assert_eq!(cr.get_dash(), (vec![3., 2., 1.], 1.));

            cr.scale(500f64, 500f64);

            cr.set_source_rgb(250.0/255.0, 224.0/255.0, 55.0/255.0);
            cr.paint();

            cr.set_line_width(0.05);

            // border
            cr.set_source_rgb(0.3, 0.3, 0.3);
            cr.rectangle(0.0, 0.0, 1.0, 1.0);
            cr.stroke();

            cr.set_line_width(0.03);

            // draw circle
            cr.arc(0.5, 0.5, 0.4, 0.0, PI * 2.);
            cr.stroke();

            // mouth
            let mouth_top = 0.68;
            let mouth_width = 0.38;

            let mouth_dx = 0.10;
            let mouth_dy = 0.10;

            cr.move_to( 0.50 - mouth_width/2.0, mouth_top);
            cr.curve_to(0.50 - mouth_dx,        mouth_top + mouth_dy,
                         0.50 + mouth_dx,        mouth_top + mouth_dy,
                         0.50 + mouth_width/2.0, mouth_top);

            println!("Extents: {:?}", cr.fill_extents());

            cr.stroke();

            let eye_y = 0.38;
            let eye_dx = 0.15;
            cr.arc(0.5 - eye_dx, eye_y, 0.05, 0.0, PI * 2.);
            cr.fill();

            cr.arc(0.5 + eye_dx, eye_y, 0.05, 0.0, PI * 2.);
            cr.fill();

            Inhibit(false)
        });
        window.add(&drawing_area);

        MainWindow { win: window }
    }

    pub fn show(&self) {
        self.win.show_all();
    }
}
<|endoftext|>