<commit_before>use graphics::*;

use mint;

type Vec3 = na::Vector3<f32>;

/// A struct containing all the necessary info for drawing a Drawable.
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust,ignore
/// graphics::draw_ex(ctx, drawable, DrawParam{ dest: my_dest, .. Default::default()} )
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// a portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub(crate) src: Rect,
    /// the position to draw the graphic expressed as a `Point2`.
    pub(crate) dest: Point2,
    /// orientation of the graphic in radians.
    pub(crate) rotation: f32,
    /// x/y scale factors expressed as a `Vector2`.
    pub(crate) scale: Vector2,
    /// specifies an offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub(crate) offset: Point2,
    /// A color to draw the target with.
    /// Default: white.
    pub(crate) color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: Point2::origin(),
            rotation: 0.0,
            scale: Vector2::new(1.0, 1.0),
            offset: Point2::new(0.0, 0.0),
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = Point2::from(p);
        self
    }

    /// TODO
    pub fn color<C>(mut self, color: C) -> Self
    where
        C: Into<Color>,
    {
        self.color = color.into();
        self
    }

    /// TODO
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// TODO
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = Vector2::from(p);
        self
    }

    /// TODO
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = Point2::from(p);
        self
    }

    // TODO: Easy mirror functions for X and Y axis might be nice.
}

/// Create a DrawTransform from a location
impl<P> From<(P,)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0).into()
    }
}

/// Create a DrawTransform from a location and color
impl<P, C> From<(P, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, color): (P, C)) -> Self {
        DrawParam::new().dest(location).color(color).into()
    }
}

/// Create a DrawTransform from a location, rotation and color
impl<P, C> From<(P, f32, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, color): (P, f32, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
            .into()
    }
}

/// Create a DrawTransform from a location, rotation, offset and color
impl<P, C> From<(P, f32, P, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, offset, color): (P, f32, P, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
            .into()
    }
}

/// Create a DrawTransform from a location, rotation, offset, scale and color
impl<P, V, C> From<(P, f32, P, V, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
            .into()
    }
}

/// A `DrawParam` that has been crunched down to a single matrix.
/// Useful for doing matrix-based coordinate transformations, I hope.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: na::one(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        let translate = Matrix4::new_translation(&Vec3::new(param.dest.x, param.dest.y, 0.0));
        let offset = Matrix4::new_translation(&Vec3::new(param.offset.x, param.offset.y, 0.0));
        let offset_inverse =
            Matrix4::new_translation(&Vec3::new(-param.offset.x, -param.offset.y, 0.0));
        let axis_angle = Vec3::z() * param.rotation;
        let rotation = Matrix4::new_rotation(axis_angle);
        let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(param.scale.x, param.scale.y, 1.0));
        let transform = translate * offset * rotation * offset_inverse * scale;
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform,
        }
    }
}

impl DrawTransform {
    /// Returns a new `PrimitiveDrawParam` with its matrix multiplied
    /// by the given one.
    ///
    /// TODO: Make some way to implement `matrix * self.matrix`, or just implement `Mul`...
    pub fn mul(self, matrix: Matrix4) -> Self {
        DrawTransform {
            matrix: self.matrix * matrix,
            ..self
        }
    }

    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        let mat: [[f32; 4]; 4] = self.matrix.into();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<commit_msg>boop?<commit_after>use graphics::*;

use mint;

type Vec3 = na::Vector3<f32>;

/// A struct containing all the necessary info for drawing a Drawable.
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust,ignore
/// graphics::draw_ex(ctx, drawable, DrawParam{ dest: my_dest, .. Default::default()} )
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// a portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub(crate) src: Rect,
    /// the position to draw the graphic expressed as a `Point2`.
    pub(crate) dest: Point2,
    /// orientation of the graphic in radians.
    pub(crate) rotation: f32,
    /// x/y scale factors expressed as a `Vector2`.
    pub(crate) scale: Vector2,
    /// specifies an offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub(crate) offset: Point2,
    /// A color to draw the target with.
    /// Default: white.
    pub(crate) color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: Point2::origin(),
            rotation: 0.0,
            scale: Vector2::new(1.0, 1.0),
            offset: Point2::new(0.0, 0.0),
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = Point2::from(p);
        self
    }

    /// TODO
    pub fn color<C>(mut self, color: C) -> Self
    where
        C: Into<Color>,
    {
        self.color = color.into();
        self
    }

    /// TODO
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// TODO
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = Vector2::from(p);
        self
    }

    /// TODO
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = Point2::from(p);
        self
    }

    // TODO: Easy mirror functions for X and Y axis might be nice.
}

/// Create a DrawTransform from a location
impl<P> From<(P,)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0).into()
    }
}

/// Create a DrawTransform from a location and color
impl<P, C> From<(P, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, color): (P, C)) -> Self {
        DrawParam::new().dest(location).color(color).into()
    }
}

/// Create a DrawTransform from a location, rotation and color
impl<P, C> From<(P, f32, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, color): (P, f32, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
            .into()
    }
}

/// Create a DrawTransform from a location, rotation, offset and color
impl<P, C> From<(P, f32, P, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, offset, color): (P, f32, P, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
            .into()
    }
}

/// Create a DrawTransform from a location, rotation, offset, scale and color
impl<P, V, C> From<(P, f32, P, V, C)> for DrawTransform
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
    C: Into<Color>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, C)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
            .into()
    }
}

/// A `DrawParam` that has been crunched down to a single matrix.
/// Useful for doing matrix-based coordinate transformations, I hope.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: na::one(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        let translate = Matrix4::new_translation(&Vec3::new(param.dest.x, param.dest.y, 0.0));
        let offset = Matrix4::new_translation(&Vec3::new(param.offset.x, param.offset.y, 0.0));
        let offset_inverse =
            Matrix4::new_translation(&Vec3::new(-param.offset.x, -param.offset.y, 0.0));
        let axis_angle = Vec3::z() * param.rotation;
        let rotation = Matrix4::new_rotation(axis_angle);
        let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(param.scale.x, param.scale.y, 1.0));
        let transform = translate * offset * rotation * scale * offset_inverse;
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform,
        }
    }
}

