<commit_before>use std::ops::Deref;

use node::Value;
use parser::{Error, Reader, Result};
use super::{Command, Number, Parameters, Position};

/// A [data][1] attribute.
///
/// [1]: https://www.w3.org/TR/SVG/paths.html#PathData
#[derive(Clone, Default)]
pub struct Data(Vec<Command>);

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Data {
    /// Create a data attribute.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Parse a data attribute.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! implement {
    (@one #[$doc:meta] fn $method:ident($command:ident, $position:ident)) => (
        #[$doc]
        pub fn $method<T>(mut self, parameters: T) -> Self where T: Into<Parameters> {
            self.0.push(Command::$command(Position::$position, parameters.into()));
            self
        }
    );
    (@one #[$doc:meta] fn $method:ident($command:ident)) => (
        #[$doc]
        pub fn $method(mut self) -> Self {
            self.0.push(Command::$command);
            self
        }
    );
    ($(#[$doc:meta] fn $method:ident($($argument:tt)*))*) => (
        impl Data {
            $(implement! { @one #[$doc] fn $method($($argument)*) })*
        }
    );
}

implement! {
    #[doc = "Add an absolute `Command::Move` command."]
    fn move_to(Move, Absolute)

    #[doc = "Add a relative `Command::Move` command."]
    fn move_by(Move, Relative)

    #[doc = "Add an absolute `Command::Line` command."]
    fn line_to(Line, Absolute)

    #[doc = "Add a relative `Command::Line` command."]
    fn line_by(Line, Relative)

    #[doc = "Add an absolute `Command::HorizontalLine` command."]
    fn horizontal_line_to(HorizontalLine, Absolute)

    #[doc = "Add a relative `Command::HorizontalLine` command."]
    fn horizontal_line_by(HorizontalLine, Relative)

    #[doc = "Add an absolute `Command::VerticalLine` command."]
    fn vertical_line_to(VerticalLine, Absolute)

    #[doc = "Add a relative `Command::VerticalLine` command."]
    fn vertical_line_by(VerticalLine, Relative)

    #[doc = "Add an absolute `Command::QuadraticCurve` command."]
    fn quadratic_curve_to(QuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::QuadraticCurve` command."]
    fn quadratic_curve_by(QuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_to(SmoothQuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_by(SmoothQuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::CubicCurve` command."]
    fn cubic_curve_to(CubicCurve, Absolute)

    #[doc = "Add a relative `Command::CubicCurve` command."]
    fn cubic_curve_by(CubicCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_to(SmoothCubicCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_by(SmoothCubicCurve, Relative)

    #[doc = "Add an absolute `Command::EllipticalArc` command."]
    fn elliptical_arc_to(EllipticalArc, Absolute)

    #[doc = "Add a relative `Command::EllipticalArc` command."]
    fn elliptical_arc_by(EllipticalArc, Relative)

    #[doc = "Add a `Command::Close` command."]
    fn close(Close)
}

impl Deref for Data {
    type Target = [Command];

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<Vec<Command>> for Data {
    #[inline]
    fn from(commands: Vec<Command>) -> Self {
        Data(commands)
    }
}

impl From<Data> for Vec<Command> {
    #[inline]
    fn from(Data(commands): Data) -> Self {
        commands
    }
}

impl From<Data> for Value {
    #[inline]
    fn from(Data(mut inner): Data) -> Self {
        inner.drain(..).map(|value| String::from(value)).collect::<Vec<_>>().join(" ").into()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }
        Ok(Data(commands))
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use super::Command::*;
        use super::Position::*;

        let name = match self.reader.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };
        self.reader.consume_whitespace();
        let parameters = try!(self.read_parameters()).into();
        Ok(Some(match name {
            'M' => Move(Absolute, parameters),
            'm' => Move(Relative, parameters),

            'L' => Line(Absolute, parameters),
            'l' => Line(Relative, parameters),

            'H' => HorizontalLine(Absolute, parameters),
            'h' => HorizontalLine(Relative, parameters),

            'V' => VerticalLine(Absolute, parameters),
            'v' => VerticalLine(Relative, parameters),

            'Q' => QuadraticCurve(Absolute, parameters),
            'q' => QuadraticCurve(Relative, parameters),

            'T' => SmoothQuadraticCurve(Absolute, parameters),
            't' => SmoothQuadraticCurve(Relative, parameters),

            'C' => CubicCurve(Absolute, parameters),
            'c' => CubicCurve(Relative, parameters),

            'S' => SmoothCubicCurve(Absolute, parameters),
            's' => SmoothCubicCurve(Relative, parameters),

            'A' => EllipticalArc(Absolute, parameters),
            'a' => EllipticalArc(Relative, parameters),

            'Z' | 'z' => Close,

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<Number>> {
        let mut parameters = Vec::new();
        loop {
            match try!(self.read_number()) {
                Some(number) => parameters.push(number),
                _ => break,
            }
            self.reader.consume_whitespace();
            self.reader.consume_char(',');
        }
        Ok(parameters)
    }

    pub fn read_number(&mut self) -> Result<Option<Number>> {
        self.reader.consume_whitespace();
        let number = self.reader.capture(|reader| reader.consume_number())
                                .and_then(|number| Some(String::from(number)));
        match number {
            Some(number) => match (&number).parse() {
                Ok(number) => Ok(Some(number)),
                _ => raise!(self, "failed to parse a number '{}'", number),
            },
            _ => Ok(None),
        }
    }
}

#[cfg(test)]
mod tests {
    use node::Value;
    use super::{Data, Parser};
    use super::super::Command::*;
    use super::super::Position::*;

    #[test]
    fn data_into_value() {
        let data = Data::new().line_to((1, 2)).cubic_curve_by((1, 2.5, 3, 4, 5, 6)).close();
        assert_eq!(Value::from(data).to_string(), "L1,2 c1,2.5,3,4,5,6 z");
    }

    #[test]
    fn data_parse() {
        let data = Data::parse("M1,2 l3,4").unwrap();
        assert_eq!(data.len(), 2);
        match data[0] {
            Move(Absolute, ref parameters) => assert_eq!(&parameters[..], &[1.0, 2.0]),
            _ => unreachable!(),
        }
        match data[1] {
            Line(Relative, ref parameters) => assert_eq!(&parameters[..], &[3.0, 4.0]),
            _ => unreachable!(),
        }
    }

    #[test]
    fn parser_read_command() {
        macro_rules! run(
            ($content:expr) => ({
                let mut parser = Parser::new($content);
                parser.read_command().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($content:expr, $command:ident, $position:ident, $parameters:expr) => (
                match run!($content) {
                    $command($position, parameters) => assert_eq!(&parameters[..], $parameters),
                    _ => unreachable!(),
                }
            );
            ($content:expr, $command:ident) => (
                match run!($content) {
                    $command => {},
                    _ => unreachable!(),
                }
            );
        );

        test!("M4,2", Move, Absolute, &[4.0, 2.0]);
        test!("m4,\n2", Move, Relative, &[4.0, 2.0]);

        test!("L7, 8  9", Line, Absolute, &[7.0, 8.0, 9.0]);
        test!("l 7,8 \n9", Line, Relative, &[7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLine, Absolute, &[6.0, 9.0]);
        test!("h6,  \t9", HorizontalLine, Relative, &[6.0, 9.0]);

        test!("V2.1,-3", VerticalLine, Absolute, &[2.1, -3.0]);
        test!("v\n2.1 -3", VerticalLine, Relative, &[2.1, -3.0]);

        test!("Q90.5 0", QuadraticCurve, Absolute, &[90.5, 0.0]);
        test!("q90.5\n, 0", QuadraticCurve, Relative, &[90.5, 0.0]);

        test!("T-1", SmoothQuadraticCurve, Absolute, &[-1.0]);
        test!("t -1", SmoothQuadraticCurve, Relative, &[-1.0]);

        test!("C0,1 0,2", CubicCurve, Absolute, &[0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CubicCurve, Relative, &[0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCubicCurve, Absolute, &[42.0, 0.0]);
        test!("s \t 42,0", SmoothCubicCurve, Relative, &[42.0, 0.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, &[2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, &[2.6, 0.0, -7.0]);

        test!("Z", Close);
        test!("z", Close);
    }

    #[test]
    fn parser_read_parameters() {
        macro_rules! test(
            ($content:expr, $parameters:expr) => ({
                let mut parser = Parser::new($content);
                let parameters = parser.read_parameters().unwrap();
                assert_eq!(&parameters[..], $parameters);
            });
        );

        test!("1,2 3,4 5 6.7", &[1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn parser_read_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                assert_eq!(parser.read_number().unwrap().unwrap(), $value);
            });
        );

        test!("0.30000000000000004", 0.3);
        test!("1e-4", 1e-4);
        test!("-1E2", -1e2);
        test!("-0.00100E-002", -1e-5);
    }
}
<commit_msg>Add a test for parsing path parameters<commit_after>use std::ops::Deref;

use node::Value;
use parser::{Error, Reader, Result};
use super::{Command, Number, Parameters, Position};

/// A [data][1] attribute.
///
/// [1]: https://www.w3.org/TR/SVG/paths.html#PathData
#[derive(Clone, Default)]
pub struct Data(Vec<Command>);

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Data {
    /// Create a data attribute.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Parse a data attribute.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! implement {
    (@one #[$doc:meta] fn $method:ident($command:ident, $position:ident)) => (
        #[$doc]
        pub fn $method<T>(mut self, parameters: T) -> Self where T: Into<Parameters> {
            self.0.push(Command::$command(Position::$position, parameters.into()));
            self
        }
    );
    (@one #[$doc:meta] fn $method:ident($command:ident)) => (
        #[$doc]
        pub fn $method(mut self) -> Self {
            self.0.push(Command::$command);
            self
        }
    );
    ($(#[$doc:meta] fn $method:ident($($argument:tt)*))*) => (
        impl Data {
            $(implement! { @one #[$doc] fn $method($($argument)*) })*
        }
    );
}

implement! {
    #[doc = "Add an absolute `Command::Move` command."]
    fn move_to(Move, Absolute)

    #[doc = "Add a relative `Command::Move` command."]
    fn move_by(Move, Relative)

    #[doc = "Add an absolute `Command::Line` command."]
    fn line_to(Line, Absolute)

    #[doc = "Add a relative `Command::Line` command."]
    fn line_by(Line, Relative)

    #[doc = "Add an absolute `Command::HorizontalLine` command."]
    fn horizontal_line_to(HorizontalLine, Absolute)

    #[doc = "Add a relative `Command::HorizontalLine` command."]
    fn horizontal_line_by(HorizontalLine, Relative)

    #[doc = "Add an absolute `Command::VerticalLine` command."]
    fn vertical_line_to(VerticalLine, Absolute)

    #[doc = "Add a relative `Command::VerticalLine` command."]
    fn vertical_line_by(VerticalLine, Relative)

    #[doc = "Add an absolute `Command::QuadraticCurve` command."]
    fn quadratic_curve_to(QuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::QuadraticCurve` command."]
    fn quadratic_curve_by(QuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_to(SmoothQuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_by(SmoothQuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::CubicCurve` command."]
    fn cubic_curve_to(CubicCurve, Absolute)

    #[doc = "Add a relative `Command::CubicCurve` command."]
    fn cubic_curve_by(CubicCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_to(SmoothCubicCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_by(SmoothCubicCurve, Relative)

    #[doc = "Add an absolute `Command::EllipticalArc` command."]
    fn elliptical_arc_to(EllipticalArc, Absolute)

    #[doc = "Add a relative `Command::EllipticalArc` command."]
    fn elliptical_arc_by(EllipticalArc, Relative)

    #[doc = "Add a `Command::Close` command."]
    fn close(Close)
}

impl Deref for Data {
    type Target = [Command];

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<Vec<Command>> for Data {
    #[inline]
    fn from(commands: Vec<Command>) -> Self {
        Data(commands)
    }
}

impl From<Data> for Vec<Command> {
    #[inline]
    fn from(Data(commands): Data) -> Self {
        commands
    }
}

impl From<Data> for Value {
    #[inline]
    fn from(Data(mut inner): Data) -> Self {
        inner.drain(..).map(|value| String::from(value)).collect::<Vec<_>>().join(" ").into()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }
        Ok(Data(commands))
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use super::Command::*;
        use super::Position::*;

        let name = match self.reader.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };
        self.reader.consume_whitespace();
        let parameters = try!(self.read_parameters()).into();
        Ok(Some(match name {
            'M' => Move(Absolute, parameters),
            'm' => Move(Relative, parameters),

            'L' => Line(Absolute, parameters),
            'l' => Line(Relative, parameters),

            'H' => HorizontalLine(Absolute, parameters),
            'h' => HorizontalLine(Relative, parameters),

            'V' => VerticalLine(Absolute, parameters),
            'v' => VerticalLine(Relative, parameters),

            'Q' => QuadraticCurve(Absolute, parameters),
            'q' => QuadraticCurve(Relative, parameters),

            'T' => SmoothQuadraticCurve(Absolute, parameters),
            't' => SmoothQuadraticCurve(Relative, parameters),

            'C' => CubicCurve(Absolute, parameters),
            'c' => CubicCurve(Relative, parameters),

            'S' => SmoothCubicCurve(Absolute, parameters),
            's' => SmoothCubicCurve(Relative, parameters),

            'A' => EllipticalArc(Absolute, parameters),
            'a' => EllipticalArc(Relative, parameters),

            'Z' | 'z' => Close,

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<Number>> {
        let mut parameters = Vec::new();
        loop {
            match try!(self.read_number()) {
                Some(number) => parameters.push(number),
                _ => break,
            }
            self.reader.consume_whitespace();
            self.reader.consume_char(',');
        }
        Ok(parameters)
    }

    pub fn read_number(&mut self) -> Result<Option<Number>> {
        self.reader.consume_whitespace();
        let number = self.reader.capture(|reader| reader.consume_number())
                                .and_then(|number| Some(String::from(number)));
        match number {
            Some(number) => match (&number).parse() {
                Ok(number) => Ok(Some(number)),
                _ => raise!(self, "failed to parse a number '{}'", number),
            },
            _ => Ok(None),
        }
    }
}

#[cfg(test)]
mod tests {
    use node::Value;
    use super::{Data, Parser};
    use super::super::Command::*;
    use super::super::Position::*;

    #[test]
    fn data_into_value() {
        let data = Data::new().line_to((1, 2)).cubic_curve_by((1, 2.5, 3, 4, 5, 6)).close();
        assert_eq!(Value::from(data).to_string(), "L1,2 c1,2.5,3,4,5,6 z");
    }

    #[test]
    fn data_parse() {
        let data = Data::parse("M1,2 l3,4").unwrap();
        assert_eq!(data.len(), 2);
        match data[0] {
            Move(Absolute, ref parameters) => assert_eq!(&parameters[..], &[1.0, 2.0]),
            _ => unreachable!(),
        }
        match data[1] {
            Line(Relative, ref parameters) => assert_eq!(&parameters[..], &[3.0, 4.0]),
            _ => unreachable!(),
        }
    }

    #[test]
    fn parser_read_command() {
        macro_rules! run(
            ($content:expr) => ({
                let mut parser = Parser::new($content);
                parser.read_command().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($content:expr, $command:ident, $position:ident, $parameters:expr) => (
                match run!($content) {
                    $command($position, parameters) => assert_eq!(&parameters[..], $parameters),
                    _ => unreachable!(),
                }
            );
            ($content:expr, $command:ident) => (
                match run!($content) {
                    $command => {},
                    _ => unreachable!(),
                }
            );
        );

        test!("M4,2", Move, Absolute, &[4.0, 2.0]);
        test!("m4,\n2", Move, Relative, &[4.0, 2.0]);

        test!("L7, 8  9", Line, Absolute, &[7.0, 8.0, 9.0]);
        test!("l 7,8 \n9", Line, Relative, &[7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLine, Absolute, &[6.0, 9.0]);
        test!("h6,  \t9", HorizontalLine, Relative, &[6.0, 9.0]);

        test!("V2.1,-3", VerticalLine, Absolute, &[2.1, -3.0]);
        test!("v\n2.1 -3", VerticalLine, Relative, &[2.1, -3.0]);

        test!("Q90.5 0", QuadraticCurve, Absolute, &[90.5, 0.0]);
        test!("q90.5\n, 0", QuadraticCurve, Relative, &[90.5, 0.0]);

        test!("T-1", SmoothQuadraticCurve, Absolute, &[-1.0]);
        test!("t -1", SmoothQuadraticCurve, Relative, &[-1.0]);

        test!("C0,1 0,2", CubicCurve, Absolute, &[0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CubicCurve, Relative, &[0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCubicCurve, Absolute, &[42.0, 0.0]);
        test!("s \t 42,0", SmoothCubicCurve, Relative, &[42.0, 0.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, &[2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, &[2.6, 0.0, -7.0]);

        test!("Z", Close);
        test!("z", Close);
    }

    #[test]
    fn parser_read_parameters() {
        macro_rules! test(
            ($content:expr, $parameters:expr) => ({
                let mut parser = Parser::new($content);
                let parameters = parser.read_parameters().unwrap();
                assert_eq!(&parameters[..], $parameters);
            });
        );

        test!("1,2 3,4 5 6.7", &[1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
        test!("4-3.1.3e2.4", &[4.0, -3.1, 0.3e2, 0.4]);
    }

    #[test]
    fn parser_read_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                assert_eq!(parser.read_number().unwrap().unwrap(), $value);
            });
        );

        test!("0.30000000000000004", 0.3);
        test!("1e-4", 1e-4);
        test!("-1E2", -1e2);
        test!("-0.00100E-002", -1e-5);
    }
}
<|endoftext|>


<commit_before>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! #![feature(async_await)]
//!
//! use futures::{FutureExt, TryStreamExt};
//! use tokio_postgres::{NoTls, Error, Row};
//!
//! # #[cfg(not(feature = "runtime"))] fn main() {}
//! # #[cfg(feature = "runtime")]
//! #[tokio::main] // By default, tokio_postgres uses the tokio crate as its runtime.
//! async fn main() -> Result<(), Error> {
//!     // Connect to the database.
//!     let (mut client, connection) =
//!         tokio_postgres::connect("host=localhost user=postgres", NoTls).await?;
//!
//!     // The connection object performs the actual communication with the database,
//!     // so spawn it off to run on its own.
//!     let connection = connection.map(|r| {
//!         if let Err(e) = r {
//!             eprintln!("connection error: {}", e);
//!         }
//!     });
//!     tokio::spawn(connection);
//!
//!     // Now we can prepare a simple statement that just returns its parameter.
//!     let stmt = client.prepare("SELECT $1::TEXT").await?;
//!
//!     // And then execute it, returning a Stream of Rows which we collect into a Vec.
//!     let rows: Vec<Row> = client
//!         .query(&stmt, &[&"hello world"])
//!         .try_collect()
//!         .await?;
//!
//!     // Now we can check that we got back the same string we sent over.
//!     let value: &str = rows[0].get(0);
//!     assert_eq!(value, "hello world");
//!
//!     Ok(())
//! }
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::future;
//! use std::future::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! fn pipelined_prepare(
//!     client: &mut Client,
//! ) -> impl Future<Output = Result<(Statement, Statement), Error>>
//! {
//!     future::try_join(
//!         client.prepare("SELECT * FROM foo"),
//!         client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)")
//!     )
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.4.0-rc.3")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]

pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::portal::Portal;
pub use crate::row::{Row, SimpleQueryRow};
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use crate::transaction::Transaction;
pub use statement::{Column, Statement};

mod bind;
#[cfg(feature = "runtime")]
mod cancel_query;
mod cancel_query_raw;
mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
mod copy_in;
mod copy_out;
pub mod error;
mod maybe_tls_stream;
mod portal;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
mod transaction;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: config/struct.Config.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    return config.connect(tls).await;
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
    #[doc(hidden)]
    __NonExhaustive,
}

/// Message returned by the `SimpleQuery` stream.
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
    #[doc(hidden)]
    __NonExhaustive,
}
<commit_msg>Remove workaround<commit_after>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! #![feature(async_await)]
//!
//! use futures::{FutureExt, TryStreamExt};
//! use tokio_postgres::{NoTls, Error, Row};
//!
//! # #[cfg(not(feature = "runtime"))] fn main() {}
//! # #[cfg(feature = "runtime")]
//! #[tokio::main] // By default, tokio_postgres uses the tokio crate as its runtime.
//! async fn main() -> Result<(), Error> {
//!     // Connect to the database.
//!     let (mut client, connection) =
//!         tokio_postgres::connect("host=localhost user=postgres", NoTls).await?;
//!
//!     // The connection object performs the actual communication with the database,
//!     // so spawn it off to run on its own.
//!     let connection = connection.map(|r| {
//!         if let Err(e) = r {
//!             eprintln!("connection error: {}", e);
//!         }
//!     });
//!     tokio::spawn(connection);
//!
//!     // Now we can prepare a simple statement that just returns its parameter.
//!     let stmt = client.prepare("SELECT $1::TEXT").await?;
//!
//!     // And then execute it, returning a Stream of Rows which we collect into a Vec.
//!     let rows: Vec<Row> = client
//!         .query(&stmt, &[&"hello world"])
//!         .try_collect()
//!         .await?;
//!
//!     // Now we can check that we got back the same string we sent over.
//!     let value: &str = rows[0].get(0);
//!     assert_eq!(value, "hello world");
//!
//!     Ok(())
//! }
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::future;
//! use std::future::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! fn pipelined_prepare(
//!     client: &mut Client,
//! ) -> impl Future<Output = Result<(Statement, Statement), Error>>
//! {
//!     future::try_join(
//!         client.prepare("SELECT * FROM foo"),
//!         client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)")
//!     )
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.4.0-rc.3")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]

pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::portal::Portal;
pub use crate::row::{Row, SimpleQueryRow};
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use crate::transaction::Transaction;
pub use statement::{Column, Statement};

mod bind;
#[cfg(feature = "runtime")]
mod cancel_query;
mod cancel_query_raw;
mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
mod copy_in;
mod copy_out;
pub mod error;
mod maybe_tls_stream;
mod portal;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
mod transaction;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: config/struct.Config.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    config.connect(tls).await
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
    #[doc(hidden)]
    __NonExhaustive,
}

/// Message returned by the `SimpleQuery` stream.
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
    #[doc(hidden)]
    __NonExhaustive,
}
<|endoftext|>


<commit_before>// UNKNOWN accessiblity
const UNKNOWN: i8 = -1;

// FOOT_FORBIDDEN that no pedestrian is allowed
const FOOT_FORBIDDEN: i8 = 0;
// FOOT_ALLOWED pedestrians are allowed in both directions
const FOOT_ALLOWED: i8 = 1;

// CAR_FORBIDDEN no car is allowed
const CAR_FORBIDDEN: i8 = 0;
// CAR_RESIDENTIAL http://wiki.openstreetmap.org/wiki/Tag:highway%3Dresidential
const CAR_RESIDENTIAL: i8 = 1;
// CAR_TERTIARY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dtertiary
const CAR_TERTIARY: i8 = 2;
// CAR_SECONDARY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dsecondary
const CAR_SECONDARY: i8 = 3;
// car_forward http://wiki.http://wiki.openstreetmap.org/wiki/Tag:highway%3Dprimary
const CAR_PRIMARY: i8 = 4;
// CAR_TRUNK http://wiki.openstreetmap.org/wiki/Tag:highway%3Dtrunk
const CAR_TRUNK: i8 = 5;
// CAR_MOTORWAY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dmotorway
const CAR_MOTORWAY: i8 = 6;

// BIKE_FORBIDDEN BIKE_ can not use this edge
const BIKE_FORBIDDEN: i8 = 0;
// BIKE_ALLOWED means that it can be used by a BIKE_, but the traffic might be shared with CAR_s
const BIKE_ALLOWED: i8 = 2;
// BIKE_LANE is a narrow lane dedicated for BIKE_, without physical separation from other traffic
const BIKE_LANE: i8 = 3;
// BIKE_BUSWAY means that BIKE_s are allowed on the bus lane
const BIKE_BUSWAY: i8 = 4;
// BIKE_TRACK is a physically separated for any other traffic
const BIKE_TRACK: i8 = 5;

// Edgeself contains what mode can use the edge in each direction
#[derive(Clone, Copy)]
pub struct EdgeProperties {
    pub foot: i8,
    pub car_forward: i8,
    pub car_backward: i8,
    pub bike_forward: i8,
    pub bike_backward: i8,
}

impl EdgeProperties {
    pub fn new() -> EdgeProperties {
        EdgeProperties {
            foot: UNKNOWN,
            car_forward: UNKNOWN,
            car_backward: UNKNOWN,
            bike_forward: UNKNOWN,
            bike_backward: UNKNOWN,
        }
    }

    // Normalize fills UNKNOWN fields
    pub fn normalize(&mut self) {
        if self.car_backward == UNKNOWN {
            self.car_backward = self.car_forward;
        }
        if self.bike_backward == UNKNOWN {
            self.bike_backward = self.bike_forward;
        }
        if self.car_forward == UNKNOWN {
            self.car_forward = CAR_FORBIDDEN;
        }
        if self.bike_forward == UNKNOWN {
            self.bike_forward = BIKE_FORBIDDEN;
        }
        if self.car_backward == UNKNOWN {
            self.car_backward = CAR_FORBIDDEN;
        }
        if self.bike_backward == UNKNOWN {
            self.bike_backward = BIKE_FORBIDDEN;
        }
        if self.foot == UNKNOWN {
            self.foot = FOOT_FORBIDDEN;
        }
    }

    // Accessible means that at least one mean of transportation can use it in one direction
    pub fn accessible(&self) -> bool {
        self.bike_forward != BIKE_FORBIDDEN || self.bike_backward != BIKE_FORBIDDEN ||
        self.car_forward != CAR_FORBIDDEN || self.car_backward != CAR_FORBIDDEN ||
        self.foot != FOOT_FORBIDDEN
    }

    pub fn update(&mut self, key_string: String, val_string: String) {
        let key = key_string.as_str();
        let val = val_string.as_str();
        self.update_with_str(key, val);
    }

    pub fn update_with_str(&mut self, key: &str, val: &str) {
        match key {
            "highway" => {
                match val {
                    "cycleway" | "path" | "footway" | "steps" | "pedestrian" => {
                        self.bike_forward = BIKE_TRACK;
                        self.foot = FOOT_ALLOWED;
                    }
                    "primary" | "primary_link" => {
                        self.car_forward = CAR_PRIMARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "secondary" => {
                        self.car_forward = CAR_SECONDARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "tertiary" => {
                        self.car_forward = CAR_TERTIARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "unclassified" | "residential" | "living_street" | "road" | "service" |
                    "track" => {
                        self.car_forward = CAR_RESIDENTIAL;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "motorway" | "motorway_link" => {
                        self.car_forward = CAR_MOTORWAY;
                        self.foot = CAR_FORBIDDEN;
                        self.bike_forward = BIKE_FORBIDDEN;
                    }
                    "trunk" | "trunk_link" => {
                        self.car_forward = CAR_TRUNK;
                        self.foot = CAR_FORBIDDEN;
                        self.bike_forward = BIKE_FORBIDDEN;
                    }
                    _ => {}
                }
            }
            "pedestrian" | "foot" => {
                match val {
                    "no" => self.foot = FOOT_FORBIDDEN,
                    _ => self.foot = FOOT_ALLOWED,
                }
            }

            // http://wiki.openstreetmap.org/wiki/Cycleway
            // http://wiki.openstreetmap.org/wiki/Map_Features#Cycleway
            "cycleway" => {
                match val {
                    "track" => self.bike_forward = BIKE_TRACK,
                    "opposite_track" => self.bike_backward = BIKE_TRACK,
                    "opposite" => self.bike_backward = BIKE_ALLOWED,
                    "share_busway" => self.bike_forward = BIKE_BUSWAY,
                    "lane_left" | "opposite_lane" => self.bike_backward = BIKE_LANE,
                    _ => self.bike_forward = BIKE_LANE,
                }
            }

            "bicycle" => {
                match val {
                    "no" | "false" => self.bike_forward = BIKE_FORBIDDEN,
                    _ => self.bike_forward = BIKE_ALLOWED,
                }
            }
            "busway" => {
                match val {
                    "opposite_lane" | "opposite_track" => self.bike_backward = BIKE_BUSWAY,
                    _ => self.bike_forward = BIKE_BUSWAY,
                }
            }
            "oneway" => {
                match val {
                    "yes" | "true" | "1" => {
                        self.car_backward = CAR_FORBIDDEN;
                        if self.bike_backward == UNKNOWN {
                            self.bike_backward = BIKE_FORBIDDEN;
                        }
                    }
                    _ => {}
                }
            }
            "junction" => {
                match val {
                    "roundabout" => {
                        self.car_backward = CAR_FORBIDDEN;
                        if self.bike_backward == UNKNOWN {
                            self.bike_backward = BIKE_FORBIDDEN;
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

#[test]
fn test_accessible() {
    let mut p = EdgeProperties::new();
    p.normalize();
    assert!(!p.accessible());

    p.foot = FOOT_ALLOWED;
    assert!(p.accessible())
}

#[test]
fn test_normalize() {
    let mut p = EdgeProperties::new();
    p.bike_forward = BIKE_LANE;
    p.normalize();
    assert_eq!(BIKE_LANE, p.bike_backward);
    p.bike_forward = BIKE_ALLOWED;
    p.normalize();
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.car_forward = CAR_SECONDARY;
    p.car_backward = UNKNOWN;
    p.normalize();
    assert_eq!(CAR_SECONDARY, p.car_backward)
}

#[test]
fn test_update() {
    let mut p = EdgeProperties::new();
    p.update_with_str("highway", "secondary");
    assert_eq!(CAR_SECONDARY, p.car_forward);

    p.update_with_str("highway", "primary_link");
    assert_eq!(CAR_PRIMARY, p.car_forward);

    p.update_with_str("highway", "motorway");
    assert_eq!(CAR_MOTORWAY, p.car_forward);

    p.update_with_str("highway", "residential");
    assert_eq!(CAR_RESIDENTIAL, p.car_forward);

    p.update_with_str("highway", "tertiary");
    assert_eq!(CAR_TERTIARY, p.car_forward);

    p.update_with_str("highway", "trunk");
    assert_eq!(CAR_TRUNK, p.car_forward);

    p.update_with_str("highway", "cycleway");
    assert_eq!(BIKE_TRACK, p.bike_forward);
    assert_eq!(FOOT_ALLOWED, p.foot);

    p.update_with_str("foot", "designated");
    assert_eq!(FOOT_ALLOWED, p.foot);

    p.update_with_str("foot", "no");
    assert_eq!(FOOT_FORBIDDEN, p.foot);

    p.update_with_str("cycleway", "lane");
    assert_eq!(BIKE_LANE, p.bike_forward);

    p.update_with_str("cycleway", "track");
    assert_eq!(BIKE_TRACK, p.bike_forward);

    p.update_with_str("cycleway", "opposite_lane");
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.update_with_str("cycleway", "opposite_track");
    assert_eq!(BIKE_TRACK, p.bike_backward);

    p.update_with_str("cycleway", "opposite");
    assert_eq!(BIKE_ALLOWED, p.bike_backward);

    p.update_with_str("cycleway", "share_busway");
    assert_eq!(BIKE_BUSWAY, p.bike_forward);

    p.update_with_str("cycleway", "lane_left");
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.update_with_str("bicycle", "yes");
    assert_eq!(BIKE_ALLOWED, p.bike_forward);

    p.update_with_str("bicycle", "no");
    assert_eq!(BIKE_FORBIDDEN, p.bike_forward);

    p.update_with_str("busway", "yes");
    assert_eq!(BIKE_BUSWAY, p.bike_forward);

    p.update_with_str("busway", "opposite_track");
    assert_eq!(BIKE_BUSWAY, p.bike_backward);

    p.update_with_str("oneway", "yes");
    assert_eq!(BIKE_FORBIDDEN, p.car_backward);
    assert!(p.bike_backward != BIKE_FORBIDDEN);

    p.bike_backward = UNKNOWN;
    p.update_with_str("oneway", "yes");
    assert_eq!(BIKE_FORBIDDEN, p.bike_backward);

    p.update_with_str("junction", "roundabout");
    assert_eq!(BIKE_FORBIDDEN, p.car_backward);

    p.bike_backward = UNKNOWN;
    p.update_with_str("junction", "roundabout");
    assert_eq!(BIKE_FORBIDDEN, p.bike_backward);
}
<commit_msg>Fix small CAR/FOOT typo.<commit_after>// UNKNOWN accessiblity
const UNKNOWN: i8 = -1;

// FOOT_FORBIDDEN that no pedestrian is allowed
const FOOT_FORBIDDEN: i8 = 0;
// FOOT_ALLOWED pedestrians are allowed in both directions
const FOOT_ALLOWED: i8 = 1;

// CAR_FORBIDDEN no car is allowed
const CAR_FORBIDDEN: i8 = 0;
// CAR_RESIDENTIAL http://wiki.openstreetmap.org/wiki/Tag:highway%3Dresidential
const CAR_RESIDENTIAL: i8 = 1;
// CAR_TERTIARY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dtertiary
const CAR_TERTIARY: i8 = 2;
// CAR_SECONDARY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dsecondary
const CAR_SECONDARY: i8 = 3;
// car_forward http://wiki.http://wiki.openstreetmap.org/wiki/Tag:highway%3Dprimary
const CAR_PRIMARY: i8 = 4;
// CAR_TRUNK http://wiki.openstreetmap.org/wiki/Tag:highway%3Dtrunk
const CAR_TRUNK: i8 = 5;
// CAR_MOTORWAY http://wiki.openstreetmap.org/wiki/Tag:highway%3Dmotorway
const CAR_MOTORWAY: i8 = 6;

// BIKE_FORBIDDEN BIKE_ can not use this edge
const BIKE_FORBIDDEN: i8 = 0;
// BIKE_ALLOWED means that it can be used by a BIKE_, but the traffic might be shared with CAR_s
const BIKE_ALLOWED: i8 = 2;
// BIKE_LANE is a narrow lane dedicated for BIKE_, without physical separation from other traffic
const BIKE_LANE: i8 = 3;
// BIKE_BUSWAY means that BIKE_s are allowed on the bus lane
const BIKE_BUSWAY: i8 = 4;
// BIKE_TRACK is a physically separated for any other traffic
const BIKE_TRACK: i8 = 5;

// Edgeself contains what mode can use the edge in each direction
#[derive(Clone, Copy)]
pub struct EdgeProperties {
    pub foot: i8,
    pub car_forward: i8,
    pub car_backward: i8,
    pub bike_forward: i8,
    pub bike_backward: i8,
}

impl EdgeProperties {
    pub fn new() -> EdgeProperties {
        EdgeProperties {
            foot: UNKNOWN,
            car_forward: UNKNOWN,
            car_backward: UNKNOWN,
            bike_forward: UNKNOWN,
            bike_backward: UNKNOWN,
        }
    }

    // Normalize fills UNKNOWN fields
    pub fn normalize(&mut self) {
        if self.car_backward == UNKNOWN {
            self.car_backward = self.car_forward;
        }
        if self.bike_backward == UNKNOWN {
            self.bike_backward = self.bike_forward;
        }
        if self.car_forward == UNKNOWN {
            self.car_forward = CAR_FORBIDDEN;
        }
        if self.bike_forward == UNKNOWN {
            self.bike_forward = BIKE_FORBIDDEN;
        }
        if self.car_backward == UNKNOWN {
            self.car_backward = CAR_FORBIDDEN;
        }
        if self.bike_backward == UNKNOWN {
            self.bike_backward = BIKE_FORBIDDEN;
        }
        if self.foot == UNKNOWN {
            self.foot = FOOT_FORBIDDEN;
        }
    }

    // Accessible means that at least one mean of transportation can use it in one direction
    pub fn accessible(&self) -> bool {
        self.bike_forward != BIKE_FORBIDDEN || self.bike_backward != BIKE_FORBIDDEN ||
        self.car_forward != CAR_FORBIDDEN || self.car_backward != CAR_FORBIDDEN ||
        self.foot != FOOT_FORBIDDEN
    }

    pub fn update(&mut self, key_string: String, val_string: String) {
        let key = key_string.as_str();
        let val = val_string.as_str();
        self.update_with_str(key, val);
    }

    pub fn update_with_str(&mut self, key: &str, val: &str) {
        match key {
            "highway" => {
                match val {
                    "cycleway" | "path" | "footway" | "steps" | "pedestrian" => {
                        self.bike_forward = BIKE_TRACK;
                        self.foot = FOOT_ALLOWED;
                    }
                    "primary" | "primary_link" => {
                        self.car_forward = CAR_PRIMARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "secondary" => {
                        self.car_forward = CAR_SECONDARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "tertiary" => {
                        self.car_forward = CAR_TERTIARY;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "unclassified" | "residential" | "living_street" | "road" | "service" |
                    "track" => {
                        self.car_forward = CAR_RESIDENTIAL;
                        self.foot = FOOT_ALLOWED;
                        self.bike_forward = BIKE_ALLOWED;
                    }
                    "motorway" | "motorway_link" => {
                        self.car_forward = CAR_MOTORWAY;
                        self.foot = FOOT_FORBIDDEN;
                        self.bike_forward = BIKE_FORBIDDEN;
                    }
                    "trunk" | "trunk_link" => {
                        self.car_forward = CAR_TRUNK;
                        self.foot = FOOT_FORBIDDEN;
                        self.bike_forward = BIKE_FORBIDDEN;
                    }
                    _ => {}
                }
            }
            "pedestrian" | "foot" => {
                match val {
                    "no" => self.foot = FOOT_FORBIDDEN,
                    _ => self.foot = FOOT_ALLOWED,
                }
            }

            // http://wiki.openstreetmap.org/wiki/Cycleway
            // http://wiki.openstreetmap.org/wiki/Map_Features#Cycleway
            "cycleway" => {
                match val {
                    "track" => self.bike_forward = BIKE_TRACK,
                    "opposite_track" => self.bike_backward = BIKE_TRACK,
                    "opposite" => self.bike_backward = BIKE_ALLOWED,
                    "share_busway" => self.bike_forward = BIKE_BUSWAY,
                    "lane_left" | "opposite_lane" => self.bike_backward = BIKE_LANE,
                    _ => self.bike_forward = BIKE_LANE,
                }
            }

            "bicycle" => {
                match val {
                    "no" | "false" => self.bike_forward = BIKE_FORBIDDEN,
                    _ => self.bike_forward = BIKE_ALLOWED,
                }
            }
            "busway" => {
                match val {
                    "opposite_lane" | "opposite_track" => self.bike_backward = BIKE_BUSWAY,
                    _ => self.bike_forward = BIKE_BUSWAY,
                }
            }
            "oneway" => {
                match val {
                    "yes" | "true" | "1" => {
                        self.car_backward = CAR_FORBIDDEN;
                        if self.bike_backward == UNKNOWN {
                            self.bike_backward = BIKE_FORBIDDEN;
                        }
                    }
                    _ => {}
                }
            }
            "junction" => {
                match val {
                    "roundabout" => {
                        self.car_backward = CAR_FORBIDDEN;
                        if self.bike_backward == UNKNOWN {
                            self.bike_backward = BIKE_FORBIDDEN;
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

#[test]
fn test_accessible() {
    let mut p = EdgeProperties::new();
    p.normalize();
    assert!(!p.accessible());

    p.foot = FOOT_ALLOWED;
    assert!(p.accessible())
}

#[test]
fn test_normalize() {
    let mut p = EdgeProperties::new();
    p.bike_forward = BIKE_LANE;
    p.normalize();
    assert_eq!(BIKE_LANE, p.bike_backward);
    p.bike_forward = BIKE_ALLOWED;
    p.normalize();
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.car_forward = CAR_SECONDARY;
    p.car_backward = UNKNOWN;
    p.normalize();
    assert_eq!(CAR_SECONDARY, p.car_backward)
}

#[test]
fn test_update() {
    let mut p = EdgeProperties::new();
    p.update_with_str("highway", "secondary");
    assert_eq!(CAR_SECONDARY, p.car_forward);

    p.update_with_str("highway", "primary_link");
    assert_eq!(CAR_PRIMARY, p.car_forward);

    p.update_with_str("highway", "motorway");
    assert_eq!(CAR_MOTORWAY, p.car_forward);

    p.update_with_str("highway", "residential");
    assert_eq!(CAR_RESIDENTIAL, p.car_forward);

    p.update_with_str("highway", "tertiary");
    assert_eq!(CAR_TERTIARY, p.car_forward);

    p.update_with_str("highway", "trunk");
    assert_eq!(CAR_TRUNK, p.car_forward);

    p.update_with_str("highway", "cycleway");
    assert_eq!(BIKE_TRACK, p.bike_forward);
    assert_eq!(FOOT_ALLOWED, p.foot);

    p.update_with_str("foot", "designated");
    assert_eq!(FOOT_ALLOWED, p.foot);

    p.update_with_str("foot", "no");
    assert_eq!(FOOT_FORBIDDEN, p.foot);

    p.update_with_str("cycleway", "lane");
    assert_eq!(BIKE_LANE, p.bike_forward);

    p.update_with_str("cycleway", "track");
    assert_eq!(BIKE_TRACK, p.bike_forward);

    p.update_with_str("cycleway", "opposite_lane");
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.update_with_str("cycleway", "opposite_track");
    assert_eq!(BIKE_TRACK, p.bike_backward);

    p.update_with_str("cycleway", "opposite");
    assert_eq!(BIKE_ALLOWED, p.bike_backward);

    p.update_with_str("cycleway", "share_busway");
    assert_eq!(BIKE_BUSWAY, p.bike_forward);

    p.update_with_str("cycleway", "lane_left");
    assert_eq!(BIKE_LANE, p.bike_backward);

    p.update_with_str("bicycle", "yes");
    assert_eq!(BIKE_ALLOWED, p.bike_forward);

    p.update_with_str("bicycle", "no");
    assert_eq!(BIKE_FORBIDDEN, p.bike_forward);

    p.update_with_str("busway", "yes");
    assert_eq!(BIKE_BUSWAY, p.bike_forward);

    p.update_with_str("busway", "opposite_track");
    assert_eq!(BIKE_BUSWAY, p.bike_backward);

    p.update_with_str("oneway", "yes");
    assert_eq!(BIKE_FORBIDDEN, p.car_backward);
    assert!(p.bike_backward != BIKE_FORBIDDEN);

    p.bike_backward = UNKNOWN;
    p.update_with_str("oneway", "yes");
    assert_eq!(BIKE_FORBIDDEN, p.bike_backward);

    p.update_with_str("junction", "roundabout");
    assert_eq!(BIKE_FORBIDDEN, p.car_backward);

    p.bike_backward = UNKNOWN;
    p.update_with_str("junction", "roundabout");
    assert_eq!(BIKE_FORBIDDEN, p.bike_backward);
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io::prelude::*;

use atty;
use termcolor::Color::{Cyan, Green, Red, Yellow};
use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};

use util::errors::CargoResult;

/// The requested verbosity of output
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
/// color.
pub struct Shell {
    /// the `Write`able object, either with or without color support (represented by different enum
    /// variants)
    err: ShellOut,
    /// How verbose messages should be
    verbosity: Verbosity,
}

impl fmt::Debug for Shell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            ShellOut::Write(_) => f.debug_struct("Shell")
                .field("verbosity", &self.verbosity)
                .finish(),
            ShellOut::Stream { color_choice, .. } => f.debug_struct("Shell")
                .field("verbosity", &self.verbosity)
                .field("color_choice", &color_choice)
                .finish(),
        }
    }
}

/// A `Write`able object, either with or without color support
enum ShellOut {
    /// A plain write object without color support
    Write(Box<Write>),
    /// Color-enabled stdio, with information on whether color should be used
    Stream {
        stream: StandardStream,
        tty: bool,
        color_choice: ColorChoice,
    },
}

/// Whether messages should use color output
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorChoice {
    /// Force color output
    Always,
    /// Force disable color output
    Never,
    /// Intelligently guess whether to use color output
    CargoAuto,
}

impl Shell {
    /// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
    /// output.
    pub fn new() -> Shell {
        Shell {
            err: ShellOut::Stream {
                stream: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()),
                color_choice: ColorChoice::CargoAuto,
                tty: atty::is(atty::Stream::Stderr),
            },
            verbosity: Verbosity::Verbose,
        }
    }

    /// Create a shell from a plain writable object, with no color, and max verbosity.
    pub fn from_write(out: Box<Write>) -> Shell {
        Shell {
            err: ShellOut::Write(out),
            verbosity: Verbosity::Verbose,
        }
    }

    /// Print a message, where the status will have `color` color, and can be justified. The
    /// messages follows without color.
    fn print(
        &mut self,
        status: &fmt::Display,
        message: Option<&fmt::Display>,
        color: Color,
        justified: bool,
    ) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.err.print(status, message, color, justified),
        }
    }

    /// Returns the width of the terminal in spaces, if any
    pub fn err_width(&self) -> Option<usize> {
        match self.err {
            ShellOut::Stream { tty: true, .. } => imp::stderr_width(),
            _ => None,
        }
    }

    /// Returns whether stderr is a tty
    pub fn is_err_tty(&self) -> bool {
        match self.err {
            ShellOut::Stream { tty, .. } => tty,
            _ => false,
        }
    }

    /// Get a reference to the underlying writer
    pub fn err(&mut self) -> &mut Write {
        self.err.as_write()
    }

    /// Shortcut to right-align and color green a status message.
    pub fn status<T, U>(&mut self, status: T, message: U) -> CargoResult<()>
    where
        T: fmt::Display,
        U: fmt::Display,
    {
        self.print(&status, Some(&message), Green, true)
    }

    pub fn status_header<T>(&mut self, status: T) -> CargoResult<()>
    where
        T: fmt::Display,
    {
        self.print(&status, None, Cyan, true)
    }

    /// Shortcut to right-align a status message.
    pub fn status_with_color<T, U>(
        &mut self,
        status: T,
        message: U,
        color: Color,
    ) -> CargoResult<()>
    where
        T: fmt::Display,
        U: fmt::Display,
    {
        self.print(&status, Some(&message), color, true)
    }

    /// Run the callback only if we are in verbose mode
    pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut(&mut Shell) -> CargoResult<()>,
    {
        match self.verbosity {
            Verbosity::Verbose => callback(self),
            _ => Ok(()),
        }
    }

    /// Run the callback if we are not in verbose mode.
    pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut(&mut Shell) -> CargoResult<()>,
    {
        match self.verbosity {
            Verbosity::Verbose => Ok(()),
            _ => callback(self),
        }
    }

    /// Print a red 'error' message
    pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        self.print(&"error:", Some(&message), Red, false)
    }

    /// Print an amber 'warning' message
    pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.print(&"warning:", Some(&message), Yellow, false),
        }
    }

    /// Update the verbosity of the shell
    pub fn set_verbosity(&mut self, verbosity: Verbosity) {
        self.verbosity = verbosity;
    }

    /// Get the verbosity of the shell
    pub fn verbosity(&self) -> Verbosity {
        self.verbosity
    }

    /// Update the color choice (always, never, or auto) from a string.
    pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
        if let ShellOut::Stream {
            ref mut stream,
            ref mut color_choice,
            ..
        } = self.err
        {
            let cfg = match color {
                Some("always") => ColorChoice::Always,
                Some("never") => ColorChoice::Never,

                Some("auto") | None => ColorChoice::CargoAuto,

                Some(arg) => bail!(
                    "argument for --color must be auto, always, or \
                     never, but found `{}`",
                    arg
                ),
            };
            *color_choice = cfg;
            *stream = StandardStream::stderr(cfg.to_termcolor_color_choice());
        }
        Ok(())
    }

    /// Get the current color choice
    ///
    /// If we are not using a color stream, this will always return Never, even if the color choice
    /// has been set to something else.
    pub fn color_choice(&self) -> ColorChoice {
        match self.err {
            ShellOut::Stream { color_choice, .. } => color_choice,
            ShellOut::Write(_) => ColorChoice::Never,
        }
    }

    /// Whether the shell supports color.
    pub fn supports_color(&self) -> bool {
        match &self.err {
            ShellOut::Write(_) => false,
            ShellOut::Stream { stream, .. } => stream.supports_color(),
        }
    }

    /// Prints a message and translates ANSI escape code into console colors.
    pub fn print_ansi(&mut self, message: &[u8]) -> CargoResult<()> {
        #[cfg(windows)]
        {
            if let ShellOut::Stream { stream, .. } = &mut self.err {
                ::fwdansi::write_ansi(stream, message)?;
                return Ok(());
            }
        }
        self.err().write_all(message)?;
        Ok(())
    }
}

impl Default for Shell {
    fn default() -> Self {
        Self::new()
    }
}

impl ShellOut {
    /// Print out a message with a status. The status comes first and is bold + the given color.
    /// The status can be justified, in which case the max width that will right align is 12 chars.
    fn print(
        &mut self,
        status: &fmt::Display,
        message: Option<&fmt::Display>,
        color: Color,
        justified: bool,
    ) -> CargoResult<()> {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => {
                stream.reset()?;
                stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?;
                if justified {
                    write!(stream, "{:>12}", status)?;
                } else {
                    write!(stream, "{}", status)?;
                }
                stream.reset()?;
                match message {
                    Some(message) => writeln!(stream, " {}", message)?,
                    None => write!(stream, " ")?,
                }
            }
            ShellOut::Write(ref mut w) => {
                if justified {
                    write!(w, "{:>12}", status)?;
                } else {
                    write!(w, "{}", status)?;
                }
                match message {
                    Some(message) => writeln!(w, " {}", message)?,
                    None => write!(w, " ")?,
                }
            }
        }
        Ok(())
    }

    /// Get this object as a `io::Write`.
    fn as_write(&mut self) -> &mut Write {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => stream,
            ShellOut::Write(ref mut w) => w,
        }
    }
}

impl ColorChoice {
    /// Convert our color choice to termcolor's version
    fn to_termcolor_color_choice(self) -> termcolor::ColorChoice {
        match self {
            ColorChoice::Always => termcolor::ColorChoice::Always,
            ColorChoice::Never => termcolor::ColorChoice::Never,
            ColorChoice::CargoAuto => {
                if atty::is(atty::Stream::Stderr) {
                    termcolor::ColorChoice::Auto
                } else {
                    termcolor::ColorChoice::Never
                }
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
mod imp {
    use std::mem;

    use libc;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let mut winsize: libc::winsize = mem::zeroed();
            if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ, &mut winsize) < 0 {
                return None;
            }
            if winsize.ws_col > 0 {
                Some(winsize.ws_col as usize)
            } else {
                None
            }
        }
    }
}

#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
mod imp {
    pub fn stderr_width() -> Option<usize> {
        None
    }
}

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

    use std::mem;
    use self::winapi::um::processenv::*;
    use self::winapi::um::winbase::*;
    use self::winapi::um::wincon::*;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let stdout = GetStdHandle(STD_ERROR_HANDLE);
            let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
            if GetConsoleScreenBufferInfo(stdout, &mut csbi) == 0 {
                return None;
            }
            Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize)
        }
    }
}
<commit_msg>Auto merge of #6010 - ehuss:winsize, r=alexcrichton<commit_after>use std::fmt;
use std::io::prelude::*;

use atty;
use termcolor::Color::{Cyan, Green, Red, Yellow};
use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};

use util::errors::CargoResult;

/// The requested verbosity of output
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
/// color.
pub struct Shell {
    /// the `Write`able object, either with or without color support (represented by different enum
    /// variants)
    err: ShellOut,
    /// How verbose messages should be
    verbosity: Verbosity,
}

impl fmt::Debug for Shell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            ShellOut::Write(_) => f.debug_struct("Shell")
                .field("verbosity", &self.verbosity)
                .finish(),
            ShellOut::Stream { color_choice, .. } => f.debug_struct("Shell")
                .field("verbosity", &self.verbosity)
                .field("color_choice", &color_choice)
                .finish(),
        }
    }
}

/// A `Write`able object, either with or without color support
enum ShellOut {
    /// A plain write object without color support
    Write(Box<Write>),
    /// Color-enabled stdio, with information on whether color should be used
    Stream {
        stream: StandardStream,
        tty: bool,
        color_choice: ColorChoice,
    },
}

/// Whether messages should use color output
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorChoice {
    /// Force color output
    Always,
    /// Force disable color output
    Never,
    /// Intelligently guess whether to use color output
    CargoAuto,
}

impl Shell {
    /// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
    /// output.
    pub fn new() -> Shell {
        Shell {
            err: ShellOut::Stream {
                stream: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()),
                color_choice: ColorChoice::CargoAuto,
                tty: atty::is(atty::Stream::Stderr),
            },
            verbosity: Verbosity::Verbose,
        }
    }

    /// Create a shell from a plain writable object, with no color, and max verbosity.
    pub fn from_write(out: Box<Write>) -> Shell {
        Shell {
            err: ShellOut::Write(out),
            verbosity: Verbosity::Verbose,
        }
    }

    /// Print a message, where the status will have `color` color, and can be justified. The
    /// messages follows without color.
    fn print(
        &mut self,
        status: &fmt::Display,
        message: Option<&fmt::Display>,
        color: Color,
        justified: bool,
    ) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.err.print(status, message, color, justified),
        }
    }

    /// Returns the width of the terminal in spaces, if any
    pub fn err_width(&self) -> Option<usize> {
        match self.err {
            ShellOut::Stream { tty: true, .. } => imp::stderr_width(),
            _ => None,
        }
    }

    /// Returns whether stderr is a tty
    pub fn is_err_tty(&self) -> bool {
        match self.err {
            ShellOut::Stream { tty, .. } => tty,
            _ => false,
        }
    }

    /// Get a reference to the underlying writer
    pub fn err(&mut self) -> &mut Write {
        self.err.as_write()
    }

    /// Shortcut to right-align and color green a status message.
    pub fn status<T, U>(&mut self, status: T, message: U) -> CargoResult<()>
    where
        T: fmt::Display,
        U: fmt::Display,
    {
        self.print(&status, Some(&message), Green, true)
    }

    pub fn status_header<T>(&mut self, status: T) -> CargoResult<()>
    where
        T: fmt::Display,
    {
        self.print(&status, None, Cyan, true)
    }

    /// Shortcut to right-align a status message.
    pub fn status_with_color<T, U>(
        &mut self,
        status: T,
        message: U,
        color: Color,
    ) -> CargoResult<()>
    where
        T: fmt::Display,
        U: fmt::Display,
    {
        self.print(&status, Some(&message), color, true)
    }

    /// Run the callback only if we are in verbose mode
    pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut(&mut Shell) -> CargoResult<()>,
    {
        match self.verbosity {
            Verbosity::Verbose => callback(self),
            _ => Ok(()),
        }
    }

    /// Run the callback if we are not in verbose mode.
    pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut(&mut Shell) -> CargoResult<()>,
    {
        match self.verbosity {
            Verbosity::Verbose => Ok(()),
            _ => callback(self),
        }
    }

    /// Print a red 'error' message
    pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        self.print(&"error:", Some(&message), Red, false)
    }

    /// Print an amber 'warning' message
    pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.print(&"warning:", Some(&message), Yellow, false),
        }
    }

    /// Update the verbosity of the shell
    pub fn set_verbosity(&mut self, verbosity: Verbosity) {
        self.verbosity = verbosity;
    }

    /// Get the verbosity of the shell
    pub fn verbosity(&self) -> Verbosity {
        self.verbosity
    }

    /// Update the color choice (always, never, or auto) from a string.
    pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
        if let ShellOut::Stream {
            ref mut stream,
            ref mut color_choice,
            ..
        } = self.err
        {
            let cfg = match color {
                Some("always") => ColorChoice::Always,
                Some("never") => ColorChoice::Never,

                Some("auto") | None => ColorChoice::CargoAuto,

                Some(arg) => bail!(
                    "argument for --color must be auto, always, or \
                     never, but found `{}`",
                    arg
                ),
            };
            *color_choice = cfg;
            *stream = StandardStream::stderr(cfg.to_termcolor_color_choice());
        }
        Ok(())
    }

    /// Get the current color choice
    ///
    /// If we are not using a color stream, this will always return Never, even if the color choice
    /// has been set to something else.
    pub fn color_choice(&self) -> ColorChoice {
        match self.err {
            ShellOut::Stream { color_choice, .. } => color_choice,
            ShellOut::Write(_) => ColorChoice::Never,
        }
    }

    /// Whether the shell supports color.
    pub fn supports_color(&self) -> bool {
        match &self.err {
            ShellOut::Write(_) => false,
            ShellOut::Stream { stream, .. } => stream.supports_color(),
        }
    }

    /// Prints a message and translates ANSI escape code into console colors.
    pub fn print_ansi(&mut self, message: &[u8]) -> CargoResult<()> {
        #[cfg(windows)]
        {
            if let ShellOut::Stream { stream, .. } = &mut self.err {
                ::fwdansi::write_ansi(stream, message)?;
                return Ok(());
            }
        }
        self.err().write_all(message)?;
        Ok(())
    }
}

impl Default for Shell {
    fn default() -> Self {
        Self::new()
    }
}

impl ShellOut {
    /// Print out a message with a status. The status comes first and is bold + the given color.
    /// The status can be justified, in which case the max width that will right align is 12 chars.
    fn print(
        &mut self,
        status: &fmt::Display,
        message: Option<&fmt::Display>,
        color: Color,
        justified: bool,
    ) -> CargoResult<()> {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => {
                stream.reset()?;
                stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?;
                if justified {
                    write!(stream, "{:>12}", status)?;
                } else {
                    write!(stream, "{}", status)?;
                }
                stream.reset()?;
                match message {
                    Some(message) => writeln!(stream, " {}", message)?,
                    None => write!(stream, " ")?,
                }
            }
            ShellOut::Write(ref mut w) => {
                if justified {
                    write!(w, "{:>12}", status)?;
                } else {
                    write!(w, "{}", status)?;
                }
                match message {
                    Some(message) => writeln!(w, " {}", message)?,
                    None => write!(w, " ")?,
                }
            }
        }
        Ok(())
    }

    /// Get this object as a `io::Write`.
    fn as_write(&mut self) -> &mut Write {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => stream,
            ShellOut::Write(ref mut w) => w,
        }
    }
}

impl ColorChoice {
    /// Convert our color choice to termcolor's version
    fn to_termcolor_color_choice(self) -> termcolor::ColorChoice {
        match self {
            ColorChoice::Always => termcolor::ColorChoice::Always,
            ColorChoice::Never => termcolor::ColorChoice::Never,
            ColorChoice::CargoAuto => {
                if atty::is(atty::Stream::Stderr) {
                    termcolor::ColorChoice::Auto
                } else {
                    termcolor::ColorChoice::Never
                }
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
mod imp {
    use std::mem;

    use libc;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let mut winsize: libc::winsize = mem::zeroed();
            if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ, &mut winsize) < 0 {
                return None;
            }
            if winsize.ws_col > 0 {
                Some(winsize.ws_col as usize)
            } else {
                None
            }
        }
    }
}

#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
mod imp {
    pub fn stderr_width() -> Option<usize> {
        None
    }
}

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

    use std::mem;
    use std::ptr;
    use self::winapi::um::fileapi::*;
    use self::winapi::um::handleapi::*;
    use self::winapi::um::processenv::*;
    use self::winapi::um::winbase::*;
    use self::winapi::um::wincon::*;
    use self::winapi::um::winnt::*;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let stdout = GetStdHandle(STD_ERROR_HANDLE);
            let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
            if GetConsoleScreenBufferInfo(stdout, &mut csbi) != 0 {
                return Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize)
            }

            // On mintty/msys/cygwin based terminals, the above fails with
            // INVALID_HANDLE_VALUE. Use an alternate method which works
            // in that case as well.
            let h = CreateFileA("CONOUT$\0".as_ptr() as *const CHAR,
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                ptr::null_mut(),
                OPEN_EXISTING,
                0,
                ptr::null_mut()
            );
            if h == INVALID_HANDLE_VALUE {
                return None;
            }

            let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
            let rc = GetConsoleScreenBufferInfo(h, &mut csbi);
            CloseHandle(h);
            if rc != 0 {
                let width = (csbi.srWindow.Right - csbi.srWindow.Left) as usize;
                // Some terminals, such as mintty, always return 79 instead of
                // the actual width. In that case, use a conservative value.
                if width == 79 {
                    return Some(60);
                } else {
                    return Some(width);
                }
            }
            return None;
        }
    }
}
<|endoftext|>


<commit_before>
use wca::*;
use wtest_basic::*;
use std::collections::HashMap;

//

fn _basic()
{
  let instruction = instruction::instruction_parse()
  .instruction( "" )
  .perform();
  let exp = instruction::Instruction
  {
    err : Some( wtools::error::Error::new( "Invalid command" ) ),
    command_name : "".to_string(),
    subject : "".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get" )
  .perform();
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some" )
  .perform();
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1" )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  /* */

  let aggregator_map = HashMap::new();
  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .properties_map( aggregator_map )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  let mut aggregator_map = HashMap::new();
  aggregator_map.insert( "ne".to_string(), "-2".to_string() );
  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .properties_map( aggregator_map )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  properties_map.insert( "ne".to_string(), "-2".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );
}

//

test_suite!
{
  basic,
}
<commit_msg>Extend test routine `basic` of instruction, add test case with command and option<commit_after>
use wca::*;
use wtest_basic::*;
use std::collections::HashMap;

//

fn _basic()
{
  let instruction = instruction::instruction_parse()
  .instruction( "" )
  .perform();
  let exp = instruction::Instruction
  {
    err : Some( wtools::error::Error::new( "Invalid command" ) ),
    command_name : "".to_string(),
    subject : "".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get" )
  .perform();
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some" )
  .perform();
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map : HashMap::new(),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get v:1" )
  .perform();
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "".to_string(),
    properties_map : HashMap::from([ ( "v".to_string(), "1".to_string() ) ]),
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1" )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  /* */

  let aggregator_map = HashMap::new();
  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .properties_map( aggregator_map )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );

  let mut aggregator_map = HashMap::new();
  aggregator_map.insert( "ne".to_string(), "-2".to_string() );
  let instruction = instruction::instruction_parse()
  .instruction( ".get some v:1 routine:some" )
  .properties_map( aggregator_map )
  .perform();
  let mut properties_map = HashMap::new();
  properties_map.insert( "v".to_string(), "1".to_string() );
  properties_map.insert( "routine".to_string(), "some".to_string() );
  properties_map.insert( "ne".to_string(), "-2".to_string() );
  let exp = instruction::Instruction
  {
    err : None,
    command_name : ".get".to_string(),
    subject : "some".to_string(),
    properties_map,
  };
  assert_eq!( instruction, exp );
}

//

test_suite!
{
  basic,
}
<|endoftext|>