<commit_before>// DOCS

extern crate tempdir;

use std::io;
use std::fs;
use std::borrow::Borrow;
use std::path;
use std::convert::AsRef;

use tempdir::TempDir;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

#[derive(Clone,Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite
}

pub struct AtomicFile {
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    tmpdir: path::PathBuf
}

impl AtomicFile {
    /// Helper for writing to `path` in write-only mode.
    ///
    /// If `DisallowOverwrite` is given, errors will be returned from `self.write(...)` if the file
    /// exists.
    pub fn new<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior) -> Self {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(p, overwrite, p.parent().unwrap_or(p))
    }

    pub fn new_with_tmpdir<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior, tmpdir: P) -> Self {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite: overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf()
        }
    }

    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path())
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path { &self.path.borrow() }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    pub fn write<E, F: FnMut(&mut fs::File) -> io::Result<E>>(&self, mut f: F) -> io::Result<E> {
        let tmpdir = match TempDir::new_in(
            &self.tmpdir,
            ".atomicwrite"
        ) {
            Ok(x) => x,
            Err(_) => return Err(io::Error::new(
                io::ErrorKind::Other,
                "Failed to create a temporary directory."
            ))
        };

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = try!({
            let mut tmpfile = try!(fs::File::create(&tmppath));
            f(&mut tmpfile)
        });
        try!(self.commit(&tmppath));
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    use std::{io,fs,path};

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::rename(src, dst)
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::hard_link(src, dst));
        fs::remove_file(src)
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate "kernel32-sys" as win32kernel;

    use std::{io,os,path};
    use std::ffi::AsOsStr;
    use std::os::windows::OsStrExt;

    macro_rules! call {
        ($e: expr) => (
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::new(
                    io::ErrorKind::Other,
                    "A Windows API error occured.",
                    Some(os::last_os_error()),
                ))
            }
        )
    }

    fn path_to_windows_str(x: &path::Path) -> winapi::LPCWSTR {
        let v: Vec<winapi::WCHAR> = x.as_os_str().encode_wide().collect();
        v.as_slice().as_ptr()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src), path_to_windows_str(dst),
            winapi::MOVEFILE_WRITE_THROUGH | winapi::MOVEFILE_REPLACE_EXISTING
        )})
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src), path_to_windows_str(dst),
            winapi::MOVEFILE_WRITE_THROUGH
        )})
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<commit_msg>Perhaps this works<commit_after>// DOCS

extern crate tempdir;

use std::io;
use std::fs;
use std::borrow::Borrow;
use std::path;
use std::convert::AsRef;

use tempdir::TempDir;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

#[derive(Clone,Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite
}

pub struct AtomicFile {
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    tmpdir: path::PathBuf
}

impl AtomicFile {
    /// Helper for writing to `path` in write-only mode.
    ///
    /// If `DisallowOverwrite` is given, errors will be returned from `self.write(...)` if the file
    /// exists.
    pub fn new<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior) -> Self {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(p, overwrite, p.parent().unwrap_or(p))
    }

    pub fn new_with_tmpdir<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior, tmpdir: P) -> Self {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite: overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf()
        }
    }

    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path())
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path { &self.path.borrow() }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    pub fn write<E, F: FnMut(&mut fs::File) -> io::Result<E>>(&self, mut f: F) -> io::Result<E> {
        let tmpdir = match TempDir::new_in(
            &self.tmpdir,
            ".atomicwrite"
        ) {
            Ok(x) => x,
            Err(_) => return Err(io::Error::new(
                io::ErrorKind::Other,
                "Failed to create a temporary directory."
            ))
        };

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = try!({
            let mut tmpfile = try!(fs::File::create(&tmppath));
            f(&mut tmpfile)
        });
        try!(self.commit(&tmppath));
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    use std::{io,fs,path};

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::rename(src, dst)
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::hard_link(src, dst));
        fs::remove_file(src)
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate kernel32 as win32kernel;

    use std::{io,os,path};
    use std::ffi::AsOsStr;
    use std::os::windows::OsStrExt;

    macro_rules! call {
        ($e: expr) => (
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::new(
                    io::ErrorKind::Other,
                    "A Windows API error occured.",
                    Some(os::last_os_error()),
                ))
            }
        )
    }

    fn path_to_windows_str(x: &path::Path) -> winapi::LPCWSTR {
        let v: Vec<winapi::WCHAR> = x.as_os_str().encode_wide().collect();
        v.as_slice().as_ptr()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src), path_to_windows_str(dst),
            winapi::MOVEFILE_WRITE_THROUGH | winapi::MOVEFILE_REPLACE_EXISTING
        )})
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src), path_to_windows_str(dst),
            winapi::MOVEFILE_WRITE_THROUGH
        )})
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Display, Formatter};

/// The version type alias used to uniquely reference migrations.
pub type Version = i64;

/// All migrations will implement this trait, and a migration trait specific to the chosen adapter.
/// This trait defines the metadata for tracking migration sequence and for human reference.
pub trait Migration {
    /// An ordered (but not necessarily sequential), unique identifier for this migration.
    /// Registered migrations will be applied in ascending order by version.
    fn version(&self) -> Version;

    /// A message describing the effects of this migration.
    fn description(&self) -> &'static str;
}

/// A migration's direction.
#[derive(Debug)]
pub enum Direction {
    Down,
    Up,
}

/// An all-encompassing error type that can be returned during interaction with the migrator
/// adapter.
#[derive(Debug)]
pub enum Error<E> {
    /// A generic error that occurred while interacting with the adapter.
    Adapter(E),
    /// An error that arose from the adapter specifically during a migration's execution.
    Migration {
        /// The version of the migration that failed.
        version: Version,
        /// The description of the migration that failed.
        description: &'static str,
        /// The direction in which the failed migration was ran.
        direction: Direction,
        /// The underlying error from the adapter.
        error: E,
    }
}

impl<E: std::error::Error> std::error::Error for Error<E> {
    fn description(&self) -> &str {
        match *self {
            Error::Adapter(ref err) => err.description(),
            Error::Migration{version: _, description: _, direction: _, ref error} => error.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::Adapter(ref err) => Some(err),
            Error::Migration{version: _, description: _, direction: _, ref error} => Some(error),
        }
    }
}

impl<E: std::error::Error> Display for Error<E> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            Error::Adapter(ref err) => write!(f, "Adataper error: {}", err),
            Error::Migration{version: _, ref description, direction: _, ref error} => write!(f, "Error running migration {}, error: {}", description, error),
        }
    }
}

/// Efficiently implement the `Migration` trait for a given type.
///
/// ## Example
///
/// ```rust
/// # #[macro_use]
/// # extern crate schemamama;
/// struct MyMigration;
/// migration!(MyMigration, 100, "create some lovely database tables");
///
/// # fn main() {
/// use schemamama::Migration;
/// let m = MyMigration;
/// assert_eq!(m.version(), 100);
/// assert_eq!(m.description(), "create some lovely database tables");
/// # }
/// ```
#[macro_export]
macro_rules! migration {
    ($ty:ident, $version:expr, $description:expr) => {
        impl $crate::Migration for $ty {
            fn version(&self) -> $crate::Version { $version }
            fn description(&self) -> &'static str { $description }
        }
    }
}

/// Use this trait to connect the migrator to your chosen database technology.
pub trait Adapter {
    /// An alias to a specific trait that extends `Migration`. Typically, the aforementioned trait
    /// will declare functions that the adapter will use to migrate upwards and downwards.
    type MigrationType: Migration + ?Sized;

    /// An adapter-specific error type that can be returned from any of this trait's methods.
    type Error;