impl DrawTransform {
    /// Returns a new `PrimitiveDrawParam` with its matrix multiplied
    /// by the given one.
    ///
    /// TODO: Make some way to implement `matrix * self.matrix`, or just implement `Mul`...
    pub fn mul(self, matrix: Matrix4) -> Self {
        DrawTransform {
            matrix: self.matrix * matrix,
            ..self
        }
    }

    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        let mat: [[f32; 4]; 4] = self.matrix.into();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate iron;
extern crate router;
extern crate bodyparser;
extern crate backlogrs;
extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

use backlogrs::*;
use backlogrs::models::*;
use iron::prelude::*;
use iron::{status};
use router::Router;

fn main() {
    let mut router = Router::new();
    router.get("/user", get_users);
    // Users aren't allowed to update; as soon as a user
    // is created it is stuck that way. At least for now.
    router.post("/user", post_login);
    router.get("/user/:id", get_user_by_id);
    router.get("/user/:id/library", get_library);
    router.get("/user/:uid/library/:eid", get_entry);
    router.post("/user/:id/library", post_entry);
    router.get("/game", get_games);
    router.get("/game/:id", get_game_by_id);
    router.get("/status", get_status);

    let mut chain = Chain::new(router);
    chain.link_before(Api);
    chain.link_before(DbConnection::new());
    // Prints the error in html body
    chain.link_after(DebugIronError);

    println!("Listening on port 3000...");
    Iron::new(chain).http("0.0.0.0:3000").unwrap();
}

fn post_entry(req: &mut Request) -> IronResult<Response> {
    let mut new_entry = try!(req.get::<bodyparser::Struct<Entry>>()
                             .on_err("bad request")).unwrap();
    let e = status::InternalServerError;
    let user_id = try!(req.get_from_router::<i32>("id").on_err(e));

    let db = req.db();
    if let Some(entry_id) = new_entry.id {
        // The entry should be updated
        let stmt = try!(db.prepare(
                "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
                JOIN Entry e ON e.id = li.entry_id WHERE e.id = $1 AND lo.id = $2")
            .on_err(e));
        let prev_entry = try!(stmt.query(&[&entry_id, &user_id]).on_err(e))
            .collect_sql::<Vec<Entry>>()[0].clone();

        if new_entry.status.is_none() {
            new_entry.status = prev_entry.status;
        }
        if new_entry.time_played.is_none() {
            new_entry.time_played = prev_entry.time_played;
        }

        try!(db.execute(
                "UPDATE Entry e SET status = $3, time_played = $4 WHERE e.id = $1 AND EXISTS \
                (SELECT * FROM Library li WHERE li.entry_id = $1 AND li.login_id = $2)",
                &[&entry_id, &user_id, &new_entry.status.unwrap(), &new_entry.time_played])
            .on_err(
                "failed, probably because name/email already exists"));
    } else {
        if new_entry.game_id.is_none() {
            return Err(LibError::Cause(
                    "Both game and entry ID can't be null!".to_string())).on_err(e);
        }
        if new_entry.status.is_none() {
            new_entry.status = Some(Status::PlanToPlay);
        }
        if new_entry.time_played.is_none() {
            new_entry.time_played = Some(0.0);
        }

        // Insert new entry
        // Create transaction and commit if everything went as expected
        let trans = try!(db.transaction().on_err(e));
        // First create entry and then map that into a library
        let stmt = try!(trans.prepare(
                "INSERT INTO Entry (game_id, time_played, status) \
                VALUES ($1, $2, $3) RETURNING *")
            .on_err(e));
        let entry_opt = try!(stmt.query(
                &[&new_entry.game_id, &new_entry.time_played, &new_entry.status.unwrap()])
            .on_err(e)).collect_sql::<Vec<Entry>>().pop();
        new_entry = try!(entry_opt.ok_or(
                LibError::Cause("Failed inserting new entry".to_string())).on_err(e));

        // Create library entry
        try!(trans.execute(
                "INSERT INTO Library (entry_id, login_id) VALUES ($1, $2)",
                &[&new_entry.id.unwrap(), &user_id])
            .on_err(e));

        try!(trans.commit().on_err(e));
    }

    Ok(Response::with((status::Ok, Json(new_entry))))
}

fn post_login(req: &mut Request) -> IronResult<Response> {
    let e = status::InternalServerError;
    let login = try!(req.get::<bodyparser::Struct<Login>>()
                     .on_err("bad request")).unwrap();

    let db = req.db();
    let stmt = try!(db.prepare(
            "INSERT INTO Login (username, password, email) \
            VALUES ($1, $2, $3) RETURNING (id, username, email)").on_err(e));
    let user = try!(stmt.query(
            &[&login.username, &login.password, &login.email]).on_err(e))
        .collect_sql::<Vec<User>>().pop();

    Ok(Response::with((status::Ok, Json(user))))
}

fn get_status(req: &mut Request) -> IronResult<Response> {
    let e = status::InternalServerError;

    let db = req.db();
    let stmt = try!(db.prepare("SELECT unnest(enum_range(NULL::Status))").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).map(|x| {
        x.get(0)
    }).collect::<Vec<Status>>();

    Ok(Response::with((status::Ok, Json(res))))
}

fn get_game_by_id(req: &mut Request) -> IronResult<Response> {
    let e = status::NoContent;
    let id = try!(req.get_from_router::<i32>("id").on_err(e));

    let db = req.db();
    let stmt = try!(db.prepare("SELECT * FROM Game WHERE id = $1").on_err(e));
    let mut res = try!(stmt.query(&[&id]).on_err(e)).collect_sql::<Vec<Game>>();

    if res.is_empty() {
        Ok(Response::with(e))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_games(req: &mut Request) -> IronResult<Response> {
    let db = req.db();
    let e = ("Database error!", status::InternalServerError);

    let stmt = try!(db.prepare("SELECT * FROM Game ORDER BY name").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).collect_sql::<Vec<Game>>();

    Ok(Response::with((status::Ok, Json(res))))
}

fn get_entry(req: &mut Request) -> IronResult<Response> {
    let e = status::NoContent;
    let user_id = try!(req.get_from_router::<i32>("uid").on_err(e));
    let entry_id = try!(req.get_from_router::<i32>("eid").on_err(e));

    let db = req.db();
    let stmt = try!(db.prepare(
            "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
            JOIN Entry e ON e.id = li.entry_id WHERE e.id = $1 AND lo.id = $2").on_err(e));
    let mut res = try!(stmt.query(&[&entry_id, &user_id]).on_err(("Oops", e)))
        .collect_sql::<Vec<Entry>>();

    if res.is_empty() {
        Ok(Response::with(e))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_library(req: &mut Request) -> IronResult<Response> {
    let e = status::InternalServerError;
    let user_id = try!(req.get_from_router::<i32>("id").on_err(e));

    let db = req.db();
    let stmt = try!(db.prepare(
            "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
            JOIN Entry e ON e.id = li.entry_id WHERE lo.id = $1").on_err(e));
    let res = try!(stmt.query(&[&user_id]).on_err(e))
        .collect_sql::<Vec<Entry>>();

    Ok(Response::with((status::Ok, Json(res))))
}

fn get_user_by_id(req: &mut Request) -> IronResult<Response> {
    let e = status::NoContent;
    let id = try!(req.get_from_router::<i32>("id").on_err(e));

    let db = req.db();
    let stmt = try!(db.prepare("SELECT * FROM Login WHERE id = $1").on_err(e));
    let mut res = try!(stmt.query(&[&id]).on_err(e)).collect_sql::<Vec<User>>();

    if res.is_empty() {
        Ok(Response::with(e))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_users(req: &mut Request) -> IronResult<Response> {
    let db = req.db();
    let e = status::InternalServerError;

    let stmt = try!(db.prepare("SELECT * FROM Login").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).collect_sql::<Vec<User>>();

    Ok(Response::with((status::Ok, Json(res))))
}
<commit_msg>(fix) http status responses now 100% more restful! E.g. wrong url path returns a 400 Bad Request. This closes #10.<commit_after>#![feature(core)]
extern crate iron;
extern crate router;
extern crate bodyparser;
extern crate backlogrs;
extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

use backlogrs::*;
use backlogrs::models::*;
use iron::prelude::*;
use iron::{status};
use router::Router;

fn main() {
    let mut router = Router::new();
    router.get("/user", get_users);
    // Users aren't allowed to update; as soon as a user
    // is created it is stuck that way. At least for now.
    router.post("/user", post_login);
    router.get("/user/:id", get_user_by_id);
    router.get("/user/:id/library", get_library);
    router.get("/user/:uid/library/:eid", get_entry);
    router.post("/user/:id/library", post_entry);
    router.get("/game", get_games);
    router.get("/game/:id", get_game_by_id);
    router.get("/status", get_status);

    let mut chain = Chain::new(router);
    chain.link_before(Api);
    chain.link_before(DbConnection::new());
    // Prints the error in html body
    chain.link_after(DebugIronError);

    println!("Listening on port 3000...");
    Iron::new(chain).http("0.0.0.0:3000").unwrap();
}

fn post_entry(req: &mut Request) -> IronResult<Response> {
    let e = status::BadRequest;
    let mut new_entry = try!(req.get::<bodyparser::Struct<Entry>>()
                             .on_err(e)).unwrap();
    let user_id = try!(req.get_from_router::<i32>("id").on_err(e));

    let e = status::InternalServerError;
    let db = req.db();
    if let Some(entry_id) = new_entry.id {
        // The entry should be updated
        let stmt = try!(db.prepare(
                "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
                JOIN Entry e ON e.id = li.entry_id WHERE e.id = $1 AND lo.id = $2")
            .on_err(e));
        let prev_entry = try!(stmt.query(&[&entry_id, &user_id]).on_err(e))
            .collect_sql::<Vec<Entry>>()[0].clone();

        if new_entry.status.is_none() {
            new_entry.status = prev_entry.status;
        }
        if new_entry.time_played.is_none() {
            new_entry.time_played = prev_entry.time_played;
        }

        try!(db.execute(
                "UPDATE Entry e SET status = $3, time_played = $4 WHERE e.id = $1 AND EXISTS \
                (SELECT * FROM Library li WHERE li.entry_id = $1 AND li.login_id = $2)",
                &[&entry_id, &user_id, &new_entry.status.unwrap(), &new_entry.time_played])
            .on_err(
                "failed, probably because name/email already exists"));
    } else {
        if new_entry.game_id.is_none() {
            return Err(LibError::Cause(
                    "Both game and entry ID can't be null!".to_string())).on_err(e);
        }
        if new_entry.status.is_none() {
            new_entry.status = Some(Status::PlanToPlay);
        }
        if new_entry.time_played.is_none() {
            new_entry.time_played = Some(0.0);
        }

        // Insert new entry
        // Create transaction and commit if everything went as expected
        let trans = try!(db.transaction().on_err(e));
        // First create entry and then map that into a library
        let stmt = try!(trans.prepare(
                "INSERT INTO Entry (game_id, time_played, status) \
                VALUES ($1, $2, $3) RETURNING *")
            .on_err(e));
        let entry_opt = try!(stmt.query(
                &[&new_entry.game_id, &new_entry.time_played, &new_entry.status.unwrap()])
            .on_err(e)).collect_sql::<Vec<Entry>>().pop();
        new_entry = try!(entry_opt.ok_or(
                LibError::Cause("Failed inserting new entry".to_string())).on_err(e));

        // Create library entry
        try!(trans.execute(
                "INSERT INTO Library (entry_id, login_id) VALUES ($1, $2)",
                &[&new_entry.id.unwrap(), &user_id])
            .on_err(e));

        try!(trans.commit().on_err(e));
    }

    Ok(Response::with((status::Ok, Json(new_entry))))
}

fn post_login(req: &mut Request) -> IronResult<Response> {
    let login = try!(req.get::<bodyparser::Struct<Login>>()
                     .on_err(status::BadRequest)).unwrap();

    let e = status::InternalServerError;
    let db = req.db();
    let stmt = try!(db.prepare(
            "INSERT INTO Login (username, password, email) \
            VALUES ($1, $2, $3) RETURNING (id, username, email)").on_err(e));
    let user = try!(stmt.query(
            &[&login.username, &login.password, &login.email]).on_err(e))
        .collect_sql::<Vec<User>>().pop();

    Ok(Response::with((status::Ok, Json(user))))
}

fn get_status(req: &mut Request) -> IronResult<Response> {
    let e = status::InternalServerError;

    let db = req.db();
    let stmt = try!(db.prepare("SELECT unnest(enum_range(NULL::Status))").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).map(|x| {
        x.get(0)
    }).collect::<Vec<Status>>();

    Ok(Response::with((status::Ok, Json(res))))
}

fn get_game_by_id(req: &mut Request) -> IronResult<Response> {
    let id = try!(req.get_from_router::<i32>("id")
                  .on_err(status::BadRequest));

    let e = status::InternalServerError;
    let db = req.db();
    let stmt = try!(db.prepare("SELECT * FROM Game WHERE id = $1").on_err(e));
    let mut res = try!(stmt.query(&[&id]).on_err(e)).collect_sql::<Vec<Game>>();

    if res.is_empty() {
        Ok(Response::with(status::NoContent))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_games(req: &mut Request) -> IronResult<Response> {
    let db = req.db();
    let e = status::InternalServerError;

    let stmt = try!(db.prepare("SELECT * FROM Game ORDER BY name").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).collect_sql::<Vec<Game>>();

    Ok(Response::with((status::Ok, Json(res))))
}

fn get_entry(req: &mut Request) -> IronResult<Response> {
    let e = status::BadRequest;
    let user_id = try!(req.get_from_router::<i32>("uid").on_err(e));
    let entry_id = try!(req.get_from_router::<i32>("eid").on_err(e));

    let e = status::InternalServerError;
    let db = req.db();
    let stmt = try!(db.prepare(
            "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
            JOIN Entry e ON e.id = li.entry_id WHERE e.id = $1 AND lo.id = $2").on_err(e));
    let mut res = try!(stmt.query(&[&entry_id, &user_id]).on_err(e))
        .collect_sql::<Vec<Entry>>();

    if res.is_empty() {
        Ok(Response::with(status::NoContent))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_library(req: &mut Request) -> IronResult<Response> {
    let e = status::InternalServerError;
    let user_id = try!(req.get_from_router::<i32>("id")
                       .on_err(status::BadRequest));

    let db = req.db();
    let stmt = try!(db.prepare(
            "SELECT e.* FROM Login lo JOIN Library li ON lo.id = li.login_id \
            JOIN Entry e ON e.id = li.entry_id WHERE lo.id = $1").on_err(e));
    let res = try!(stmt.query(&[&user_id]).on_err(e))
        .collect_sql::<Vec<Entry>>();

    if res.is_empty() {
        Ok(Response::with(status::NoContent))
    } else {
        Ok(Response::with((status::Ok, Json(res))))
    }
}

fn get_user_by_id(req: &mut Request) -> IronResult<Response> {
    let id = try!(req.get_from_router::<i32>("id")
                  .on_err(status::BadRequest));

    let e = status::NoContent;
    let db = req.db();
    let stmt = try!(db.prepare("SELECT * FROM Login WHERE id = $1").on_err(e));
    let mut res = try!(stmt.query(&[&id]).on_err(e)).collect_sql::<Vec<User>>();

    if res.is_empty() {
        Ok(Response::with(e))
    } else {
        Ok(Response::with((status::Ok, Json(res.pop()))))
    }
}

fn get_users(req: &mut Request) -> IronResult<Response> {
    let db = req.db();
    let e = status::InternalServerError;

    let stmt = try!(db.prepare("SELECT * FROM Login").on_err(e));
    let res = try!(stmt.query(&[]).on_err(e)).collect_sql::<Vec<User>>();

    Ok(Response::with((status::Ok, Json(res))))
}
<|endoftext|>


<commit_before>//! Create graphene and other substrates for use in molecular dynamics simulations.

extern crate colored;
extern crate dialoguer;
extern crate serde;
extern crate serde_json;
extern crate structopt;
#[macro_use] extern crate structopt_derive;

extern crate grafen;
extern crate mdio;

mod error;
mod output;
mod ui;

use error::{GrafenCliError, Result};
use ui::read_configuration;

use grafen::database::{read_database, ComponentEntry, DataBase};
use grafen::read_conf::ReadConf;

use colored::*;
use std::env::{current_dir, home_dir, var_os};
use std::fs::DirBuilder;
use std::process;
use std::path::PathBuf;
use structopt::StructOpt;

/// The program run configuration.
pub struct Config {
    /// Title of output system.
    pub title: String,
    /// Path to output file.
    pub output_path: PathBuf,
    /// Input components that were read from the command line.
    pub components: Vec<ComponentEntry>,
    /// Database of residue and substrate definitions.
    pub database: DataBase,
}

impl Config {
    /// Parse the input command line arguments and read the `DataBase`.
    ///
    /// # Errors
    /// Returns an error if the `DataBase` (if given as an input) could not be read.
    fn new() -> Result<Config> {
        eprintln!("{} {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));

        let options = CliOptions::from_args();

        let output_path = options.output;
        let title = options.title.unwrap_or("System created by grafen".into());

        let mut database = match options.database {
            Some(path) => read_database(&path).map_err(|err| GrafenCliError::from(err)),
            None => read_or_create_default_database(),
        }?;

        let (components, mut entries) = read_input_configurations(options.input_confs);
        database.component_defs.append(&mut entries);

        Ok(Config { title, output_path, components, database })
    }
}

#[derive(StructOpt, Debug)]
#[structopt(raw(setting = "structopt::clap::AppSettings::ColoredHelp"))]
/// Command line options
struct CliOptions {
    #[structopt(short = "t", long = "title")]
    /// Title of output system
    title: Option<String>,
    #[structopt(short = "o", long = "output", default_value = "conf.gro", parse(from_os_str))]
    /// Output configuration file
    output: PathBuf,
    #[structopt(short = "d", long = "database", parse(from_os_str))]
    /// Path to residue and component database
    database: Option<PathBuf>,
    #[structopt(short = "c", long = "conf", parse(from_os_str))]
    /// Path to input configuration files to add as components
    input_confs: Vec<PathBuf>,
}

fn main() {
    if let Err(err) = Config::new().and_then(|conf| ui::user_menu(conf)) {
        eprintln!("{}", err);
        process::exit(1);
    }
}

fn read_or_create_default_database() -> Result<DataBase> {
    match get_default_database() {
        Some(default_path) => {
            if default_path.is_file() {
                read_database(&default_path).map_err(|err| GrafenCliError::from(err))
            } else {
                let mut default_database = DataBase::new();

                if let Some(parent_dir) = default_path.parent() {
                    match DirBuilder::new().recursive(true).create(&parent_dir) {
                        Ok(_) => default_database.set_path(&default_path).unwrap(),
                        Err(err) => {
                            eprintln!("{}", format!(
                                "Warning: Could not create a folder for the \
                                default database at '{}' ({}). \
                                Opening a directory-local database.",
                                default_path.display(), err
                            ).color("yellow"));
                        },
                    }
                }

                Ok(default_database)
            }
        },
        None => {
            eprintln!("{}", format!(
                "Could not find a location for the default database. \
                Opening a directory-local database."
            ).color("yellow"));

            Ok(DataBase::new())
        },
    }
}

fn read_input_configurations(confs: Vec<PathBuf>) -> (Vec<ComponentEntry>, Vec<ComponentEntry>) {
    let mut configurations = Vec::new();

    for path in confs {
        match read_configuration(&path) {
            Ok(conf) => configurations.push(conf),
            Err(err) => eprintln!("{}", err),
        }
    }

    eprint!("\n");

    let current_dir = current_dir().unwrap_or(PathBuf::new());
    let entries = configurations
        .iter()
        .map(|conf| ReadConf {
            conf: None,
            path: current_dir.join(&conf.path),
            backup_conf: None,
            description: conf.description.clone(),
            volume_type: conf.volume_type.clone(),
        })
        .map(|conf| ComponentEntry::ConfigurationFile(conf))
        .collect::<Vec<_>>();

    let components = configurations
        .into_iter()
        .map(|conf| ComponentEntry::ConfigurationFile(conf))
        .collect::<Vec<_>>();

    (components, entries)
}

fn get_default_database() -> Option<PathBuf> {
    const DEFAULT_DBNAME: &str = "database.json";
    get_platform_dependent_data_dir().map(|dir| dir.join(DEFAULT_DBNAME))
}

fn get_platform_dependent_data_dir() -> Option<PathBuf> {
    if cfg!(target_os = "linux") {
        var_os("XDG_DATA_HOME").map(|dir| PathBuf::from(dir))
            .or(home_dir().map(|dir| dir.join(".local").join("share")))
    } else if cfg!(target_os = "macos") {
        home_dir().map(|dir| dir.join("Library").join("Application Support"))
    } else if cfg!(target_os = "windows") {
        var_os("APPDATA").map(|dir| PathBuf::from(dir))
    } else {
        None
    }.map(|dir| dir.join("grafen"))
}
<commit_msg>Default database now follows XDG specifications on macos and linux<commit_after>//! Create graphene and other substrates for use in molecular dynamics simulations.

extern crate colored;
extern crate dialoguer;
extern crate serde;
extern crate serde_json;
extern crate structopt;
#[macro_use] extern crate structopt_derive;

extern crate grafen;
extern crate mdio;

mod error;
mod output;
mod ui;

use error::{GrafenCliError, Result};
use ui::read_configuration;

use grafen::database::{read_database, ComponentEntry, DataBase};
use grafen::read_conf::ReadConf;

use colored::*;
use std::env::{current_dir, home_dir, var, var_os};
use std::fs::DirBuilder;
use std::process;
use std::path::PathBuf;
use structopt::StructOpt;

const DEFAULT_DBNAME: &str = "database.json";

/// The program run configuration.
pub struct Config {
    /// Title of output system.
    pub title: String,
    /// Path to output file.
    pub output_path: PathBuf,
    /// Input components that were read from the command line.
    pub components: Vec<ComponentEntry>,
    /// Database of residue and substrate definitions.
    pub database: DataBase,
}

impl Config {
    /// Parse the input command line arguments and read the `DataBase`.
    ///
    /// # Errors
    /// Returns an error if the `DataBase` (if given as an input) could not be read.
    fn new() -> Result<Config> {
        eprintln!("{} {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));

        let options = CliOptions::from_args();

        let output_path = options.output;
        let title = options.title.unwrap_or("System created by grafen".into());

        let mut database = match options.database {
            Some(path) => read_database(&path).map_err(|err| GrafenCliError::from(err)),
            None => read_or_create_default_database(),
        }?;

        let (components, mut entries) = read_input_configurations(options.input_confs);
        database.component_defs.append(&mut entries);

        Ok(Config { title, output_path, components, database })
    }
}

#[derive(StructOpt, Debug)]
#[structopt(raw(setting = "structopt::clap::AppSettings::ColoredHelp"))]
/// Command line options
struct CliOptions {
    #[structopt(short = "t", long = "title")]
    /// Title of output system
    title: Option<String>,
    #[structopt(short = "o", long = "output", default_value = "conf.gro", parse(from_os_str))]
    /// Output configuration file
    output: PathBuf,
    #[structopt(short = "d", long = "database", parse(from_os_str))]
    /// Path to residue and component database
    database: Option<PathBuf>,
    #[structopt(short = "c", long = "conf", parse(from_os_str))]
    /// Path to input configuration files to add as components
    input_confs: Vec<PathBuf>,
}

fn main() {
    if let Err(err) = Config::new().and_then(|conf| ui::user_menu(conf)) {
        eprintln!("{}", err);
        process::exit(1);
    }
}

fn read_input_configurations(confs: Vec<PathBuf>) -> (Vec<ComponentEntry>, Vec<ComponentEntry>) {
    let mut configurations = Vec::new();

    for path in confs {
        match read_configuration(&path) {
            Ok(conf) => configurations.push(conf),
            Err(err) => eprintln!("{}", err),
        }
    }

    eprint!("\n");

    let current_dir = current_dir().unwrap_or(PathBuf::new());
    let entries = configurations
        .iter()
        .map(|conf| ReadConf {
            conf: None,
            path: current_dir.join(&conf.path),
            backup_conf: None,
            description: conf.description.clone(),
            volume_type: conf.volume_type.clone(),
        })
        .map(|conf| ComponentEntry::ConfigurationFile(conf))
        .collect::<Vec<_>>();

    let components = configurations
        .into_iter()
        .map(|conf| ComponentEntry::ConfigurationFile(conf))
        .collect::<Vec<_>>();

    (components, entries)
}

fn read_or_create_default_database() -> Result<DataBase> {
    let default_database_paths = get_default_database_paths();

    if default_database_paths.is_empty() {
        eprintln!("{}", format!(
            "Could not find a location for the default database. \
            Opening a database which cannot be saved.",
        ).color("yellow"));

        return Ok(DataBase::new());
    }

    // See if a default database can be found at any path before creating a new one.
    for path in &default_database_paths {
        if path.is_file() {
            return read_database(&path).map_err(|err| GrafenCliError::from(err))
        }
    }

    let mut default_database = DataBase::new();
    let default_path = &default_database_paths[0];

    if let Some(parent_dir) = default_path.parent() {
        match DirBuilder::new().recursive(true).create(&parent_dir) {
            Ok(_) => default_database.set_path(&default_path).unwrap(),
            Err(err) => {
                eprintln!("{}", format!(
                    "Warning: Could not create a folder for a default database at '{}' ({}). \
                    Opening a database which cannot be saved.",
                    default_path.display(), err
                ).color("yellow"));
            },
        }
    }

    Ok(default_database)
}

fn get_default_database_paths() -> Vec<PathBuf> {
    get_platform_dependent_data_dirs()
        .into_iter()
        .map(|dir| dir.join("grafen").join(DEFAULT_DBNAME))
        .collect()
}

fn get_platform_dependent_data_dirs() -> Vec<PathBuf> {
    let xdg_data_dirs_variable = var("XDG_DATA_DIRS")
        .unwrap_or(String::from("/usr/local/share:/usr/local"));
    let xdg_dirs_iter = xdg_data_dirs_variable.split(':').map(|s| Some(PathBuf::from(s)));

    let dirs = if cfg!(target_os = "macos") {
        vec![
            var_os("XDG_DATA_HOME").map(|dir| PathBuf::from(dir)),
            home_dir().map(|dir| dir.join("Library").join("Application Support"))
        ].into_iter()
         .chain(xdg_dirs_iter)
         .chain(vec![Some(PathBuf::from("/").join("Library").join("Application Support"))])
         .collect()
    } else if cfg!(target_os = "linux") {
        vec![
            var_os("XDG_DATA_HOME").map(|dir| PathBuf::from(dir)),
            home_dir().map(|dir| dir.join(".local").join("share"))
        ].into_iter()
         .chain(xdg_dirs_iter)
         .collect()
    } else if cfg!(target_os = "windows") {
        vec![var_os("APPDATA").map(|dir| PathBuf::from(dir))]
    } else {
        Vec::new()
    };

    dirs.into_iter().filter_map(|dir| dir).collect()
}

#[cfg(test)]
pub mod tests {
    use super::*;
    use std::env::set_var;
    use std::path::Component;

    #[test]
    #[cfg(target_os = "macos")]
    fn default_database_dirs_on_macos_lead_with_xdg_dirs_then_application_support() {
        let xdg_data_home = "data_home";
        set_var("XDG_DATA_HOME", xdg_data_home);

        let xdg_data_directories = vec!["data_dir1", "data_dir2"];
        let xdg_data_dirs = format!("{}:{}", xdg_data_directories[0], xdg_data_directories[1]);
        set_var("XDG_DATA_DIRS", xdg_data_dirs);

        let user_appsupport = home_dir().unwrap().join("Library").join("Application Support");
        let root_appsupport = PathBuf::from("/").join("Library").join("Application Support");

        let result = get_platform_dependent_data_dirs();
        let priority_list = vec![
            PathBuf::from(xdg_data_home),
            user_appsupport,
            PathBuf::from(xdg_data_directories[0]),
            PathBuf::from(xdg_data_directories[1]),
            root_appsupport
        ];

        assert_eq!(result, priority_list);
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn default_database_dirs_on_linux_lead_with_xdg_dirs_then_local_share() {
        let xdg_data_home = "data_home";
        set_var("XDG_DATA_HOME", xdg_data_home);

        let xdg_data_directories = vec!["data_dir1", "data_dir2"];
        let xdg_data_dirs = format!("{}:{}", xdg_data_directories[0], xdg_data_directories[1]);
        set_var("XDG_DATA_DIRS", xdg_data_dirs);

        let user_local_share = home_dir().unwrap().join(".local").join("share");
        let root_local_share = PathBuf::from("/").join("usr").join("local").join("share");
        let root_share = PathBuf::from("/").join("usr").join("share");

        let result = get_platform_dependent_data_dirs();
        let priority_list = vec![
            PathBuf::from(xdg_data_home),
            user_local_share,
            PathBuf::from(xdg_data_directories[0]),
            PathBuf::from(xdg_data_directories[1]),
            root_local_share,
            root_share
        ];

        assert_eq!(result, priority_list);
    }

    #[test]
    #[cfg(any(unix, windows))]
    fn default_database_path_adds_grafen_directory_and_database_path() {
        let dirs = get_default_database_paths();
        assert!(!dirs.is_empty());

        for path in dirs {
            let mut iter = path.components().rev();
            assert_eq!(iter.next().unwrap(), Component::Normal(DEFAULT_DBNAME.as_ref()));
            assert_eq!(iter.next().unwrap(), Component::Normal("grafen".as_ref()));
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate maplit;
extern crate correlation;

use correlation::{config, conditions, Correlator, Message};
use correlation::action::message;
use correlation::action::ActionHandlers;
use std::thread;

struct Printer;

impl message::ActionHandler for Printer {
    fn handle(&mut self, _: message::ExecResult) {
        println!("I'm the message handler");
    }
}

#[allow(dead_code)]
fn main() {
    let patterns = vec!["1".to_string(), "2".to_string(), "3".to_string()];
    let condition = conditions::Builder::new(100).patterns(patterns)
                                                .first_opens(true)
                                                .last_closes(true)
                                                .build();
    let actions = vec![ message::Action::new().into() ];
    let contexts = vec!{
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
    };
    let handlers = ActionHandlers::new(Box::new(Printer));
    let mut correlator = Correlator::new(contexts, handlers);
    let _ = correlator.push_message(Message::new("1".to_string()));
    thread::sleep_ms(20);
    let _ = correlator.push_message(Message::new("2".to_string()));
    thread::sleep_ms(80);
    let _ = correlator.push_message(Message::new("3".to_string()));
    let _ = correlator.stop();
}
<commit_msg>test: add some sleep()<commit_after>#[macro_use]
extern crate maplit;
extern crate correlation;

use correlation::{config, conditions, Correlator, Message};
use correlation::action::message;
use correlation::action::ActionHandlers;
use std::thread;

struct Printer;

impl message::ActionHandler for Printer {
    fn handle(&mut self, _: message::ExecResult) {
        println!("I'm the message handler");
    }
}

#[allow(dead_code)]
fn main() {
    let patterns = vec!["1".to_string(), "2".to_string(), "3".to_string()];
    let condition = conditions::Builder::new(100).patterns(patterns)
                                                .first_opens(true)
                                                .last_closes(true)
                                                .build();
    let actions = vec![ message::Action::new().into() ];
    let contexts = vec!{
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
        config::ContextBuilder::new(condition.clone()).actions(actions.clone()).build(),
    };
    let handlers = ActionHandlers::new(Box::new(Printer));
    let mut correlator = Correlator::new(contexts, handlers);
    let _ = correlator.push_message(Message::new("1".to_string()));
    thread::sleep_ms(20);
    let _ = correlator.push_message(Message::new("2".to_string()));
    thread::sleep_ms(80);
    let _ = correlator.push_message(Message::new("3".to_string()));
    thread::sleep_ms(50);
    let _ = correlator.stop();
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc_front::hir::*;
use rustc_front::intravisit::*;
use syntax::ast::LitKind;
use utils::{span_lint_and_then, in_macro, snippet_opt};

/// **What it does:** This lint checks for boolean expressions that can be written more concisely
///
/// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication
///
/// **Known problems:** None
///
/// **Example:** `if a && b || a` should be `if a`
declare_lint! {
    pub NONMINIMAL_BOOL, Warn,
    "checks for boolean expressions that can be written more concisely"
}

#[derive(Copy,Clone)]
pub struct NonminimalBool;

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

impl LateLintPass for NonminimalBool {
    fn check_crate(&mut self, cx: &LateContext, krate: &Crate) {
        krate.visit_all_items(&mut NonminimalBoolVisitor(cx))
    }
}

struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);

use quine_mc_cluskey::Bool;
struct Hir2Qmm<'tcx>(Vec<&'tcx Expr>);

impl<'tcx> Hir2Qmm<'tcx> {
    fn extract(&mut self, op: BinOp_, a: &[&'tcx Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
        for a in a {
            if let ExprBinary(binop, ref lhs, ref rhs) = a.node {
                if binop.node == op {
                    v = self.extract(op, &[lhs, rhs], v)?;
                    continue;
                }
            }
            v.push(self.run(a)?);
        }
        Ok(v)
    }

    fn run(&mut self, e: &'tcx Expr) -> Result<Bool, String> {
        match e.node {
            ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)),
            ExprBinary(binop, ref lhs, ref rhs) => {
                match binop.node {
                    BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)),
                    BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)),
                    _ => {},
                }
            },
            ExprLit(ref lit) => {
                match lit.node {
                    LitKind::Bool(true) => return Ok(Bool::True),
                    LitKind::Bool(false) => return Ok(Bool::False),
                    _ => {},
                }
            },
            _ => {},
        }
        let n = self.0.len();
        self.0.push(e);
        if n < 32 {
            #[allow(cast_possible_truncation)]
            Ok(Bool::Term(n as u8))
        } else {
            Err("too many literals".to_owned())
        }
    }
}

fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
    fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String {
        use quine_mc_cluskey::Bool::*;
        match *suggestion {
            True => {
                s.extend("true".chars());
                s
            },
            False => {
                s.extend("false".chars());
                s
            },
            Not(ref inner) => {
                s.push('!');
                recurse(true, cx, inner, terminals, s)
            },
            And(ref v) => {
                if brackets {
                    s.push('(');
                }
                s = recurse(true, cx, &v[0], terminals, s);
                for inner in &v[1..] {
                    s.extend(" && ".chars());
                    s = recurse(true, cx, inner, terminals, s);
                }
                if brackets {
                    s.push(')');
                }
                s
            },
            Or(ref v) => {
                if brackets {
                    s.push('(');
                }
                s = recurse(true, cx, &v[0], terminals, s);
                for inner in &v[1..] {
                    s.extend(" || ".chars());
                    s = recurse(true, cx, inner, terminals, s);
                }
                if brackets {
                    s.push(')');
                }
                s
            },
            Term(n) => {
                s.extend(snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros").chars());
                s
            }
        }
    }
    recurse(false, cx, suggestion, terminals, String::new())
}

fn simple_negate(b: Bool) -> Bool {
    use quine_mc_cluskey::Bool::*;
    match b {
        True => False,
        False => True,
        t @ Term(_) => Not(Box::new(t)),
        And(mut v) => {
            for el in &mut v {
                *el = simple_negate(::std::mem::replace(el, True));
            }
            Or(v)
        },
        Or(mut v) => {
            for el in &mut v {
                *el = simple_negate(::std::mem::replace(el, True));
            }
            And(v)
        },
        Not(inner) => *inner,
    }
}

impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
    fn bool_expr(&self, e: &Expr) {
        let mut h2q = Hir2Qmm(Vec::new());
        if let Ok(expr) = h2q.run(e) {
            let mut simplified = expr.simplify();
            for simple in Bool::Not(Box::new(expr.clone())).simplify() {
                let simple_negated = simple_negate(simple);
                if simplified.iter().any(|s| *s == simple_negated) {
                    continue;
                }
                simplified.push(simple_negated);
            }
            if !simplified.iter().any(|s| *s == expr) {
                span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| {
                    for suggestion in &simplified {
                        db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.0));
                    }
                });
            }
        }
    }
}

impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, e: &'v Expr) {
        if in_macro(self.0, e.span) { return }
        match e.node {
            ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e),
            ExprUnary(UnNot, ref inner) => {
                if self.0.tcx.node_types()[&inner.id].is_bool() {
                    self.bool_expr(e);
                } else {
                    walk_expr(self, e);
                }
            },
            _ => walk_expr(self, e),
        }
    }
}
<commit_msg>improve lint attribute detail<commit_after>use rustc::lint::*;
use rustc_front::hir::*;
use rustc_front::intravisit::*;
use syntax::ast::LitKind;
use utils::{span_lint_and_then, in_macro, snippet_opt};

/// **What it does:** This lint checks for boolean expressions that can be written more concisely
///
/// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication
///
/// **Known problems:** None
///
/// **Example:** `if a && b || a` should be `if a`
declare_lint! {
    pub NONMINIMAL_BOOL, Warn,
    "checks for boolean expressions that can be written more concisely"
}

#[derive(Copy,Clone)]
pub struct NonminimalBool;

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

impl LateLintPass for NonminimalBool {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        NonminimalBoolVisitor(cx).visit_item(item)
    }
}

struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);

use quine_mc_cluskey::Bool;
struct Hir2Qmm<'tcx>(Vec<&'tcx Expr>);

impl<'tcx> Hir2Qmm<'tcx> {
    fn extract(&mut self, op: BinOp_, a: &[&'tcx Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
        for a in a {
            if let ExprBinary(binop, ref lhs, ref rhs) = a.node {
                if binop.node == op {
                    v = self.extract(op, &[lhs, rhs], v)?;
                    continue;
                }
            }
            v.push(self.run(a)?);
        }
        Ok(v)
    }

    fn run(&mut self, e: &'tcx Expr) -> Result<Bool, String> {
        match e.node {
            ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)),
            ExprBinary(binop, ref lhs, ref rhs) => {
                match binop.node {
                    BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)),
                    BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)),
                    _ => {},
                }
            },
            ExprLit(ref lit) => {
                match lit.node {
                    LitKind::Bool(true) => return Ok(Bool::True),
                    LitKind::Bool(false) => return Ok(Bool::False),
                    _ => {},
                }
            },
            _ => {},
        }
        let n = self.0.len();
        self.0.push(e);
        if n < 32 {
            #[allow(cast_possible_truncation)]
            Ok(Bool::Term(n as u8))
        } else {
            Err("too many literals".to_owned())
        }
    }
}

fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
    fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String {
        use quine_mc_cluskey::Bool::*;
        match *suggestion {
            True => {
                s.extend("true".chars());
                s
            },
            False => {
                s.extend("false".chars());
                s
            },
            Not(ref inner) => {
                s.push('!');
                recurse(true, cx, inner, terminals, s)
            },
            And(ref v) => {
                if brackets {
                    s.push('(');
                }
                s = recurse(true, cx, &v[0], terminals, s);
                for inner in &v[1..] {
                    s.extend(" && ".chars());
                    s = recurse(true, cx, inner, terminals, s);
                }
                if brackets {
                    s.push(')');
                }
                s
            },
            Or(ref v) => {
                if brackets {
                    s.push('(');
                }
                s = recurse(true, cx, &v[0], terminals, s);
                for inner in &v[1..] {
                    s.extend(" || ".chars());
                    s = recurse(true, cx, inner, terminals, s);
                }
                if brackets {
                    s.push(')');
                }
                s
            },
            Term(n) => {
                s.extend(snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros").chars());
                s
            }
        }
    }
    recurse(false, cx, suggestion, terminals, String::new())
}

fn simple_negate(b: Bool) -> Bool {
    use quine_mc_cluskey::Bool::*;
    match b {
        True => False,
        False => True,
        t @ Term(_) => Not(Box::new(t)),
        And(mut v) => {
            for el in &mut v {
                *el = simple_negate(::std::mem::replace(el, True));
            }
            Or(v)
        },
        Or(mut v) => {
            for el in &mut v {
                *el = simple_negate(::std::mem::replace(el, True));
            }
            And(v)
        },
        Not(inner) => *inner,
    }
}

impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
    fn bool_expr(&self, e: &Expr) {
        let mut h2q = Hir2Qmm(Vec::new());
        if let Ok(expr) = h2q.run(e) {
            let mut simplified = expr.simplify();
            for simple in Bool::Not(Box::new(expr.clone())).simplify() {
                let simple_negated = simple_negate(simple);
                if simplified.iter().any(|s| *s == simple_negated) {
                    continue;
                }
                simplified.push(simple_negated);
            }
            if !simplified.iter().any(|s| *s == expr) {
                span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| {
                    for suggestion in &simplified {
                        db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.0));
                    }
                });
            }
        }
    }
}

impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, e: &'v Expr) {
        if in_macro(self.0, e.span) { return }
        match e.node {
            ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e),
            ExprUnary(UnNot, ref inner) => {
                if self.0.tcx.node_types()[&inner.id].is_bool() {
                    self.bool_expr(e);
                } else {
                    walk_expr(self, e);
                }
            },
            _ => walk_expr(self, e),
        }
    }
}
<|endoftext|>


<commit_before>//! CLI arguments and library Args struct
//!
//! Use `ArgsBuilder` preferentially as that will shield you from breaking changes resulting from
//! added fields and some field type changes.
//!
//! # Examples
//!
//! ```
//! # use watchexec::cli::ArgsBuilder;
//! ArgsBuilder::default()
//!     .cmd(vec!["echo hello world".into()])
//!     .paths(vec![".".into()])
//!     .build()
//!     .expect("mission failed");
//! ```

use crate::error;
use clap::{App, Arg, Error};
use std::{
    ffi::OsString,
    path::{PathBuf, MAIN_SEPARATOR},
    process::Command,
};

/// Arguments to the watcher
#[derive(Builder, Clone, Debug)]
#[builder(setter(into, strip_option))]
#[builder(build_fn(validate = "Self::validate"))]
pub struct Args {
    /// Command to execute in popen3 format (first program, rest arguments).
    pub cmd: Vec<String>,
    /// List of paths to watch for changes.
    pub paths: Vec<PathBuf>,
    /// Positive filters (trigger only on matching changes). Glob format.
    #[builder(default)]
    pub filters: Vec<String>,
    /// Negative filters (do not trigger on matching changes). Glob format.
    #[builder(default)]
    pub ignores: Vec<String>,
    /// Clear the screen before each run.
    #[builder(default)]
    pub clear_screen: bool,
    /// If Some, send that signal (e.g. SIGHUP) to the child on change.
    #[builder(default)]
    pub signal: Option<String>,
    /// If true, kill the child if it's still running when a change comes in.
    #[builder(default)]
    pub restart: bool,
    /// Interval to debounce the changes. (milliseconds)
    #[builder(default = "500")]
    pub debounce: u64,
    /// Enable debug/verbose logging.
    #[builder(default)]
    pub debug: bool,
    /// Run the commands right after starting.
    #[builder(default = "true")]
    pub run_initially: bool,
    /// Do not wrap the commands in a shell.
    #[builder(default)]
    pub no_shell: bool,
    /// Skip auto-loading .gitignore files
    #[builder(default)]
    pub no_vcs_ignore: bool,
    /// Skip auto-loading .ignore files
    #[builder(default)]
    pub no_ignore: bool,
    /// For testing only, always set to false.
    #[builder(setter(skip))]
    #[builder(default)]
    pub once: bool,
    /// Force using the polling backend.
    #[builder(default)]
    pub poll: bool,
    /// Interval for polling. (seconds)
    #[builder(default = "2")]
    pub poll_interval: u32,
}

