<commit_before>//! Edit constructed `ComponentEntry` objects.

use error::{GrafenCliError, Result};
use ui::utils::{MenuResult, get_value_from_user, get_position_from_user, print_description,
                select_command, select_item, select_item_index};

use grafen::coord::Direction;
use grafen::database::*;
use grafen::system::*;
use grafen::coord::{Coord, Translate};
use grafen::volume::{Contains, Cuboid, Cylinder, prune_residues_from_volume};

use std::borrow::Borrow;

/// Prompt the user to select a defined component and then edit it.
pub fn user_menu(components: &mut Vec<ComponentEntry>) -> MenuResult {
    // The component should be a mutable reference to the object in the list,
    // since we want to edit it in-place.
    eprintln!("Select component to edit:");
    let mut index = select_item_index(components, 0)?;
    let mut component = components[index].clone();

    create_menu![
        @pre: {
            eprint!("State: ");
            print_description(&component);
            eprint!("\n");
        };

        Clone, "Clone the component and edit it" => {
            components.push(component);
            index = components.len() - 1;
            component = components[index].clone();

            Ok(None)
        },
        Translate, "Translate the component" => {
            let coord = get_position_from_user(None)?;
            component.translate_in_place(coord);

            Ok(None)
        },
        PruneByVolume, "Remove residues which overlap another component" => {
            let volume: Box<Contains> = get_volume_from_user(components)?;
            let num_before = component.num_atoms();

            let remaining_residues = prune_residues_from_volume::<_, Contains>(
                &component, volume.borrow());

            component.assign_residues(&remaining_residues);

            let num_after = component.num_atoms();

            Ok(Some(format!("Removed {} atoms from the component", num_before - num_after)))
        },
        QuitAndSave, "Finish editing component" => {
            components[index] = component;
            return Ok(Some("Finished editing component".to_string()));
        },
        QuitWithoutSaving, "Abort editing and discard changes" => {
            return Ok(Some("Discarding changes to component".to_string()));
        }
    ];
}

/// Ask the user to select a volume object that has been constructed.
fn get_volume_from_user(components: &[ComponentEntry]) -> Result<Box<Contains>> {
    let volume_components = get_volume_objects(components);
    let component = select_item(&volume_components, Some("Select component to cut with"))?
        .clone();

    let margin: f64 = get_value_from_user("Margin around volume to also exclude (nm)")?;

    match component {
        ComponentEntry::VolumeCuboid(mut obj) => {
            let coord_margins = Coord::new(margin, margin, margin);
            obj.origin -= coord_margins;
            obj.size += coord_margins * 2.0;

            Ok(Box::new(obj))
        },
        ComponentEntry::VolumeCylinder(mut obj) => {
            obj.radius += margin;
            obj.height += 2.0 * margin;

            match obj.alignment {
                Direction::X => obj.translate_in_place(Coord::new(-margin, 0.0, 0.0)),
                Direction::Y => obj.translate_in_place(Coord::new(0.0, -margin, 0.0)),
                Direction::Z => obj.translate_in_place(Coord::new(0.0, 0.0, -margin)),
            }

            Ok(Box::new(obj))
        },
        _ => Err(GrafenCliError::RunError(String::from(
            "Tried to get a volume type that has not been implemented: this should be impossible")
        )),
    }
}