    /// Returns the latest migration version, or `None` if no migrations have been recorded.
    fn current_version(&self) -> Result<Option<Version>, Self::Error>;

    /// Returns a set of the versions of all of the currently applied migrations.
    fn migrated_versions(&self) -> Result<BTreeSet<Version>, Self::Error>;

    /// Applies the specified migration.
    fn apply_migration(&self, migration: &Self::MigrationType) -> Result<(), Self::Error>;

    /// Reverts the specified migration.
    fn revert_migration(&self, migration: &Self::MigrationType) -> Result<(), Self::Error>;
}

/// Maintains an ordered collection of migrations to utilize.
pub struct Migrator<T: Adapter> {
    adapter: T,
    migrations: BTreeMap<Version, Box<T::MigrationType>>
}

impl<T: Adapter> Migrator<T> {
    /// Create a migrator with a given adapter.
    pub fn new(adapter: T) -> Migrator<T> {
        Migrator { adapter: adapter, migrations: BTreeMap::new() }
    }

    /// Get a reference to the adapter.
    pub fn adapter(&self) -> &T {
        &self.adapter
    }

    /// Register a migration. If a migration with the same version is already registered, a warning
    /// is logged and the registration fails.
    pub fn register(&mut self, migration: Box<T::MigrationType>) {
        let version = migration.version();
        if self.version_registered(version) {
            warn!("Migration with version {:?} is already registered", version);
        } else {
            self.migrations.insert(version, migration);
        }
    }

    /// Returns true is a migration with the provided version has been registered.
    pub fn version_registered(&self, version: Version) -> bool {
        self.migrations.contains_key(&version)
    }

    /// Returns the set of all registered migration versions.
    pub fn registered_versions(&self) -> BTreeSet<Version> {
        self.migrations.keys().cloned().collect()
    }

    /// Returns the lowest version of the registered migrations, or `None` if no migrations have
    /// been registered.
    pub fn first_version(&self) -> Option<Version> {
        self.migrations.keys().next().map(|v| *v)
    }

    /// Returns the highest version of the registered migrations, or `None` if no migrations have
    /// been registered.
    pub fn last_version(&self) -> Option<Version> {
        self.migrations.keys().last().map(|v| *v)
    }

    /// Returns the latest migration version, or `None` if no migrations have been recorded.
    pub fn current_version(&self) -> Result<Option<Version>, Error<T::Error>> {
        match self.adapter.current_version() {
            Ok(ver) => Ok(ver),
            Err(err) => Err(Error::Adapter(err)),
        }
    }

    /// Returns a set of the versions of all of the currently applied migrations.
    pub fn migrated_versions(&self) -> Result<BTreeSet<Version>, Error<T::Error>> {
        match self.adapter.migrated_versions() {
            Ok(vers) => Ok(vers),
            Err(err) => Err(Error::Adapter(err)),
        }
    }

    /// Rollback to the specified version (exclusive), or rollback to the state before any
    /// registered migrations were applied if `None` is specified.
    pub fn down(&self, to: Option<Version>) -> Result<(), Error<T::Error>> {
        let from = try!(self.current_version());
        if from.is_none() {
            return Ok(());
        }

        let migrated_versions = try!(self.migrated_versions());
        let targets = self.migrations.iter()
            // Rollback migrations from latest to oldest:
            .rev()
            // Rollback the current version, and all versions downwards until the specified version
            // (exclusive):
            .filter(|&(&v, _)| within_range(v, to, from))
            // Rollback only the migrations that are actually already migrated (in the case that
            // some intermediary migrations were never executed).
            .filter(|&(v, _)| migrated_versions.contains(v));

        for (&version, migration) in targets {
            info!("Reverting migration {:?}: {}", version, migration.description());
            if let Err(err) = self.adapter.revert_migration(migration) {
                return Err(Error::Migration {
                    version: version,
                    description: migration.description(),
                    direction: Direction::Down,
                    error: err,
                });
            }
        }

        Ok(())
    }

    /// Migrate to the specified version (inclusive).
    pub fn up(&self, to: Option<Version>) -> Result<(), Error<T::Error>> {
        let migrated_versions = try!(self.migrated_versions());
        let targets = self.migrations.iter()
            // Execute all versions upwards until the specified version (inclusive):
            .filter(|&(&v, _)| within_range(v, None, to))
            // Execute only the migrations that are actually not already migrated (in the case that
            // some intermediary migrations were previously executed).
            .filter(|&(v, _)| !migrated_versions.contains(v));

        for (&version, migration) in targets {
            info!("Applying migration {:?}: {}", version, migration.description());
            if let Err(err) = self.adapter.apply_migration(migration) {
                return Err(Error::Migration {
                    version: version,
                    description: migration.description(),
                    direction: Direction::Up,
                    error: err,
                });
            }
        }

        Ok(())
    }
}

// Tests whether a `Version` is within a range defined by the exclusive `low` and the inclusive
// `high` bounds.
fn within_range(version: Version, low: Option<Version>, high: Option<Version>) -> bool {
    match (low, high) {
        (None, None) => true,
        (Some(low), None) => version > low,
        (None, Some(high)) => version <= high,
        (Some(low), Some(high)) => version > low && version <= high,
    }
}

#[test]
fn test_within_range() {
    // no lower or upper bound
    assert!(within_range(0, None, None));
    assert!(within_range(42, None, None));
    assert!(within_range(100000, None, None));

    // both lower and upper bounds
    assert!(!within_range(1, Some(2), Some(5)));
    assert!(!within_range(2, Some(2), Some(5)));
    assert!(within_range(3, Some(2), Some(5)));
    assert!(within_range(5, Some(2), Some(5)));
    assert!(!within_range(6, Some(2), Some(5)));

    // lower bound only
    assert!(!within_range(0, Some(5), None));
    assert!(!within_range(4, Some(5), None));
    assert!(!within_range(5, Some(5), None));
    assert!(within_range(6, Some(5), None));
    assert!(within_range(60, Some(5), None));

    // upper bound only
    assert!(within_range(0, None, Some(5)));
    assert!(within_range(5, None, Some(5)));
    assert!(!within_range(6, None, Some(5)));
}
<commit_msg>Code style normalization<commit_after>#[macro_use]
extern crate log;

use std::collections::{BTreeMap, BTreeSet};
use std::error::Error as StdError;
use std::fmt::{self, Display, Formatter};

/// The version type alias used to uniquely reference migrations.
pub type Version = i64;

/// All migrations will implement this trait, and a migration trait specific to the chosen adapter.
/// This trait defines the metadata for tracking migration sequence and for human reference.
pub trait Migration {
    /// An ordered (but not necessarily sequential), unique identifier for this migration.
    /// Registered migrations will be applied in ascending order by version.
    fn version(&self) -> Version;

    /// A message describing the effects of this migration.
    fn description(&self) -> &'static str;
}

/// A migration's direction.
#[derive(Debug)]
pub enum Direction {
    Down,
    Up,
}

/// An all-encompassing error type that can be returned during interaction with the migrator
/// adapter.
#[derive(Debug)]
pub enum Error<E> {
    /// A generic error that occurred while interacting with the adapter.
    Adapter(E),
    /// An error that arose from the adapter specifically during a migration's execution.
    Migration {
        /// The version of the migration that failed.
        version: Version,
        /// The description of the migration that failed.
        description: &'static str,
        /// The direction in which the failed migration was ran.
        direction: Direction,
        /// The underlying error from the adapter.
        error: E,
    }
}

