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

use std::collections::btree_map::{BTreeMap, Range};
use std::collections::Bound::*;
use std::cmp::Ordering::*;
use std::iter::Peekable;

use super::Result;

use self::NextIterValue::*;

/// A set of serial changes that should be applied to a storage atomically.
pub type Patch = BTreeMap<Vec<u8>, Change>;

/// A generalized iterator over the storage views.
pub type Iter<'a> = Box<Iterator + 'a>;

/// An enum that represents a kind of change to some key in storage.
#[derive(Debug, Clone)]
pub enum Change {
    /// Put the specified value into storage for a corresponding key.
    Put(Vec<u8>),
    /// Delete a value from storage for a corresponding key.
    Delete,
}

/// A combination of a database snapshot and a sequence of changes on top of it.
///
/// A `Fork` provides both immutable and mutable operations over database. As well as [`Snapshot`],
/// it provides read isolation. When mutable operations ([`put`], [`remove`] and
/// [`remove_by_prefix`] methods) are performed for fork, the data is presented as if these changes
/// are applied to the database. However, instead of applying changes directly to the database,
/// fork only accumulates these changes in memory.
///
/// To apply changes to the database, you need to convert a `Fork` into a [`Patch`] using method
/// [`into_patch`] and then atomically merge it into the database using method [`merge`]. If two
/// conflicting forks are merged into a database, this can lead to a non-consistent state. If you
/// need to consistently apply several sets of changes for the same data, the next fork should be
/// created after the previous fork has been merged.
///
/// `Fork` also supports a checkpoint mechanism (methods [`checkpoint`], [`commit`] and
/// [`rollback`]) that allows you to rollback some of the latest changes if for some reason you
/// can not provide a consistent state after the changes due to a runtime error.
///
/// `Fork` implements [`Snapshot`] trait and provides all the necessary methods for both reading and
/// writing data from the database, so `&mut Fork` is used as a storage view for creating
/// read-write indices representation.
///
/// [`Snapshot`]: trait.Snapshot.html
/// [`put`]: #method.put
/// [`remove`]: #method.remove
/// [`remove_by_prefix`]: #method.remove_by_prefix
/// [`Patch`]: type.Patch.html
/// [`into_patch`]: #method.into_patch
/// [`merge`]: trait.Database.html#tymethod.merge
/// [`checkpoint`]: #method.checkpoint
/// [`commit`]: #method.commit
/// [`rollback`]: #method.rollback
// FIXME: make &mut Fork "unwind safe"
pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch,
    changelog: Vec<(Vec<u8>, Option<Change>)>,
    logged: bool,
}

struct ForkIter<'a> {
    snapshot: Iter<'a>,
    changes: Peekable<Range<'a, Vec<u8>, Change>>,
}

#[derive(Debug, PartialEq, Eq)]
enum NextIterValue {
    Stored,
    Replaced,
    Inserted,
    Deleted,
    MissDeleted,
    Finished,
}

/// A trait that defines a low-level storage backend.
///
/// The trait `Database` requires to implement traits `Send` and `Sync` and should not be borrowed
/// data, so you can use method [`clone`] to get the references to the database for concurrent
/// usage.
///
/// There is no way to directly interact with data in the database.
///
/// If you only need to read the data, you can create a [`Snapshot`] using method [`snapshot`][1].
/// Snapshots provide a read isolation, so you are guaranteed to work with consistent values even
/// if the data in the database changes between reads.
///
/// If you need to make any changes to the data, you need to create a [`Fork`] using method
/// [`fork`][2]. As well as `Snapshot`, `Fork` provides read isolation and also allows you to create
/// a sequence of changes to the database that are specified as a [`Patch`]. Later you can
/// atomically merge a patch into the database using method [`merge`].
///
/// [`clone`]: #tymethod.fork
/// [`Snapshot`]: trait.Snapshot.html
/// [1]: #tymethod.snapshot
/// [`Fork`]: struct.Fork.html
/// [2]: #method.fork
/// [`Patch`]: type.Patch.html
/// [`merge`]: #tymethod.merge
pub trait Database: Send + Sync + 'static {
    /// Creates a new reference to the database as `Box<Database>`.
    fn clone(&self) -> Box<Database>;

    /// Creates a new snapshot of the database from its current state.
    ///
    /// See [`Snapshot`] documentation for more.
    /// [`Snapshot`]: trait.Snapshot.html
    fn snapshot(&self) -> Box<Snapshot>;

    /// Creates a new fork of the database from its current state.
    ///
    /// See [`Fork`] documentation for more.
    /// [`Fork`]: struct.Fork.html
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
            changelog: Vec::new(),
            logged: false,
        }
    }

    /// Atomically applies a sequence of patch changes to the database.
    ///
    /// # Errors
    /// If this method encounters any form of I/O or other error during merging, an error variant
    /// will be returned. In case of an error the method guarantees no changes were applied to
    /// the database.
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

/// A trait that defines a snapshot of storage backend.
///
/// `Snapshot` instance is immutable representation of storage state. It provides read isolation,
/// so using snapshot you are guaranteed to work with consistent values even if the data in
/// the database changes between reads.
///
/// `Snapshot` provides all the necessary methods for reading data from the database, so `&Storage`
/// is used as a storage view for creating read-only indices representation.
// TODO: should Snapshot be Send or Sync?
pub trait Snapshot: 'static {
    /// Returns a value as raw vector of bytes corresponding to the specified key
    /// or `None` if does not exist.
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;

    /// Returns `true` if the snapshot contains a value for the specified key.
    ///
    /// Default implementation tries to read the value using method [`get`].
    /// [`get`]: #tymethod.get
    fn contains(&self, key: &[u8]) -> bool {
        self.get(key).is_some()
    }

    /// Returns an iterator over the entries of the snapshot in ascending order starting from
    /// the specified key. The iterator element type is `(&[u8], &[u8])`.
    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a>;
}

/// A trait that defines streaming iterator over storage view entries.
pub trait Iterator {
    /// Advances the iterator and returns the next key and value.
    fn next(&mut self) -> Option<(&[u8], &[u8])>;

    /// Returns references to the current key and value of the iterator.
    fn peek(&mut self) -> Option<(&[u8], &[u8])>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(ref v) => Some(v.clone()),
                    Change::Delete => None,
                }
            }
            None => self.snapshot.get(key),
        }
    }

    fn contains(&self, key: &[u8]) -> bool {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(..) => true,
                    Change::Delete => false,
                }
            }
            None => self.snapshot.contains(key),
        }
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        let range = (Included(from), Unbounded);
        Box::new(ForkIter {
            snapshot: self.snapshot.iter(from),
            changes: self.changes.range::<[u8], _>(range).peekable(),
        })
    }
}

impl Fork {
    /// Creates a new checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if another checkpoint was created before and it was not committed or rollbacked yet.
    pub fn checkpoint(&mut self) {
        if self.logged {
            panic!("call checkpoint before rollback or commit");
        }
        self.logged = true;
    }

    /// Finalizes all changes after the last checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was not created before or last checkpoint is already committed or
    /// rollbacked.
    pub fn commit(&mut self) {
        if !self.logged {
            panic!("call commit before checkpoint");
        }
        self.changelog.clear();
        self.logged = false;
    }

    /// Rollbakcs all changes after the last checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was not created before or last checkpoint is already committed or
    /// rollbacked.
    pub fn rollback(&mut self) {
        if !self.logged {
            panic!("call rollback before checkpoint");
        }
        for (k, c) in self.changelog.drain(..).rev() {
            match c {
                Some(change) => self.changes.insert(k, change),
                None => self.changes.remove(&k),
            };
        }
        self.logged = false;
    }

