<commit_before>//! An undo-redo library with dynamic dispatch and automatic command merging.
//! It uses the [command pattern](https://en.wikipedia.org/wiki/Command_pattern)
//! where the user modifies a receiver by applying commands on it.
//!
//! The library has currently two data structures that can be used to modify the receiver:
//!
//! * A stack that can push and pop commands to modify the receiver.
//! * A record that can roll the state of the receiver forwards and backwards.

#![forbid(unstable_features, bad_style)]
#![deny(missing_debug_implementations, unused_import_braces, unused_qualifications, unsafe_code)]

mod group;
mod record;
mod stack;

use std::error;
use std::fmt::{self, Debug, Display, Formatter};

pub use group::{Group, GroupBuilder};
pub use record::{Commands, Record, RecordBuilder, Signal};
pub use stack::Stack;

/// Base functionality for all commands.
#[cfg(not(feature = "display"))]
pub trait Command<R>: Debug {
    /// Executes the desired command and returns `Ok` if everything went fine, and `Err` if
    /// something went wrong.
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    /// Restores the state as it was before [`exec`] was called and returns `Ok` if everything
    /// went fine, and `Err` if something went wrong.
    ///
    /// [`exec`]: trait.Command.html#tymethod.exec
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    /// Used for automatic merging of commands.
    ///
    /// Two commands are merged together when a command is pushed, and it has
    /// the same id as the top command already on the stack or record. When commands are merged together,
    /// undoing and redoing them are done in one step.
    ///
    /// # Examples
    /// ```
    /// # use std::error::Error;
    /// # use undo::*;
    /// #[derive(Debug)]
    /// struct Add(char);
    ///
    /// impl Command<String> for Add {
    ///     fn exec(&mut self, s: &mut String) -> Result<(), Box<Error>> {
    ///         s.push(self.0);
    ///         Ok(())
    ///     }
    ///
    ///     fn undo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
    ///         self.0 = s.pop().ok_or("`String` is unexpectedly empty")?;
    ///         Ok(())
    ///     }
    ///
    ///     fn id(&self) -> Option<u32> {
    ///         Some(1)
    ///     }
    /// }
    ///
    /// fn foo() -> Result<(), Box<Error>> {
    ///     let mut record = Record::default();
    ///
    ///     // 'a', 'b', and 'c' are merged.
    ///     record.exec(Add('a'))?;
    ///     record.exec(Add('b'))?;
    ///     record.exec(Add('c'))?;
    ///     assert_eq!(record.len(), 1);
    ///     assert_eq!(record.as_receiver(), "abc");
    ///
    ///     // Calling `undo` once will undo all merged commands.
    ///     record.undo().unwrap()?;
    ///     assert_eq!(record.as_receiver(), "");
    ///
    ///     // Calling `redo` once will redo all merged commands.
    ///     record.redo().unwrap()?;
    ///     assert_eq!(record.into_receiver(), "abc");
    ///
    ///     Ok(())
    /// }
    /// # foo().unwrap();
    /// ```
    #[inline]
    fn id(&self) -> Option<u32> {
        None
    }
}

#[cfg(feature = "display")]
pub trait Command<R>: Debug + Display {
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    #[inline]
    fn id(&self) -> Option<u32> {
        None
    }
}

impl<R, C: Command<R> + ?Sized> Command<R> for Box<C> {
    #[inline]
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        (**self).exec(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        (**self).undo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        (**self).id()
    }
}

struct Merger<R> {
    cmd1: Box<Command<R>>,
    cmd2: Box<Command<R>>,
}

impl<R> Command<R> for Merger<R> {
    #[inline]
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.exec(receiver)?;
        self.cmd2.exec(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R> Debug for Merger<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R> Display for Merger<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} + {}", self.cmd1, self.cmd2)
    }
}

/// The error type.
///
/// The error contains the error itself and the command that caused the error.
#[derive(Debug)]
pub struct Error<R>(pub Box<Command<R>>, pub Box<error::Error>);

impl<R> Display for Error<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.1)
    }
}