/// Prune the list of components to only return those that are volumes, without their
/// coordinates since we don't want to copy those.
// fn get_volume_objects(components: &[ComponentEntry]) -> Vec<VolumeComponent> {
fn get_volume_objects(components: &[ComponentEntry]) -> Vec<ComponentEntry> {
    components.iter()
              .filter_map(|comp| {
                  match comp {
                      &ComponentEntry::VolumeCuboid(ref obj) => {
                          let volume = Cuboid {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              size: obj.size,
                              density: obj.density,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      &ComponentEntry::VolumeCylinder(ref obj) => {
                          let volume = Cylinder {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              radius: obj.radius,
                              height: obj.height,
                              density: obj.density,
                              alignment: obj.alignment,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      &ComponentEntry::SurfaceCylinder(ref obj) => {
                          let volume = Cylinder {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              radius: obj.radius,
                              height: obj.height,
                              density: None,
                              alignment: obj.alignment,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      _ => None,
                  }
              })
              .collect::<Vec<_>>()
}
<commit_msg>UI: Edit a text description<commit_after>//! Edit constructed `ComponentEntry` objects.

use error::{GrafenCliError, Result};
use ui::utils::{MenuResult, get_value_from_user, get_position_from_user, print_description,
                select_command, select_item, select_item_index};

use grafen::coord::Direction;
use grafen::database::*;
use grafen::system::*;
use grafen::coord::{Coord, Translate};
use grafen::volume::{Contains, Cuboid, Cylinder, prune_residues_from_volume};

use std::borrow::Borrow;

/// Prompt the user to select a defined component and then edit it.
pub fn user_menu(components: &mut Vec<ComponentEntry>) -> MenuResult {
    // The component should be a mutable reference to the object in the list,
    // since we want to edit it in-place.
    eprintln!("Select component to edit:");
    let mut index = select_item_index(components, 0)?;
    let mut component = components[index].clone();

    create_menu![
        @pre: {
            eprint!("State: ");
            print_description(&component);
            eprint!("\n");
        };

        Clone, "Clone the component and edit the new copy" => {
            components.push(component);
            index = components.len() - 1;
            component = components[index].clone();

            Ok(None)
        },

        Translate, "Translate the component" => {
            let coord = get_position_from_user(None)?;
            component.translate_in_place(coord);

            Ok(None)
        },

        PruneByVolume, "Remove residues which overlap another component" => {
            let volume: Box<Contains> = get_volume_from_user(components)?;
            let num_before = component.num_atoms();

            let remaining_residues = prune_residues_from_volume::<_, Contains>(
                &component, volume.borrow());

            component.assign_residues(&remaining_residues);

            let num_after = component.num_atoms();

            Ok(Some(format!("Removed {} atoms from the component", num_before - num_after)))
        },

        QuitAndSave, "Finish editing component" => {
            components[index] = component;
            return Ok(Some("Finished editing component".to_string()));
        },

        QuitWithoutSaving, "Abort editing and discard changes" => {
            return Ok(Some("Discarding changes to component".to_string()));
        }
    ];
}

/// Ask the user to select a volume object that has been constructed.
fn get_volume_from_user(components: &[ComponentEntry]) -> Result<Box<Contains>> {
    let volume_components = get_volume_objects(components);
    let component = select_item(&volume_components, Some("Select component to cut with"))?
        .clone();

    let margin: f64 = get_value_from_user("Margin around volume to also exclude (nm)")?;

    match component {
        ComponentEntry::VolumeCuboid(mut obj) => {
            let coord_margins = Coord::new(margin, margin, margin);
            obj.origin -= coord_margins;
            obj.size += coord_margins * 2.0;

            Ok(Box::new(obj))
        },
        ComponentEntry::VolumeCylinder(mut obj) => {
            obj.radius += margin;
            obj.height += 2.0 * margin;

            match obj.alignment {
                Direction::X => obj.translate_in_place(Coord::new(-margin, 0.0, 0.0)),
                Direction::Y => obj.translate_in_place(Coord::new(0.0, -margin, 0.0)),
                Direction::Z => obj.translate_in_place(Coord::new(0.0, 0.0, -margin)),
            }

            Ok(Box::new(obj))
        },
        _ => Err(GrafenCliError::RunError(String::from(
            "Tried to get a volume type that has not been implemented: this should be impossible")
        )),
    }
}

/// Prune the list of components to only return those that are volumes, without their
/// coordinates since we don't want to copy those.
// fn get_volume_objects(components: &[ComponentEntry]) -> Vec<VolumeComponent> {
fn get_volume_objects(components: &[ComponentEntry]) -> Vec<ComponentEntry> {
    components.iter()
              .filter_map(|comp| {
                  match comp {
                      &ComponentEntry::VolumeCuboid(ref obj) => {
                          let volume = Cuboid {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              size: obj.size,
                              density: obj.density,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      &ComponentEntry::VolumeCylinder(ref obj) => {
                          let volume = Cylinder {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              radius: obj.radius,
                              height: obj.height,
                              density: obj.density,
                              alignment: obj.alignment,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      &ComponentEntry::SurfaceCylinder(ref obj) => {
                          let volume = Cylinder {
                              name: obj.name.clone(),
                              residue: obj.residue.clone(),
                              origin: obj.origin,
                              radius: obj.radius,
                              height: obj.height,
                              density: None,
                              alignment: obj.alignment,
                              coords: vec![],
                          };

                          Some(ComponentEntry::from(volume))
                      },

                      _ => None,
                  }
              })
              .collect::<Vec<_>>()
}
<|endoftext|>


<commit_before>use super::{AssertionFailure, Spec};

use std::borrow::Borrow;
use std::fmt::Debug;

pub trait ResultAssertions<'s, T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok(&mut self) -> Spec<'s, T>;
    fn is_err(&mut self) -> Spec<'s, E>;

    #[deprecated(since="0.5.1", note="Please use `is_err` instead as a direct replacement")]
    fn is_error(&mut self) -> Spec<'s, E>;
}

pub trait ContainingResultAssertions<T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok_containing<V: Borrow<T>>(&mut self, expected_value: V) where T: PartialEq;
    fn is_err_containing<V: Borrow<E>>(&mut self, expected_value: V) where E: PartialEq;
}

impl<'s, T, E> ContainingResultAssertions<T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is an `Ok` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok_containing(&1);
    /// ```
    fn is_ok_containing<V: Borrow<T>>(&mut self, expected_value: V)
        where T: PartialEq
    {
        let borrowed_expected_value = expected_value.borrow();

        match *self.subject {
            Ok(ref val) => {
                if !val.eq(borrowed_expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("ok", borrowed_expected_value))
                        .with_actual(build_detail_message("ok", val))
                        .fail();
                }
            }
            Err(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("ok", borrowed_expected_value))
                    .with_actual(build_detail_message("err", val))
                    .fail();
            }
        }
    }

    /// Asserts that the subject is an `Err` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err_containing(&1);
    /// ```
    fn is_err_containing<V: Borrow<E>>(&mut self, expected_value: V)
        where E: PartialEq
    {
        let borrowed_expected_value = expected_value.borrow();

        match *self.subject {
            Err(ref val) => {
                if !val.eq(borrowed_expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("err", borrowed_expected_value))
                        .with_actual(build_detail_message("err", val))
                        .fail();
                }
            }
            Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("err", borrowed_expected_value))
                    .with_actual(build_detail_message("ok", val))
                    .fail();
            }
        }
    }
}

fn build_detail_message<T: Debug>(variant: &'static str, value: T) -> String {
    format!("Result[{}] containing <{:?}>", variant, value)
}

impl<'s, T, E> ResultAssertions<'s, T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is `Ok`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Ok`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok();
    /// ```
    fn is_ok(&mut self) -> Spec<'s, T> {
        match *self.subject {
            Ok(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            Err(ref err) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[ok]"))
                    .with_actual(format!("result[error]<{:?}>", err))
                    .fail();

                unreachable!();
            }
        }
    }

    /// Asserts that the subject is `Err`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Err`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err();
    /// ```
    fn is_err(&mut self) -> Spec<'s, E> {
        match *self.subject {
            Err(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[error]"))
                    .with_actual(format!("result[ok]<{:?}>", val))
                    .fail();

                unreachable!();
            }
        }
    }

    /// DEPRECATED: Use `is_err` instead to match standard Rust naming conventions.
    ///
    /// Asserts that the subject is `Err`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Err`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_error();
    /// ```
    fn is_error(&mut self) -> Spec<'s, E> {
        self.is_err()
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_ok_and_is() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[ok]\n\t but was: result[error]<\"Oh no\">")]
    fn should_panic_if_result_is_expected_to_be_ok_and_is_not() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_ok();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_ok() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok().is_equal_to(&"Hello");
    }

    #[test]
    fn should_still_support_deprecated_is_error() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_error();
    }

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_error_and_is() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[error]\n\t but was: result[ok]<\"Hello\">")]
    fn should_panic_if_result_is_expected_to_be_error_and_is_not() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_err();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_err() {
        let result: Result<&str, &str> = Err("Hello");
        assert_that(&result).is_err().is_equal_to(&"Hello");
    }

    #[test]
    fn is_ok_containing_should_allow_multiple_borrow_forms() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing("Hello");
        assert_that(&result).is_ok_containing(&mut "Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomparable;
        let result: Result<&str, Incomparable> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[ok] containing <\"Hello\">")]
    fn should_panic_if_result_is_ok_without_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[err] containing <\"Hi\">")]
    fn should_panic_if_result_is_err_if_ok_with_value_expected() {
        let result: Result<&str, &str> = Err("Hi");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    fn is_error_containing_should_allow_multiple_borrow_forms() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing("Oh no");
        assert_that(&result).is_err_containing(&mut "Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_expected_value() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomparable;
        let result: Result<Incomparable, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[err] containing <\"Whoops\">")]
    fn should_panic_if_result_is_err_without_expected_value() {
        let result: Result<&str, &str> = Err("Whoops");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[ok] containing <\"Oh no\">")]
    fn should_panic_if_result_is_ok_if_err_with_value_expected() {
        let result: Result<&str, &str> = Ok("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

}
<commit_msg>Remove deprecated 'is_error' from ResultAssertions<commit_after>use super::{AssertionFailure, Spec};

use std::borrow::Borrow;
use std::fmt::Debug;

pub trait ResultAssertions<'s, T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok(&mut self) -> Spec<'s, T>;
    fn is_err(&mut self) -> Spec<'s, E>;
}