    /// Inserts the key-value pair into the fork.
    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        if self.logged {
            self.changelog.push((
                key.clone(),
                self.changes.insert(key, Change::Put(value)),
            ));
        } else {
            self.changes.insert(key, Change::Put(value));
        }
    }

    /// Removes the key from the fork.
    pub fn remove(&mut self, key: Vec<u8>) {
        if self.logged {
            self.changelog.push((
                key.clone(),
                self.changes.insert(key, Change::Delete),
            ));
        } else {
            self.changes.insert(key, Change::Delete);
        }
    }

    /// Removes all keys starting with the specified prefix from the fork.
    pub fn remove_by_prefix(&mut self, prefix: &[u8]) {
        // Remove changes
        let keys = self.changes
            .range::<[u8], _>((Included(prefix), Unbounded))
            .map(|(k, ..)| k.to_vec())
            .take_while(|k| k.starts_with(prefix))
            .collect::<Vec<_>>();
        for k in keys {
            self.changes.remove(&k);
        }
        // Remove from storage
        let mut iter = self.snapshot.iter(prefix);
        while let Some((k, ..)) = iter.next() {
            if !k.starts_with(prefix) {
                return;
            }
            let change = self.changes.insert(k.to_vec(), Change::Delete);
            if self.logged {
                self.changelog.push((k.to_vec(), change));
            }
        }
    }

    /// Converts the fork into `Patch`.
    pub fn into_patch(self) -> Patch {
        self.changes
    }

    /// Merges patch from another fork to this fork.
    ///
    /// If both forks have changed the same data, this can lead to a non-consistent state. So this
    /// method is useful only if you are sure that forks interacted with different indices.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was created before and it was not committed or rollbacked yet.
    pub fn merge(&mut self, patch: Patch) {
        if self.logged {
            panic!("call merge before commit or rollback");
        }
        self.changes.extend(patch)
    }
}

impl AsRef<Snapshot> for Snapshot + 'static {
    fn as_ref(&self) -> &Snapshot {
        self
    }
}

impl AsRef<Snapshot> for Fork {
    fn as_ref(&self) -> &Snapshot {
        self
    }
}

impl ::std::fmt::Debug for Fork {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Fork(..)")
    }
}

impl<'a> ForkIter<'a> {
    fn step(&mut self) -> NextIterValue {
        match self.changes.peek() {
            Some(&(k, change)) => {
                match self.snapshot.peek() {
                    Some((key, ..)) => {
                        match *change {
                            Change::Put(..) => {
                                match k[..].cmp(key) {
                                    Equal => Replaced,
                                    Less => Inserted,
                                    Greater => Stored,
                                }
                            }
                            Change::Delete => {
                                match k[..].cmp(key) {
                                    Equal => Deleted,
                                    Less => MissDeleted,
                                    Greater => Stored,
                                }
                            }
                        }
                    }
                    None => {
                        match *change {
                            Change::Put(..) => Inserted,
                            Change::Delete => MissDeleted,
                        }
                    }
                }
            }
            None => {
                match self.snapshot.peek() {
                    Some(..) => Stored,
                    None => Finished,
                }
            }
        }
    }
}

impl<'a> Iterator for ForkIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.next(),
                Replaced => {
                    self.snapshot.next();
                    return self.changes.next().map(|(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    });
                }
                Inserted => {
                    return self.changes.next().map(|(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.peek(),
                Replaced | Inserted => {
                    return self.changes.peek().map(|&(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }
}
<commit_msg>Fix code formatting<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::btree_map::{BTreeMap, Range};
use std::collections::Bound::*;
use std::cmp::Ordering::*;
use std::iter::Peekable;

use super::Result;

use self::NextIterValue::*;

/// A set of serial changes that should be applied to a storage atomically.
pub type Patch = BTreeMap<Vec<u8>, Change>;

/// A generalized iterator over the storage views.
pub type Iter<'a> = Box<Iterator + 'a>;

/// An enum that represents a kind of change to some key in storage.
#[derive(Debug, Clone)]
pub enum Change {
    /// Put the specified value into storage for a corresponding key.
    Put(Vec<u8>),
    /// Delete a value from storage for a corresponding key.
    Delete,
}

/// A combination of a database snapshot and a sequence of changes on top of it.
///
/// A `Fork` provides both immutable and mutable operations over database. As well as [`Snapshot`],
/// it provides read isolation. When mutable operations ([`put`], [`remove`] and
/// [`remove_by_prefix`] methods) are performed for fork, the data is presented as if these changes
/// are applied to the database. However, instead of applying changes directly to the database,
/// fork only accumulates these changes in memory.
///
/// To apply changes to the database, you need to convert a `Fork` into a [`Patch`] using method
/// [`into_patch`] and then atomically merge it into the database using method [`merge`]. If two
/// conflicting forks are merged into a database, this can lead to a non-consistent state. If you
/// need to consistently apply several sets of changes for the same data, the next fork should be
/// created after the previous fork has been merged.
///
/// `Fork` also supports a checkpoint mechanism (methods [`checkpoint`], [`commit`] and
/// [`rollback`]) that allows you to rollback some of the latest changes if for some reason you
/// can not provide a consistent state after the changes due to a runtime error.
///
/// `Fork` implements [`Snapshot`] trait and provides all the necessary methods for both reading and
/// writing data from the database, so `&mut Fork` is used as a storage view for creating
/// read-write indices representation.
///
/// [`Snapshot`]: trait.Snapshot.html
/// [`put`]: #method.put
/// [`remove`]: #method.remove
/// [`remove_by_prefix`]: #method.remove_by_prefix
/// [`Patch`]: type.Patch.html
/// [`into_patch`]: #method.into_patch
/// [`merge`]: trait.Database.html#tymethod.merge
/// [`checkpoint`]: #method.checkpoint
/// [`commit`]: #method.commit
/// [`rollback`]: #method.rollback
// FIXME: make &mut Fork "unwind safe"
pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch,
    changelog: Vec<(Vec<u8>, Option<Change>)>,
    logged: bool,
}

struct ForkIter<'a> {
    snapshot: Iter<'a>,
    changes: Peekable<Range<'a, Vec<u8>, Change>>,
}

#[derive(Debug, PartialEq, Eq)]
enum NextIterValue {
    Stored,
    Replaced,
    Inserted,
    Deleted,
    MissDeleted,
    Finished,
}

/// A trait that defines a low-level storage backend.
///
/// The trait `Database` requires to implement traits `Send` and `Sync` and should not be borrowed
/// data, so you can use method [`clone`] to get the references to the database for concurrent
/// usage.
///
/// There is no way to directly interact with data in the database.
///
/// If you only need to read the data, you can create a [`Snapshot`] using method [`snapshot`][1].
/// Snapshots provide a read isolation, so you are guaranteed to work with consistent values even
/// if the data in the database changes between reads.
///
/// If you need to make any changes to the data, you need to create a [`Fork`] using method
/// [`fork`][2]. As well as `Snapshot`, `Fork` provides read isolation and also allows you to create
/// a sequence of changes to the database that are specified as a [`Patch`]. Later you can
/// atomically merge a patch into the database using method [`merge`].
///
/// [`clone`]: #tymethod.fork
/// [`Snapshot`]: trait.Snapshot.html
/// [1]: #tymethod.snapshot
/// [`Fork`]: struct.Fork.html
/// [2]: #method.fork
/// [`Patch`]: type.Patch.html
/// [`merge`]: #tymethod.merge
pub trait Database: Send + Sync + 'static {
    /// Creates a new reference to the database as `Box<Database>`.
    fn clone(&self) -> Box<Database>;

    /// Creates a new snapshot of the database from its current state.
    ///
    /// See [`Snapshot`] documentation for more.
    /// [`Snapshot`]: trait.Snapshot.html
    fn snapshot(&self) -> Box<Snapshot>;

    /// Creates a new fork of the database from its current state.
    ///
    /// See [`Fork`] documentation for more.
    /// [`Fork`]: struct.Fork.html
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
            changelog: Vec::new(),
            logged: false,
        }
    }

    /// Atomically applies a sequence of patch changes to the database.
    ///
    /// # Errors
    /// If this method encounters any form of I/O or other error during merging, an error variant
    /// will be returned. In case of an error the method guarantees no changes were applied to
    /// the database.
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

/// A trait that defines a snapshot of storage backend.
///
/// `Snapshot` instance is immutable representation of storage state. It provides read isolation,
/// so using snapshot you are guaranteed to work with consistent values even if the data in
/// the database changes between reads.
///
/// `Snapshot` provides all the necessary methods for reading data from the database, so `&Storage`
/// is used as a storage view for creating read-only indices representation.
// TODO: should Snapshot be Send or Sync?
pub trait Snapshot: 'static {
    /// Returns a value as raw vector of bytes corresponding to the specified key
    /// or `None` if does not exist.
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;

    /// Returns `true` if the snapshot contains a value for the specified key.
    ///
    /// Default implementation tries to read the value using method [`get`].
    /// [`get`]: #tymethod.get
    fn contains(&self, key: &[u8]) -> bool {
        self.get(key).is_some()
    }

    /// Returns an iterator over the entries of the snapshot in ascending order starting from
    /// the specified key. The iterator element type is `(&[u8], &[u8])`.
    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a>;
}