impl<E: StdError> StdError for Error<E> {
    fn description(&self) -> &str {
        match *self {
            Error::Adapter(ref err) => err.description(),
            Error::Migration { ref error, .. } => error.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::Adapter(ref err) => Some(err),
            Error::Migration { ref error, .. } => Some(error),
        }
    }
}

impl<E: StdError> Display for Error<E> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Adapter(ref err) => write!(f, "Adataper error: {}", err),
            Error::Migration { ref description, ref error, .. } => {
                write!(f, "Error running migration {}, error: {}", description, error)
            },
        }
    }
}

/// Efficiently implement the `Migration` trait for a given type.
///
/// ## Example
///
/// ```rust
/// # #[macro_use]
/// # extern crate schemamama;
/// struct MyMigration;
/// migration!(MyMigration, 100, "create some lovely database tables");
///
/// # fn main() {
/// use schemamama::Migration;
/// let m = MyMigration;
/// assert_eq!(m.version(), 100);
/// assert_eq!(m.description(), "create some lovely database tables");
/// # }
/// ```
#[macro_export]
macro_rules! migration {
    ($ty:ident, $version:expr, $description:expr) => {
        impl $crate::Migration for $ty {
            fn version(&self) -> $crate::Version { $version }
            fn description(&self) -> &'static str { $description }
        }
    }
}

/// Use this trait to connect the migrator to your chosen database technology.
pub trait Adapter {
    /// An alias to a specific trait that extends `Migration`. Typically, the aforementioned trait
    /// will declare functions that the adapter will use to migrate upwards and downwards.
    type MigrationType: Migration + ?Sized;

    /// An adapter-specific error type that can be returned from any of this trait's methods.
    type Error;

    /// Returns the latest migration version, or `None` if no migrations have been recorded.
    fn current_version(&self) -> Result<Option<Version>, Self::Error>;

    /// Returns a set of the versions of all of the currently applied migrations.
    fn migrated_versions(&self) -> Result<BTreeSet<Version>, Self::Error>;

    /// Applies the specified migration.
    fn apply_migration(&self, migration: &Self::MigrationType) -> Result<(), Self::Error>;

    /// Reverts the specified migration.
    fn revert_migration(&self, migration: &Self::MigrationType) -> Result<(), Self::Error>;
}

/// Maintains an ordered collection of migrations to utilize.
pub struct Migrator<T: Adapter> {
    adapter: T,
    migrations: BTreeMap<Version, Box<T::MigrationType>>
}

impl<T: Adapter> Migrator<T> {
    /// Create a migrator with a given adapter.
    pub fn new(adapter: T) -> Migrator<T> {
        Migrator { adapter: adapter, migrations: BTreeMap::new() }
    }

    /// Get a reference to the adapter.
    pub fn adapter(&self) -> &T {
        &self.adapter
    }

    /// Register a migration. If a migration with the same version is already registered, a warning
    /// is logged and the registration fails.
    pub fn register(&mut self, migration: Box<T::MigrationType>) {
        let version = migration.version();
        if self.version_registered(version) {
            warn!("Migration with version {:?} is already registered", version);
        } else {
            self.migrations.insert(version, migration);
        }
    }

    /// Returns true is a migration with the provided version has been registered.
    pub fn version_registered(&self, version: Version) -> bool {
        self.migrations.contains_key(&version)
    }

    /// Returns the set of all registered migration versions.
    pub fn registered_versions(&self) -> BTreeSet<Version> {
        self.migrations.keys().cloned().collect()
    }

    /// Returns the lowest version of the registered migrations, or `None` if no migrations have
    /// been registered.
    pub fn first_version(&self) -> Option<Version> {
        self.migrations.keys().next().map(|v| *v)
    }

    /// Returns the highest version of the registered migrations, or `None` if no migrations have
    /// been registered.
    pub fn last_version(&self) -> Option<Version> {
        self.migrations.keys().last().map(|v| *v)
    }

    /// Returns the latest migration version, or `None` if no migrations have been recorded.
    pub fn current_version(&self) -> Result<Option<Version>, Error<T::Error>> {
        match self.adapter.current_version() {
            Ok(ver) => Ok(ver),
            Err(err) => Err(Error::Adapter(err)),
        }
    }

    /// Returns a set of the versions of all of the currently applied migrations.
    pub fn migrated_versions(&self) -> Result<BTreeSet<Version>, Error<T::Error>> {
        match self.adapter.migrated_versions() {
            Ok(vers) => Ok(vers),
            Err(err) => Err(Error::Adapter(err)),
        }
    }

    /// Rollback to the specified version (exclusive), or rollback to the state before any
    /// registered migrations were applied if `None` is specified.
    pub fn down(&self, to: Option<Version>) -> Result<(), Error<T::Error>> {
        let from = try!(self.current_version());
        if from.is_none() {
            return Ok(());
        }

        let migrated_versions = try!(self.migrated_versions());
        let targets = self.migrations.iter()
            // Rollback migrations from latest to oldest:
            .rev()
            // Rollback the current version, and all versions downwards until the specified version
            // (exclusive):
            .filter(|&(&v, _)| within_range(v, to, from))
            // Rollback only the migrations that are actually already migrated (in the case that
            // some intermediary migrations were never executed).
            .filter(|&(v, _)| migrated_versions.contains(v));

        for (&version, migration) in targets {
            info!("Reverting migration {:?}: {}", version, migration.description());
            if let Err(err) = self.adapter.revert_migration(migration) {
                return Err(Error::Migration {
                    version: version,
                    description: migration.description(),
                    direction: Direction::Down,
                    error: err,
                });
            }
        }

        Ok(())
    }

    /// Migrate to the specified version (inclusive).
    pub fn up(&self, to: Option<Version>) -> Result<(), Error<T::Error>> {
        let migrated_versions = try!(self.migrated_versions());
        let targets = self.migrations.iter()
            // Execute all versions upwards until the specified version (inclusive):
            .filter(|&(&v, _)| within_range(v, None, to))
            // Execute only the migrations that are actually not already migrated (in the case that
            // some intermediary migrations were previously executed).
            .filter(|&(v, _)| !migrated_versions.contains(v));

        for (&version, migration) in targets {
            info!("Applying migration {:?}: {}", version, migration.description());
            if let Err(err) = self.adapter.apply_migration(migration) {
                return Err(Error::Migration {
                    version: version,
                    description: migration.description(),
                    direction: Direction::Up,
                    error: err,
                });
            }
        }

        Ok(())
    }
}

// Tests whether a `Version` is within a range defined by the exclusive `low` and the inclusive
// `high` bounds.
fn within_range(version: Version, low: Option<Version>, high: Option<Version>) -> bool {
    match (low, high) {
        (None, None) => true,
        (Some(low), None) => version > low,
        (None, Some(high)) => version <= high,
        (Some(low), Some(high)) => version > low && version <= high,
    }
}