pub trait ContainingResultAssertions<T, E>
    where T: Debug,
          E: Debug
{
    fn is_ok_containing<V: Borrow<T>>(&mut self, expected_value: V) where T: PartialEq;
    fn is_err_containing<V: Borrow<E>>(&mut self, expected_value: V) where E: PartialEq;
}

impl<'s, T, E> ContainingResultAssertions<T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is an `Ok` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok_containing(&1);
    /// ```
    fn is_ok_containing<V: Borrow<T>>(&mut self, expected_value: V)
        where T: PartialEq
    {
        let borrowed_expected_value = expected_value.borrow();

        match *self.subject {
            Ok(ref val) => {
                if !val.eq(borrowed_expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("ok", borrowed_expected_value))
                        .with_actual(build_detail_message("ok", val))
                        .fail();
                }
            }
            Err(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("ok", borrowed_expected_value))
                    .with_actual(build_detail_message("err", val))
                    .fail();
            }
        }
    }

    /// Asserts that the subject is an `Err` Result containing the expected value.
    /// The subject type must be a `Result`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err_containing(&1);
    /// ```
    fn is_err_containing<V: Borrow<E>>(&mut self, expected_value: V)
        where E: PartialEq
    {
        let borrowed_expected_value = expected_value.borrow();

        match *self.subject {
            Err(ref val) => {
                if !val.eq(borrowed_expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(build_detail_message("err", borrowed_expected_value))
                        .with_actual(build_detail_message("err", val))
                        .fail();
                }
            }
            Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(build_detail_message("err", borrowed_expected_value))
                    .with_actual(build_detail_message("ok", val))
                    .fail();
            }
        }
    }
}

fn build_detail_message<T: Debug>(variant: &'static str, value: T) -> String {
    format!("Result[{}] containing <{:?}>", variant, value)
}

impl<'s, T, E> ResultAssertions<'s, T, E> for Spec<'s, Result<T, E>>
    where T: Debug,
          E: Debug
{
    /// Asserts that the subject is `Ok`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Ok`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Ok::<usize, usize>(1)).is_ok();
    /// ```
    fn is_ok(&mut self) -> Spec<'s, T> {
        match *self.subject {
            Ok(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            Err(ref err) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[ok]"))
                    .with_actual(format!("result[error]<{:?}>", err))
                    .fail();

                unreachable!();
            }
        }
    }

    /// Asserts that the subject is `Err`. The value type must be a `Result`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Err`.
    ///
    /// ```rust,ignore
    /// assert_that(&Result::Err::<usize, usize>(1)).is_err();
    /// ```
    fn is_err(&mut self) -> Spec<'s, E> {
        match *self.subject {
            Err(ref val) => {
                Spec {
                    subject: val,
                    subject_name: self.subject_name,
                    location: self.location.clone(),
                    description: self.description,
                }
            }
            Ok(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("result[error]"))
                    .with_actual(format!("result[ok]<{:?}>", val))
                    .fail();

                unreachable!();
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_ok_and_is() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[ok]\n\t but was: result[error]<\"Oh no\">")]
    fn should_panic_if_result_is_expected_to_be_ok_and_is_not() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_ok();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_ok() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_expected_to_be_error_and_is() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: result[error]\n\t but was: result[ok]<\"Hello\">")]
    fn should_panic_if_result_is_expected_to_be_error_and_is_not() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_err();
    }

    #[test]
    fn should_return_unwrapped_value_if_subject_is_err() {
        let result: Result<&str, &str> = Err("Hello");
        assert_that(&result).is_err().is_equal_to(&"Hello");
    }

    #[test]
    fn is_ok_containing_should_allow_multiple_borrow_forms() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing("Hello");
        assert_that(&result).is_ok_containing(&mut "Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    fn should_not_panic_if_result_is_ok_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomparable;
        let result: Result<&str, Incomparable> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[ok] containing <\"Hello\">")]
    fn should_panic_if_result_is_ok_without_expected_value() {
        let result: Result<&str, &str> = Ok("Hello");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[ok] containing <\"Hi\">\
                   \n\t but was: Result[err] containing <\"Hi\">")]
    fn should_panic_if_result_is_err_if_ok_with_value_expected() {
        let result: Result<&str, &str> = Err("Hi");
        assert_that(&result).is_ok_containing(&"Hi");
    }

    #[test]
    fn is_error_containing_should_allow_multiple_borrow_forms() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing("Oh no");
        assert_that(&result).is_err_containing(&mut "Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_expected_value() {
        let result: Result<&str, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    fn should_not_panic_if_result_is_err_with_uncomparable_ok() {
        #[derive(Debug)]
        struct Incomparable;
        let result: Result<Incomparable, &str> = Err("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[err] containing <\"Whoops\">")]
    fn should_panic_if_result_is_err_without_expected_value() {
        let result: Result<&str, &str> = Err("Whoops");
        assert_that(&result).is_err_containing(&"Oh no");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Result[err] containing <\"Oh no\">\
                   \n\t but was: Result[ok] containing <\"Oh no\">")]
    fn should_panic_if_result_is_ok_if_err_with_value_expected() {
        let result: Result<&str, &str> = Ok("Oh no");
        assert_that(&result).is_err_containing(&"Oh no");
    }

}
<|endoftext|>


<commit_before>#[crate_id = "prob0096"];
#[crate_type = "rlib"];

use std::{char, fmt, iter};
use std::io::{BufferedReader, File};
use std::num::Bitwise;

pub static EXPECTED_ANSWER: &'static str = "24702";

static BOARD_WIDTH: uint = 9;
static BOARD_HEIGHT: uint = 9;
static GROUP_WIDTH: uint = 3;
static GROUP_HEIGHT: uint = 3;
static MAX_NUMBER: uint = 9;
type BITS = u16;
static MASK_ALL: BITS = 0x1ff;

struct SuDoku {
    name: ~str,
    map: [[BITS, .. BOARD_WIDTH], .. BOARD_HEIGHT]
}