/// A trait that defines streaming iterator over storage view entries.
pub trait Iterator {
    /// Advances the iterator and returns the next key and value.
    fn next(&mut self) -> Option<(&[u8], &[u8])>;

    /// Returns references to the current key and value of the iterator.
    fn peek(&mut self) -> Option<(&[u8], &[u8])>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(ref v) => Some(v.clone()),
                    Change::Delete => None,
                }
            }
            None => self.snapshot.get(key),
        }
    }

    fn contains(&self, key: &[u8]) -> bool {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(..) => true,
                    Change::Delete => false,
                }
            }
            None => self.snapshot.contains(key),
        }
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        let range = (Included(from), Unbounded);
        Box::new(ForkIter {
            snapshot: self.snapshot.iter(from),
            changes: self.changes.range::<[u8], _>(range).peekable(),
        })
    }
}

impl Fork {
    /// Creates a new checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if another checkpoint was created before and it was not committed or rollbacked yet.
    pub fn checkpoint(&mut self) {
        if self.logged {
            panic!("call checkpoint before rollback or commit");
        }
        self.logged = true;
    }

    /// Finalizes all changes after the last checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was not created before or last checkpoint is already committed or
    /// rollbacked.
    pub fn commit(&mut self) {
        if !self.logged {
            panic!("call commit before checkpoint");
        }
        self.changelog.clear();
        self.logged = false;
    }

    /// Rollbakcs all changes after the last checkpoint.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was not created before or last checkpoint is already committed or
    /// rollbacked.
    pub fn rollback(&mut self) {
        if !self.logged {
            panic!("call rollback before checkpoint");
        }
        for (k, c) in self.changelog.drain(..).rev() {
            match c {
                Some(change) => self.changes.insert(k, change),
                None => self.changes.remove(&k),
            };
        }
        self.logged = false;
    }

    /// Inserts the key-value pair into the fork.
    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        if self.logged {
            self.changelog.push((
                key.clone(),
                self.changes.insert(key, Change::Put(value)),
            ));
        } else {
            self.changes.insert(key, Change::Put(value));
        }
    }

    /// Removes the key from the fork.
    pub fn remove(&mut self, key: Vec<u8>) {
        if self.logged {
            self.changelog.push((
                key.clone(),
                self.changes.insert(key, Change::Delete),
            ));
        } else {
            self.changes.insert(key, Change::Delete);
        }
    }

    /// Removes all keys starting with the specified prefix from the fork.
    pub fn remove_by_prefix(&mut self, prefix: &[u8]) {
        // Remove changes
        let keys = self.changes
            .range::<[u8], _>((Included(prefix), Unbounded))
            .map(|(k, ..)| k.to_vec())
            .take_while(|k| k.starts_with(prefix))
            .collect::<Vec<_>>();
        for k in keys {
            self.changes.remove(&k);
        }
        // Remove from storage
        let mut iter = self.snapshot.iter(prefix);
        while let Some((k, ..)) = iter.next() {
            if !k.starts_with(prefix) {
                return;
            }
            let change = self.changes.insert(k.to_vec(), Change::Delete);
            if self.logged {
                self.changelog.push((k.to_vec(), change));
            }
        }
    }

    /// Converts the fork into `Patch`.
    pub fn into_patch(self) -> Patch {
        self.changes
    }

    /// Merges patch from another fork to this fork.
    ///
    /// If both forks have changed the same data, this can lead to a non-consistent state. So this
    /// method is useful only if you are sure that forks interacted with different indices.
    ///
    /// # Panics
    ///
    /// Panics if checkpoint was created before and it was not committed or rollbacked yet.
    pub fn merge(&mut self, patch: Patch) {
        if self.logged {
            panic!("call merge before commit or rollback");
        }
        self.changes.extend(patch)
    }
}

impl AsRef<Snapshot> for Snapshot + 'static {
    fn as_ref(&self) -> &Snapshot {
        self
    }
}

impl AsRef<Snapshot> for Fork {
    fn as_ref(&self) -> &Snapshot {
        self
    }
}

impl ::std::fmt::Debug for Fork {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Fork(..)")
    }
}

impl<'a> ForkIter<'a> {
    fn step(&mut self) -> NextIterValue {
        match self.changes.peek() {
            Some(&(k, change)) => {
                match self.snapshot.peek() {
                    Some((key, ..)) => {
                        match *change {
                            Change::Put(..) => {
                                match k[..].cmp(key) {
                                    Equal => Replaced,
                                    Less => Inserted,
                                    Greater => Stored,
                                }
                            }
                            Change::Delete => {
                                match k[..].cmp(key) {
                                    Equal => Deleted,
                                    Less => MissDeleted,
                                    Greater => Stored,
                                }
                            }
                        }
                    }
                    None => {
                        match *change {
                            Change::Put(..) => Inserted,
                            Change::Delete => MissDeleted,
                        }
                    }
                }
            }
            None => {
                match self.snapshot.peek() {
                    Some(..) => Stored,
                    None => Finished,
                }
            }
        }
    }
}

impl<'a> Iterator for ForkIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.next(),
                Replaced => {
                    self.snapshot.next();
                    return self.changes.next().map(|(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    });
                }
                Inserted => {
                    return self.changes.next().map(|(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.peek(),
                Replaced | Inserted => {
                    return self.changes.peek().map(|&(key, change)| {
                        (
                            key.as_slice(),
                            match *change {
                                Change::Put(ref value) => value.as_slice(),
                                Change::Delete => unreachable!(),
                            },
                        )
                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use diesel::expression::sql;
#[cfg(feature = "postgres")]
use diesel::pg::PgConnection;
#[cfg(feature = "sqlite")]
use diesel::sqlite::SqliteConnection;
use diesel::types::Bool;
use diesel::{migrations, Connection, select, LoadDsl};

use database_error::DatabaseResult;

use std::error::Error;
use std::{env, fs};

// FIXME: Remove the duplicates of this macro once expression level attributes
// are stable (I believe this is in 1.7)
#[cfg(all(feature = "sqlite", feature = "postgres"))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        match ::database::backend(&$database_url) {
            "postgres" => {
                let conn = PgConnection::establish(&$database_url).unwrap();
                $func(&conn)
            },
            "sqlite" => {
                let conn = SqliteConnection::establish(&$database_url).unwrap();
                $func(&conn)
            },
            _ => unreachable!("The backend function should ensure we never get here."),
        }
    }};
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        let conn = SqliteConnection::establish(&$database_url).unwrap();
        $func(&conn)
    }};
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        let conn = PgConnection::establish(&$database_url).unwrap();
        $func(&conn)
    }};
}

pub fn reset_database(args: &ArgMatches) -> DatabaseResult<()> {
    try!(drop_database(&database_url(args)));
    setup_database(args)
}

pub fn setup_database(args: &ArgMatches) -> DatabaseResult<()> {
    let database_url = database_url(args);

    try!(create_database_if_needed(&database_url));
    create_schema_table_and_run_migrations_if_needed(&database_url)
}

pub fn drop_database_command(args: &ArgMatches) -> DatabaseResult<()> {
    drop_database(&database_url(args))
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Creates the database specified in the connection url. It returns an error
/// it it was unable to create the database.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    match backend(database_url) {
        "postgres" => {
            if PgConnection::establish(database_url).is_err() {
                let(database, postgres_url) = split_pg_connection_string(database_url);
                try!(create_postgres_database(&postgres_url, &database));
            }
        },
        "sqlite" => {
            println!("Creating database: {}", database_url);
            try!(SqliteConnection::establish(database_url));
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    }

    Ok(())
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    println!("Creating database: {}", database_url);
    try!(SqliteConnection::establish(database_url));
    Ok(())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    println!("Creating database: {}", database_url);
    if PgConnection::establish(database_url).is_err() {
        let(database, postgres_url) = split_pg_connection_string(database_url);
        try!(create_postgres_database(&postgres_url, &database));
    }
    Ok(())
}

#[cfg(feature = "postgres")]
fn create_postgres_database(database_url: &String, database: &String)
    -> DatabaseResult<()>
{
    let conn = try!(PgConnection::establish(database_url));
    println!("Creating database: {}", database);
    try!(conn.execute(&format!("CREATE DATABASE {}", database)));
    Ok(())
}