impl ArgsBuilder {
    fn validate(&self) -> Result<(), String> {
        if self.cmd.as_ref().map_or(true, Vec::is_empty) {
            return Err("cmd must not be empty".into());
        }

        if self.paths.as_ref().map_or(true, Vec::is_empty) {
            return Err("paths must not be empty".into());
        }

        Ok(())
    }
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cmd")
        .arg("/c")
        .arg("tput reset || cls")
        .status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("tput").arg("reset").status();
}

pub fn get_args() -> error::Result<Args> {
    get_args_impl(None::<&[&str]>)
}

pub fn get_args_from<I, T>(from: I) -> error::Result<Args>
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    get_args_impl(Some(from))
}

fn get_args_impl<I, T>(from: Option<I>) -> error::Result<Args>
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    let app = App::new("watchexec")
        .version(crate_version!())
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("command")
                 .help("Command to execute")
                 .multiple(true)
                 .required(true))
        .arg(Arg::with_name("extensions")
                 .help("Comma-separated list of file extensions to watch (js,css,html)")
                 .short("e")
                 .long("exts")
                 .takes_value(true))
        .arg(Arg::with_name("path")
                 .help("Watch a specific directory")
                 .short("w")
                 .long("watch")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true))
        .arg(Arg::with_name("clear")
                 .help("Clear screen before executing command")
                 .short("c")
                 .long("clear"))
        .arg(Arg::with_name("restart")
                 .help("Restart the process if it's still running")
                 .short("r")
                 .long("restart"))
        .arg(Arg::with_name("signal")
                 .help("Send signal to process upon changes, e.g. SIGHUP")
                 .short("s")
                 .long("signal")
                 .takes_value(true)
                 .number_of_values(1)
                 .value_name("signal"))
        .arg(Arg::with_name("kill")
                 .help("Send SIGKILL to child processes (deprecated, use -s SIGKILL instead)")
                 .short("k")
                 .long("kill"))
        .arg(Arg::with_name("debounce")
                 .help("Set the timeout between detected change and command execution, defaults to 500ms")
                 .takes_value(true)
                 .value_name("milliseconds")
                 .short("d")
                 .long("debounce"))
        .arg(Arg::with_name("verbose")
                 .help("Print debugging messages to stderr")
                 .short("v")
                 .long("verbose"))
        .arg(Arg::with_name("filter")
                 .help("Ignore all modifications except those matching the pattern")
                 .short("f")
                 .long("filter")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("ignore")
                 .help("Ignore modifications to paths matching the pattern")
                 .short("i")
                 .long("ignore")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("no-vcs-ignore")
                 .help("Skip auto-loading of .gitignore files for filtering")
                 .long("no-vcs-ignore"))
        .arg(Arg::with_name("no-ignore")
                 .help("Skip auto-loading of ignore files (.gitignore, .ignore, etc.) for filtering")
                 .long("no-ignore"))
        .arg(Arg::with_name("no-default-ignore")
                 .help("Skip auto-ignoring of commonly ignored globs")
                 .long("no-default-ignore"))
        .arg(Arg::with_name("postpone")
                 .help("Wait until first change to execute command")
                 .short("p")
                 .long("postpone"))
        .arg(Arg::with_name("poll")
                 .help("Forces polling mode")
                 .long("force-poll")
                 .value_name("interval"))
        .arg(Arg::with_name("no-shell")
                 .help("Do not wrap command in 'sh -c' resp. 'cmd.exe /C'")
                 .short("n")
                 .long("no-shell"))
        .arg(Arg::with_name("once").short("1").hidden(true));

    let args = match from {
        None => app.get_matches(),
        Some(i) => app.get_matches_from(i),
    };

    let cmd: Vec<String> = values_t!(args.values_of("command"), String)?;
    let paths = values_t!(args.values_of("path"), String)
        .unwrap_or_else(|_| vec![".".into()])
        .iter()
        .map(|string_path| string_path.into())
        .collect();

    // Treat --kill as --signal SIGKILL (for compatibility with older syntax)
    let signal = if args.is_present("kill") {
        Some("SIGKILL".to_string())
    } else {
        // Convert Option<&str> to Option<String>
        args.value_of("signal").map(str::to_string)
    };

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or_else(|_| Vec::new());

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',').filter_map(|ext| {
                if ext.is_empty() {
                    None
                } else {
                    Some(format!("*.{}", ext.replace(".", "")))
                }
            }));
        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![
        format!("**{}.DS_Store", MAIN_SEPARATOR),
        String::from("*.py[co]"),
        String::from("#*#"),
        String::from(".#*"),
        String::from(".*.sw?"),
        String::from(".*.sw?x"),
        format!("**{}.git{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
        format!("**{}.hg{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
        format!("**{}.svn{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
    ];

    if args.occurrences_of("no-default-ignore") == 0 {
        ignores.extend(default_ignores)
    };
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or_else(|_| Vec::new()));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    let debounce = if args.occurrences_of("debounce") > 0 {
        value_t!(args.value_of("debounce"), u64).unwrap_or_else(|e| e.exit())
    } else {
        500
    };

    if signal.is_some() && args.is_present("postpone") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto("--postpone and --signal are mutually exclusive".to_string())
            .exit();
    }

    if signal.is_some() && args.is_present("kill") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto("--kill and --signal is ambiguous.\n       Hint: Use only '--signal SIGKILL' without --kill".to_string())
            .exit();
    }

    Ok(Args {
        cmd,
        paths,
        filters,
        ignores,
        signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debounce,
        debug: args.is_present("verbose"),
        run_initially: !args.is_present("postpone"),
        no_shell: args.is_present("no-shell"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        no_ignore: args.is_present("no-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval,
    })
}
<commit_msg>Fix verb tense on help message for `--force-poll`<commit_after>//! CLI arguments and library Args struct
//!
//! Use `ArgsBuilder` preferentially as that will shield you from breaking changes resulting from
//! added fields and some field type changes.
//!
//! # Examples
//!
//! ```
//! # use watchexec::cli::ArgsBuilder;
//! ArgsBuilder::default()
//!     .cmd(vec!["echo hello world".into()])
//!     .paths(vec![".".into()])
//!     .build()
//!     .expect("mission failed");
//! ```

use crate::error;
use clap::{App, Arg, Error};
use std::{
    ffi::OsString,
    path::{PathBuf, MAIN_SEPARATOR},
    process::Command,
};

/// Arguments to the watcher
#[derive(Builder, Clone, Debug)]
#[builder(setter(into, strip_option))]
#[builder(build_fn(validate = "Self::validate"))]
pub struct Args {
    /// Command to execute in popen3 format (first program, rest arguments).
    pub cmd: Vec<String>,
    /// List of paths to watch for changes.
    pub paths: Vec<PathBuf>,
    /// Positive filters (trigger only on matching changes). Glob format.
    #[builder(default)]
    pub filters: Vec<String>,
    /// Negative filters (do not trigger on matching changes). Glob format.
    #[builder(default)]
    pub ignores: Vec<String>,
    /// Clear the screen before each run.
    #[builder(default)]
    pub clear_screen: bool,
    /// If Some, send that signal (e.g. SIGHUP) to the child on change.
    #[builder(default)]
    pub signal: Option<String>,
    /// If true, kill the child if it's still running when a change comes in.
    #[builder(default)]
    pub restart: bool,
    /// Interval to debounce the changes. (milliseconds)
    #[builder(default = "500")]
    pub debounce: u64,
    /// Enable debug/verbose logging.
    #[builder(default)]
    pub debug: bool,
    /// Run the commands right after starting.
    #[builder(default = "true")]
    pub run_initially: bool,
    /// Do not wrap the commands in a shell.
    #[builder(default)]
    pub no_shell: bool,
    /// Skip auto-loading .gitignore files
    #[builder(default)]
    pub no_vcs_ignore: bool,
    /// Skip auto-loading .ignore files
    #[builder(default)]
    pub no_ignore: bool,
    /// For testing only, always set to false.
    #[builder(setter(skip))]
    #[builder(default)]
    pub once: bool,
    /// Force using the polling backend.
    #[builder(default)]
    pub poll: bool,
    /// Interval for polling. (seconds)
    #[builder(default = "2")]
    pub poll_interval: u32,
}

impl ArgsBuilder {
    fn validate(&self) -> Result<(), String> {
        if self.cmd.as_ref().map_or(true, Vec::is_empty) {
            return Err("cmd must not be empty".into());
        }

        if self.paths.as_ref().map_or(true, Vec::is_empty) {
            return Err("paths must not be empty".into());
        }

        Ok(())
    }
}

#[cfg(target_family = "windows")]
pub fn clear_screen() {
    let _ = Command::new("cmd")
        .arg("/c")
        .arg("tput reset || cls")
        .status();
}

#[cfg(target_family = "unix")]
pub fn clear_screen() {
    let _ = Command::new("tput").arg("reset").status();
}

pub fn get_args() -> error::Result<Args> {
    get_args_impl(None::<&[&str]>)
}

pub fn get_args_from<I, T>(from: I) -> error::Result<Args>
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    get_args_impl(Some(from))
}