impl<R: Debug> error::Error for Error<R> {
    #[inline]
    fn description(&self) -> &str {
        self.1.description()
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        self.1.cause()
    }
}
<commit_msg>Force all commands to implement Send and Sync<commit_after>//! An undo-redo library with dynamic dispatch and automatic command merging.
//! It uses the [command pattern](https://en.wikipedia.org/wiki/Command_pattern)
//! where the user modifies a receiver by applying commands on it.
//!
//! The library has currently two data structures that can be used to modify the receiver:
//!
//! * A stack that can push and pop commands to modify the receiver.
//! * A record that can roll the state of the receiver forwards and backwards.

#![forbid(unstable_features, bad_style)]
#![deny(missing_debug_implementations, unused_import_braces, unused_qualifications, unsafe_code)]

mod group;
mod record;
mod stack;

use std::error;
use std::fmt::{self, Debug, Display, Formatter};

pub use group::{Group, GroupBuilder};
pub use record::{Commands, Record, RecordBuilder, Signal};
pub use stack::Stack;

/// Base functionality for all commands.
#[cfg(not(feature = "display"))]
pub trait Command<R>: Debug + Send + Sync {
    /// Executes the desired command and returns `Ok` if everything went fine, and `Err` if
    /// something went wrong.
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    /// Restores the state as it was before [`exec`] was called and returns `Ok` if everything
    /// went fine, and `Err` if something went wrong.
    ///
    /// [`exec`]: trait.Command.html#tymethod.exec
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    /// Used for automatic merging of commands.
    ///
    /// Two commands are merged together when a command is pushed, and it has
    /// the same id as the top command already on the stack or record. When commands are merged together,
    /// undoing and redoing them are done in one step.
    ///
    /// # Examples
    /// ```
    /// # use std::error::Error;
    /// # use undo::*;
    /// #[derive(Debug)]
    /// struct Add(char);
    ///
    /// impl Command<String> for Add {
    ///     fn exec(&mut self, s: &mut String) -> Result<(), Box<Error>> {
    ///         s.push(self.0);
    ///         Ok(())
    ///     }
    ///
    ///     fn undo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
    ///         self.0 = s.pop().ok_or("`String` is unexpectedly empty")?;
    ///         Ok(())
    ///     }
    ///
    ///     fn id(&self) -> Option<u32> {
    ///         Some(1)
    ///     }
    /// }
    ///
    /// fn foo() -> Result<(), Box<Error>> {
    ///     let mut record = Record::default();
    ///
    ///     // 'a', 'b', and 'c' are merged.
    ///     record.exec(Add('a'))?;
    ///     record.exec(Add('b'))?;
    ///     record.exec(Add('c'))?;
    ///     assert_eq!(record.len(), 1);
    ///     assert_eq!(record.as_receiver(), "abc");
    ///
    ///     // Calling `undo` once will undo all merged commands.
    ///     record.undo().unwrap()?;
    ///     assert_eq!(record.as_receiver(), "");
    ///
    ///     // Calling `redo` once will redo all merged commands.
    ///     record.redo().unwrap()?;
    ///     assert_eq!(record.into_receiver(), "abc");
    ///
    ///     Ok(())
    /// }
    /// # foo().unwrap();
    /// ```
    #[inline]
    fn id(&self) -> Option<u32> {
        None
    }
}

#[cfg(feature = "display")]
pub trait Command<R>: Debug + Display + Send + Sync {
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>>;

    #[inline]
    fn id(&self) -> Option<u32> {
        None
    }
}

impl<R, C: Command<R> + ?Sized> Command<R> for Box<C> {
    #[inline]
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        (**self).exec(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        (**self).undo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        (**self).id()
    }
}

struct Merger<R> {
    cmd1: Box<Command<R>>,
    cmd2: Box<Command<R>>,
}

impl<R> Command<R> for Merger<R> {
    #[inline]
    fn exec(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd1.exec(receiver)?;
        self.cmd2.exec(receiver)
    }

    #[inline]
    fn undo(&mut self, receiver: &mut R) -> Result<(), Box<error::Error>> {
        self.cmd2.undo(receiver)?;
        self.cmd1.undo(receiver)
    }

    #[inline]
    fn id(&self) -> Option<u32> {
        self.cmd1.id()
    }
}

impl<R> Debug for Merger<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Merger")
            .field("cmd1", &self.cmd1)
            .field("cmd2", &self.cmd2)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<R> Display for Merger<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} + {}", self.cmd1, self.cmd2)
    }
}