// #7622 (rust): #[deriving(TotalEq, Eq, Clone)] cannnot be used
impl TotalEq for SuDoku {}

impl Eq for SuDoku {
    #[inline]
    fn eq(&self, other: &SuDoku) -> bool { self.eq(other) }
    #[inline]
    fn ne(&self, other: &SuDoku) -> bool { self.ne(other) }
}

impl fmt::Show for SuDoku {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(f.buf.write_line(self.name));

        for row in self.map.iter() {
            for cell in row.iter() {
                if cell.count_ones() == 1 {
                    try!(write!(f.buf, "_"));
                } else {
                    try!(write!(f.buf, "{}", 1u << cell.trailing_zeros()));
                }
            }
            try!(f.buf.write_line(""));
        }

        Ok(())
    }
}

impl Clone for SuDoku {
    #[inline]
    fn clone(&self) -> SuDoku {
        SuDoku { name: self.name.clone(), map: self.map }
    }
}

impl SuDoku {
    #[inline]
    fn get_num(&self, x: uint, y: uint) -> BITS {
        match self.map[y][x].count_ones() {
            0 => -1,
            1 => self.map[y][x].trailing_zeros() + 1,
            _ => 0
        }
    }
}

fn read_sudoku<T: Reader>(r: &mut BufferedReader<T>) -> Option<SuDoku> {
    r.read_line().ok()
        .and_then(|name| {
            let mut sudoku = SuDoku {
                name: name,
                map: [[MASK_ALL, .. BOARD_WIDTH], .. BOARD_HEIGHT]
            };
            for y in range(0, BOARD_HEIGHT) {
                match r.read_line().ok() {
                    None => return None,
                    Some(line) => {
                        for x in range(0, BOARD_WIDTH) {
                            let n = char::to_digit(line[x] as char, 10).unwrap();
                            if n != 0 { sudoku.map[y][x] = 1 << (n - 1); }
                        }
                    }
                }
            }
            Some(sudoku)
        })
}

fn solve_sudoku(mut puzzle: SuDoku) -> ~[SuDoku] {
    let group_it = range(0, GROUP_WIDTH * GROUP_HEIGHT)
        .map(|i| (i % GROUP_WIDTH, i / GROUP_WIDTH))
        .collect::<~[(uint, uint)]>();

    loop {
        let bkup = puzzle.clone();

        for y in range(0, BOARD_HEIGHT) {
            for x in range(0, BOARD_WIDTH) {
                if puzzle.map[y][x].count_ones() != 1 { continue }

                let (x0, y0) = (x / GROUP_WIDTH * GROUP_WIDTH,
                                y / GROUP_HEIGHT * GROUP_HEIGHT);
                let row = range(0, BOARD_WIDTH).map(|x| (x, y));
                let col = range(0, BOARD_HEIGHT).map(|y| (x, y));
                let grp = group_it.iter().map(|&(dx, dy)| (x0 + dx, y0 + dy));

                let mut it = row.chain(col).chain(grp)
                    .filter(|&pos: &(uint, uint)| pos != (x, y));
                let mask = !puzzle.map[y][x] & MASK_ALL;
                for (x, y) in it { puzzle.map[y][x] &= mask; }
            }
        }

        for n in range(0, MAX_NUMBER) {
            let bit = 1 << n;

            for y in range(0, BOARD_HEIGHT) {
                let next = {
                    let mut it = range(0, BOARD_WIDTH)
                        .filter(|&x| puzzle.map[y][x] & bit != 0);
                    let next = it.next();
                    if next.is_none() || it.next().is_some() { continue }
                    next
                };
                puzzle.map[y][next.unwrap()] = bit;
            }

            for x in range(0, BOARD_WIDTH) {
                let next = {
                    let mut it = range(0, BOARD_HEIGHT)
                        .filter(|&y| puzzle.map[y][x] & bit != 0);
                    let next = it.next();
                    if next.is_none() || it.next().is_some() { continue }
                    next
                };
                puzzle.map[next.unwrap()][x] = bit;
            }

            for y0 in iter::range_step(0, BOARD_HEIGHT, GROUP_WIDTH) {
                for x0 in iter::range_step(0, BOARD_WIDTH, GROUP_HEIGHT) {
                    let next = {
                        let mut it = group_it
                            .iter()
                            .map(|&(dx, dy)| (x0 + dx, y0 + dy))
                            .filter(|&(x, y)| puzzle.map[y][x] & bit != 0);
                        let next = it.next();
                        if next.is_none() || it.next().is_some() { continue }
                        next
                    };
                    let (x, y) = next.unwrap();
                    puzzle.map[y][x] = bit;
                }
            }
        }

        if puzzle == bkup { break }
    }

    let it = range(0, BOARD_HEIGHT * BOARD_WIDTH)
        .map(|i| (i % BOARD_WIDTH, i / BOARD_WIDTH))
        .map(|(x, y)| (x, y, puzzle.map[y][x].count_ones()))
        .collect::<~[(uint, uint, u16)]>();

    if it.iter().any(|&(_x, _y, cnt)| cnt == 0) { return ~[]; }
    if it.iter().all(|&(_x, _y, cnt)| cnt == 1) { return ~[puzzle]; }

    let (x, y, _cnt) = *it.iter()
        .filter(|& &(_x, _y, cnt)| cnt > 1)
        .min_by(|& &(_x, _y, cnt)| cnt)
        .unwrap();

    let mut answers = ~[];
    for n in range(0, MAX_NUMBER) {
        let bit = 1 << n;
        if puzzle.map[y][x] & bit == 0 { continue }

        let mut p2 = puzzle.clone();
        p2.map[y][x] = bit;
        answers.push_all(solve_sudoku(p2));
    }

    answers
}

pub fn solve() -> ~str {
    let mut br = BufferedReader::new(
        File::open(&Path::new("files/sudoku.txt")).ok().expect("file not found."));

    let mut puzzles = ~[];
    loop {
        match read_sudoku(&mut br) {
            Some(sudoku) => puzzles.push(sudoku),
            None => break
        }
    }
    let mut answers = puzzles
        .move_iter()
        .map(solve_sudoku)
        .map(|ans| { assert_eq!(ans.len(), 1); ans[0] });
    let mut sum = 0;
    for ans in answers {
        sum += 100 * ans.get_num(0, 0) + 10 * ans.get_num(1, 0) + ans.get_num(2, 0);
    }
    sum.to_str()
}
<commit_msg>fix SuDoku::eq<commit_after>#[crate_id = "prob0096"];
#[crate_type = "rlib"];