fn get_args_impl<I, T>(from: Option<I>) -> error::Result<Args>
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    let app = App::new("watchexec")
        .version(crate_version!())
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("command")
                 .help("Command to execute")
                 .multiple(true)
                 .required(true))
        .arg(Arg::with_name("extensions")
                 .help("Comma-separated list of file extensions to watch (js,css,html)")
                 .short("e")
                 .long("exts")
                 .takes_value(true))
        .arg(Arg::with_name("path")
                 .help("Watch a specific directory")
                 .short("w")
                 .long("watch")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true))
        .arg(Arg::with_name("clear")
                 .help("Clear screen before executing command")
                 .short("c")
                 .long("clear"))
        .arg(Arg::with_name("restart")
                 .help("Restart the process if it's still running")
                 .short("r")
                 .long("restart"))
        .arg(Arg::with_name("signal")
                 .help("Send signal to process upon changes, e.g. SIGHUP")
                 .short("s")
                 .long("signal")
                 .takes_value(true)
                 .number_of_values(1)
                 .value_name("signal"))
        .arg(Arg::with_name("kill")
                 .help("Send SIGKILL to child processes (deprecated, use -s SIGKILL instead)")
                 .short("k")
                 .long("kill"))
        .arg(Arg::with_name("debounce")
                 .help("Set the timeout between detected change and command execution, defaults to 500ms")
                 .takes_value(true)
                 .value_name("milliseconds")
                 .short("d")
                 .long("debounce"))
        .arg(Arg::with_name("verbose")
                 .help("Print debugging messages to stderr")
                 .short("v")
                 .long("verbose"))
        .arg(Arg::with_name("filter")
                 .help("Ignore all modifications except those matching the pattern")
                 .short("f")
                 .long("filter")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("ignore")
                 .help("Ignore modifications to paths matching the pattern")
                 .short("i")
                 .long("ignore")
                 .number_of_values(1)
                 .multiple(true)
                 .takes_value(true)
                 .value_name("pattern"))
        .arg(Arg::with_name("no-vcs-ignore")
                 .help("Skip auto-loading of .gitignore files for filtering")
                 .long("no-vcs-ignore"))
        .arg(Arg::with_name("no-ignore")
                 .help("Skip auto-loading of ignore files (.gitignore, .ignore, etc.) for filtering")
                 .long("no-ignore"))
        .arg(Arg::with_name("no-default-ignore")
                 .help("Skip auto-ignoring of commonly ignored globs")
                 .long("no-default-ignore"))
        .arg(Arg::with_name("postpone")
                 .help("Wait until first change to execute command")
                 .short("p")
                 .long("postpone"))
        .arg(Arg::with_name("poll")
                 .help("Force polling mode")
                 .long("force-poll")
                 .value_name("interval"))
        .arg(Arg::with_name("no-shell")
                 .help("Do not wrap command in 'sh -c' resp. 'cmd.exe /C'")
                 .short("n")
                 .long("no-shell"))
        .arg(Arg::with_name("once").short("1").hidden(true));

    let args = match from {
        None => app.get_matches(),
        Some(i) => app.get_matches_from(i),
    };

    let cmd: Vec<String> = values_t!(args.values_of("command"), String)?;
    let paths = values_t!(args.values_of("path"), String)
        .unwrap_or_else(|_| vec![".".into()])
        .iter()
        .map(|string_path| string_path.into())
        .collect();

    // Treat --kill as --signal SIGKILL (for compatibility with older syntax)
    let signal = if args.is_present("kill") {
        Some("SIGKILL".to_string())
    } else {
        // Convert Option<&str> to Option<String>
        args.value_of("signal").map(str::to_string)
    };

    let mut filters = values_t!(args.values_of("filter"), String).unwrap_or_else(|_| Vec::new());

    if let Some(extensions) = args.values_of("extensions") {
        for exts in extensions {
            filters.extend(exts.split(',').filter_map(|ext| {
                if ext.is_empty() {
                    None
                } else {
                    Some(format!("*.{}", ext.replace(".", "")))
                }
            }));
        }
    }

    let mut ignores = vec![];
    let default_ignores = vec![
        format!("**{}.DS_Store", MAIN_SEPARATOR),
        String::from("*.py[co]"),
        String::from("#*#"),
        String::from(".#*"),
        String::from(".*.sw?"),
        String::from(".*.sw?x"),
        format!("**{}.git{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
        format!("**{}.hg{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
        format!("**{}.svn{}**", MAIN_SEPARATOR, MAIN_SEPARATOR),
    ];

    if args.occurrences_of("no-default-ignore") == 0 {
        ignores.extend(default_ignores)
    };
    ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or_else(|_| Vec::new()));

    let poll_interval = if args.occurrences_of("poll") > 0 {
        value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
    } else {
        1000
    };

    let debounce = if args.occurrences_of("debounce") > 0 {
        value_t!(args.value_of("debounce"), u64).unwrap_or_else(|e| e.exit())
    } else {
        500
    };

    if signal.is_some() && args.is_present("postpone") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto("--postpone and --signal are mutually exclusive".to_string())
            .exit();
    }

    if signal.is_some() && args.is_present("kill") {
        // TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
        Error::value_validation_auto("--kill and --signal is ambiguous.\n       Hint: Use only '--signal SIGKILL' without --kill".to_string())
            .exit();
    }

    Ok(Args {
        cmd,
        paths,
        filters,
        ignores,
        signal,
        clear_screen: args.is_present("clear"),
        restart: args.is_present("restart"),
        debounce,
        debug: args.is_present("verbose"),
        run_initially: !args.is_present("postpone"),
        no_shell: args.is_present("no-shell"),
        no_vcs_ignore: args.is_present("no-vcs-ignore"),
        no_ignore: args.is_present("no-ignore"),
        once: args.is_present("once"),
        poll: args.occurrences_of("poll") > 0,
        poll_interval,
    })
}
<|endoftext|>