#[test]
fn test_within_range() {
    // no lower or upper bound
    assert!(within_range(0, None, None));
    assert!(within_range(42, None, None));
    assert!(within_range(100000, None, None));

    // both lower and upper bounds
    assert!(!within_range(1, Some(2), Some(5)));
    assert!(!within_range(2, Some(2), Some(5)));
    assert!(within_range(3, Some(2), Some(5)));
    assert!(within_range(5, Some(2), Some(5)));
    assert!(!within_range(6, Some(2), Some(5)));

    // lower bound only
    assert!(!within_range(0, Some(5), None));
    assert!(!within_range(4, Some(5), None));
    assert!(!within_range(5, Some(5), None));
    assert!(within_range(6, Some(5), None));
    assert!(within_range(60, Some(5), None));

    // upper bound only
    assert!(within_range(0, None, Some(5)));
    assert!(within_range(5, None, Some(5)));
    assert!(!within_range(6, None, Some(5)));
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::ffi::{CStr, CString};
use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;
use std::ptr;

#[derive(Debug)]
pub enum AresError {
    ENODATA = 1,
    EFORMERR,
    ESERVFAIL,
    ENOTFOUND,
    ENOTIMP,
    EREFUSED,
    EBADQUERY,
    EBADNAME,
    EBADFAMILY,
    EBADRESP,
    ECONNREFUSED,
    ETIMEOUT,
    EOF,
    EFILE,
    ENOMEM,
    EDESTRUCTION,
    EBADSTR,
    EBADFLAGS,
    ENONAME,
    EBADHINTS,
    ENOTINITIALIZED,
    ELOADIPHLPAPI,
    EADDRGETNETWORKPARAMS,
    ECANCELLED,
    UNKNOWN,
}

pub const SOCKET_BAD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD;

pub struct AResult {
    pub ip_addrs: Vec<Ipv4Addr>,
}

pub struct AAAAResult {
    pub ip_addrs: Vec<Ipv6Addr>,
}

pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

unsafe impl Send for Channel { }

impl Channel {
    pub fn new<F>(callback: F) -> Result<Channel, AresError>
        where F: FnOnce(io::RawFd, bool, bool) + 'static {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        match lib_rc {
            c_ares_sys::ARES_SUCCESS => (),
            _ => return Err(ares_error(lib_rc))
        }

        // TODO suport user-provided options
        let mut ares_channel = ptr::null_mut();
        let mut options = c_ares_sys::Struct_ares_options::default();
        options.flags = c_ares_sys::ARES_FLAG_STAYOPEN;
        options.timeout = 500;
        options.tries = 3;
        options.sock_state_cb = Some(socket_callback::<F>);
        options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        let optmask =
            c_ares_sys::ARES_OPT_FLAGS |
            c_ares_sys::ARES_OPT_TIMEOUT |
            c_ares_sys::ARES_OPT_TRIES |
            c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(&mut ares_channel, &mut options, optmask)
        };

        match channel_rc {
            c_ares_sys::ARES_SUCCESS => (),
            _ => {
                unsafe { c_ares_sys::ares_library_cleanup(); }
                return Err(ares_error(channel_rc))
            }
        }
        let channel = Channel {
            ares_channel: ares_channel,
        };

        // TODO ares_set_servers() here too?
        Ok(channel)
    }

    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }

    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(self.ares_channel, read_fd, write_fd);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

pub fn str_error<'a>(code: AresError) -> &'a str {
    let buf = unsafe {
        let ptr = c_ares_sys::ares_strerror(code as libc::c_int);
        CStr::from_ptr(ptr).to_bytes()
    };
    std::str::from_utf8(buf).unwrap()
}

// Convert an error code from the library into a more strongly typed AresError.
fn ares_error(code: libc::c_int) -> AresError {
    match code {
        c_ares_sys::ARES_ENODATA => AresError::ENODATA,
        c_ares_sys::ARES_EFORMERR => AresError::EFORMERR,
        c_ares_sys::ARES_ESERVFAIL => AresError::ESERVFAIL,
        c_ares_sys::ARES_ENOTFOUND => AresError::ENOTFOUND,
        c_ares_sys::ARES_ENOTIMP => AresError::ENOTIMP,
        c_ares_sys::ARES_EREFUSED => AresError::EREFUSED,
        c_ares_sys::ARES_EBADQUERY => AresError::EBADQUERY,
        c_ares_sys::ARES_EBADNAME => AresError::EBADNAME,
        c_ares_sys::ARES_EBADFAMILY => AresError::EBADFAMILY,
        c_ares_sys::ARES_EBADRESP => AresError::EBADRESP,
        c_ares_sys::ARES_ECONNREFUSED => AresError::ECONNREFUSED,
        c_ares_sys::ARES_ETIMEOUT => AresError::ETIMEOUT,
        c_ares_sys::ARES_EOF => AresError::EOF,
        c_ares_sys::ARES_EFILE => AresError::EFILE,
        c_ares_sys::ARES_ENOMEM => AresError::ENOMEM,
        c_ares_sys::ARES_EDESTRUCTION => AresError::EDESTRUCTION,
        c_ares_sys::ARES_EBADSTR => AresError::EBADSTR,
        c_ares_sys::ARES_EBADFLAGS => AresError::EBADFLAGS,
        c_ares_sys::ARES_ENONAME => AresError::ENONAME,
        c_ares_sys::ARES_EBADHINTS => AresError::EBADHINTS,
        c_ares_sys::ARES_ENOTINITIALIZED => AresError::ENOTINITIALIZED,
        c_ares_sys::ARES_ELOADIPHLPAPI => AresError::ELOADIPHLPAPI,
        c_ares_sys::ARES_EADDRGETNETWORKPARAMS => AresError::EADDRGETNETWORKPARAMS,
        c_ares_sys::ARES_ECANCELLED => AresError::ECANCELLED,
        _ => AresError::UNKNOWN,
    }
}

#[repr(C)]
struct hostent {
    h_name: *mut libc::c_char,
    h_aliases: *mut *mut libc::c_char,
    h_addrtype: libc::c_int,
    h_length: libc::c_int,
    h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
enum DnsClass {
   IN = 1,
}

extern "C" fn socket_callback<F>(
    data: *mut libc::c_void,
    socket_fd: c_ares_sys::ares_socket_t,
    readable: libc::c_int,
    writable: libc::c_int)
    where F: FnOnce(io::RawFd, bool, bool) + 'static {
    let handler: Box<F> = unsafe { mem::transmute(data) };
    handler(socket_fd as io::RawFd, readable != 0, writable != 0);
}

extern "C" fn query_a_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AResult, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_a_reply(
                abuf,
                alen,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let mut answers = Vec::new();
            unsafe {
                let mut ptr = (*hostent).h_addr_list;
                while !(*ptr).is_null() {
                    let h_addr = *ptr;
                    let ip_addr = Ipv4Addr::new(
                        *h_addr as u8,
                        *h_addr.offset(1) as u8,
                        *h_addr.offset(2) as u8,
                        *h_addr.offset(3) as u8);
                    answers.push(ip_addr);
                    ptr = ptr.offset(1);
                }
                c_ares_sys::ares_free_hostent(hostent as *mut c_ares_sys::Struct_hostent);
            }
            Ok(AResult { ip_addrs: answers })
        }
    };

    let handler: Box<F> = unsafe { mem::transmute(arg) };
    handler(result);
}

extern "C" fn query_aaaa_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                abuf,
                alen,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let mut answers = Vec::new();
            unsafe {
                let mut ptr = (*hostent).h_addr_list;
                while !(*ptr).is_null() {
                    let h_addr = *ptr;
                    let ip_addr = Ipv6Addr::new(
                        ((*h_addr as u16) << 8) + *h_addr.offset(1) as u16,
                        ((*h_addr.offset(2) as u16) << 8) + *h_addr.offset(3) as u16,
                        ((*h_addr.offset(4) as u16) << 8) + *h_addr.offset(5) as u16,
                        ((*h_addr.offset(6) as u16) << 8) + *h_addr.offset(7) as u16,
                        ((*h_addr.offset(8) as u16) << 8) + *h_addr.offset(9) as u16,
                        ((*h_addr.offset(10) as u16) << 8) + *h_addr.offset(11) as u16,
                        ((*h_addr.offset(12) as u16) << 8) + *h_addr.offset(13) as u16,
                        ((*h_addr.offset(14) as u16) << 8) + *h_addr.offset(15) as u16);
                    answers.push(ip_addr);
                    ptr = ptr.offset(1);
                }
                c_ares_sys::ares_free_hostent(hostent as *mut c_ares_sys::Struct_hostent);
            }
            Ok(AAAAResult { ip_addrs: answers })
        }
    };

    let handler: Box<F> = unsafe { mem::transmute(arg) };
    handler(result);
}
<commit_msg>More moving code - no real changes<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::ffi::{CStr, CString};
use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;
use std::ptr;