use std::{char, fmt, iter};
use std::io::{BufferedReader, File};
use std::num::Bitwise;

pub static EXPECTED_ANSWER: &'static str = "24702";

static BOARD_WIDTH: uint = 9;
static BOARD_HEIGHT: uint = 9;
static GROUP_WIDTH: uint = 3;
static GROUP_HEIGHT: uint = 3;
static MAX_NUMBER: uint = 9;
type BITS = u16;
static MASK_ALL: BITS = 0x1ff;

struct SuDoku {
    name: ~str,
    map: [[BITS, .. BOARD_WIDTH], .. BOARD_HEIGHT]
}

// #7622 (rust): #[deriving(TotalEq, Eq, Clone)] cannnot be used
impl TotalEq for SuDoku {}

impl Eq for SuDoku {
    #[inline]
    fn eq(&self, other: &SuDoku) -> bool {
        self.name == other.name && range(0, BOARD_HEIGHT).all(|y| self.map[y] == other.map[y])
    }
}

impl fmt::Show for SuDoku {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(f.buf.write_line(self.name));

        for row in self.map.iter() {
            for cell in row.iter() {
                if cell.count_ones() == 1 {
                    try!(write!(f.buf, "_"));
                } else {
                    try!(write!(f.buf, "{}", 1u << cell.trailing_zeros()));
                }
            }
            try!(f.buf.write_line(""));
        }

        Ok(())
    }
}

impl Clone for SuDoku {
    #[inline]
    fn clone(&self) -> SuDoku {
        SuDoku { name: self.name.clone(), map: self.map }
    }
}

impl SuDoku {
    #[inline]
    fn get_num(&self, x: uint, y: uint) -> BITS {
        match self.map[y][x].count_ones() {
            0 => -1,
            1 => self.map[y][x].trailing_zeros() + 1,
            _ => 0
        }
    }
}

fn read_sudoku<T: Reader>(r: &mut BufferedReader<T>) -> Option<SuDoku> {
    r.read_line().ok()
        .and_then(|name| {
            let mut sudoku = SuDoku {
                name: name,
                map: [[MASK_ALL, .. BOARD_WIDTH], .. BOARD_HEIGHT]
            };
            for y in range(0, BOARD_HEIGHT) {
                match r.read_line().ok() {
                    None => return None,
                    Some(line) => {
                        for x in range(0, BOARD_WIDTH) {
                            let n = char::to_digit(line[x] as char, 10).unwrap();
                            if n != 0 { sudoku.map[y][x] = 1 << (n - 1); }
                        }
                    }
                }
            }
            Some(sudoku)
        })
}

fn solve_sudoku(mut puzzle: SuDoku) -> ~[SuDoku] {
    let group_it = range(0, GROUP_WIDTH * GROUP_HEIGHT)
        .map(|i| (i % GROUP_WIDTH, i / GROUP_WIDTH))
        .collect::<~[(uint, uint)]>();

    loop {
        let bkup = puzzle.clone();

        for y in range(0, BOARD_HEIGHT) {
            for x in range(0, BOARD_WIDTH) {
                if puzzle.map[y][x].count_ones() != 1 { continue }

                let (x0, y0) = (x / GROUP_WIDTH * GROUP_WIDTH,
                                y / GROUP_HEIGHT * GROUP_HEIGHT);
                let row = range(0, BOARD_WIDTH).map(|x| (x, y));
                let col = range(0, BOARD_HEIGHT).map(|y| (x, y));
                let grp = group_it.iter().map(|&(dx, dy)| (x0 + dx, y0 + dy));

                let mut it = row.chain(col).chain(grp)
                    .filter(|&pos: &(uint, uint)| pos != (x, y));
                let mask = !puzzle.map[y][x] & MASK_ALL;
                for (x, y) in it { puzzle.map[y][x] &= mask; }
            }
        }

        for n in range(0, MAX_NUMBER) {
            let bit = 1 << n;

            for y in range(0, BOARD_HEIGHT) {
                let next = {
                    let mut it = range(0, BOARD_WIDTH)
                        .filter(|&x| puzzle.map[y][x] & bit != 0);
                    let next = it.next();
                    if next.is_none() || it.next().is_some() { continue }
                    next
                };
                puzzle.map[y][next.unwrap()] = bit;
            }

            for x in range(0, BOARD_WIDTH) {
                let next = {
                    let mut it = range(0, BOARD_HEIGHT)
                        .filter(|&y| puzzle.map[y][x] & bit != 0);
                    let next = it.next();
                    if next.is_none() || it.next().is_some() { continue }
                    next
                };
                puzzle.map[next.unwrap()][x] = bit;
            }

            for y0 in iter::range_step(0, BOARD_HEIGHT, GROUP_WIDTH) {
                for x0 in iter::range_step(0, BOARD_WIDTH, GROUP_HEIGHT) {
                    let next = {
                        let mut it = group_it
                            .iter()
                            .map(|&(dx, dy)| (x0 + dx, y0 + dy))
                            .filter(|&(x, y)| puzzle.map[y][x] & bit != 0);
                        let next = it.next();
                        if next.is_none() || it.next().is_some() { continue }
                        next
                    };
                    let (x, y) = next.unwrap();
                    puzzle.map[y][x] = bit;
                }
            }
        }

        if puzzle == bkup { break }
    }

    let it = range(0, BOARD_HEIGHT * BOARD_WIDTH)
        .map(|i| (i % BOARD_WIDTH, i / BOARD_WIDTH))
        .map(|(x, y)| (x, y, puzzle.map[y][x].count_ones()))
        .collect::<~[(uint, uint, u16)]>();

    if it.iter().any(|&(_x, _y, cnt)| cnt == 0) { return ~[]; }
    if it.iter().all(|&(_x, _y, cnt)| cnt == 1) { return ~[puzzle]; }

    let (x, y, _cnt) = *it.iter()
        .filter(|& &(_x, _y, cnt)| cnt > 1)
        .min_by(|& &(_x, _y, cnt)| cnt)
        .unwrap();

    let mut answers = ~[];
    for n in range(0, MAX_NUMBER) {
        let bit = 1 << n;
        if puzzle.map[y][x] & bit == 0 { continue }

        let mut p2 = puzzle.clone();
        p2.map[y][x] = bit;
        answers.push_all(solve_sudoku(p2));
    }

    answers
}