/// The error type.
///
/// The error contains the error itself and the command that caused the error.
#[derive(Debug)]
pub struct Error<R>(pub Box<Command<R>>, pub Box<error::Error>);

impl<R> Display for Error<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.1)
    }
}

impl<R: Debug> error::Error for Error<R> {
    #[inline]
    fn description(&self) -> &str {
        self.1.description()
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        self.1.cause()
    }
}
<|endoftext|>


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

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
#![deny(unconditional_recursion)]

#[cfg(test)]
use std as core;

pub use crate::angle::Angle;
pub use crate::box2d::Box2D;
pub use crate::length::Length;
pub use crate::scale::Scale;
pub use crate::transform2d::Transform2D;
pub use crate::transform3d::Transform3D;
pub use crate::point::{Point2D, Point3D, point2, point3};
pub use crate::vector::{Vector2D, Vector3D, vec2, vec3};
pub use crate::vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use crate::homogen::HomogeneousVector;
pub use crate::nonempty::NonEmpty;

pub use crate::rect::{rect, Rect};
pub use crate::rigid::{RigidTransform3D};
pub use crate::box3d::{box3d, Box3D};
pub use crate::translation::{Translation2D, Translation3D};
pub use crate::rotation::{Rotation2D, Rotation3D};
pub use crate::side_offsets::SideOffsets2D;
pub use crate::size::{Size2D, Size3D, size2, size3};
pub use crate::trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Length<T> = super::Length<T, UnknownUnit>;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<commit_msg>Remove test-only re-export of `std` as `core`<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
#![deny(unconditional_recursion)]

pub use crate::angle::Angle;
pub use crate::box2d::Box2D;
pub use crate::length::Length;
pub use crate::scale::Scale;
pub use crate::transform2d::Transform2D;
pub use crate::transform3d::Transform3D;
pub use crate::point::{Point2D, Point3D, point2, point3};
pub use crate::vector::{Vector2D, Vector3D, vec2, vec3};
pub use crate::vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use crate::homogen::HomogeneousVector;
pub use crate::nonempty::NonEmpty;

pub use crate::rect::{rect, Rect};
pub use crate::rigid::{RigidTransform3D};
pub use crate::box3d::{box3d, Box3D};
pub use crate::translation::{Translation2D, Translation3D};
pub use crate::rotation::{Rotation2D, Rotation3D};
pub use crate::side_offsets::SideOffsets2D;
pub use crate::size::{Size2D, Size3D, size2, size3};
pub use crate::trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Length<T> = super::Length<T, UnknownUnit>;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<|endoftext|>


<commit_before><commit_msg>Implement std::error::Error trait for ParseError<commit_after><|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/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consume exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
#[macro_use] extern crate procedural_masquerade;
#[doc(hidden)] pub extern crate phf as _internal__phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use cssparser_macros::*;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

// For macros
#[doc(hidden)] pub use macros::_internal__to_lowercase;

// For macros when used in this crate. Unsure how $crate works with procedural-masquerade.
mod cssparser { pub use _internal__phf; }

#[macro_use]
mod macros;

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<commit_msg>Fix doc typo<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/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consumed exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
#[macro_use] extern crate procedural_masquerade;
#[doc(hidden)] pub extern crate phf as _internal__phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use cssparser_macros::*;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

// For macros
#[doc(hidden)] pub use macros::_internal__to_lowercase;

// For macros when used in this crate. Unsure how $crate works with procedural-masquerade.
mod cssparser { pub use _internal__phf; }

#[macro_use]
mod macros;

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before><commit_msg>Fix #2 - automatic documentation<commit_after><|endoftext|>


<commit_before><commit_msg>Added parser.dynamic().<commit_after><|endoftext|>


<commit_before><commit_msg>Add `Deserialize` implementation for `Bytes`<commit_after><|endoftext|>


<commit_before><commit_msg>add trailing comma, conforming to style guide<commit_after><|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::WHITESPACE,
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let anchor_stmt = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        buf.push_str("let var_name = ");
        expr.syntax().text().push_to(&mut buf);
        let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
        }
        edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
    })
}