#[derive(Debug)]
pub enum AresError {
    ENODATA = 1,
    EFORMERR,
    ESERVFAIL,
    ENOTFOUND,
    ENOTIMP,
    EREFUSED,
    EBADQUERY,
    EBADNAME,
    EBADFAMILY,
    EBADRESP,
    ECONNREFUSED,
    ETIMEOUT,
    EOF,
    EFILE,
    ENOMEM,
    EDESTRUCTION,
    EBADSTR,
    EBADFLAGS,
    ENONAME,
    EBADHINTS,
    ENOTINITIALIZED,
    ELOADIPHLPAPI,
    EADDRGETNETWORKPARAMS,
    ECANCELLED,
    UNKNOWN,
}

pub const SOCKET_BAD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD;

pub struct AResult {
    pub ip_addrs: Vec<Ipv4Addr>,
}

pub struct AAAAResult {
    pub ip_addrs: Vec<Ipv6Addr>,
}

pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    pub fn new<F>(callback: F) -> Result<Channel, AresError>
        where F: FnOnce(io::RawFd, bool, bool) + 'static {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        match lib_rc {
            c_ares_sys::ARES_SUCCESS => (),
            _ => return Err(ares_error(lib_rc))
        }

        // TODO suport user-provided options
        let mut ares_channel = ptr::null_mut();
        let mut options = c_ares_sys::Struct_ares_options::default();
        options.flags = c_ares_sys::ARES_FLAG_STAYOPEN;
        options.timeout = 500;
        options.tries = 3;
        options.sock_state_cb = Some(socket_callback::<F>);
        options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        let optmask =
            c_ares_sys::ARES_OPT_FLAGS |
            c_ares_sys::ARES_OPT_TIMEOUT |
            c_ares_sys::ARES_OPT_TRIES |
            c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(&mut ares_channel, &mut options, optmask)
        };

        match channel_rc {
            c_ares_sys::ARES_SUCCESS => (),
            _ => {
                unsafe { c_ares_sys::ares_library_cleanup(); }
                return Err(ares_error(channel_rc))
            }
        }
        let channel = Channel {
            ares_channel: ares_channel,
        };

        // TODO ares_set_servers() here too?
        Ok(channel)
    }

    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }

    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(self.ares_channel, read_fd, write_fd);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }

pub fn str_error<'a>(code: AresError) -> &'a str {
    let buf = unsafe {
        let ptr = c_ares_sys::ares_strerror(code as libc::c_int);
        CStr::from_ptr(ptr).to_bytes()
    };
    std::str::from_utf8(buf).unwrap()
}

// Convert an error code from the library into a more strongly typed AresError.
fn ares_error(code: libc::c_int) -> AresError {
    match code {
        c_ares_sys::ARES_ENODATA => AresError::ENODATA,
        c_ares_sys::ARES_EFORMERR => AresError::EFORMERR,
        c_ares_sys::ARES_ESERVFAIL => AresError::ESERVFAIL,
        c_ares_sys::ARES_ENOTFOUND => AresError::ENOTFOUND,
        c_ares_sys::ARES_ENOTIMP => AresError::ENOTIMP,
        c_ares_sys::ARES_EREFUSED => AresError::EREFUSED,
        c_ares_sys::ARES_EBADQUERY => AresError::EBADQUERY,
        c_ares_sys::ARES_EBADNAME => AresError::EBADNAME,
        c_ares_sys::ARES_EBADFAMILY => AresError::EBADFAMILY,
        c_ares_sys::ARES_EBADRESP => AresError::EBADRESP,
        c_ares_sys::ARES_ECONNREFUSED => AresError::ECONNREFUSED,
        c_ares_sys::ARES_ETIMEOUT => AresError::ETIMEOUT,
        c_ares_sys::ARES_EOF => AresError::EOF,
        c_ares_sys::ARES_EFILE => AresError::EFILE,
        c_ares_sys::ARES_ENOMEM => AresError::ENOMEM,
        c_ares_sys::ARES_EDESTRUCTION => AresError::EDESTRUCTION,
        c_ares_sys::ARES_EBADSTR => AresError::EBADSTR,
        c_ares_sys::ARES_EBADFLAGS => AresError::EBADFLAGS,
        c_ares_sys::ARES_ENONAME => AresError::ENONAME,
        c_ares_sys::ARES_EBADHINTS => AresError::EBADHINTS,
        c_ares_sys::ARES_ENOTINITIALIZED => AresError::ENOTINITIALIZED,
        c_ares_sys::ARES_ELOADIPHLPAPI => AresError::ELOADIPHLPAPI,
        c_ares_sys::ARES_EADDRGETNETWORKPARAMS => AresError::EADDRGETNETWORKPARAMS,
        c_ares_sys::ARES_ECANCELLED => AresError::ECANCELLED,
        _ => AresError::UNKNOWN,
    }
}

#[repr(C)]
struct hostent {
    h_name: *mut libc::c_char,
    h_aliases: *mut *mut libc::c_char,
    h_addrtype: libc::c_int,
    h_length: libc::c_int,
    h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
enum DnsClass {
   IN = 1,
}

extern "C" fn socket_callback<F>(
    data: *mut libc::c_void,
    socket_fd: c_ares_sys::ares_socket_t,
    readable: libc::c_int,
    writable: libc::c_int)
    where F: FnOnce(io::RawFd, bool, bool) + 'static {
    let handler: Box<F> = unsafe { mem::transmute(data) };
    handler(socket_fd as io::RawFd, readable != 0, writable != 0);
}

extern "C" fn query_a_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AResult, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_a_reply(
                abuf,
                alen,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let mut answers = Vec::new();
            unsafe {
                let mut ptr = (*hostent).h_addr_list;
                while !(*ptr).is_null() {
                    let h_addr = *ptr;
                    let ip_addr = Ipv4Addr::new(
                        *h_addr as u8,
                        *h_addr.offset(1) as u8,
                        *h_addr.offset(2) as u8,
                        *h_addr.offset(3) as u8);
                    answers.push(ip_addr);
                    ptr = ptr.offset(1);
                }
                c_ares_sys::ares_free_hostent(hostent as *mut c_ares_sys::Struct_hostent);
            }
            Ok(AResult { ip_addrs: answers })
        }
    };

    let handler: Box<F> = unsafe { mem::transmute(arg) };
    handler(result);
}

extern "C" fn query_aaaa_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                abuf,
                alen,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let mut answers = Vec::new();
            unsafe {
                let mut ptr = (*hostent).h_addr_list;
                while !(*ptr).is_null() {
                    let h_addr = *ptr;
                    let ip_addr = Ipv6Addr::new(
                        ((*h_addr as u16) << 8) + *h_addr.offset(1) as u16,
                        ((*h_addr.offset(2) as u16) << 8) + *h_addr.offset(3) as u16,
                        ((*h_addr.offset(4) as u16) << 8) + *h_addr.offset(5) as u16,
                        ((*h_addr.offset(6) as u16) << 8) + *h_addr.offset(7) as u16,
                        ((*h_addr.offset(8) as u16) << 8) + *h_addr.offset(9) as u16,
                        ((*h_addr.offset(10) as u16) << 8) + *h_addr.offset(11) as u16,
                        ((*h_addr.offset(12) as u16) << 8) + *h_addr.offset(13) as u16,
                        ((*h_addr.offset(14) as u16) << 8) + *h_addr.offset(15) as u16);
                    answers.push(ip_addr);
                    ptr = ptr.offset(1);
                }
                c_ares_sys::ares_free_hostent(hostent as *mut c_ares_sys::Struct_hostent);
            }
            Ok(AAAAResult { ip_addrs: answers })
        }
    };

    let handler: Box<F> = unsafe { mem::transmute(arg) };
    handler(result);
}
<|endoftext|>