/// Creates the __diesel_schema_migrations table if it doesn't exist. If the
/// table didn't exist, it also runs any pending migrations. Returns a
/// `DatabaseError::ConnectionError` if it can't create the table, and exits
/// with a migration error if it can't run migrations.
fn create_schema_table_and_run_migrations_if_needed(database_url: &String)
    -> DatabaseResult<()>
{
    if !schema_table_exists(database_url).map_err(handle_error).unwrap() {
        try!(call_with_conn!(database_url, migrations::setup_database));
        call_with_conn!(database_url, migrations::run_pending_migrations).unwrap_or_else(handle_error);
    };
    Ok(())
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Drops the database specified in the connection url. It returns an error
/// if it was unable to drop the database.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    match backend(database_url) {
        "postgres" => {
            let (database, postgres_url) = split_pg_connection_string(database_url);
            println!("Dropping database: {}", database);
            let conn = try!(PgConnection::establish(&postgres_url));
            try!(conn.silence_notices(|| {
                conn.execute(&format!("DROP DATABASE IF EXISTS {}", database))
            }));
        },
        "sqlite" => {
            println!("Dropping database: {}", database_url);
            try!(fs::remove_file(&database_url));
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    }
    Ok(())
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    println!("Dropping database: {}", database_url);
    try!(fs::remove_file(&database_url));
    Ok(())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    let (database, postgres_url) = split_pg_connection_string(database_url);
    println!("Dropping database: {}", database);
    let conn = try!(PgConnection::establish(&postgres_url));
    try!(conn.silence_notices(|| {
        conn.execute(&format!("DROP DATABASE IF EXISTS {}", database))
    }));
    Ok(())
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Returns true if the '__diesel_schema_migrations' table exists in the
/// database we connect to, returns false if it does not.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let result = match backend(database_url) {
        "postgres" => {
            let conn = PgConnection::establish(database_url).unwrap();
            try!(select(sql::<Bool>("EXISTS \
                    (SELECT 1 \
                     FROM information_schema.tables \
                     WHERE table_name = '__diesel_schema_migrations')"))
                .get_result(&conn))
        },
        "sqlite" => {
            let conn = SqliteConnection::establish(database_url).unwrap();
            try!(select(sql::<Bool>("EXISTS \
                    (SELECT 1 \
                     FROM sqlite_master \
                     WHERE type = 'table' \
                     AND name = '__diesel_schema_migrations')"))
                .get_result(&conn))
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    };
    Ok(result)
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let conn = SqliteConnection::establish(database_url).unwrap();
    select(sql::<Bool>("EXISTS \
            (SELECT 1 \
             FROM sqlite_master \
             WHERE type = 'table' \
             AND name = '__diesel_schema_migrations')"))
        .get_result(&conn)
        .map_err(|e| e.into())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let conn = PgConnection::establish(database_url).unwrap();
    select(sql::<Bool>("EXISTS \
            (SELECT 1 \
             FROM information_schema.tables \
             WHERE table_name = '__diesel_schema_migrations')"))
        .get_result(&conn)
        .map_err(|e| e.into())
}

pub fn database_url(matches: &ArgMatches) -> String {
    matches.value_of("DATABASE_URL")
        .map(|s| s.into())
        .or(env::var("DATABASE_URL").ok())
        .expect("The --database-url argument must be passed, \
                or the DATABASE_URL environment variable must be set.")
}

/// Returns a &str representing the type of backend being used, determined
/// by the format of the database url.
pub fn backend(database_url: &String) -> &str {
    if database_url.starts_with("postgres://") || database_url.starts_with("postgresql://") {
        "postgres"
    } else {
        "sqlite"
    }
}

fn split_pg_connection_string(database_url: &String) -> (String, String) {
    let mut split: Vec<&str> = database_url.split("/").collect();
    let database = split.pop().unwrap();
    let postgres_url = split.join("/");
    (database.to_owned(), postgres_url)
}

fn handle_error<E: Error>(error: E) {
    panic!("{}", error);
}

#[cfg(test)]
mod tests {
    use dotenv::dotenv;
    use diesel::Connection;

    use std::{env, fs};

    use super::{create_database_if_needed, drop_database, schema_table_exists};
    use super::split_pg_connection_string;
    // use super::create_schema_table_and_run_migrations_if_needed;

    #[cfg(feature = "postgres")]
    type TestConnection = ::diesel::pg::PgConnection;
    #[cfg(feature = "sqlite")]
    type TestConnection = ::diesel::sqlite::SqliteConnection;

    type TestBackend = <TestConnection as Connection>::Backend;

    #[cfg(feature = "postgres")]
    fn database_url(identifier: &str) -> String {
        dotenv().ok();
        let database_url = env::var("DATABASE_URL")
            .expect("DATABASE_URL must be set in order to run diesel_cli tests");
        let (_, base_url) = split_pg_connection_string(&database_url);
        format!("{}/{}", base_url, identifier)
    }

    #[cfg(feature = "postgres")]
    fn connection(database_url: &String) -> TestConnection {
        ::diesel::pg::PgConnection::establish(database_url).unwrap()
    }

    #[cfg(feature = "postgres")]
    fn teardown(_: String) {
    }

    #[cfg(feature = "sqlite")]
    fn database_url(identifier: &str) -> String {
        let dir = env::current_dir().unwrap();
        let db_file = dir.join(identifier);
        fs::remove_file(&db_file).ok();
        fs::File::create(&db_file).unwrap();
        db_file.to_str().unwrap().to_owned()
    }

    #[cfg(feature = "sqlite")]
    fn connection(database_url: &String) -> TestConnection {
        ::diesel::sqlite::SqliteConnection::establish(database_url).unwrap()
    }

    #[cfg(feature = "sqlite")]
    fn teardown(database_path: String) {
        fs::remove_file(&database_path).unwrap();
    }

    #[test]
    fn schema_table_exists_finds_table() {
        let database_url = database_url("test1");
        create_database_if_needed(&database_url)
            .expect("Unable to create test database");
        let connection = connection(&database_url);
        connection.silence_notices(|| {
            connection.execute("DROP TABLE IF EXISTS __diesel_schema_migrations").unwrap();
            connection.execute("CREATE TABLE __diesel_schema_migrations (version INTEGER)").unwrap();
        });

        assert!(schema_table_exists(&database_url).unwrap());

        teardown(database_url);
    }

    #[test]
    fn schema_table_exists_doesnt_find_table() {
        let database_url = database_url("test2");
        create_database_if_needed(&database_url)
            .expect("Unable to create test database");
        let connection = connection(&database_url);
        connection.silence_notices(|| {
            connection.execute("DROP TABLE IF EXISTS __diesel_schema_migrations").unwrap();
        });

        assert!(!schema_table_exists(&database_url).unwrap());

        teardown(database_url);
    }

    #[test]
    fn create_database_creates_the_database() {
        let database_url = database_url("test3");
        drop_database(&database_url).unwrap();
        create_database_if_needed(&database_url).unwrap();
        assert!(TestConnection::establish(&database_url).is_ok());

        teardown(database_url);
    }

    #[test]
    #[cfg(feature = "postgres")]
    fn drop_database_drops_the_database() {
        let database_url = database_url("test4");
        drop_database(&database_url).unwrap();
        assert!(TestConnection::establish(&database_url).is_err());
    }

    #[test]
    #[cfg(feature = "sqlite")]
    fn drop_database_drops_the_database() {
        let database_url = database_url("test4");
        drop_database(&database_url).unwrap();
        assert!(fs::File::open(database_url).is_err());
    }

    // #[test]
    // #[should_panic] // FIXME: Our migration structure is non-standard
    // // we need to test this against a clean env with a normal structure
    // // once we get integration test coverage (we can't change cwd in the test
    // // process)
    // fn create_schema_table_creates_diesel_table() {
    //     let database_url = database_url("test5");
    //     create_database_if_needed(&database_url)
    //         .expect("Unable to create test database");
    //     let connection = connection(&database_url);
    //     connection.silence_notices(|| {
    //         connection.execute("DROP TABLE IF EXISTS __diesel_schema_migrations").unwrap();
    //     });
    //     assert!(!schema_table_exists(&database_url).unwrap());
    //     create_schema_table_and_run_migrations_if_needed(&database_url).unwrap();
    //     assert!(schema_table_exists(&database_url).unwrap());
    //
    //     teardown(database_url);
    // }