<commit_before>use crate::{
    analysis::{self, namespaces::NsId},
    config::{gobjects::GStatus, Config},
    library::*,
    version::Version,
};
use std::cell::RefCell;

#[derive(Debug)]
pub struct Env {
    pub library: Library,
    pub config: Config,
    pub namespaces: analysis::namespaces::Info,
    pub symbols: RefCell<analysis::symbols::Info>,
    pub class_hierarchy: analysis::class_hierarchy::Info,
    pub analysis: analysis::Analysis,
}

impl Env {
    #[inline]
    pub fn type_(&self, tid: TypeId) -> &Type {
        self.library.type_(tid)
    }
    pub fn type_status(&self, name: &str) -> GStatus {
        self.config
            .objects
            .get(name)
            .map(|o| o.status)
            .unwrap_or_default()
    }
    pub fn type_status_sys(&self, name: &str) -> GStatus {
        self.config
            .objects
            .get(name)
            .map(|o| o.status)
            .unwrap_or(GStatus::Generate)
    }

    pub fn is_totally_deprecated(
        &self,
        ns_id: Option<NsId>,
        deprecated_version: Option<Version>,
    ) -> bool {
        let to_compare_with = self.config.min_required_version(self, ns_id);
        if let (Some(v), Some(to_compare_v)) = (deprecated_version, to_compare_with) {
            if v <= to_compare_v {
                return self.config.deprecate_by_min_version;
            }
        }
        false
    }