<commit_before>//! `textwrap` provides functions for word wrapping and filling text.

extern crate unicode_width;

use std::iter;
use unicode_width::UnicodeWidthStr;

/// Fill a line of text at `width` bytes.
///
/// The result is a string with newlines between each line. Use `wrap`
/// if you need access to the individual lines.
///
/// ```
/// use textwrap::fill;
///
/// assert_eq!(fill("Memory safety without garbage collection.", 15),
///            "Memory safety\nwithout garbage\ncollection.");
/// ```
pub fn fill(s: &str, width: usize) -> String {
    wrap(s, width).join("\n")
}

/// Wrap a line of text at `width` bytes and return a vector of lines.
///
/// ```
/// use textwrap::wrap;
///
/// assert_eq!(wrap("Concurrency without data races.", 15),
///            vec!["Concurrency",
///                 "without data",
///                 "races."]);
///
/// assert_eq!(wrap("Concurrency without data races.", 20),
///            vec!["Concurrency without",
///                 "data races."]);
/// ```
pub fn wrap(s: &str, width: usize) -> Vec<String> {
    let mut result = Vec::new();
    let mut line = Vec::new();
    let mut line_width = 0;

    for mut word in s.split_whitespace() {
        while !word.is_empty() {
            let splits = split_word(&word);
            let (smallest, longest) = splits[0];
            let min_width = smallest.width();

            // Add a new line if even the smallest split doesn't fit.
            if !line.is_empty() && line_width + line.len() + min_width > width {
                result.push(line.join(" "));
                line = Vec::new();
                line_width = 0;
            }

            // Find a split that fits on the current line.
            for &(head, tail) in splits.iter().rev() {
                if line_width + line.len() + head.width() <= width {
                    line.push(head);
                    line_width += head.width();
                    word = tail;
                    break;
                }
            }

            // If nothing got added, we forcibly add the smallest
            // split and continue with the longest tail.
            if line_width == 0 {
                result.push(String::from(smallest));
                line_width = 0;
                word = longest;
            }
        }
    }
    if !line.is_empty() {
        result.push(line.join(" "));
    }
    return result;
}

/// Split word into all possible parts (head, tail). Word must be
/// non-empty. The returned vector will always be non-empty.
fn split_word(word: &str) -> Vec<(&str, &str)> {
    let hyphens = word.match_indices('-');
    let word_end = iter::once((word.len() - 1, ""));
    return hyphens.chain(word_end)
        .map(|(n, _)| word.split_at(n + 1))
        .collect();
}

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

    #[test]
    fn no_wrap() {
        assert_eq!(wrap("foo", 10), vec!["foo"]);
    }

    #[test]
    fn simple() {
        assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
    }

    #[test]
    fn multi_word_on_line() {
        assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
    }

    #[test]
    fn long_word() {
        assert_eq!(wrap("foo", 0), vec!["foo"]);
    }

    #[test]
    fn long_words() {
        assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
    }

    #[test]
    fn whitespace_is_squeezed() {
        assert_eq!(wrap(" foo \t  bar  ", 10), vec!["foo bar"]);
    }

    #[test]
    fn wide_character_handling() {
        assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
        assert_eq!(wrap("Ｈｅｌｌｏ, Ｗｏｒｌｄ!", 15),
                   vec!["Ｈｅｌｌｏ,", "Ｗｏｒｌｄ!"]);
    }

    #[test]
    fn hyphens() {
        assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
    }

    #[test]
    fn trailing_hyphen() {
        assert_eq!(wrap("foobar-", 5), vec!["foobar-"]);
    }

    #[test]
    fn multiple_hyphens() {
        assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
    }

    #[test]
    fn multiple_splits() {
        assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
    }

    #[test]
    fn forced_split() {
        assert_eq!(wrap("foobar-baz", 5), vec!["foobar-", "baz"]);
    }

    #[test]
    fn test_fill() {
        assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
    }
}
<commit_msg>Wrapper: introduce struct for holding settings<commit_after>//! `textwrap` provides functions for word wrapping and filling text.

extern crate unicode_width;

use std::iter;
use unicode_width::UnicodeWidthStr;

/// A Wrapper holds settings for wrapping text.
pub struct Wrapper {
    width: usize,
}

impl Wrapper {
    /// Create a new Wrapper for wrapping at the specified width.
    pub fn new(width: usize) -> Wrapper {
        Wrapper { width: width }
    }

    /// Fill a line of text at `self.width` bytes.
    ///
    /// The result is a string with newlines between each line. Use
    /// the `wrap` method if you need access to the individual lines.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrapper = Wrapper::new(15);
    /// assert_eq!(wrapper.fill("Memory safety without garbage collection."),
    ///            "Memory safety\nwithout garbage\ncollection.");
    /// ```
    pub fn fill(&self, s: &str) -> String {
        self.wrap(&s).join("\n")
    }

    /// Wrap a line of text at `self.width` bytes and return a vector
    /// of lines.
    ///
    /// ```
    /// use textwrap::Wrapper;
    ///
    /// let wrap15 = Wrapper::new(15);
    /// assert_eq!(wrap15.wrap("Concurrency without data races."),
    ///            vec!["Concurrency",
    ///                 "without data",
    ///                 "races."]);
    ///
    /// let wrap20 = Wrapper::new(20);
    /// assert_eq!(wrap20.wrap("Concurrency without data races."),
    ///            vec!["Concurrency without",
    ///                 "data races."]);
    /// ```
    pub fn wrap(&self, s: &str) -> Vec<String> {
        let mut result = Vec::new();
        let mut line = Vec::new();
        let mut line_width = 0;

        for mut word in s.split_whitespace() {
            while !word.is_empty() {
                let splits = split_word(&word);
                let (smallest, longest) = splits[0];
                let min_width = smallest.width();

                // Add a new line if even the smallest split doesn't
                // fit.
                if !line.is_empty() && line_width + line.len() + min_width > self.width {
                    result.push(line.join(" "));
                    line = Vec::new();
                    line_width = 0;
                }

                // Find a split that fits on the current line.
                for &(head, tail) in splits.iter().rev() {
                    if line_width + line.len() + head.width() <= self.width {
                        line.push(head);
                        line_width += head.width();
                        word = tail;
                        break;
                    }
                }

                // If nothing got added, we forcibly add the smallest
                // split and continue with the longest tail.
                if line_width == 0 {
                    result.push(String::from(smallest));
                    line_width = 0;
                    word = longest;
                }
            }
        }
        if !line.is_empty() {
            result.push(line.join(" "));
        }
        return result;
    }
}