    #[test]
    fn split_pg_connection_string_returns_postgres_url_and_database() {
        let database = "database".to_owned();
        let postgres_url = "postgresql://localhost:5432".to_owned();
        let database_url = format!("{}/{}", postgres_url, database);
        assert_eq!((database, postgres_url), split_pg_connection_string(&database_url));
    }
}
<commit_msg>Remove dead CLI test now that we have integration tests<commit_after>use clap::ArgMatches;
use diesel::expression::sql;
#[cfg(feature = "postgres")]
use diesel::pg::PgConnection;
#[cfg(feature = "sqlite")]
use diesel::sqlite::SqliteConnection;
use diesel::types::Bool;
use diesel::{migrations, Connection, select, LoadDsl};

use database_error::DatabaseResult;

use std::error::Error;
use std::{env, fs};

// FIXME: Remove the duplicates of this macro once expression level attributes
// are stable (I believe this is in 1.7)
#[cfg(all(feature = "sqlite", feature = "postgres"))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        match ::database::backend(&$database_url) {
            "postgres" => {
                let conn = PgConnection::establish(&$database_url).unwrap();
                $func(&conn)
            },
            "sqlite" => {
                let conn = SqliteConnection::establish(&$database_url).unwrap();
                $func(&conn)
            },
            _ => unreachable!("The backend function should ensure we never get here."),
        }
    }};
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        let conn = SqliteConnection::establish(&$database_url).unwrap();
        $func(&conn)
    }};
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
macro_rules! call_with_conn {
    ( $database_url:ident,
      $func:path
    ) => {{
        let conn = PgConnection::establish(&$database_url).unwrap();
        $func(&conn)
    }};
}

pub fn reset_database(args: &ArgMatches) -> DatabaseResult<()> {
    try!(drop_database(&database_url(args)));
    setup_database(args)
}

pub fn setup_database(args: &ArgMatches) -> DatabaseResult<()> {
    let database_url = database_url(args);

    try!(create_database_if_needed(&database_url));
    create_schema_table_and_run_migrations_if_needed(&database_url)
}

pub fn drop_database_command(args: &ArgMatches) -> DatabaseResult<()> {
    drop_database(&database_url(args))
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Creates the database specified in the connection url. It returns an error
/// it it was unable to create the database.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    match backend(database_url) {
        "postgres" => {
            if PgConnection::establish(database_url).is_err() {
                let(database, postgres_url) = split_pg_connection_string(database_url);
                try!(create_postgres_database(&postgres_url, &database));
            }
        },
        "sqlite" => {
            println!("Creating database: {}", database_url);
            try!(SqliteConnection::establish(database_url));
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    }

    Ok(())
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    println!("Creating database: {}", database_url);
    try!(SqliteConnection::establish(database_url));
    Ok(())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
fn create_database_if_needed(database_url: &String) -> DatabaseResult<()> {
    println!("Creating database: {}", database_url);
    if PgConnection::establish(database_url).is_err() {
        let(database, postgres_url) = split_pg_connection_string(database_url);
        try!(create_postgres_database(&postgres_url, &database));
    }
    Ok(())
}

#[cfg(feature = "postgres")]
fn create_postgres_database(database_url: &String, database: &String)
    -> DatabaseResult<()>
{
    let conn = try!(PgConnection::establish(database_url));
    println!("Creating database: {}", database);
    try!(conn.execute(&format!("CREATE DATABASE {}", database)));
    Ok(())
}

/// Creates the __diesel_schema_migrations table if it doesn't exist. If the
/// table didn't exist, it also runs any pending migrations. Returns a
/// `DatabaseError::ConnectionError` if it can't create the table, and exits
/// with a migration error if it can't run migrations.
fn create_schema_table_and_run_migrations_if_needed(database_url: &String)
    -> DatabaseResult<()>
{
    if !schema_table_exists(database_url).map_err(handle_error).unwrap() {
        try!(call_with_conn!(database_url, migrations::setup_database));
        call_with_conn!(database_url, migrations::run_pending_migrations).unwrap_or_else(handle_error);
    };
    Ok(())
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Drops the database specified in the connection url. It returns an error
/// if it was unable to drop the database.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    match backend(database_url) {
        "postgres" => {
            let (database, postgres_url) = split_pg_connection_string(database_url);
            println!("Dropping database: {}", database);
            let conn = try!(PgConnection::establish(&postgres_url));
            try!(conn.silence_notices(|| {
                conn.execute(&format!("DROP DATABASE IF EXISTS {}", database))
            }));
        },
        "sqlite" => {
            println!("Dropping database: {}", database_url);
            try!(fs::remove_file(&database_url));
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    }
    Ok(())
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    println!("Dropping database: {}", database_url);
    try!(fs::remove_file(&database_url));
    Ok(())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
fn drop_database(database_url: &String) -> DatabaseResult<()> {
    let (database, postgres_url) = split_pg_connection_string(database_url);
    println!("Dropping database: {}", database);
    let conn = try!(PgConnection::establish(&postgres_url));
    try!(conn.silence_notices(|| {
        conn.execute(&format!("DROP DATABASE IF EXISTS {}", database))
    }));
    Ok(())
}

// FIXME: Remove the duplicates of this function once expression level attributes
// are stable (I believe this is in 1.7)
/// Returns true if the '__diesel_schema_migrations' table exists in the
/// database we connect to, returns false if it does not.
#[cfg(all(feature = "sqlite", feature = "postgres"))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let result = match backend(database_url) {
        "postgres" => {
            let conn = PgConnection::establish(database_url).unwrap();
            try!(select(sql::<Bool>("EXISTS \
                    (SELECT 1 \
                     FROM information_schema.tables \
                     WHERE table_name = '__diesel_schema_migrations')"))
                .get_result(&conn))
        },
        "sqlite" => {
            let conn = SqliteConnection::establish(database_url).unwrap();
            try!(select(sql::<Bool>("EXISTS \
                    (SELECT 1 \
                     FROM sqlite_master \
                     WHERE type = 'table' \
                     AND name = '__diesel_schema_migrations')"))
                .get_result(&conn))
        },
        _ => unreachable!("The backend function should ensure we never get here."),
    };
    Ok(result)
}

#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let conn = SqliteConnection::establish(database_url).unwrap();
    select(sql::<Bool>("EXISTS \
            (SELECT 1 \
             FROM sqlite_master \
             WHERE type = 'table' \
             AND name = '__diesel_schema_migrations')"))
        .get_result(&conn)
        .map_err(|e| e.into())
}

#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
pub fn schema_table_exists(database_url: &String) -> DatabaseResult<bool> {
    let conn = PgConnection::establish(database_url).unwrap();
    select(sql::<Bool>("EXISTS \
            (SELECT 1 \
             FROM information_schema.tables \
             WHERE table_name = '__diesel_schema_migrations')"))
        .get_result(&conn)
        .map_err(|e| e.into())
}

pub fn database_url(matches: &ArgMatches) -> String {
    matches.value_of("DATABASE_URL")
        .map(|s| s.into())
        .or(env::var("DATABASE_URL").ok())
        .expect("The --database-url argument must be passed, \
                or the DATABASE_URL environment variable must be set.")
}

/// Returns a &str representing the type of backend being used, determined
/// by the format of the database url.
pub fn backend(database_url: &String) -> &str {
    if database_url.starts_with("postgres://") || database_url.starts_with("postgresql://") {
        "postgres"
    } else {
        "sqlite"
    }
}

fn split_pg_connection_string(database_url: &String) -> (String, String) {
    let mut split: Vec<&str> = database_url.split("/").collect();
    let database = split.pop().unwrap();
    let postgres_url = split.join("/");
    (database.to_owned(), postgres_url)
}

fn handle_error<E: Error>(error: E) {
    panic!("{}", error);
}

#[cfg(test)]
mod tests {
    use dotenv::dotenv;
    use diesel::Connection;

    use std::{env, fs};

    use super::{create_database_if_needed, drop_database, schema_table_exists};
    use super::split_pg_connection_string;
    // use super::create_schema_table_and_run_migrations_if_needed;

    #[cfg(feature = "postgres")]
    type TestConnection = ::diesel::pg::PgConnection;
    #[cfg(feature = "sqlite")]
    type TestConnection = ::diesel::sqlite::SqliteConnection;

    type TestBackend = <TestConnection as Connection>::Backend;

    #[cfg(feature = "postgres")]
    fn database_url(identifier: &str) -> String {
        dotenv().ok();
        let database_url = env::var("DATABASE_URL")
            .expect("DATABASE_URL must be set in order to run diesel_cli tests");
        let (_, base_url) = split_pg_connection_string(&database_url);
        format!("{}/{}", base_url, identifier)
    }