    pub fn is_too_low_version(&self, ns_id: Option<NsId>, version: Option<Version>) -> bool {
        let to_compare_with = self.config.min_required_version(self, ns_id);
        if let (Some(v), Some(to_compare_v)) = (version, to_compare_with) {
            return v <= to_compare_v;
        }
        false
    }

    pub fn main_sys_crate_name(&self) -> &str {
        &self.namespaces[MAIN_NAMESPACE].sys_crate_name
    }
}
<commit_msg>Fix env::is_totally_deprecated logic<commit_after>use crate::{
    analysis::{self, namespaces::NsId},
    config::{gobjects::GStatus, Config},
    library::*,
    version::Version,
};
use std::cell::RefCell;

#[derive(Debug)]
pub struct Env {
    pub library: Library,
    pub config: Config,
    pub namespaces: analysis::namespaces::Info,
    pub symbols: RefCell<analysis::symbols::Info>,
    pub class_hierarchy: analysis::class_hierarchy::Info,
    pub analysis: analysis::Analysis,
}

impl Env {
    #[inline]
    pub fn type_(&self, tid: TypeId) -> &Type {
        self.library.type_(tid)
    }
    pub fn type_status(&self, name: &str) -> GStatus {
        self.config
            .objects
            .get(name)
            .map(|o| o.status)
            .unwrap_or_default()
    }
    pub fn type_status_sys(&self, name: &str) -> GStatus {
        self.config
            .objects
            .get(name)
            .map(|o| o.status)
            .unwrap_or(GStatus::Generate)
    }

    pub fn is_totally_deprecated(
        &self,
        ns_id: Option<NsId>,
        deprecated_version: Option<Version>,
    ) -> bool {
        let to_compare_with = self.config.min_required_version(self, ns_id);
        match (deprecated_version, to_compare_with) {
            (Some(v), Some(to_compare_v)) => {
                if v <= to_compare_v {
                    self.config.deprecate_by_min_version
                } else {
                    false
                }
            }
            (Some(v), _) => {
                if v <= self.config.min_cfg_version {
                    self.config.deprecate_by_min_version
                } else {
                    false
                }
            }
            _ => false,
        }
    }

    pub fn is_too_low_version(&self, ns_id: Option<NsId>, version: Option<Version>) -> bool {
        let to_compare_with = self.config.min_required_version(self, ns_id);
        if let (Some(v), Some(to_compare_v)) = (version, to_compare_with) {
            return v <= to_compare_v;
        }
        false
    }

    pub fn main_sys_crate_name(&self) -> &str {
        &self.namespaces[MAIN_NAMESPACE].sys_crate_name
    }
}
<|endoftext|>