/// Fill a line of text at `width` bytes.
///
/// The result is a string with newlines between each line. Use `wrap`
/// if you need access to the individual lines.
///
/// ```
/// use textwrap::fill;
///
/// assert_eq!(fill("Memory safety without garbage collection.", 15),
///            "Memory safety\nwithout garbage\ncollection.");
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`fill` method](struct.Wrapper.html#method.fill).
pub fn fill(s: &str, width: usize) -> String {
    wrap(s, width).join("\n")
}

/// Wrap a line of text at `width` bytes and return a vector of lines.
///
/// ```
/// use textwrap::wrap;
///
/// assert_eq!(wrap("Concurrency without data races.", 15),
///            vec!["Concurrency",
///                 "without data",
///                 "races."]);
///
/// assert_eq!(wrap("Concurrency without data races.", 20),
///            vec!["Concurrency without",
///                 "data races."]);
/// ```
///
/// This function creates a Wrapper on the fly. If you need to wrap
/// many strings, it can be more efficient to create a single Wrapper
/// and call its [`wrap` method](struct.Wrapper.html#method.wrap).
pub fn wrap(s: &str, width: usize) -> Vec<String> {
    Wrapper::new(width).wrap(s)
}

/// Split word into all possible parts (head, tail). Word must be
/// non-empty. The returned vector will always be non-empty.
fn split_word(word: &str) -> Vec<(&str, &str)> {
    let hyphens = word.match_indices('-');
    let word_end = iter::once((word.len() - 1, ""));
    return hyphens.chain(word_end)
        .map(|(n, _)| word.split_at(n + 1))
        .collect();
}

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

    #[test]
    fn no_wrap() {
        assert_eq!(wrap("foo", 10), vec!["foo"]);
    }

    #[test]
    fn simple() {
        assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
    }

    #[test]
    fn multi_word_on_line() {
        assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
    }

    #[test]
    fn long_word() {
        assert_eq!(wrap("foo", 0), vec!["foo"]);
    }

    #[test]
    fn long_words() {
        assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
    }

    #[test]
    fn whitespace_is_squeezed() {
        assert_eq!(wrap(" foo \t  bar  ", 10), vec!["foo bar"]);
    }

    #[test]
    fn wide_character_handling() {
        assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
        assert_eq!(wrap("Ｈｅｌｌｏ, Ｗｏｒｌｄ!", 15),
                   vec!["Ｈｅｌｌｏ,", "Ｗｏｒｌｄ!"]);
    }

    #[test]
    fn hyphens() {
        assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
    }

    #[test]
    fn trailing_hyphen() {
        assert_eq!(wrap("foobar-", 5), vec!["foobar-"]);
    }

    #[test]
    fn multiple_hyphens() {
        assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
    }

    #[test]
    fn multiple_splits() {
        assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
    }

    #[test]
    fn forced_split() {
        assert_eq!(wrap("foobar-baz", 5), vec!["foobar-", "baz"]);
    }

    #[test]
    fn test_fill() {
        assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(convert)]
mod token;

pub fn compile(sass: String, style: &str) -> Result<String, &'static str> {
    let mut sp = SassParser::new(sass);
    let parsed = try!(sp.parse());
    match style {
        "nested"     => Ok(parsed.nested(&sp)),
        "compressed" => Ok(parsed.compressed(&sp)),
        "expanded"   => Ok(parsed.expanded(&sp)),
        "compact"    => Ok(parsed.compact(&sp)),
        _            => Err("Unknown style:. Please specify one of nested, compressed, expanded, or compact."),
    }
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

impl SassRuleSet {
    fn nested(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).nested(&sp).as_str());
        }
        output
    }

    fn compressed(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).compressed(&sp).as_str());
        }
        output
    }

    fn expanded(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).expanded(&sp).as_str());
        }
        output
    }

    fn compact(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).compact(&sp).as_str());
        }
        output
    }
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
}

impl SassRule {
    fn nested(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("\n  {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str(" }\n");

        output
    }

    fn compressed(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str("{");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("{}:{}", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str("}\n");

        output
    }

    fn expanded(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("\n  {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str("\n}\n");

        output
    }

    fn compact(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!(" {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str(" }\n");

        output
    }
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub token: token::Range,
    pub last_token: token::Range,
    pub tokenizer: SassTokenizer,
    sass: String,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut tokenizer = SassTokenizer::new(str.clone());
        let initial_token = tokenizer.real_token();
        SassParser {
            token: initial_token.clone(),
            last_token: initial_token.clone(),
            tokenizer: tokenizer,
            sass: str,
        }
    }

    pub fn extract(&self, range: &token::Range) -> &str {
        self.sass.slice_chars(range.start_pos as usize, range.end_pos as usize)
    }

    pub fn bump(&mut self) {
        self.last_token = self.token.clone();
        self.token = self.tokenizer.real_token();
    }

    pub fn parse(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            return Err("Empty selector!")
        }

        let mut props_and_values = vec![];
        while let Some(property_value_set_or_subrule) = try!(self.parse_property_value_set_or_subrule()) {
            props_and_values.push(property_value_set_or_subrule);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values }))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::Text {
            self.bump();
            return Ok(Some(self.last_token.clone()))
        }

        match &self.token.token {
            &token::OpenDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set_or_subrule(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::CloseDelim(token::Brace) {
            self.bump();
            return Ok(None)
        }

        let p = self.token.clone();

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now

                let v = self.token.clone();

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    return Err("Expected a value here, instead got who knows what!")
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    pub peek_range: token::Range,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
            sass: str,
        };
        sr.bump();
        sr.advance_token();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn advance_token(&mut self) {
        match self.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.is_eof() {
                    self.peek_range = token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.next_token_inner();
                }
            },
        }
    }

    fn next_token(&mut self) -> token::Range {
        let retval = self.peek_range.clone();
        self.advance_token();
        retval
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn real_token(&mut self) -> token::Range {
        let mut t = self.next_token();
        loop {
            match t.token {
                token::Whitespace => {
                    t = self.next_token();
                },
                _ => break,
            }
        }
        t
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<commit_msg>Set up data structures to have subrule sets<commit_after>#![feature(collections)]
#![feature(convert)]
mod token;

pub fn compile(sass: String, style: &str) -> Result<String, &'static str> {
    let mut sp = SassParser::new(sass);
    let parsed = try!(sp.parse());
    match style {
        "nested"     => Ok(parsed.nested(&sp)),
        "compressed" => Ok(parsed.compressed(&sp)),
        "expanded"   => Ok(parsed.expanded(&sp)),
        "compact"    => Ok(parsed.compact(&sp)),
        _            => Err("Unknown style:. Please specify one of nested, compressed, expanded, or compact."),
    }
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

impl SassRuleSet {
    fn nested(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).nested(&sp).as_str());
        }
        output
    }

    fn compressed(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).compressed(&sp).as_str());
        }
        output
    }

    fn expanded(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).expanded(&sp).as_str());
        }
        output
    }

    fn compact(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");
        for rule in &self.rules {
            output.push_str((&rule).compact(&sp).as_str());
        }
        output
    }
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
    pub subrule_set: SassRuleSet,
}

impl SassRule {
    fn nested(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("\n  {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str(" }\n");

        output
    }

    fn compressed(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str("{");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("{}:{}", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str("}\n");

        output
    }

    fn expanded(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!("\n  {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str("\n}\n");

        output
    }

    fn compact(&self, sp: &SassParser) -> String {
        let mut output =  String::from_str("");

        for selector in &self.selectors {
            output.push_str(&sp.extract(selector));
        }

        output.push_str(" {");

        for prop_and_val in &self.props_and_values {
            output.push_str(format!(" {}: {};", &sp.extract(&prop_and_val.property), &sp.extract(&prop_and_val.value)).as_str());
        }

        output.push_str(" }\n");

        output
    }
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub token: token::Range,
    pub last_token: token::Range,
    pub tokenizer: SassTokenizer,
    sass: String,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut tokenizer = SassTokenizer::new(str.clone());
        let initial_token = tokenizer.real_token();
        SassParser {
            token: initial_token.clone(),
            last_token: initial_token.clone(),
            tokenizer: tokenizer,
            sass: str,
        }
    }