/// Statement or last in the block expression, which will follow
/// the freshly introduced var.
fn anchor_stmt(expr: &ast::Expr) -> Option<&SyntaxNode> {
    expr.syntax().ancestors().find(|&node| {
        if ast::Stmt::cast(node).is_some() {
            return true;
        }
        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return true;
            }
        }
        false
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    something_else();
}",
        );
    }
}
<commit_msg>add semicolon for block expr in introduce_variable<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::{WHITESPACE, BLOCK_EXPR},
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let anchor_stmt = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        buf.push_str("let var_name = ");
        expr.syntax().text().push_to(&mut buf);
        let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            if expr.syntax().kind() == BLOCK_EXPR {
                buf.push_str(";");
            }
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
        }
        edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
    })
}

/// Statement or last in the block expression, which will follow
/// the freshly introduced var.
fn anchor_stmt(expr: &ast::Expr) -> Option<&SyntaxNode> {
    expr.syntax().ancestors().find(|&node| {
        if ast::Stmt::cast(node).is_some() {
            return true;
        }
        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return true;
            }
        }
        false
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    something_else();
}",
        );
    }
}
<|endoftext|>


<commit_before>use glib;
use glib_sys;
use libc;

use error::*;
use parsers::Parse;
use std::marker::PhantomData;
use util::utf8_cstr;

use self::glib::translate::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
struct RequiredExtensions(bool);

impl Parse for RequiredExtensions {
    type Data = ();
    type Err = AttributeError;

    // Parse a requiredExtensions attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    fn parse(s: &str, _: ()) -> Result<RequiredExtensions, AttributeError> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
struct RequiredFeatures(bool);

impl Parse for RequiredFeatures {
    type Data = ();
    type Err = AttributeError;

    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    fn parse(s: &str, _: ()) -> Result<RequiredFeatures, AttributeError> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }
}

#[derive(Debug, PartialEq)]
struct SystemLanguage<'a>(bool, PhantomData<&'a i8>);

impl<'a> Parse for SystemLanguage<'a> {
    type Data = &'a [String];
    type Err = AttributeError;