pub fn solve() -> ~str {
    let mut br = BufferedReader::new(
        File::open(&Path::new("files/sudoku.txt")).ok().expect("file not found."));

    let mut puzzles = ~[];
    loop {
        match read_sudoku(&mut br) {
            Some(sudoku) => puzzles.push(sudoku),
            None => break
        }
    }
    let mut answers = puzzles
        .move_iter()
        .map(solve_sudoku)
        .map(|ans| { assert_eq!(ans.len(), 1); ans[0] });
    let mut sum = 0;
    for ans in answers {
        sum += 100 * ans.get_num(0, 0) + 10 * ans.get_num(1, 0) + ans.get_num(2, 0);
    }
    sum.to_str()
}
<|endoftext|>


<commit_before>use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError),
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => {
                match err.kind() {
                    ErrorKind::NotFound => "no such file or directory",
                    _ => err.description(),
                }
            }
            RunnerError::PrefReader(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        Some(match *self {
            RunnerError::Io(ref err) => err as &Error,
            RunnerError::PrefReader(ref err) => err as &Error,
        })
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        find_binary("firefox-bin")
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = try!(subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ));
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<commit_msg>Allow firefox_registry_path to check for both 32bit and 64bit binaries (#3)<commit_after>use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError),
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => {
                match err.kind() {
                    ErrorKind::NotFound => "no such file or directory",
                    _ => err.description(),
                }
            }
            RunnerError::PrefReader(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        Some(match *self {
            RunnerError::Io(ref err) => err as &Error,
            RunnerError::PrefReader(ref err) => err as &Error,
        })
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        find_binary("firefox-bin")
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = match subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ) {
                Ok(val) => val,
                Err(_) => continue
            };
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<|endoftext|>


<commit_before>use super::geo_class_and_kind;
use crate::util::AsArray2D;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Holds the state of a shape entity
#[derive(Clone, Debug)]
pub struct StateOfShape {
    // -- steady ----------------------------------------------------------------------------------------------------
    //
    /// Matrix Xᵀ: (space_ndim,nnode) transposed coordinates matrix (real space)
    ///
    /// ```text
    /// The (non-transposed) matrix X is such that:
    ///
    ///     ┌               ┐
    ///     | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///     | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// X = | x²₀  x²₁  x²₂ |
    ///     |      ...      |
    ///     | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///     └               ┘_(nnode,space_ndim)
    ///
    /// where `M = nnode - 1`
    /// ```
    pub coords_transp: Matrix,

    /// Minimum (space_ndim) coordinates from the X matrix
    pub coords_min: Vec<f64>,

    /// Maximum (space_ndim) coordinates from the X matrix
    pub coords_max: Vec<f64>,

    // -- transient -------------------------------------------------------------------------------------------------
    //
    /// Array N: (nnode) interpolation functions at reference coordinate ksi
    pub interp: Vector,

    /// Matrix L: (nnode,geo_ndim) derivatives of interpolation functions w.r.t reference coordinate ksi
    pub deriv: Matrix,

    /// Matrix J: (space_ndim,geo_ndim) Jacobian matrix
    pub jacobian: Matrix,

    /// Matrix inv(J): (space_ndim,space_ndim) Inverse Jacobian matrix (only if geo_ndim == space_ndim) at ksi
    pub inv_jacobian: Matrix,

    /// Matrix G: (nnode,space_ndim) Gradient of shape functions (only if geo_ndim == space_ndim) at ksi
    pub gradient: Matrix,
}

impl StateOfShape {
    /// Allocates a new instance
    ///
    /// # Input
    ///
    /// * `geo_ndim` -- the dimension of the shape; e.g. a 1D line in a 3D space
    /// * `coords` -- the (non-transposed) matrix of coordinates (`X` matrix); see below
    ///
    /// ```text
    ///          ┌               ┐
    ///          | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///          | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// coords = | x²₀  x²₁  x²₂ |
    ///          |      ...      |
    ///          | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///          └               ┘_(nnode,space_ndim)
    /// ```
    pub fn new<'a, T>(geo_ndim: usize, coords: &'a T) -> Result<Self, StrError>
    where
        T: AsArray2D<'a, f64>,
    {
        let (nnode, space_ndim) = coords.size();
        if space_ndim < 1 || space_ndim > 3 {
            return Err("space_ndim must be 1, 2 or 3");
        }
        geo_class_and_kind(geo_ndim, nnode)?; // just to check combination
        let mut state = StateOfShape {
            coords_transp: Matrix::new(space_ndim, nnode),
            coords_min: vec![f64::MAX; space_ndim],
            coords_max: vec![f64::MIN; space_ndim],
            interp: Vector::new(nnode),
            deriv: Matrix::new(nnode, geo_ndim),
            jacobian: Matrix::new(space_ndim, geo_ndim),
            inv_jacobian: if geo_ndim == space_ndim {
                Matrix::new(space_ndim, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
            gradient: if geo_ndim == space_ndim {
                Matrix::new(nnode, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
        };
        for m in 0..nnode {
            for j in 0..space_ndim {
                let value = coords.at(m, j);
                state.coords_transp[j][m] = value;
                if value < state.coords_min[j] {
                    state.coords_min[j] = value;
                }
                if value > state.coords_max[j] {
                    state.coords_max[j] = value;
                }
            }
        }
        Ok(state)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::StateOfShape;
    use crate::StrError;

    #[test]
    fn new_fails_on_wrong_input() {
        assert_eq!(
            StateOfShape::new(1, &[[], []]).err(),
            Some("space_ndim must be 1, 2 or 3")
        );
        assert_eq!(
            StateOfShape::new(1, &[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]).err(),
            Some("space_ndim must be 1, 2 or 3")
        );
    }

    #[test]
    fn new_works() -> Result<(), StrError> {
        let state = StateOfShape::new(2, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌                   ┐\n\
             │ -1.23 -4.56 -7.89 │\n\
             │  1.23  4.56  7.89 │\n\
             └                   ┘"
        );
        Ok(())
    }
}
<commit_msg>Add test<commit_after>use super::geo_class_and_kind;
use crate::util::AsArray2D;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Holds the state of a shape entity
#[derive(Clone, Debug)]
pub struct StateOfShape {
    // -- steady ----------------------------------------------------------------------------------------------------
    //
    /// Matrix Xᵀ: (space_ndim,nnode) transposed coordinates matrix (real space)
    ///
    /// ```text
    /// The (non-transposed) matrix X is such that:
    ///
    ///     ┌               ┐
    ///     | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///     | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// X = | x²₀  x²₁  x²₂ |
    ///     |      ...      |
    ///     | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///     └               ┘_(nnode,space_ndim)
    ///
    /// where `M = nnode - 1`
    /// ```
    pub coords_transp: Matrix,

    /// Minimum (space_ndim) coordinates from the X matrix
    pub coords_min: Vec<f64>,

    /// Maximum (space_ndim) coordinates from the X matrix
    pub coords_max: Vec<f64>,

    // -- transient -------------------------------------------------------------------------------------------------
    //
    /// Array N: (nnode) interpolation functions at reference coordinate ksi
    pub interp: Vector,

    /// Matrix L: (nnode,geo_ndim) derivatives of interpolation functions w.r.t reference coordinate ksi
    pub deriv: Matrix,

    /// Matrix J: (space_ndim,geo_ndim) Jacobian matrix
    pub jacobian: Matrix,

    /// Matrix inv(J): (space_ndim,space_ndim) Inverse Jacobian matrix (only if geo_ndim == space_ndim) at ksi
    pub inv_jacobian: Matrix,

    /// Matrix G: (nnode,space_ndim) Gradient of shape functions (only if geo_ndim == space_ndim) at ksi
    pub gradient: Matrix,
}

impl StateOfShape {
    /// Allocates a new instance
    ///
    /// # Input
    ///
    /// * `geo_ndim` -- the dimension of the shape; e.g. a 1D line in a 3D space
    /// * `coords` -- the (non-transposed) matrix of coordinates (`X` matrix); see below
    ///
    /// ```text
    ///          ┌               ┐
    ///          | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///          | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// coords = | x²₀  x²₁  x²₂ |
    ///          |      ...      |
    ///          | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///          └               ┘_(nnode,space_ndim)
    /// ```
    pub fn new<'a, T>(geo_ndim: usize, coords: &'a T) -> Result<Self, StrError>
    where
        T: AsArray2D<'a, f64>,
    {
        let (nnode, space_ndim) = coords.size();
        if space_ndim < 1 || space_ndim > 3 {
            return Err("space_ndim must be 1, 2 or 3");
        }
        geo_class_and_kind(geo_ndim, nnode)?; // just to check combination
        let mut state = StateOfShape {
            coords_transp: Matrix::new(space_ndim, nnode),
            coords_min: vec![f64::MAX; space_ndim],
            coords_max: vec![f64::MIN; space_ndim],
            interp: Vector::new(nnode),
            deriv: Matrix::new(nnode, geo_ndim),
            jacobian: Matrix::new(space_ndim, geo_ndim),
            inv_jacobian: if geo_ndim == space_ndim {
                Matrix::new(space_ndim, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
            gradient: if geo_ndim == space_ndim {
                Matrix::new(nnode, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
        };
        for m in 0..nnode {
            for j in 0..space_ndim {
                let value = coords.at(m, j);
                state.coords_transp[j][m] = value;
                if value < state.coords_min[j] {
                    state.coords_min[j] = value;
                }
                if value > state.coords_max[j] {
                    state.coords_max[j] = value;
                }
            }
        }
        Ok(state)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::StateOfShape;
    use crate::StrError;

    #[test]
    fn new_fails_on_wrong_input() {
        assert_eq!(
            StateOfShape::new(1, &[[], []]).err(),
            Some("space_ndim must be 1, 2 or 3")
        );
        assert_eq!(
            StateOfShape::new(1, &[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]).err(),
            Some("space_ndim must be 1, 2 or 3")
        );
    }

    #[test]
    fn new_works() -> Result<(), StrError> {
        let state = StateOfShape::new(2, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌                   ┐\n\
             │ -1.23 -4.56 -7.89 │\n\
             │  1.23  4.56  7.89 │\n\
             └                   ┘"
        );
        assert_eq!(state.coords_min, &[-7.89, 1.23]);
        assert_eq!(state.coords_max, &[-1.23, 7.89]);
        Ok(())
    }

    #[test]
    fn derive_works() -> Result<(), StrError> {
        let state = StateOfShape::new(2, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        let state_clone = state.clone();
        assert_eq!(format!("{:?}", state), "StateOfShape { coords_transp: NumMatrix { nrow: 2, ncol: 3, data: [-1.23, -4.56, -7.89, 1.23, 4.56, 7.89] }, coords_min: [-7.89, 1.23], coords_max: [-1.23, 7.89], interp: NumVector { data: [0.0, 0.0, 0.0] }, deriv: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] }, jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, inv_jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, gradient: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] } }");
        assert_eq!(state_clone.coords_min, &[-7.89, 1.23]);
        assert_eq!(state_clone.coords_max, &[-1.23, 7.89]);
        Ok(())
    }
}
<|endoftext|>


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

//! Structs and methods for searching for tweets.
//!
//! Since there are several optional parameters for searches, egg-mode handles it with a builder
//! pattern. To begin, call `search` with your requested search term. Additional parameters can be
//! added onto the `SearchBuilder` struct that is returned. When you're ready to load the first
//! page of results, hand your tokens to `call`.
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core; extern crate futures;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//! use egg_mode::search::{self, ResultType};
//!
//! let search = core.run(search::search("rustlang")
//!                              .result_type(ResultType::Recent)
//!                              .call(&token, &handle))
//!                  .unwrap();
//!
//! for tweet in &search.statuses {
//!     println!("(@{}) {}", tweet.user.as_ref().unwrap().screen_name, tweet.text);
//! }
//! # }
//! ```
//!
//! Once you have your `SearchResult`, you can navigate the search results by calling `older` and
//! `newer` to get the next and previous pages, respsectively. In addition, you can see your
//! original query in the search result struct as well, so you can categorize multiple searches by
//! their query. While this is given as a regular field, note that modifying `query` will not
//! change what is searched for when you call `older` or `newer`; the `SearchResult` keeps its
//! search arguments in a separate private field.
//!
//! The search parameter given in the initial call to `search` has several options itself. A full
//! reference is available in [Twitter's Search API documentation][search-doc]. This listing by
//! itself does not include the search by Place ID, as mentioned on [a separate Tweets by Place
//! page][search-place]. A future version of egg-mode might break these options into further
//! methods on `SearchBuilder`.
//!
//! [search-doc]: https://dev.twitter.com/rest/public/search
//! [search-place]: https://dev.twitter.com/rest/public/search-by-place

use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;
use futures::{Future, Poll, Async};

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query,
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
        since_id: None,
        max_id: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(f32),
    ///A radius given in kilometers.
    Kilometers(f32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: &'a str,
    lang: Option<&'a str>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>,
    since_id: Option<u64>,
    max_id: Option<u64>,
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang(self, lang: &'a str) -> Self {
        SearchBuilder {
            lang: Some(lang),
            ..self
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            result_type: Some(result_type),
            ..self
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            count: Some(count),
            ..self
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            until: Some((year, month, day)),
            ..self
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            geocode: Some((latitude, longitude, radius)),
            ..self
        }
    }

    ///Restricts results to those with higher IDs than (i.e. that were posted after) the given
    ///tweet ID.
    pub fn since_tweet(self, since_id: u64) -> Self {
        SearchBuilder {
            since_id: Some(since_id),
            ..self
        }
    }

    ///Restricts results to those with IDs no higher than (i.e. were posted earlier than) the given
    ///tweet ID. Will include the given tweet in search results.
    pub fn max_tweet(self, max_id: u64) -> Self {
        SearchBuilder {
            max_id: Some(max_id),
            ..self
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        if let Some(since_id) = self.since_id {
            add_param(&mut params, "since_id", since_id.to_string());
        }

        if let Some(max_id) = self.max_id {
            add_param(&mut params, "max_id", max_id.to_string());
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }
}

/// `Future` that represents a search query in progress.
///
/// When this future resolves, it will either contain a `SearchResult` or the error that was
/// encountered while loading or parsing the response.
#[must_use = "futures do nothing unless polled"]
pub struct SearchFuture<'a> {
    loader: FutureResponse<SearchResult<'a>>,
    params: Option<ParamList<'a>>,
}

impl<'a> Future for SearchFuture<'a> {
    type Item = Response<SearchResult<'a>>;
    type Error = error::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut resp = match self.loader.poll() {
            Ok(Async::Ready(resp)) => resp,
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(e) => return Err(e),
        };

        resp.params = self.params.take();
        Ok(Async::Ready(resp))
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    ///Last tweet id in this page of results. This id can be used in `SearchBuilder::since_tweet`
    pub max_id: u64,
    ///First tweet id in this page of results. This id can be used in `SearchBuilder::since_tweet`
    pub since_id: u64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }
}
<commit_msg>change `&'a str` into `Cow<'a, str>` in SearchFuture et al<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Structs and methods for searching for tweets.
//!
//! Since there are several optional parameters for searches, egg-mode handles it with a builder
//! pattern. To begin, call `search` with your requested search term. Additional parameters can be
//! added onto the `SearchBuilder` struct that is returned. When you're ready to load the first
//! page of results, hand your tokens to `call`.
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core; extern crate futures;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//! use egg_mode::search::{self, ResultType};
//!
//! let search = core.run(search::search("rustlang")
//!                              .result_type(ResultType::Recent)
//!                              .call(&token, &handle))
//!                  .unwrap();
//!
//! for tweet in &search.statuses {
//!     println!("(@{}) {}", tweet.user.as_ref().unwrap().screen_name, tweet.text);
//! }
//! # }
//! ```
//!
//! Once you have your `SearchResult`, you can navigate the search results by calling `older` and
//! `newer` to get the next and previous pages, respsectively. In addition, you can see your
//! original query in the search result struct as well, so you can categorize multiple searches by
//! their query. While this is given as a regular field, note that modifying `query` will not
//! change what is searched for when you call `older` or `newer`; the `SearchResult` keeps its
//! search arguments in a separate private field.
//!
//! The search parameter given in the initial call to `search` has several options itself. A full
//! reference is available in [Twitter's Search API documentation][search-doc]. This listing by
//! itself does not include the search by Place ID, as mentioned on [a separate Tweets by Place
//! page][search-place]. A future version of egg-mode might break these options into further
//! methods on `SearchBuilder`.
//!
//! The lifetime parameter on `SearchBuilder`, `SearchFuture`, and `SearchResult` correspond to the
//! text given as the search query and (if applicable) to the `lang` method of `SearchBuilder`. As
//! these types use `Cow<'a, str>` internally, you can hand these types owned Strings to give them
//! a `'static` lifetime, if necessary.
//!
//! [search-doc]: https://dev.twitter.com/rest/public/search
//! [search-place]: https://dev.twitter.com/rest/public/search-by-place

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;
use futures::{Future, Poll, Async};

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a, S: Into<Cow<'a, str>>>(query: S) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query.into(),
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
        since_id: None,
        max_id: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(f32),
    ///A radius given in kilometers.
    Kilometers(f32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: Cow<'a, str>,
    lang: Option<Cow<'a, str>>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>,
    since_id: Option<u64>,
    max_id: Option<u64>,
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang<S: Into<Cow<'a, str>>>(self, lang: S) -> Self {
        SearchBuilder {
            lang: Some(lang.into()),
            ..self
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            result_type: Some(result_type),
            ..self
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            count: Some(count),
            ..self
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            until: Some((year, month, day)),
            ..self
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            geocode: Some((latitude, longitude, radius)),
            ..self
        }
    }

    ///Restricts results to those with higher IDs than (i.e. that were posted after) the given
    ///tweet ID.
    pub fn since_tweet(self, since_id: u64) -> Self {
        SearchBuilder {
            since_id: Some(since_id),
            ..self
        }
    }

    ///Restricts results to those with IDs no higher than (i.e. were posted earlier than) the given
    ///tweet ID. Will include the given tweet in search results.
    pub fn max_tweet(self, max_id: u64) -> Self {
        SearchBuilder {
            max_id: Some(max_id),
            ..self
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        if let Some(since_id) = self.since_id {
            add_param(&mut params, "since_id", since_id.to_string());
        }

        if let Some(max_id) = self.max_id {
            add_param(&mut params, "max_id", max_id.to_string());
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }
}

/// `Future` that represents a search query in progress.
///
/// When this future resolves, it will either contain a `SearchResult` or the error that was
/// encountered while loading or parsing the response.
#[must_use = "futures do nothing unless polled"]
pub struct SearchFuture<'a> {
    loader: FutureResponse<SearchResult<'a>>,
    params: Option<ParamList<'a>>,
}

impl<'a> Future for SearchFuture<'a> {
    type Item = Response<SearchResult<'a>>;
    type Error = error::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut resp = match self.loader.poll() {
            Ok(Async::Ready(resp)) => resp,
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(e) => return Err(e),
        };

        resp.params = self.params.take();
        Ok(Async::Ready(resp))
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    ///Last tweet id in this page of results. This id can be used in `SearchBuilder::since_tweet`
    pub max_id: u64,
    ///First tweet id in this page of results. This id can be used in `SearchBuilder::since_tweet`
    pub since_id: u64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, token: &auth::Token, handle: &Handle) -> SearchFuture<'a> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let req = auth::get(links::statuses::SEARCH, token, Some(&params));

        SearchFuture {
            loader: make_parsed_future(handle, req),
            params: Some(params),
        }
    }
}
<|endoftext|>