    pub fn extract(&self, range: &token::Range) -> &str {
        self.sass.slice_chars(range.start_pos as usize, range.end_pos as usize)
    }

    pub fn bump(&mut self) {
        self.last_token = self.token.clone();
        self.token = self.tokenizer.real_token();
    }

    pub fn parse(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            return Err("Empty selector!")
        }

        let mut props_and_values = vec![];
        let mut subrules = vec![];
        while let Some(property_value_set_or_subrule) = try!(self.parse_property_value_set_or_subrule()) {
            props_and_values.push(property_value_set_or_subrule);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values, subrule_set: SassRuleSet { rules: subrules }}))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::Text {
            self.bump();
            return Ok(Some(self.last_token.clone()))
        }

        match &self.token.token {
            &token::OpenDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set_or_subrule(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        if self.token.token == token::Eof {
            return Ok(None)
        }

        if self.token.token == token::CloseDelim(token::Brace) {
            self.bump();
            return Ok(None)
        }

        let p = self.token.clone();

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now

                let v = self.token.clone();

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    return Err("Expected a value here, instead got who knows what!")
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    pub peek_range: token::Range,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
            sass: str,
        };
        sr.bump();
        sr.advance_token();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn advance_token(&mut self) {
        match self.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.is_eof() {
                    self.peek_range = token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.next_token_inner();
                }
            },
        }
    }

    fn next_token(&mut self) -> token::Range {
        let retval = self.peek_range.clone();
        self.advance_token();
        retval
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn real_token(&mut self) -> token::Range {
        let mut t = self.next_token();
        loop {
            match t.token {
                token::Whitespace => {
                    t = self.next_token();
                },
                _ => break,
            }
        }
        t
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>/*!

[Sidekiq](https://github.com/mperham/sidekiq) client allowing to push jobs.
Using the [Sidekiq job
format](https://github.com/mperham/sidekiq/wiki/Job-Format) as reference.

# Default environment variables

* `REDIS_URL`="redis://127.0.0.1/"
*/
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![crate_name = "sidekiq"]

extern crate serde;
extern crate serde_json;
extern crate rand;
extern crate r2d2;
extern crate r2d2_redis;

mod sidekiq;
pub use serde_json::value::Value;
pub use sidekiq::{Job, JobOpts, Client, ClientOpts, RedisPool, RedisPooledConnection,
                  create_redis_pool};
<commit_msg>Rust fmt<commit_after>//! [Sidekiq](https://github.com/mperham/sidekiq) client allowing to push jobs.
//! Using the [Sidekiq job
//! format](https://github.com/mperham/sidekiq/wiki/Job-Format) as reference.
//!
//! # Default environment variables
//!
//! `REDIS_URL`="redis://127.0.0.1/"
//!
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![crate_name = "sidekiq"]

extern crate serde;
extern crate serde_json;
extern crate rand;
extern crate r2d2;
extern crate r2d2_redis;

mod sidekiq;
pub use serde_json::value::Value;
pub use sidekiq::{Job, JobOpts, Client, ClientOpts, RedisPool, RedisPooledConnection,
                  create_redis_pool};
<|endoftext|>


<commit_before>#![feature(zero_one)]
use std::iter::Iterator;
use std::num::{Zero, One};
use std::ops::{BitAnd, BitOr, Shr, Shl};

pub struct BiteratorLsb<T> {
    val: T,
    at_end: bool
}

impl<T> BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    pub fn new(init: T) -> BiteratorLsb<T> {
        BiteratorLsb{val: init, at_end: false}
    }
}

impl<T> Iterator for BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    type Item = bool;

    fn next(&mut self) -> Option<bool> {
        if self.at_end { return None; }

        let lsb = self.val & T::one();
        self.val = self.val >> 1usize;
        if self.val == T::zero() {
            self.at_end = true;
        }

        if lsb == T::zero() {
            Some(false)
        } else {
            Some(true)
        }
    }
}

pub fn build_from<T, I>(iter: &mut I, max: usize) -> T
    where I: Iterator<Item=bool>,
          T: Zero + One + BitOr<T, Output=T> + Shl<usize, Output=T>
{
    let mut val: T = T::zero();

    let mut i = 0;
    loop {
        if i >= max { break; }
        let bit = match iter.next() {
            Some(true)  => T::one(),
            Some(false) => T::zero(),
            None => break
        };
        val = val | (bit << i);
        i += 1;
    }

    return val;
}

#[test]
fn test_bitstream() {
    let v: Vec<_> = BiteratorLsb::new(12u64).collect();
    assert_eq!([false, false, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b1110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b001110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);
}

#[test]
fn test_build_from() {
    let num = 0b001110u8;
    let n = build_from(&mut BiteratorLsb::new(num), 8);
    assert_eq!(num, n);
}

#[test]
fn test_build_from_partial() {
    let mut iter = BiteratorLsb::new(0b1110u8);
    assert_eq!(0b0u8, build_from(&mut iter, 1));
    assert_eq!(0b11u8, build_from(&mut iter, 2));
    assert_eq!(0b1u8, build_from(&mut iter, 1));
}
<commit_msg>Change to Self::Item<commit_after>#![feature(zero_one)]
use std::iter::Iterator;
use std::num::{Zero, One};
use std::ops::{BitAnd, BitOr, Shr, Shl};

pub struct BiteratorLsb<T> {
    val: T,
    at_end: bool
}

impl<T> BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    pub fn new(init: T) -> BiteratorLsb<T> {
        BiteratorLsb{val: init, at_end: false}
    }
}

impl<T> Iterator for BiteratorLsb<T>
    where T : Sized+Eq+Shr<usize, Output=T>+Ord+BitAnd<T, Output=T>+Zero+One+Copy
{
    type Item = bool;

    fn next(&mut self) -> Option<Self::Item> {
        if self.at_end { return None; }

        let lsb = self.val & T::one();
        self.val = self.val >> 1usize;
        if self.val == T::zero() {
            self.at_end = true;
        }

        if lsb == T::zero() {
            Some(false)
        } else {
            Some(true)
        }
    }
}

pub fn build_from<T, I>(iter: &mut I, max: usize) -> T
    where I: Iterator<Item=bool>,
          T: Zero + One + BitOr<T, Output=T> + Shl<usize, Output=T>
{
    let mut val: T = T::zero();

    let mut i = 0;
    loop {
        if i >= max { break; }
        let bit = match iter.next() {
            Some(true)  => T::one(),
            Some(false) => T::zero(),
            None => break
        };
        val = val | (bit << i);
        i += 1;
    }

    return val;
}

#[test]
fn test_bitstream() {
    let v: Vec<_> = BiteratorLsb::new(12u64).collect();
    assert_eq!([false, false, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b1110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);

    let v: Vec<_> = BiteratorLsb::new(0b001110u8).collect();
    assert_eq!([false, true, true, true], &v[..]);
}

#[test]
fn test_build_from() {
    let num = 0b001110u8;
    let n = build_from(&mut BiteratorLsb::new(num), 8);
    assert_eq!(num, n);
}

#[test]
fn test_build_from_partial() {
    let mut iter = BiteratorLsb::new(0b1110u8);
    assert_eq!(0b0u8, build_from(&mut iter, 1));
    assert_eq!(0b11u8, build_from(&mut iter, 2));
    assert_eq!(0b1u8, build_from(&mut iter, 1));
}
<|endoftext|>