    // Parse a systemLanguage attribute
    // http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
    fn parse(s: &str, system_languages: &[String]) -> Result<SystemLanguage<'a>, AttributeError> {
        Ok(SystemLanguage(
            s.split(',')
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .any(|l| {
                    system_languages.iter().any(|sl| {
                        if sl.eq_ignore_ascii_case(l) {
                            return true;
                        }

                        if let Some(offset) = l.find('-') {
                            return sl.eq_ignore_ascii_case(&l[..offset]);
                        }

                        false
                    })
                }),
            PhantomData,
        ))
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_required_extensions(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match RequiredExtensions::parse(value, ()) {
        Ok(RequiredExtensions(res)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_required_features(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match RequiredFeatures::parse(value, ()) {
        Ok(RequiredFeatures(res)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_system_language(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match SystemLanguage::parse(value, &glib::get_language_names()) {
        Ok(SystemLanguage(res, _)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

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

    #[test]
    fn parse_required_extensions() {
        assert_eq!(
            RequiredExtensions::parse("http://test.org/NotExisting/1.0", ()),
            Ok(RequiredExtensions(false))
        );
    }

    #[test]
    fn parse_required_features() {
        assert_eq!(
            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#NotExisting", ()),
            Ok(RequiredFeatures(false))
        );

        assert_eq!(
            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#BasicFilter", ()),
            Ok(RequiredFeatures(true))
        );

        assert_eq!(
            RequiredFeatures::parse(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
                ()
            ),
            Ok(RequiredFeatures(false))
        );

        assert_eq!(
            RequiredFeatures::parse(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
                ()
            ),
            Ok(RequiredFeatures(true))
        );
    }

    #[test]
    fn parse_system_language() {
        let system_languages = vec![String::from("de"), String::from("en_US")];

        assert_eq!(
            SystemLanguage::parse("", &system_languages),
            Ok(SystemLanguage(false, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("fr", &system_languages),
            Ok(SystemLanguage(false, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("de", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("en_US", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("DE", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("de-LU", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("fr, de", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );
    }
}
<commit_msg>cond.rs: Use AsciiExt to maintain backwards compatibility.<commit_after>use glib;
use glib_sys;
use libc;

use error::*;
use parsers::Parse;
use std::marker::PhantomData;
use util::utf8_cstr;

#[allow(unused_imports)]
use std::ascii::AsciiExt;

use self::glib::translate::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
struct RequiredExtensions(bool);

impl Parse for RequiredExtensions {
    type Data = ();
    type Err = AttributeError;

    // Parse a requiredExtensions attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    fn parse(s: &str, _: ()) -> Result<RequiredExtensions, AttributeError> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
struct RequiredFeatures(bool);

impl Parse for RequiredFeatures {
    type Data = ();
    type Err = AttributeError;

    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    fn parse(s: &str, _: ()) -> Result<RequiredFeatures, AttributeError> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }
}

#[derive(Debug, PartialEq)]
struct SystemLanguage<'a>(bool, PhantomData<&'a i8>);

impl<'a> Parse for SystemLanguage<'a> {
    type Data = &'a [String];
    type Err = AttributeError;

    // Parse a systemLanguage attribute
    // http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
    fn parse(s: &str, system_languages: &[String]) -> Result<SystemLanguage<'a>, AttributeError> {
        Ok(SystemLanguage(
            s.split(',')
                .map(|s| s.trim())
                .filter(|s| !s.is_empty())
                .any(|l| {
                    system_languages.iter().any(|sl| {
                        if sl.eq_ignore_ascii_case(l) {
                            return true;
                        }

                        if let Some(offset) = l.find('-') {
                            return sl.eq_ignore_ascii_case(&l[..offset]);
                        }

                        false
                    })
                }),
            PhantomData,
        ))
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_required_extensions(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match RequiredExtensions::parse(value, ()) {
        Ok(RequiredExtensions(res)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_required_features(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match RequiredFeatures::parse(value, ()) {
        Ok(RequiredFeatures(res)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

#[no_mangle]
pub extern "C" fn rsvg_cond_check_system_language(
    raw_value: *const libc::c_char,
) -> glib_sys::gboolean {
    let value = unsafe { utf8_cstr(raw_value) };

    match SystemLanguage::parse(value, &glib::get_language_names()) {
        Ok(SystemLanguage(res, _)) => res.to_glib(),
        Err(_) => false.to_glib(),
    }
}

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

    #[test]
    fn parse_required_extensions() {
        assert_eq!(
            RequiredExtensions::parse("http://test.org/NotExisting/1.0", ()),
            Ok(RequiredExtensions(false))
        );
    }

    #[test]
    fn parse_required_features() {
        assert_eq!(
            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#NotExisting", ()),
            Ok(RequiredFeatures(false))
        );

        assert_eq!(
            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#BasicFilter", ()),
            Ok(RequiredFeatures(true))
        );

        assert_eq!(
            RequiredFeatures::parse(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
                ()
            ),
            Ok(RequiredFeatures(false))
        );

        assert_eq!(
            RequiredFeatures::parse(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
                ()
            ),
            Ok(RequiredFeatures(true))
        );
    }

    #[test]
    fn parse_system_language() {
        let system_languages = vec![String::from("de"), String::from("en_US")];

        assert_eq!(
            SystemLanguage::parse("", &system_languages),
            Ok(SystemLanguage(false, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("fr", &system_languages),
            Ok(SystemLanguage(false, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("de", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("en_US", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("DE", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("de-LU", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );

        assert_eq!(
            SystemLanguage::parse("fr, de", &system_languages),
            Ok(SystemLanguage(true, PhantomData))
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate libc;
extern crate num;

use self::num::complex::{Complex32, Complex64};
use self::libc::{c_double, c_float, c_void};

pub trait CPtr<T> {
    fn as_c_ptr(self) -> T;
}

macro_rules! c_ptr_impl(
    ($t: ty, $c_type: ty) => (
        impl CPtr<*const $c_type> for *const $t {
            #[inline]
            fn as_c_ptr(self) -> *const $c_type {
                self as *const $c_type
            }
        }

        impl CPtr<*mut $c_type> for *mut $t {
            #[inline]
            fn as_c_ptr(self) -> *mut $c_type {
                self as *mut $c_type
            }
        }
    );
)

c_ptr_impl!(f32, c_float)
c_ptr_impl!(f64, c_double)
c_ptr_impl!(Complex32, c_void)
c_ptr_impl!(Complex64, c_void)
<commit_msg>Add integer types to pointer extension<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate libc;
extern crate num;

use self::num::complex::{Complex32, Complex64};
use self::libc::{c_double, c_int, c_float, c_long, c_void};

pub trait CPtr<T> {
    fn as_c_ptr(self) -> T;
}

macro_rules! c_ptr_impl(
    ($t: ty, $c_type: ty) => (
        impl CPtr<*const $c_type> for *const $t {
            #[inline]
            fn as_c_ptr(self) -> *const $c_type {
                self as *const $c_type
            }
        }

        impl CPtr<*mut $c_type> for *mut $t {
            #[inline]
            fn as_c_ptr(self) -> *mut $c_type {
                self as *mut $c_type
            }
        }
    );
)

c_ptr_impl!(i32, c_int)
c_ptr_impl!(i64, c_long)
c_ptr_impl!(f32, c_float)
c_ptr_impl!(f64, c_double)
c_ptr_impl!(Complex32, c_void)
c_ptr_impl!(Complex64, c_void)
<|endoftext|>


<commit_before>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process {
                        pgid: child,
                        lock: Mutex::new(false),
                        cvar: Condvar::new(),
                    })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => {
                        finished = false;
                        break;
                    }
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::{Path, PathBuf};

    use mktemp::Temp;

    use super::spawn;
    use super::get_longest_common_path;

    fn file_contents(path: &Path) -> String {
        use std::fs::File;
        use std::io::Read;

        let mut f = File::open(path).unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        s
    }

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn test_wait() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();
        let process = spawn(&format!("echo hi > {}", path.to_str().unwrap()), vec![]);
        process.wait();

        assert!(file_contents(&path).starts_with("hi"));
    }

    #[test]
    fn test_kill() {
        let file = Temp::new_file().unwrap();
        let path = file.to_path_buf();

        let process = spawn(&format!("sleep 20; echo hi > {}", path.to_str().unwrap()),
                            vec![]);
        process.kill();
        process.wait();

        assert!(file_contents(&path) == "");
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<commit_msg>Remove kill/wait tests as process handling is async now<commit_after>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process {
                        pgid: child,
                        lock: Mutex::new(false),
                        cvar: Condvar::new(),
                    })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => {
                        finished = false;
                        break;
                    }
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::PathBuf;

    use super::spawn;
    use super::get_longest_common_path;

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<|endoftext|>


<commit_before>use iron::middleware::Handler;
use iron::prelude::*;
use iron::status;
use std::process;
use std::error::Error;

use std::ffi::OsString;

use rustc_serialize::json;

use rand::Rng;
use rand;

use std::sync::{Mutex, RwLock, Barrier, Arc};
use std::thread;
use std::io::{BufReader, BufRead};

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
struct StartSuccessful {
    id: String
}

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
struct LogOutput {
    id: String,
    lines: Vec<String>,
    next_line: usize
}

struct RunnerState {
    /// Current process identifier, process will stop if identifier is changed
    id: Mutex<String>,

    /// The output of the current process
    output: RwLock<Vec<String>>,

    /// Barrier used to check if starting the subprocess (owned by a thread) went ok
    start_barrier: Barrier,

    /// Any error
    error: Mutex<Option<Result<(), ::std::io::Error>>>
}

pub struct ProcessRunner {
    pub program: OsString,
    state: Arc<RunnerState>
}

impl ProcessRunner {
    pub fn new<S: Into<String>>(s: S) -> ProcessRunner {
        ProcessRunner {
            program: OsString::from(s.into()),
            state: Arc::new(RunnerState {
                id: Mutex::new("".to_owned()),
                output: RwLock::new(vec![]),
                start_barrier: Barrier::new(2),
                error: Mutex::new(None)
            })
        }
    }

    fn start(&self) -> Result<(), ::std::io::Error> {
        let id : String = rand::thread_rng().gen_ascii_chars().take(10).collect();
        *self.state.id.lock().unwrap() = id.clone();
        self.state.output.write().unwrap().clear();

        let state = self.state.clone();
        let program = self.program.clone();

        thread::spawn(move || {
            let child_result = process::Command::new(&program)
                    .stdout(process::Stdio::piped())
                    .spawn();
            if child_result.is_err() {
                {
                    *state.error.lock().unwrap() = Some(child_result.map(|_| ()));
                }
                state.start_barrier.wait();
                return;
            }

            {
                *state.error.lock().unwrap() = Some(Ok(()));
            }
            state.start_barrier.wait();

            if let Ok(mut child) = child_result {
                {
                    let mut reader = BufReader::new(child.stdout.as_mut().unwrap());
                    let mut s = String::new();
                    loop {
                        {
                            if *state.id.lock().unwrap() != id { break; } // End of the party boys, ID changed
                        }

                        match reader.read_line(&mut s) {
                            Ok(n) if n > 0 => (),
                            _ => break
                        };

                        {
                            state.output.write().unwrap().push(s.clone());
                        }
                        s.clear();
                    }
                }

                if let Some(err) = child.kill().err() {
                    println!("Error killing subprocess: {}", err);
                } else {
                    println!("Subprocess stopped");
                }
            }
        });

        self.state.start_barrier.wait();
        {
            self.state.error.lock().unwrap().take().unwrap()
        }
    }

    fn stop(&self) -> Result<(), Box<Error>> {
        // This will cause the background thread to terminate
        self.state.id.lock().unwrap().clear();
        Ok(())
    }

    fn read(&self, line: usize) -> LogOutput {
        let output = self.state.output.read().unwrap();

        let len = output.len();

        LogOutput {
            id: self.state.id.lock().unwrap().to_owned(),
            lines: output[::std::cmp::min(line, len)..].iter().map(|x| x.to_owned()).collect(),
            next_line: len
        }
    }

    fn do_stop(&self) -> Result<String, Box<Error>> {
        try!(self.stop());
        Ok("ok".to_owned())
    }

    fn do_start(&self) -> Result<String, Box<Error>> {
        try!(self.stop());
        try!(self.start());
        let response = StartSuccessful { id: self.state.id.lock().unwrap().clone() };
        Ok(try!(json::encode(&response)))
    }

    fn do_read(&self, id: &str, page: &str) -> Result<String, Box<Error>> {
        let result = self.read(try!(page.parse::<usize>()));

        if result.id == id {
            Ok(try!(json::encode(&result)))
        } else {
            Err(Box::new(ErrString("Incorrect id provided".to_owned())))
        }
    }
}

impl Handler for ProcessRunner {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.url.path.len() {
            1 => {
                match req.url.path[0].as_ref() {
                    "start" => Ok(make_response(self.do_start())),
                    "stop" => Ok(make_response(self.do_stop())),
                    _ => Ok(Response::with((status::BadRequest, "Command must be 'start' or 'stop'")))
                }
            },
            2 => {
                Ok(make_response(self.do_read(&req.url.path[0], &req.url.path[1])))
            },
            _ => Ok(Response::with((status::BadRequest, "Expecting exactly one URL part")))
        }
    }
}

fn make_response(r: Result<String, Box<Error>>) -> Response {
    match r {
        Ok(s) => Response::with((status::Ok, s)),
        Err(e) => {
            println!("{:?}", e);
            Response::with((status::InternalServerError, e.description()))
        }
    }
}

#[derive(Debug)]
struct ErrString(String);

// Just so I can error out with strings
impl Error for ErrString {
    fn description(&self) -> &str {
        &self.0
    }
}

impl ::std::fmt::Display for ErrString {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        try!(write!(f, "{}", self.0));
        Ok(())
    }
}
<commit_msg>Make terminating started processes more reliable<commit_after>use iron::middleware::Handler;
use iron::prelude::*;
use iron::status;
use std::process;
use std::error::Error;

use std::ffi::OsString;

use rustc_serialize::json;

use rand::Rng;
use rand;

use std::sync::{Mutex, RwLock, Arc};
use std::thread;
use std::io::{BufReader, BufRead};

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
struct StartSuccessful {
    id: String
}

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
struct LogOutput {
    id: String,
    lines: Vec<String>,
    next_line: usize
}

struct RunnerState {
    /// Current process identifier, process will stop if identifier is changed
    id: Mutex<String>,

    /// The output of the current process
    output: RwLock<Vec<String>>,

    /// Handle to the child process
    child: Mutex<Option<process::Child>>
}

pub struct ProcessRunner {
    pub program: OsString,
    state: Arc<RunnerState>
}

impl ProcessRunner {
    pub fn new<S: Into<String>>(s: S) -> ProcessRunner {
        ProcessRunner {
            program: OsString::from(s.into()),
            state: Arc::new(RunnerState {
                id: Mutex::new("".to_owned()),
                output: RwLock::new(vec![]),
                child: Mutex::new(None)
            })
        }
    }

    fn start(&self) -> Result<(), ::std::io::Error> {
        let id : String = rand::thread_rng().gen_ascii_chars().take(10).collect();
        *self.state.id.lock().unwrap() = id.clone();
        self.state.output.write().unwrap().clear();

        let state = self.state.clone();
        let program = self.program.clone();

        let mut child = try!(process::Command::new(&program)
                .stdout(process::Stdio::piped())
                .spawn());

        let out = child.stdout.take().expect("No stdout on child");

        *state.child.lock().unwrap() = Some(child);

        thread::spawn(move || {
            let mut reader = BufReader::new(out);
            let mut s = String::new();
            loop {
                {
                    if *state.id.lock().unwrap() != id { break; } // End of the party boys, ID changed
                }

                match reader.read_line(&mut s) {
                    Ok(n) if n > 0 => (),
                    _ => break
                };

                {
                    state.output.write().unwrap().push(s.clone());
                }
                s.clear();
            }
        });

        Ok(())
    }

    fn stop(&self) -> Result<(), Box<Error>> {
        // This will cause the background thread to terminate
        self.state.id.lock().unwrap().clear();
        for child in self.state.child.lock().unwrap().iter_mut() {
            if let Some(err) = child.kill().err() {
                println!("Error killing subprocess: {}", err);
            } else {
                println!("Subprocess stopped");
            }
        }
        Ok(())
    }

    fn read(&self, line: usize) -> LogOutput {
        let output = self.state.output.read().unwrap();

        let len = output.len();

        LogOutput {
            id: self.state.id.lock().unwrap().to_owned(),
            lines: output[::std::cmp::min(line, len)..].iter().map(|x| x.to_owned()).collect(),
            next_line: len
        }
    }

    fn do_stop(&self) -> Result<String, Box<Error>> {
        try!(self.stop());
        Ok("ok".to_owned())
    }

    fn do_start(&self) -> Result<String, Box<Error>> {
        try!(self.stop());
        try!(self.start());
        let response = StartSuccessful { id: self.state.id.lock().unwrap().clone() };
        Ok(try!(json::encode(&response)))
    }

    fn do_read(&self, id: &str, page: &str) -> Result<String, Box<Error>> {
        let result = self.read(try!(page.parse::<usize>()));

        if result.id == id {
            Ok(try!(json::encode(&result)))
        } else {
            Err(Box::new(ErrString("Incorrect id provided".to_owned())))
        }
    }
}

impl Handler for ProcessRunner {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        match req.url.path.len() {
            1 => {
                match req.url.path[0].as_ref() {
                    "start" => Ok(make_response(self.do_start())),
                    "stop" => Ok(make_response(self.do_stop())),
                    _ => Ok(Response::with((status::BadRequest, "Command must be 'start' or 'stop'")))
                }
            },
            2 => {
                Ok(make_response(self.do_read(&req.url.path[0], &req.url.path[1])))
            },
            _ => Ok(Response::with((status::BadRequest, "Expecting exactly one URL part")))
        }
    }
}

fn make_response(r: Result<String, Box<Error>>) -> Response {
    match r {
        Ok(s) => Response::with((status::Ok, s)),
        Err(e) => {
            println!("{:?}", e);
            Response::with((status::InternalServerError, e.description()))
        }
    }
}

#[derive(Debug)]
struct ErrString(String);

// Just so I can error out with strings
impl Error for ErrString {
    fn description(&self) -> &str {
        &self.0
    }
}

impl ::std::fmt::Display for ErrString {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        try!(write!(f, "{}", self.0));
        Ok(())
    }
}
<|endoftext|>