    #[cfg(feature = "postgres")]
    fn connection(database_url: &String) -> TestConnection {
        ::diesel::pg::PgConnection::establish(database_url).unwrap()
    }

    #[cfg(feature = "postgres")]
    fn teardown(_: String) {
    }

    #[cfg(feature = "sqlite")]
    fn database_url(identifier: &str) -> String {
        let dir = env::current_dir().unwrap();
        let db_file = dir.join(identifier);
        fs::remove_file(&db_file).ok();
        fs::File::create(&db_file).unwrap();
        db_file.to_str().unwrap().to_owned()
    }

    #[cfg(feature = "sqlite")]
    fn connection(database_url: &String) -> TestConnection {
        ::diesel::sqlite::SqliteConnection::establish(database_url).unwrap()
    }

    #[cfg(feature = "sqlite")]
    fn teardown(database_path: String) {
        fs::remove_file(&database_path).unwrap();
    }

    #[test]
    fn schema_table_exists_finds_table() {
        let database_url = database_url("test1");
        create_database_if_needed(&database_url)
            .expect("Unable to create test database");
        let connection = connection(&database_url);
        connection.silence_notices(|| {
            connection.execute("DROP TABLE IF EXISTS __diesel_schema_migrations").unwrap();
            connection.execute("CREATE TABLE __diesel_schema_migrations (version INTEGER)").unwrap();
        });

        assert!(schema_table_exists(&database_url).unwrap());

        teardown(database_url);
    }

    #[test]
    fn schema_table_exists_doesnt_find_table() {
        let database_url = database_url("test2");
        create_database_if_needed(&database_url)
            .expect("Unable to create test database");
        let connection = connection(&database_url);
        connection.silence_notices(|| {
            connection.execute("DROP TABLE IF EXISTS __diesel_schema_migrations").unwrap();
        });

        assert!(!schema_table_exists(&database_url).unwrap());

        teardown(database_url);
    }

    #[test]
    fn create_database_creates_the_database() {
        let database_url = database_url("test3");
        drop_database(&database_url).unwrap();
        create_database_if_needed(&database_url).unwrap();
        assert!(TestConnection::establish(&database_url).is_ok());

        teardown(database_url);
    }

    #[test]
    #[cfg(feature = "postgres")]
    fn drop_database_drops_the_database() {
        let database_url = database_url("test4");
        drop_database(&database_url).unwrap();
        assert!(TestConnection::establish(&database_url).is_err());
    }

    #[test]
    #[cfg(feature = "sqlite")]
    fn drop_database_drops_the_database() {
        let database_url = database_url("test4");
        drop_database(&database_url).unwrap();
        assert!(fs::File::open(database_url).is_err());
    }

    #[test]
    fn split_pg_connection_string_returns_postgres_url_and_database() {
        let database = "database".to_owned();
        let postgres_url = "postgresql://localhost:5432".to_owned();
        let database_url = format!("{}/{}", postgres_url, database);
        assert_eq!((database, postgres_url), split_pg_connection_string(&database_url));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-fast

/*!
 * Try to double-check that static fns have the right size (with or
 * without dummy env ptr, as appropriate) by iterating a size-2 array.
 * If the static size differs from the runtime size, the second element
 * should be read as a null or otherwise wrong pointer and crash.
 */

fn f() { }
static bare_fns: &'static [extern fn()] = &[f, f];
struct S<'self>(&'self fn());
static closures: &'static [S<'static>] = &[S(f), S(f)];

pub fn main() {
    for bare_fns.iter().advance |&bare_fn| { bare_fn() }
    for closures.iter().advance |&closure| { (*closure)() }
}
<commit_msg>xfail test hitting a codegen bug (issue #7385)<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-test
// FIXME: #7385: hits a codegen bug on OS X x86_64

/*!
 * Try to double-check that static fns have the right size (with or
 * without dummy env ptr, as appropriate) by iterating a size-2 array.
 * If the static size differs from the runtime size, the second element
 * should be read as a null or otherwise wrong pointer and crash.
 */

fn f() { }
static bare_fns: &'static [extern fn()] = &[f, f];
struct S<'self>(&'self fn());
static closures: &'static [S<'static>] = &[S(f), S(f)];

pub fn main() {
    for bare_fns.iter().advance |&bare_fn| { bare_fn() }
    for closures.iter().advance |&closure| { (*closure)() }
}
<|endoftext|>


<commit_before>extern crate dotenv;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quicli;

extern crate isymtope_ast_common;
extern crate isymtope_generate;

use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::Write;

use dotenv::dotenv;
use quicli::prelude::*;

use isymtope_ast_common::*;
use isymtope_generate::*;

/// Compile Isymtope files to static pages
#[derive(Debug, StructOpt)]
struct Cli {
    #[structopt(long = "base-url")]
    base_url: String,

    #[structopt(long = "output", short = "o")]
    output: String,

    input: String,
}

main!(|args: Cli| {
    dotenv().ok();

    let mut template_cache: HashMap<String, DefaultTemplateContext> = Default::default();
    let app_dir: PathBuf = env::var_os("APP_DIR").expect("APP_DIR must be provided").into();
    let app_name: String = env::var_os("DEFAULT_APP").expect("DEFAULT_APP must be provided").to_string_lossy().to_string();

    let app_root = app_dir.join(&app_name);

    let template_path = args.input;
    // let app_key = format!("[appName={}, templatePath={}]", app_name, &template_path);
    let template_key = format!("[templatePath={}]", template_path);

    // let output_string = TEMPLATE_CACHE.with(|cache| {
    //     let mut cache = cache.lock().unwrap();
    //     let app_context = cache
    //         .entry(app_key.clone())
    //         .or_insert_with(|| DefaultTemplateContext::create(app_dir, app_name, template_path).unwrap());

    //     ""
    // });

    let base_url = args.base_url;
    let template_path = "/app.ism".to_owned();
    let path = "/";

    let template_context = template_cache
        .entry(template_key.clone())
        .or_insert_with(|| DefaultTemplateContext::create(&app_root, &template_path).unwrap());

    let req = TemplateRequestMsg::RenderAppRoute(
        base_url.to_owned(),
        app_name.to_owned(),
        template_path.to_owned(),
        path.to_owned(),
    );

    let response = template_context.handle_msg(req)?;
    let TemplateResponseMsg::RenderComplete(result) = response;
    let body = result.into_inner();

    let mut f = File::create("./test.html")?;
    f.write_all(body.as_bytes())?;

    // eprintln!("{}", body);
});
<commit_msg>isymtope-cli: honor --output parameter<commit_after>extern crate dotenv;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quicli;

extern crate isymtope_ast_common;
extern crate isymtope_generate;

use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::io::Write;

use dotenv::dotenv;
use quicli::prelude::*;

use isymtope_ast_common::*;
use isymtope_generate::*;

/// Compile Isymtope files to static pages
#[derive(Debug, StructOpt)]
struct Cli {
    #[structopt(long = "base-url")]
    base_url: String,

    #[structopt(long = "output", short = "o")]
    output: String,

    input: String,
}

main!(|args: Cli| {
    dotenv().ok();

    let mut template_cache: HashMap<String, DefaultTemplateContext> = Default::default();
    let app_dir: PathBuf = env::var_os("APP_DIR").expect("APP_DIR must be provided").into();
    let app_name: String = env::var_os("DEFAULT_APP").expect("DEFAULT_APP must be provided").to_string_lossy().to_string();

    let app_root = app_dir.join(&app_name);

    let template_path = args.input;
    // let app_key = format!("[appName={}, templatePath={}]", app_name, &template_path);
    let template_key = format!("[templatePath={}]", template_path);

    // let output_string = TEMPLATE_CACHE.with(|cache| {
    //     let mut cache = cache.lock().unwrap();
    //     let app_context = cache
    //         .entry(app_key.clone())
    //         .or_insert_with(|| DefaultTemplateContext::create(app_dir, app_name, template_path).unwrap());

    //     ""
    // });

    let base_url = args.base_url;
    let template_path = "/app.ism".to_owned();
    let path = "/";

    let template_context = template_cache
        .entry(template_key.clone())
        .or_insert_with(|| DefaultTemplateContext::create(&app_root, &template_path).unwrap());

    let req = TemplateRequestMsg::RenderAppRoute(
        base_url.to_owned(),
        app_name.to_owned(),
        template_path.to_owned(),
        path.to_owned(),
    );

    let response = template_context.handle_msg(req)?;
    let TemplateResponseMsg::RenderComplete(result) = response;
    let body = result.into_inner();

    let mut f = File::create(args.output)?;
    f.write_all(body.as_bytes())?;

    // eprintln!("{}", body);
});
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow_check::borrow_set::BorrowData;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
use rustc::mir::{Location, Place, TerminatorKind};
use rustc_errors::DiagnosticBuilder;

mod find_use;

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
    /// Adds annotations to `err` explaining *why* the borrow contains the
    /// point from `context`. This is key for the "3-point errors"
    /// [described in the NLL RFC][d].
    ///
    /// # Parameters
    ///
    /// - `borrow`: the borrow in question
    /// - `context`: where the borrow occurs
    /// - `kind_place`: if Some, this describes the statement that triggered the error.
    ///   - first half is the kind of write, if any, being performed
    ///   - second half is the place being accessed
    /// - `err`: where the error annotations are going to be added
    ///
    /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
    pub(in borrow_check) fn explain_why_borrow_contains_point(
        &mut self,
        context: Context,
        borrow: &BorrowData<'tcx>,
        kind_place: Option<(WriteKind, &Place<'tcx>)>,
        err: &mut DiagnosticBuilder<'_>,
    ) {
        debug!(
            "explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
            context, borrow, kind_place,
        );

        let regioncx = &self.nonlexical_regioncx;
        let mir = self.mir;
        let tcx = self.tcx;

        let borrow_region_vid = regioncx.to_region_vid(borrow.region);

        debug!(
            "explain_why_borrow_contains_point: borrow_region_vid={:?}",
            borrow_region_vid
        );

        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);

        debug!(
            "explain_why_borrow_contains_point: region_sub={:?}",
            region_sub
        );

        match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
            Some(Cause::LiveVar(local, location)) => {
                let span = mir.source_info(location).span;
                let spans = self.move_spans(&Place::Local(local), location)
                    .or_else(|| self.borrow_spans(span, location));
                let message = if self.is_borrow_location_in_loop(context.loc) {
                    if spans.for_closure() {
                        "borrow captured here by closure in later iteration of loop"
                    } else {
                        "borrow used here in later iteration of loop"
                    }
                } else {
                    if spans.for_closure() {
                        "borrow later captured here by closure"
                    } else {
                        "borrow later used here"
                    }
                };
                err.span_label(spans.var_or_use(), message);
            }

            Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
                Some(local_name) => {
                    err.span_label(
                        mir.source_info(location).span,
                        format!("borrow later used here, when `{}` is dropped", local_name),
                    );

                    if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
                        if let Place::Local(borrowed_local) = place {
                            let dropped_local_scope = mir.local_decls[local].visibility_scope;
                            let borrowed_local_scope =
                                mir.local_decls[*borrowed_local].visibility_scope;

                            if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
                                err.note(
                                    "values in a scope are dropped \
                                     in the opposite order they are defined",
                                );
                            }
                        }
                    }
                }

                None => {}
            },

            None => {
                if let Some(region) = regioncx.to_error_region(region_sub) {
                    self.tcx.note_and_explain_free_region(
                        err,
                        "borrowed value must be valid for ",
                        region,
                        "...",
                    );
                }
            }
        }
    }

    /// Check if a borrow location is within a loop.
    fn is_borrow_location_in_loop(
        &self,
        borrow_location: Location,
    ) -> bool {
        let mut visited_locations = Vec::new();
        let mut pending_locations = vec![ borrow_location ];
        debug!("is_in_loop: borrow_location={:?}", borrow_location);

        while let Some(location) = pending_locations.pop() {
            debug!("is_in_loop: location={:?} pending_locations={:?} visited_locations={:?}",
                   location, pending_locations, visited_locations);
            if location == borrow_location && visited_locations.contains(&borrow_location) {
                // We've managed to return to where we started (and this isn't the start of the
                // search).
                debug!("is_in_loop: found!");
                return true;
            }

            // Skip locations we've been.
            if visited_locations.contains(&location) { continue; }

            let block = &self.mir.basic_blocks()[location.block];
            if location.statement_index ==  block.statements.len() {
                // Add start location of the next blocks to pending locations.
                match block.terminator().kind {
                    TerminatorKind::Goto { target } => {
                        pending_locations.push(target.start_location());
                    },
                    TerminatorKind::SwitchInt { ref targets, .. } => {
                        for target in targets {
                            pending_locations.push(target.start_location());
                        }
                    },
                    TerminatorKind::Drop { target, unwind, .. } |
                    TerminatorKind::DropAndReplace { target, unwind, .. } |
                    TerminatorKind::Assert { target, cleanup: unwind, .. } |
                    TerminatorKind::Yield { resume: target, drop: unwind, .. } |
                    TerminatorKind::FalseUnwind { real_target: target, unwind, .. } => {
                        pending_locations.push(target.start_location());
                        if let Some(unwind) = unwind {
                            pending_locations.push(unwind.start_location());
                        }
                    },
                    TerminatorKind::Call { ref destination, cleanup, .. } => {
                        if let Some((_, destination)) = destination {
                            pending_locations.push(destination.start_location());
                        }
                        if let Some(cleanup) = cleanup {
                            pending_locations.push(cleanup.start_location());
                        }
                    },
                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => {
                        pending_locations.push(real_target.start_location());
                        for target in imaginary_targets {
                            pending_locations.push(target.start_location());
                        }
                    },
                    _ => {},
                }
            } else {
                // Add the next statement to pending locations.
                pending_locations.push(location.successor_within_block());
            }

            // Keep track of where we have visited.
            visited_locations.push(location);
        }

        false
    }
}
<commit_msg>Split explain_why_borrow_contains_point into two functions<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow_check::borrow_set::BorrowData;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
use rustc::mir::{Local, Location, Place, TerminatorKind};
use rustc_errors::DiagnosticBuilder;
use rustc::ty::Region;

mod find_use;

#[derive(Copy, Clone, Debug)]
pub enum BorrowContainsPointReason<'tcx> {
    Liveness {
        local: Local,
        location: Location,
        in_loop: bool,
    },
    DropLiveness {
        local: Local,
        location: Location,
    },
    OutlivesFreeRegion {
        outlived_region: Option<Region<'tcx>>,
    },
}

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
    /// Adds annotations to `err` explaining *why* the borrow contains the
    /// point from `context`. This is key for the "3-point errors"
    /// [described in the NLL RFC][d].
    ///
    /// # Parameters
    ///
    /// - `borrow`: the borrow in question
    /// - `context`: where the borrow occurs
    /// - `kind_place`: if Some, this describes the statement that triggered the error.
    ///   - first half is the kind of write, if any, being performed
    ///   - second half is the place being accessed
    /// - `err`: where the error annotations are going to be added
    ///
    /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
    pub(in borrow_check) fn explain_why_borrow_contains_point(
        &self,
        context: Context,
        borrow: &BorrowData<'tcx>,
        kind_place: Option<(WriteKind, &Place<'tcx>)>,
        err: &mut DiagnosticBuilder<'_>,
    ) {
        let reason = self.find_why_borrow_contains_point(context, borrow);
        self.report_why_borrow_contains_point(err, reason, kind_place);
    }

    /// Finds the reason that [explain_why_borrow_contains_point] will report
    /// but doesn't add it to any message. This is a separate function in case
    /// the caller wants to change the error they report based on the reason
    /// that will be reported.
    pub(in borrow_check) fn find_why_borrow_contains_point(
        &self,
        context: Context,
        borrow: &BorrowData<'tcx>
    ) -> BorrowContainsPointReason<'tcx> {
        use self::BorrowContainsPointReason::*;

        debug!(
            "find_why_borrow_contains_point(context={:?}, borrow={:?})",
            context, borrow,
        );

        let regioncx = &self.nonlexical_regioncx;
        let mir = self.mir;
        let tcx = self.tcx;

        let borrow_region_vid = regioncx.to_region_vid(borrow.region);

        debug!(
            "explain_why_borrow_contains_point: borrow_region_vid={:?}",
            borrow_region_vid
        );

        let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);

        debug!(
            "explain_why_borrow_contains_point: region_sub={:?}",
            region_sub
        );

        match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
            Some(Cause::LiveVar(local, location)) => Liveness {
                local,
                location,
                in_loop: self.is_borrow_location_in_loop(context.loc),
            },
            Some(Cause::DropVar(local, location)) => DropLiveness {
                local,
                location,
            },
            None => OutlivesFreeRegion {
                outlived_region: regioncx.to_error_region(region_sub),
            },
        }
    }

    /// Adds annotations to `err` for the explanation `reason`. This is a
    /// separate method so that the caller can change their error message based
    /// on the reason that is going to be reported.
    pub (in borrow_check) fn report_why_borrow_contains_point(
        &self,
        err: &mut DiagnosticBuilder,
        reason: BorrowContainsPointReason<'tcx>,
        kind_place: Option<(WriteKind, &Place<'tcx>)>,
    ) {
        use self::BorrowContainsPointReason::*;

        debug!(
            "find_why_borrow_contains_point(reason={:?}, kind_place={:?})",
            reason, kind_place,
        );

        let mir = self.mir;

        match reason {
            Liveness { local, location, in_loop } => {
                let span = mir.source_info(location).span;
                let spans = self.move_spans(&Place::Local(local), location)
                    .or_else(|| self.borrow_spans(span, location));
                let message = if in_loop {
                    if spans.for_closure() {
                        "borrow captured here by closure in later iteration of loop"
                    } else {
                        "borrow used here in later iteration of loop"
                    }
                } else {
                    if spans.for_closure() {
                        "borrow later captured here by closure"
                    } else {
                        "borrow later used here"
                    }
                };
                err.span_label(spans.var_or_use(), message);
            }
            DropLiveness { local, location } => match &mir.local_decls[local].name {
                Some(local_name) => {
                    err.span_label(
                        mir.source_info(location).span,
                        format!("borrow later used here, when `{}` is dropped", local_name),
                    );

                    if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
                        if let Place::Local(borrowed_local) = place {
                            let dropped_local_scope = mir.local_decls[local].visibility_scope;
                            let borrowed_local_scope =
                            mir.local_decls[*borrowed_local].visibility_scope;

                            if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
                                err.note(
                                "values in a scope are dropped \
                                                     in the opposite order they are defined",
                                );
                            }
                        }
                    }
                }

                None => {}
            }
            OutlivesFreeRegion { outlived_region: Some(region) } => {
                self.tcx.note_and_explain_free_region(
                    err,
                    "borrowed value must be valid for ",
                    region,
                    "...",
                );
            }
            OutlivesFreeRegion { outlived_region: None } => (),
        }
    }

    /// Check if a borrow location is within a loop.
    fn is_borrow_location_in_loop(
        &self,
        borrow_location: Location,
    ) -> bool {
        let mut visited_locations = Vec::new();
        let mut pending_locations = vec![ borrow_location ];
        debug!("is_in_loop: borrow_location={:?}", borrow_location);

        while let Some(location) = pending_locations.pop() {
            debug!("is_in_loop: location={:?} pending_locations={:?} visited_locations={:?}",
                   location, pending_locations, visited_locations);
            if location == borrow_location && visited_locations.contains(&borrow_location) {
                // We've managed to return to where we started (and this isn't the start of the
                // search).
                debug!("is_in_loop: found!");
                return true;
            }

            // Skip locations we've been.
            if visited_locations.contains(&location) { continue; }

            let block = &self.mir.basic_blocks()[location.block];
            if location.statement_index ==  block.statements.len() {
                // Add start location of the next blocks to pending locations.
                match block.terminator().kind {
                    TerminatorKind::Goto { target } => {
                        pending_locations.push(target.start_location());
                    },
                    TerminatorKind::SwitchInt { ref targets, .. } => {
                        for target in targets {
                            pending_locations.push(target.start_location());
                        }
                    },
                    TerminatorKind::Drop { target, unwind, .. } |
                    TerminatorKind::DropAndReplace { target, unwind, .. } |
                    TerminatorKind::Assert { target, cleanup: unwind, .. } |
                    TerminatorKind::Yield { resume: target, drop: unwind, .. } |
                    TerminatorKind::FalseUnwind { real_target: target, unwind, .. } => {
                        pending_locations.push(target.start_location());
                        if let Some(unwind) = unwind {
                            pending_locations.push(unwind.start_location());
                        }
                    },
                    TerminatorKind::Call { ref destination, cleanup, .. } => {
                        if let Some((_, destination)) = destination {
                            pending_locations.push(destination.start_location());
                        }
                        if let Some(cleanup) = cleanup {
                            pending_locations.push(cleanup.start_location());
                        }
                    },
                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => {
                        pending_locations.push(real_target.start_location());
                        for target in imaginary_targets {
                            pending_locations.push(target.start_location());
                        }
                    },
                    _ => {},
                }
            } else {
                // Add the next statement to pending locations.
                pending_locations.push(location.successor_within_block());
            }

            // Keep track of where we have visited.
            visited_locations.push(location);
        }

        false
    }
}

<|endoftext|>


<commit_before>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use time::precise_time_ns;
use super::command::{Command, Listener};
use super::storage::Storage;

///
/// Minimum duration between expiration checks in nanoseconds
///
const CHECK_INTERVAL: u64 = 1000000000;

///
/// Receive timeout for incoming messages in milliseconds
///
const RECV_TIMEOUT: u64 = 500;

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<u64>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) -> thread::JoinHandle<()> {
        self.check_expired();

        loop {
            let incoming = self.receiver.recv_timeout(Duration::from_millis(RECV_TIMEOUT));

            self.listener.on_tick();

            match incoming {
                Err(err) => self.handle_error(err),
                Ok(command) => self.handle_command(command)
            }

            if self.needs_checking() {
                self.check_expired();
            }
        }
    }

    fn handle_error(&self, err: RecvTimeoutError) {
        match err {
            RecvTimeoutError::Timeout => {}
            RecvTimeoutError::Disconnected => panic!("channel disconnected"),
        }
    }

    fn handle_command(&mut self, command: Command) {
        match command {
            Command::AddEntry(entry) => {
                self.storage.add_entry(entry);
            }
            Command::RemoveEntry(entry) => {
                self.storage.remove_entry(&entry);
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(precise_time_ns());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                return (precise_time_ns() - value) >= CHECK_INTERVAL;
            }
        }
    }
}
<commit_msg>Update formatting<commit_after>use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;
use time::precise_time_ns;
use super::command::{Command, Listener};
use super::storage::Storage;

///
/// Minimum duration between expiration checks in nanoseconds
///
const CHECK_INTERVAL: u64 = 1000000000;

///
/// Receive timeout for incoming messages in milliseconds
///
const RECV_TIMEOUT: u64 = 500;

pub struct Worker {
    storage: Storage,
    receiver: Receiver<Command>,
    listener: Box<Listener>,
    last_checked: Option<u64>,
}

pub fn spawn(storage: Storage,
             receiver: Receiver<Command>,
             listener: Box<Listener>)
             -> thread::JoinHandle<()> {
    thread::spawn(move || {
        let worker = Worker::new(storage, receiver, listener);

        worker.run();
    })
}

impl Worker {
    pub fn new(storage: Storage, receiver: Receiver<Command>, listener: Box<Listener>) -> Worker {
        Worker {
            storage,
            receiver,
            listener,
            last_checked: None,
        }
    }

    pub fn run(mut self) -> thread::JoinHandle<()> {
        self.check_expired();

        loop {
            let incoming = self.receiver
                .recv_timeout(Duration::from_millis(RECV_TIMEOUT));

            self.listener.on_tick();

            match incoming {
                Err(err) => self.handle_error(err),
                Ok(command) => self.handle_command(command),
            }

            if self.needs_checking() {
                self.check_expired();
            }
        }
    }

    fn handle_error(&self, err: RecvTimeoutError) {
        match err {
            RecvTimeoutError::Timeout => {}
            RecvTimeoutError::Disconnected => panic!("channel disconnected"),
        }
    }

    fn handle_command(&mut self, command: Command) {
        match command {
            Command::AddEntry(entry) => {
                self.storage.add_entry(entry);
            }
            Command::RemoveEntry(entry) => {
                self.storage.remove_entry(&entry);
            }
        }
    }

    fn check_expired(&mut self) {
        self.last_checked = Some(precise_time_ns());

        for entry in self.storage.expired_entries() {
            self.listener.on_expired(entry);
            self.storage.remove_entry(&entry);
        }
    }

    fn needs_checking(&self) -> bool {
        match self.last_checked {
            None => true,
            Some(value) => {
                return (precise_time_ns() - value) >= CHECK_INTERVAL;
            }
        }
    }
}
<|endoftext|>