<commit_before>use csv;

use CliResult;
use config::{Config, Delimiter};
use util;

static USAGE: &'static str = "
Formats CSV data with a custom delimiter or CRLF line endings.

Generally, all commands in xsv output CSV data in a default format, which is
the same as the default format for reading CSV data. This makes it easy to
pipe multiple xsv commands together. However, you may want the final result to
have a specific delimiter or record separator, and this is where 'xsv fmt' is
useful.

Usage:
    xsv fmt [options] [<input>]

fmt options:
    -t, --out-delimiter <arg>  The field delimiter for writing CSV data.
                               [default: ,]
    --crlf                     Use '\\r\\n' line endings in the output.
    --ascii                    Use ASCII field and record separators.
    --quote <arg>              The quote character to use. [default: \"]
    --quote-always             Put quotes around every value.
    --escape <arg>             The escape character to use. When not specified,
                               quotes are escaped by doubling them.

Common options:
    -h, --help             Display this message
    -o, --output <file>    Write output to <file> instead of stdout.
    -d, --delimiter <arg>  The field delimiter for reading CSV data.
                           Must be a single character. [default: ,]
";

#[derive(RustcDecodable)]
struct Args {
    arg_input: Option<String>,
    flag_out_delimiter: Option<Delimiter>,
    flag_crlf: bool,
    flag_ascii: bool,
    flag_output: Option<String>,
    flag_delimiter: Option<Delimiter>,
    flag_quote: Delimiter,
    flag_quote_always: bool,
    flag_escape: Option<Delimiter>,
}

pub fn run(argv: &[&str]) -> CliResult<()> {
    let args: Args = util::get_args(USAGE, argv)?;

    let rconfig = Config::new(&args.arg_input)
        .delimiter(args.flag_delimiter)
        .no_headers(true);
    let mut wconfig = Config::new(&args.flag_output)
        .delimiter(args.flag_out_delimiter)
        .crlf(args.flag_crlf);

    if args.flag_ascii {
        wconfig = wconfig
            .delimiter(Some(Delimiter(b'\x1f')))
            .terminator(csv::Terminator::Any(b'\x1e'));
    }
    if args.flag_quote_always {
        wconfig = wconfig.quote_style(csv::QuoteStyle::Always);
    }
    if let Some(escape) = args.flag_escape {
        wconfig = wconfig.escape(Some(escape.as_byte())).double_quote(false);
    }
    wconfig = wconfig.quote(args.flag_quote.as_byte());

    let mut rdr = rconfig.reader()?;
    let mut wtr = wconfig.writer()?;
    let mut r = csv::ByteRecord::new();
    while rdr.read_byte_record(&mut r)? {
        wtr.write_byte_record(&r)?;
    }
    wtr.flush()?;
    Ok(())
}
<commit_msg>cmd/fmt: recognize tsv automatically<commit_after>use csv;

use CliResult;
use config::{Config, Delimiter};
use util;

static USAGE: &'static str = "
Formats CSV data with a custom delimiter or CRLF line endings.

Generally, all commands in xsv output CSV data in a default format, which is
the same as the default format for reading CSV data. This makes it easy to
pipe multiple xsv commands together. However, you may want the final result to
have a specific delimiter or record separator, and this is where 'xsv fmt' is
useful.

Usage:
    xsv fmt [options] [<input>]

fmt options:
    -t, --out-delimiter <arg>  The field delimiter for writing CSV data.
                               [default: ,]
    --crlf                     Use '\\r\\n' line endings in the output.
    --ascii                    Use ASCII field and record separators.
    --quote <arg>              The quote character to use. [default: \"]
    --quote-always             Put quotes around every value.
    --escape <arg>             The escape character to use. When not specified,
                               quotes are escaped by doubling them.

Common options:
    -h, --help             Display this message
    -o, --output <file>    Write output to <file> instead of stdout.
    -d, --delimiter <arg>  The field delimiter for reading CSV data.
                           Must be a single character. (default: ,)
";

#[derive(RustcDecodable)]
struct Args {
    arg_input: Option<String>,
    flag_out_delimiter: Option<Delimiter>,
    flag_crlf: bool,
    flag_ascii: bool,
    flag_output: Option<String>,
    flag_delimiter: Option<Delimiter>,
    flag_quote: Delimiter,
    flag_quote_always: bool,
    flag_escape: Option<Delimiter>,
}

pub fn run(argv: &[&str]) -> CliResult<()> {
    let args: Args = util::get_args(USAGE, argv)?;

    let rconfig = Config::new(&args.arg_input)
        .delimiter(args.flag_delimiter)
        .no_headers(true);
    let mut wconfig = Config::new(&args.flag_output)
        .delimiter(args.flag_out_delimiter)
        .crlf(args.flag_crlf);

    if args.flag_ascii {
        wconfig = wconfig
            .delimiter(Some(Delimiter(b'\x1f')))
            .terminator(csv::Terminator::Any(b'\x1e'));
    }
    if args.flag_quote_always {
        wconfig = wconfig.quote_style(csv::QuoteStyle::Always);
    }
    if let Some(escape) = args.flag_escape {
        wconfig = wconfig.escape(Some(escape.as_byte())).double_quote(false);
    }
    wconfig = wconfig.quote(args.flag_quote.as_byte());

    let mut rdr = rconfig.reader()?;
    let mut wtr = wconfig.writer()?;
    let mut r = csv::ByteRecord::new();
    while rdr.read_byte_record(&mut r)? {
        wtr.write_byte_record(&r)?;
    }
    wtr.flush()?;
    Ok(())
}
<|endoftext|>


<commit_before>///! State machine composition macros

#[macro_export]
macro_rules! rotor_compose_state_machines {
    (STRUCT_REPEAT $name:ident $context:ty [ $($name1:ident/$type1:ty)* ]
                               [ $($name2:ident/$type2:ty)* ]) => {
        mod scope {
            $(
                rotor_compose_state_machines!(SCOPE_STRUCT $name $name1);
            )*
        }
        rotor_compose_state_machines!(SCOPE_WRAPPER
            $name $context [ $({$name1 $type1})* ] [ $($name2/$type2)* ]);
    };
    (SCOPE_STRUCT $name:ident $cursub:ident) => {
        pub struct $cursub<'a, S: 'a>(pub &'a mut S);
    };
    (SCOPE_WRAPPER $name:ident $context:ty [ { $cursub:ident $curtyp:ty } ]
                               [ $($subname:ident / $subtype:ty)* ]) => {
        rotor_compose_state_machines!(SCOPE_IMPL
            $name $context { $cursub $curtyp } $($subname/$subtype)*);
    };
    (SCOPE_WRAPPER $name:ident $context:ty
        [ { $firstsub:ident $firsttyp:ty } $( { $tail:ident $tailtyp:ty } )* ]
        [ $($name2:ident/$type2:ty)* ]) => {
        rotor_compose_state_machines!(SCOPE_IMPL
            $name $context { $firstsub $firsttyp } $($name2/$type2)*);
        rotor_compose_state_machines!(SCOPE_WRAPPER
            $name $context [ $({ $tail $tailtyp })* ] [ $($name2/$type2)* ]);
    };
    (SCOPE_IMPL $name:ident $context:ty { $cursub:ident $curtyp:ty }
        $($subname:ident/$subtype:ty)*) => {
        impl<'a, S> $crate::Scope<$curtyp>
            for scope::$cursub<'a, S>
            where S: $crate::Scope<$name<$($subtype),*>> + 'a,
        {
            fn async_add_machine(&mut self, m: $curtyp) -> Result<(), $curtyp> {
                self.0.async_add_machine($name::$cursub(m))
                .map_err(|x| if let $name::$cursub(c) = x {
                    c
                } else {
                    unreachable!();
                })
            }
            fn add_timeout_ms(&mut self, delay: u64,
                t: <$curtyp as $crate::BaseMachine>::Timeout)
                -> Result<::mio::Timeout, ::mio::TimerError>
            {
                self.0.add_timeout_ms(delay, $name::$cursub(t))
            }
            fn clear_timeout(&mut self, timeout: ::mio::Timeout) -> bool {
                self.0.clear_timeout(timeout)
            }
            fn register<E: ?Sized>(&mut self, io: &E,
                interest: ::mio::EventSet, opt: ::mio::PollOpt)
                -> Result<(), ::std::io::Error>
                where E: ::mio::Evented
            {
                self.0.register(io, interest, opt)
            }
        }
    };
    ($name: ident <$context:ty>  { $( $subname:ident($subtype:ty), )* }) => {
        pub enum $name<$($subname),*> {
            $( $subname($subname) ),*
        }

        rotor_compose_state_machines!(STRUCT_REPEAT $name $context
            [ $($subname / $subtype)* ] [ $($subname / $subtype)* ]);

        impl $crate::BaseMachine for $name<$($subtype),*> {
            type Timeout = $name<$(
                <$subtype as $crate::BaseMachine>::Timeout
            ),*>;
        }
        impl $crate::EventMachine<$context> for $name<$($subtype),*> {
            fn ready<S>(self, events: ::mio::EventSet,
                context: &mut $context, scope: &mut S)
                -> Option<Self>
                where S: $crate::Scope<Self>
            {
                match self {
                    $(
                        $name::$subname(m)
                        => m.ready(events, context, &mut scope::$subname(scope))
                                               .map($name::$subname),
                    )*
                }
            }
            fn register<S>(&mut self, scope: &mut S)
                -> Result<(), ::std::io::Error>
                where S: $crate::Scope<Self>
            {
                match self {
                    $(
                        &mut $name::$subname(ref mut m)
                        => m.register(&mut scope::$subname(scope)),
                    )*
                }
            }
        }
    };
}
<commit_msg>Remove old and broken composition macro<commit_after><|endoftext|>


<commit_before>
use {
    AddColor,
    AddEllipse,
    AddImage,
    AddLine,
    AddPolygon,
    AddRectangle,
    AddTween,
    Borrowed,
    Color,
    ColorContext,
    EllipseContext,
    Field,
    Image,
    ImageRectangleContext,
    Line,
    LineContext,
    Matrix2d,
    PolygonContext,
    Rectangle,
    RectangleContext,
    TweenContext,
    Value,
};
use internal::{
    CanTransform,
    CanViewTransform,
    HasTransform,
    HasViewTransform,
};

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Clone for Context<'a> {
    #[inline(always)]
    fn clone(&self) -> Context<'static> {
        Context {
            base: self.base.clone(),
            transform: self.transform.clone(),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, Context<'a>, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value(value),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.base.get()
    }
}

impl<'a> CanViewTransform<'a, Context<'a>, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> Context<'a> {
        Context {
            base: Value(value),
            transform: Borrowed(self.transform.get()),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value(Matrix2d(
                [1.0, 0.0, 0.0,
                 0.0, 1.0, 0.0]
            )),
            transform: Value(Matrix2d(
                [1.0, 0.0, 0.0,
                 0.0, 1.0, 0.0]
            )),
        }
    }
}

#[test]
fn test_context() {
    use RelativeTransform2d;

    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        let &Matrix2d(transform) = d.transform.get();
        assert_eq!(transform[2], 30.0);
        assert_eq!(transform[5], 50.0);
    }

    let &Matrix2d(transform) = c.transform.get();
    assert_eq!(transform[2], 0.0);
    assert_eq!(transform[5], 0.0);

    let c = c.rot_deg(90.0);
    let &Matrix2d(transform) = c.transform.get();
    assert!((transform[0] - 0.0).abs() < 0.00001);
    assert!((transform[1] + 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    use RelativeTransform2d;

    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    let &Matrix2d(transform) = c.transform.get();
    assert!((transform[0] - 2.0).abs() < 0.00001);
    assert!((transform[4] - 3.0).abs() < 0.00001);
}

impl<'a> AddRectangle<'a, RectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([x, y, w, h])),
        }
    }
}

#[test]
fn test_rect() {
    let c = Context::new();
    let d = c.rect(0.0, 0.0, 100.0, 50.0);
    let &Rectangle(rect) = d.rect.get();
    assert_eq!(rect[2], 100.0);
}

impl<'a> AddColor<'a, ColorContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(Color([r, g, b, a])),
        }
    }
}

#[test]
fn test_rgba() {
    let c = Context::new();
    let d: ColorContext = c.rgba(1.0, 0.0, 0.0, 1.0);
    let &Color(color) = d.color.get();
    assert_eq!(color[0], 1.0);
}

impl<'a> AddEllipse<'a, EllipseContext<'a>> for Context<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([x, y, w, h])),
        }
    }
}

#[test]
fn test_ellipse() {
    let c = Context::new();
    let d: EllipseContext = c.ellipse(0.0, 0.0, 100.0, 100.0);
    let &Rectangle(rect) = d.rect.get();
    assert_eq!(rect[2], 100.0);
}

impl<'a, 'b> AddPolygon<'a, PolygonContext<'a, 'b>> for Context<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: &'b [f64]) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> AddImage<'a, ImageRectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn image(&'a self, image: Image) -> ImageRectangleContext<'a> {
        ImageRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([
                0.0,
                0.0,
                image.source_rect[2] as f64,
                image.source_rect[3] as f64
            ])),
            image: Value(image),
        }
    }
}

impl<'a> AddTween<'a, TweenContext<'a>> for Context<'a> {
    #[inline(always)]
    fn lerp(&'a self, tween_factor: f64) -> TweenContext<'a> {
        TweenContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            tween_factor: Value(tween_factor),
        }
    }
}

impl<'a> AddLine<'a, LineContext<'a>> for Context<'a> {
    #[inline(always)]
    fn line(&'a self, x1: f64, y1: f64, x2: f64, y2: f64) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Value(Line([x1, y1, x2, y2])),
        }
    }
}

<commit_msg>Using type alias for `Polygon` in `Context`<commit_after>
use {
    AddColor,
    AddEllipse,
    AddImage,
    AddLine,
    AddPolygon,
    AddRectangle,
    AddTween,
    Borrowed,
    Color,
    ColorContext,
    EllipseContext,
    Field,
    Image,
    ImageRectangleContext,
    Line,
    LineContext,
    Matrix2d,
    Polygon,
    PolygonContext,
    Rectangle,
    RectangleContext,
    TweenContext,
    Value,
};
use internal::{
    CanTransform,
    CanViewTransform,
    HasTransform,
    HasViewTransform,
};

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Clone for Context<'a> {
    #[inline(always)]
    fn clone(&self) -> Context<'static> {
        Context {
            base: self.base.clone(),
            transform: self.transform.clone(),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, Context<'a>, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value(value),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.base.get()
    }
}

impl<'a> CanViewTransform<'a, Context<'a>, Matrix2d> for Context<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> Context<'a> {
        Context {
            base: Value(value),
            transform: Borrowed(self.transform.get()),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value(Matrix2d(
                [1.0, 0.0, 0.0,
                 0.0, 1.0, 0.0]
            )),
            transform: Value(Matrix2d(
                [1.0, 0.0, 0.0,
                 0.0, 1.0, 0.0]
            )),
        }
    }
}

#[test]
fn test_context() {
    use RelativeTransform2d;

    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        let &Matrix2d(transform) = d.transform.get();
        assert_eq!(transform[2], 30.0);
        assert_eq!(transform[5], 50.0);
    }

    let &Matrix2d(transform) = c.transform.get();
    assert_eq!(transform[2], 0.0);
    assert_eq!(transform[5], 0.0);

    let c = c.rot_deg(90.0);
    let &Matrix2d(transform) = c.transform.get();
    assert!((transform[0] - 0.0).abs() < 0.00001);
    assert!((transform[1] + 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    use RelativeTransform2d;

    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    let &Matrix2d(transform) = c.transform.get();
    assert!((transform[0] - 2.0).abs() < 0.00001);
    assert!((transform[4] - 3.0).abs() < 0.00001);
}

impl<'a> AddRectangle<'a, RectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([x, y, w, h])),
        }
    }
}

#[test]
fn test_rect() {
    let c = Context::new();
    let d = c.rect(0.0, 0.0, 100.0, 50.0);
    let &Rectangle(rect) = d.rect.get();
    assert_eq!(rect[2], 100.0);
}

impl<'a> AddColor<'a, ColorContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(Color([r, g, b, a])),
        }
    }
}

#[test]
fn test_rgba() {
    let c = Context::new();
    let d: ColorContext = c.rgba(1.0, 0.0, 0.0, 1.0);
    let &Color(color) = d.color.get();
    assert_eq!(color[0], 1.0);
}

impl<'a> AddEllipse<'a, EllipseContext<'a>> for Context<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([x, y, w, h])),
        }
    }
}

#[test]
fn test_ellipse() {
    let c = Context::new();
    let d: EllipseContext = c.ellipse(0.0, 0.0, 100.0, 100.0);
    let &Rectangle(rect) = d.rect.get();
    assert_eq!(rect[2], 100.0);
}

impl<'a, 'b> AddPolygon<'a, PolygonContext<'a, 'b>> for Context<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: Polygon<'b>) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> AddImage<'a, ImageRectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn image(&'a self, image: Image) -> ImageRectangleContext<'a> {
        ImageRectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(Rectangle([
                0.0,
                0.0,
                image.source_rect[2] as f64,
                image.source_rect[3] as f64
            ])),
            image: Value(image),
        }
    }
}

impl<'a> AddTween<'a, TweenContext<'a>> for Context<'a> {
    #[inline(always)]
    fn lerp(&'a self, tween_factor: f64) -> TweenContext<'a> {
        TweenContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            tween_factor: Value(tween_factor),
        }
    }
}

impl<'a> AddLine<'a, LineContext<'a>> for Context<'a> {
    #[inline(always)]
    fn line(&'a self, x1: f64, y1: f64, x2: f64, y2: f64) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Value(Line([x1, y1, x2, y2])),
        }
    }
}

<|endoftext|>


<commit_before>use log::*;
use term;

pub use log::LogLevelFilter as Filter;

/// Writes log messages to standard output and standard error.
///
/// The enabled filter level can be customized by passing in a specific filter.
struct Logger(LogLevelFilter);

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.0
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            // Print with colors matching the level.
            match record.level() {
                LogLevel::Error => {
                    let mut t = term::stderr().unwrap();

                    t.attr(term::Attr::Bold).unwrap();
                    t.fg(term::color::BRIGHT_RED).unwrap();
                    write!(t, "error: ").unwrap();
                    t.fg(term::color::BRIGHT_WHITE).unwrap();
                    writeln!(t, "{}", record.args()).unwrap();
                    t.reset().unwrap();
                }
                LogLevel::Warn => {
                    let mut t = term::stderr().unwrap();

                    t.attr(term::Attr::Bold).unwrap();
                    t.fg(term::color::BRIGHT_YELLOW).unwrap();
                    write!(t, "warn: ").unwrap();
                    t.fg(term::color::BRIGHT_WHITE).unwrap();
                    writeln!(t, "{}", record.args()).unwrap();
                    t.reset().unwrap();
                }
                LogLevel::Info => {
                    let mut t = term::stdout().unwrap();

                    t.attr(term::Attr::Bold).unwrap();
                    t.fg(term::color::BRIGHT_GREEN).unwrap();
                    write!(t, "info: ").unwrap();
                    t.fg(term::color::BRIGHT_WHITE).unwrap();
                    writeln!(t, "{}", record.args()).unwrap();
                    t.reset().unwrap();
                }
                LogLevel::Debug => {
                    let mut t = term::stdout().unwrap();

                    t.fg(term::color::BRIGHT_BLUE).unwrap();
                    write!(t, "debug: ").unwrap();
                    t.reset().unwrap();
                    writeln!(t, "{}", record.args()).unwrap();
                }
                LogLevel::Trace => {
                    let mut t = term::stdout().unwrap();

                    t.attr(term::Attr::Bold).unwrap();
                    t.fg(term::color::BRIGHT_WHITE).unwrap();
                    write!(t, "trace: ").unwrap();
                    t.reset().unwrap();
                    writeln!(t, "{}", record.args()).unwrap();
                }
            }
        }
    }
}

/// Initializes the global logger with a given level filter.
pub fn init(level: LogLevelFilter) -> Result<(), SetLoggerError> {
    set_logger(|max_log_level| {
        max_log_level.set(level);
        Box::new(Logger(level))
    })
}
<commit_msg>Improve log formatting<commit_after>use log::*;
use term;

pub use log::LogLevelFilter as Filter;

/// Writes log messages to standard error.
///
/// The enabled filter level can be customized by passing in a specific filter.
struct Logger(LogLevelFilter);

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.0
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let mut err = term::stderr().expect("failed to open stderr");

            // Print with colors matching the level.
            match record.level() {
                LogLevel::Error => {
                    err.attr(term::Attr::Bold).ok();
                    err.fg(term::color::BRIGHT_RED).ok();
                    write!(err, "error: ").unwrap();

                    err.fg(term::color::BRIGHT_WHITE).ok();
                    writeln!(err, "{}", record.args()).unwrap();
                    err.reset().ok();
                }
                LogLevel::Warn => {
                    err.fg(term::color::BRIGHT_YELLOW).ok();
                    write!(err, "warn: ").unwrap();
                    err.reset().ok();

                    err.attr(term::Attr::Bold).ok();
                    err.fg(term::color::BRIGHT_WHITE).ok();
                    writeln!(err, "{}", record.args()).unwrap();
                    err.reset().ok();
                }
                LogLevel::Info => {
                    err.fg(term::color::BRIGHT_GREEN).ok();
                    write!(err, "info: ").unwrap();

                    err.fg(term::color::BRIGHT_WHITE).ok();
                    writeln!(err, "{}", record.args()).unwrap();
                    err.reset().ok();
                }
                LogLevel::Debug => {
                    err.fg(term::color::BRIGHT_BLUE).ok();
                    write!(err, "debug: ").unwrap();
                    err.reset().ok();

                    err.fg(term::color::BRIGHT_WHITE).ok();
                    writeln!(err, "{}", record.args()).unwrap();
                    err.reset().ok();
                }
                LogLevel::Trace => {
                    err.fg(term::color::BRIGHT_WHITE).ok();
                    writeln!(err, "trace: {}", record.args()).unwrap();
                    err.reset().ok();
                }
            }

            err.flush().unwrap();
        }
    }
}

/// Initializes the global logger with a given level filter.
pub fn init(level: LogLevelFilter) -> Result<(), SetLoggerError> {
    set_logger(|max_log_level| {
        max_log_level.set(level);
        Box::new(Logger(level))
    })
}
<|endoftext|>


<commit_before>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {} [{}/{}]", item.title, title, item.page, item.max_page));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item,
                   self.scrollY);
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

// fn display(vec: Vec<NodeType>, depth: u8) {
//     for (index, node) in vec.iter().enumerate() {
//         let node2 = node.clone();
//         let spaces = (0..depth).map(|_| ">").collect::<Vec<_>>().join("");
//         match node2 {
//             NodeType::Text(n) => {
//                 println!("{}[{}] = Text {}", spaces, index, n.data);
//             }
//             NodeType::Image(n) => {
//                 println!("{}[{}] = Image {}", spaces, index, n.data);
//             }
//             NodeType::BlockQuote(n) => {
//                 println!("{}[{}] = BlockQuote", spaces, index);
//                 display(n.data, depth + 1);
//             }
//             NodeType::Br(n) => {
//                 println!("{}[{}] = Br", spaces, index);
//             }
//         }
//     }
// }

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String){
    rustbox.print(0,
                  y,
                  rustbox::RB_NORMAL,
                  Color::White,
                  Color::Black,
                  &s);
}

fn print_reply(vec: &Vec<NodeType>, depth: u8, scrollY: usize, y: usize, rustbox: &rustbox::RustBox) -> usize {
    let padding = (0..depth).map(|_| ">").collect::<Vec<_>>().join("");
    let mut m = 0; let mut recursive_offset = 0; let mut total_y = 0;
    let mut line = String::new();

    // clean up lines
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter().rev().take(4).enumerate().all(|(j, node)| match node.clone() {
            NodeType::Br(n) => { j == 1 || j == 2 || j == 3 }
            NodeType::Text(n) => { j == 0  && n.data.is_empty() }
            _ => { false }
        } );

        let vec_short_length = if vec_length > 4 && is_last4_empty { vec_length - 4 } else { vec_length };

        vec.iter().take(vec_short_length)
    };

    for (j, node) in vec2.enumerate() {
        total_y = y + m + recursive_offset;
        if scrollY + 1 < total_y {
            let node2 = node.clone();
            match node2 {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                 }
                NodeType::Image(n) => {
                     print_default(rustbox, 0, total_y - scrollY, format!("{}[{}] = Image {}", padding, m, n.data));
                     m +=1;
                 }
                NodeType::BlockQuote(n) => {
                    print_default(rustbox, 0, total_y - scrollY, format!("{}[{}] = BlockQuote", padding, m));
                    m +=1;
                    recursive_offset += print_reply(&n.data, depth + 1, scrollY, total_y + 1, &rustbox);
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        print_default(rustbox, 0, total_y - scrollY, format!("{}{}", padding, line));
                        line = String::new();
                    }
                    m +=1;
                }
            }
        }
    }

    if !line.is_empty() {
        total_y = y + m + recursive_offset;
        print_default(rustbox, 0, total_y - scrollY, format!("{}{}  ", padding, line));
        line = String::new();
        m+=1;
    }

    m + recursive_offset
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem,
              scrollY: usize) {

    let mut y = offset_y;
    let replier_max_width = 14;
    let time_max_width = 5;
    let now = Local::now();

    let separator_width = if rustbox.width() >= 2 {
        rustbox.width() - 2
    } else {
        0
    };
    let separator_padding_width = if rustbox.width() > separator_width {
        rustbox.width() - separator_width
    } else {
        0
    } / 2;

    let separator_padding = (0..separator_padding_width).map(|_| " ").collect::<Vec<_>>().join("");

    let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

    for (i, reply) in item.replies.iter().take(rows).enumerate() {

        let mut m = print_reply(&reply.body, 0, scrollY, y, &rustbox);

        if scrollY + 1 < y + m {

            let replier_name = reply.username.clone();

            let published_at = reply.published_at.clone();

            let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
                Ok(v) => v,
                Err(e) => now,
            };
            let time = published_at_format(&(now - published_at_dt));

            let separator_top = make_separator_top(separator_width,
                                                   &separator_padding,
                                                   replier_max_width,
                                                   &replier_name,
                                                   time_max_width,
                                                   &time);

            rustbox.print(0,
                          m + y - scrollY,
                          rustbox::RB_NORMAL,
                          Color::Green,
                          Color::Black,
                          &separator_top);
        }
        m += 1;

        if scrollY + 1 < y + m {
            rustbox.print(0,
                          m + y - scrollY,
                          rustbox::RB_NORMAL,
                          Color::Green,
                          Color::Black,
                          &separator_bottom);
        }
        m += 1;
        y += m;
    }
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = (0..replier_name_left_spacing_width)
                                        .map(|_| "─")
                                        .collect::<Vec<_>>()
                                        .join("");

    let replier_name_right_spacing = (0..replier_name_right_spacing_width)
                                         .map(|_| "─")
                                         .collect::<Vec<_>>()
                                         .join("");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = (0..time_left_spacing_width)
                                .map(|_| "─")
                                .collect::<Vec<_>>()
                                .join("");

    let time_right_spacing = (0..time_right_spacing_width)
                                 .map(|_| "─")
                                 .collect::<Vec<_>>()
                                 .join("");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = (0..separator_top_middle_width)
                                   .map(|_| " ")
                                   .collect::<Vec<_>>()
                                   .join("");

    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = (0..separator_bottom_middle_width)
                                      .map(|_| "─")
                                      .collect::<Vec<_>>()
                                      .join("");
    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}
<commit_msg>show - reformat code<commit_after>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {} [{}/{}]",
                              item.title,
                              title,
                              item.page,
                              item.max_page));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item,
                   self.scrollY);
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String) {
    rustbox.print(0, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn print_reply(vec: &Vec<NodeType>,
               depth: u8,
               scrollY: usize,
               y: usize,
               rustbox: &rustbox::RustBox)
               -> usize {
    let padding = (0..depth).map(|_| ">").collect::<Vec<_>>().join("");
    let mut m = 0;
    let mut recursive_offset = 0;
    let mut total_y = 0;
    let mut line = String::new();

    // clean up lines
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    for (j, node) in vec2.enumerate() {
        total_y = y + m + recursive_offset;
        if scrollY + 1 < total_y {
            let node2 = node.clone();
            match node2 {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                }
                NodeType::Image(n) => {
                    print_default(rustbox,
                                  0,
                                  total_y - scrollY,
                                  format!("{}[{}] = Image {}", padding, m, n.data));
                    m += 1;
                }
                NodeType::BlockQuote(n) => {
                    print_default(rustbox,
                                  0,
                                  total_y - scrollY,
                                  format!("{}[{}] = BlockQuote", padding, m));
                    m += 1;
                    recursive_offset += print_reply(&n.data,
                                                    depth + 1,
                                                    scrollY,
                                                    total_y + 1,
                                                    &rustbox);
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        print_default(rustbox,
                                      0,
                                      total_y - scrollY,
                                      format!("{}{}", padding, line));
                        line = String::new();
                    }
                    m += 1;
                }
            }
        }
    }

    if !line.is_empty() {
        total_y = y + m + recursive_offset;
        print_default(rustbox,
                      0,
                      total_y - scrollY,
                      format!("{}{}  ", padding, line));
        line = String::new();
        m += 1;
    }

    m + recursive_offset
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem,
              scrollY: usize) {

    let mut y = offset_y;
    let replier_max_width = 14;
    let time_max_width = 5;
    let now = Local::now();

    let separator_width = if rustbox.width() >= 2 {
        rustbox.width() - 2
    } else {
        0
    };
    let separator_padding_width = if rustbox.width() > separator_width {
        rustbox.width() - separator_width
    } else {
        0
    } / 2;

    let separator_padding = (0..separator_padding_width).map(|_| " ").collect::<Vec<_>>().join("");

    let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

    for (i, reply) in item.replies.iter().take(rows).enumerate() {

        let mut m = print_reply(&reply.body, 0, scrollY, y, &rustbox);

        if scrollY + 1 < y + m {

            let replier_name = reply.username.clone();

            let published_at = reply.published_at.clone();

            let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
                Ok(v) => v,
                Err(e) => now,
            };
            let time = published_at_format(&(now - published_at_dt));

            let separator_top = make_separator_top(separator_width,
                                                   &separator_padding,
                                                   replier_max_width,
                                                   &replier_name,
                                                   time_max_width,
                                                   &time);

            rustbox.print(0,
                          m + y - scrollY,
                          rustbox::RB_NORMAL,
                          Color::Green,
                          Color::Black,
                          &separator_top);
        }
        m += 1;

        if scrollY + 1 < y + m {
            rustbox.print(0,
                          m + y - scrollY,
                          rustbox::RB_NORMAL,
                          Color::Green,
                          Color::Black,
                          &separator_bottom);
        }
        m += 1;
        y += m;
    }
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = (0..replier_name_left_spacing_width)
                                        .map(|_| "─")
                                        .collect::<Vec<_>>()
                                        .join("");

    let replier_name_right_spacing = (0..replier_name_right_spacing_width)
                                         .map(|_| "─")
                                         .collect::<Vec<_>>()
                                         .join("");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = (0..time_left_spacing_width)
                                .map(|_| "─")
                                .collect::<Vec<_>>()
                                .join("");

    let time_right_spacing = (0..time_right_spacing_width)
                                 .map(|_| "─")
                                 .collect::<Vec<_>>()
                                 .join("");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = (0..separator_top_middle_width)
                                   .map(|_| " ")
                                   .collect::<Vec<_>>()
                                   .join("");

    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = (0..separator_bottom_middle_width)
                                      .map(|_| "─")
                                      .collect::<Vec<_>>()
                                      .join("");
    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::default::Default;
use std::io::BufReader;
use std::path::Path;
use std::fs::File;
use std::sync::mpsc::{SyncSender, Receiver};
use std::sync::mpsc;
use std::marker::Send;
use std::thread;
use std::io::Cursor;
use self::mad_decoder_mode::* ;

#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: &mad_decoder,
                        message: &mad_message,
                        input_callback: extern fn(message: &mut mad_message, stream: isize) -> mad_flow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: &mut mad_message,
                                                   header: isize,
                                                   pcm: &mad_pcm) -> mad_flow,
                        error_callback: extern fn(),
                        message_callback: extern fn());
    fn mad_decoder_run(input: &mut mad_decoder, mode: mad_decoder_mode) -> i32;
    fn mad_stream_buffer(stream: isize, buf_start: *const u8, buf_length: usize);
}

#[repr(C)]
enum mad_flow {
    mf_continue = 0x0000,	/* continue normally */
    mf_stop     = 0x0010,	/* stop decoding normally */
    mf_break    = 0x0011,	/* stop decoding and signal an error */
    mf_ignore   = 0x0020	/* ignore the current frame */
}

#[repr(C)]
struct mad_pcm {
    sample_rate: u32,
    channels: u16,
    length: u16,
    samples: [[i32; 1152]; 2],
}

#[repr(C)]
struct mad_message<'a> {
    buffer: &'a mut [u8; 4096],
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Frame>,
}

#[repr(C)]
enum mad_decoder_mode {
    MAD_DECODER_MODE_SYNC = 0,
    MAD_DECODER_MODE_ASYNC
}

impl Default for mad_decoder_mode {
    fn default() -> mad_decoder_mode {MAD_DECODER_MODE_SYNC}
}

#[derive(Default)]
#[repr(C)]
struct mad_async_parameters {
    pid: u32,
    ain: isize,
    aout: isize,
}

#[derive(Default)]
#[repr(C)]
struct mad_decoder {
    mode: mad_decoder_mode,
    options: isize,
    async: mad_async_parameters,
    sync: usize,
    cb_data: usize,
    input_func: usize,
    header_func: usize,
    filter_func: usize,
    output_func: usize,
    error_func: usize,
    message_func: usize,
}

extern fn empty_callback() {

}

pub struct Frame {
    sample_rate: u32,
    channels: u16,
    length: u16,
    samples: [[i32; 1152]; 2],
}

pub fn decode<T>(mut reader: T) -> Receiver<Frame>
    where T: io::Read + Send + 'static {
    let (tx, rx) = mpsc::sync_channel::<Frame>(2);
    thread::spawn(move || {
        let mut input_buffer = [0u8; 4096];
        reader.read(&mut input_buffer);
        let message = &mut mad_message {
            buffer: &mut input_buffer,
            reader: &mut reader,
            sender: &tx,
        };
        let mut decoder: mad_decoder = Default::default();
        let mut decoding_result: i32 = 42;

        extern fn input_callback (msg: &mut mad_message, stream: isize) -> mad_flow {
            let read_result = msg.reader.read(msg.buffer).unwrap();
            unsafe {
                mad_stream_buffer(stream, msg.buffer.as_ptr(), msg.buffer.len());
            }

            if read_result == 0 {
                return mad_flow::mf_stop;
            }

            mad_flow::mf_continue
        }

        extern fn output_callback(msg: &mut mad_message,
                                  header: isize,
                                  pcm: &mad_pcm) -> mad_flow
        {
            msg.sender.send(Frame {sample_rate: pcm.sample_rate,
                                   channels: pcm.channels,
                                   length: pcm.length,
                                   samples: pcm.samples});
            mad_flow::mf_stop
        }

        unsafe {
            mad_decoder_init(&mut decoder,
                             message,
                             input_callback,
                             empty_callback,
                             empty_callback,
                             output_callback,
                             empty_callback,
                             empty_callback);
            mad_decoder_run(&mut decoder, mad_decoder_mode::MAD_DECODER_MODE_SYNC);
        }
    });
    rx
}

#[test]
fn test_open_file() {
    println!("");
    let path = Path::new("test_samples/fs-242.mp3");
    let f = File::open(&path).unwrap();
    let f_b = File::open(&path).unwrap();
    let reader_b = BufReader::new(f_b);
    let decoder = self::decode(f);
    let decoder_b = self::decode(reader_b);
    for frame in decoder.iter() {
        println!("Got frame: {}", frame.sample_rate);
    }

    for frame in decoder_b.iter() {
        println!("Got frame: {}", frame.sample_rate);
    }
    assert!(true);
}
<commit_msg>Fixed incorrect length parameter in input callback<commit_after>use std::io;
use std::io::Read;
use std::default::Default;
use std::io::BufReader;
use std::path::Path;
use std::fs::File;
use std::sync::mpsc::{SyncSender, Receiver};
use std::sync::mpsc;
use std::marker::Send;
use std::thread;
use std::io::Cursor;
use self::mad_decoder_mode::* ;

#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: &mad_decoder,
                        message: &mad_message,
                        input_callback: extern fn(message: &mut mad_message, stream: isize) -> mad_flow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: &mut mad_message,
                                                   header: isize,
                                                   pcm: &mad_pcm) -> mad_flow,
                        error_callback: extern fn(),
                        message_callback: extern fn());
    fn mad_decoder_run(input: &mut mad_decoder, mode: mad_decoder_mode) -> i32;
    fn mad_stream_buffer(stream: isize, buf_start: *const u8, buf_length: usize);
}

#[repr(C)]
enum mad_flow {
    mf_continue = 0x0000,	/* continue normally */
    mf_stop     = 0x0010,	/* stop decoding normally */
    mf_break    = 0x0011,	/* stop decoding and signal an error */
    mf_ignore   = 0x0020	/* ignore the current frame */
}

#[repr(C)]
struct mad_pcm {
    sample_rate: u32,
    channels: u16,
    length: u16,
    samples: [[i32; 1152]; 2],
}

#[repr(C)]
struct mad_message<'a> {
    buffer: &'a mut [u8; 4096],
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Frame>,
}

#[repr(C)]
enum mad_decoder_mode {
    MAD_DECODER_MODE_SYNC = 0,
    MAD_DECODER_MODE_ASYNC
}

impl Default for mad_decoder_mode {
    fn default() -> mad_decoder_mode {MAD_DECODER_MODE_SYNC}
}

#[derive(Default)]
#[repr(C)]
struct mad_async_parameters {
    pid: u32,
    ain: isize,
    aout: isize,
}

#[derive(Default)]
#[repr(C)]
struct mad_decoder {
    mode: mad_decoder_mode,
    options: isize,
    async: mad_async_parameters,
    sync: usize,
    cb_data: usize,
    input_func: usize,
    header_func: usize,
    filter_func: usize,
    output_func: usize,
    error_func: usize,
    message_func: usize,
}

extern fn empty_callback() {

}

pub struct Frame {
    sample_rate: u32,
    channels: u16,
    length: u16,
    samples: [[i32; 1152]; 2],
}

pub fn decode<T>(mut reader: T) -> Receiver<Frame>
    where T: io::Read + Send + 'static {
    let (tx, rx) = mpsc::sync_channel::<Frame>(2);
    thread::spawn(move || {
        let mut input_buffer = [0u8; 4096];
        reader.read(&mut input_buffer);
        let message = &mut mad_message {
            buffer: &mut input_buffer,
            reader: &mut reader,
            sender: &tx,
        };
        let mut decoder: mad_decoder = Default::default();
        let mut decoding_result: i32 = 42;

        extern fn input_callback (msg: &mut mad_message, stream: isize) -> mad_flow {
            let read_result = msg.reader.read(msg.buffer).unwrap();
            unsafe {
                mad_stream_buffer(stream, msg.buffer.as_ptr(), read_result);
            }

            if read_result == 0 {
                return mad_flow::mf_stop;
            }

            mad_flow::mf_continue
        }

        extern fn output_callback(msg: &mut mad_message,
                                  header: isize,
                                  pcm: &mad_pcm) -> mad_flow
        {
            msg.sender.send(Frame {sample_rate: pcm.sample_rate,
                                   channels: pcm.channels,
                                   length: pcm.length,
                                   samples: pcm.samples});
            mad_flow::mf_stop
        }

        unsafe {
            mad_decoder_init(&mut decoder,
                             message,
                             input_callback,
                             empty_callback,
                             empty_callback,
                             output_callback,
                             empty_callback,
                             empty_callback);
            mad_decoder_run(&mut decoder, mad_decoder_mode::MAD_DECODER_MODE_SYNC);
        }
    });
    rx
}

#[test]
fn test_open_file() {
    println!("");
    let path = Path::new("test_samples/fs-242.mp3");
    let f = File::open(&path).unwrap();
    let f_b = File::open(&path).unwrap();
    let reader_b = BufReader::new(f_b);
    let decoder = self::decode(f);
    let decoder_b = self::decode(reader_b);
    for frame in decoder.iter() {
        println!("Got frame: {}, {}, {}", frame.sample_rate, frame.channels, frame.length);
    }

    for frame in decoder_b.iter() {
        println!("Got frame: {}, {}, {}", frame.sample_rate, frame.channels, frame.length);
    }
    assert!(true);
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Processes that are directly spawned by shared mempool runtime initialization

use crate::{
    core_mempool::{CoreMempool, TimelineState},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{MempoolNetworkEvents, MempoolSyncMsg},
    shared_mempool::{
        tasks,
        types::{notify_subscribers, ScheduledBroadcast, SharedMempool, SharedMempoolNotification},
    },
    CommitNotification, ConsensusRequest, SubmissionStatus,
};
use ::network::protocols::network::Event;
use anyhow::Result;
use bounded_executor::BoundedExecutor;
use channel::diem_channel;
use diem_config::{config::PeerNetworkId, network_id::NodeNetworkId};
use diem_infallible::Mutex;
use diem_logger::prelude::*;
use diem_trace::prelude::*;
use diem_types::{on_chain_config::OnChainConfigPayload, transaction::SignedTransaction};
use futures::{
    channel::{mpsc, oneshot},
    stream::{select_all, FuturesUnordered},
    StreamExt,
};
use std::{
    ops::Deref,
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::{runtime::Handle, time::interval};
use tokio_stream::wrappers::IntervalStream;
use vm_validator::vm_validator::TransactionValidation;

/// Coordinator that handles inbound network events and outbound txn broadcasts.
pub(crate) async fn coordinator<V>(
    mut smp: SharedMempool<V>,
    executor: Handle,
    network_events: Vec<(NodeNetworkId, MempoolNetworkEvents)>,
    mut client_events: mpsc::Receiver<(
        SignedTransaction,
        oneshot::Sender<Result<SubmissionStatus>>,
    )>,
    mut consensus_requests: mpsc::Receiver<ConsensusRequest>,
    mut state_sync_requests: mpsc::Receiver<CommitNotification>,
    mut mempool_reconfig_events: diem_channel::Receiver<(), OnChainConfigPayload>,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Start
    ));
    let smp_events: Vec<_> = network_events
        .into_iter()
        .map(|(network_id, events)| events.map(move |e| (network_id.clone(), e)))
        .collect();
    let mut events = select_all(smp_events).fuse();
    let mempool = smp.mempool.clone();
    let mut scheduled_broadcasts = FuturesUnordered::new();

    // Use a BoundedExecutor to restrict only `workers_available` concurrent
    // worker tasks that can process incoming transactions.
    let workers_available = smp.config.shared_mempool_max_concurrent_inbound_syncs;
    let bounded_executor = BoundedExecutor::new(workers_available, executor.clone());

    loop {
        let _timer = counters::MAIN_LOOP.start_timer();
        ::futures::select! {
            (msg, callback) = client_events.select_next_some() => {
                trace_event!("mempool::client_event", {"txn", msg.sender(), msg.sequence_number()});
                // This timer measures how long it took for the bounded executor to *schedule* the
                // task.
                let _timer = counters::TASK_SPAWN_LATENCY
                    .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::SPAWN_LABEL])
                    .start_timer();
                // This timer measures how long it took for the task to go from scheduled to started.
                let task_start_timer = counters::TASK_SPAWN_LATENCY
                    .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::START_LABEL])
                    .start_timer();
                bounded_executor
                .spawn(tasks::process_client_transaction_submission(
                    smp.clone(),
                    msg,
                    callback,
                    task_start_timer,
                ))
                .await;
            },
            msg = consensus_requests.select_next_some() => {
                tasks::process_consensus_request(&mempool, msg).await;
            }
            msg = state_sync_requests.select_next_some() => {
                let _timer = counters::TASK_SPAWN_LATENCY
                    .with_label_values(&[counters::STATE_SYNC_EVENT_LABEL, counters::SPAWN_LABEL])
                    .start_timer();
                tokio::spawn(tasks::process_state_sync_request(mempool.clone(), msg));
            }
            config_update = mempool_reconfig_events.select_next_some() => {
                info!(LogSchema::event_log(LogEntry::ReconfigUpdate, LogEvent::Received));
                let _timer = counters::TASK_SPAWN_LATENCY
                    .with_label_values(&[counters::RECONFIG_EVENT_LABEL, counters::SPAWN_LABEL])
                    .start_timer();
                bounded_executor
                    .spawn(tasks::process_config_update(config_update, smp.validator.clone()))
                    .await;
            },
            (peer, backoff) = scheduled_broadcasts.select_next_some() => {
                tasks::execute_broadcast(peer, backoff, &mut smp, &mut scheduled_broadcasts, executor.clone());
            },
            (network_id, event) = events.select_next_some() => {
                handle_event(&executor, &bounded_executor, &mut scheduled_broadcasts, &mut smp, network_id, event).await;
            },
            complete => break,
        }
    }
    error!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Terminated
    ));
}

async fn handle_event<V>(
    executor: &Handle,
    bounded_executor: &BoundedExecutor,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    smp: &mut SharedMempool<V>,
    network_id: NodeNetworkId,
    event: Event<MempoolSyncMsg>,
) where
    V: TransactionValidation,
{
    match event {
        Event::NewPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["new_peer".to_string().deref()])
                .inc();
            let origin = metadata.origin;
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            let is_new_peer = smp.peer_manager.add_peer(peer.clone(), origin);
            let is_upstream_peer = smp.peer_manager.is_upstream_peer(&peer, Some(origin));
            debug!(LogSchema::new(LogEntry::NewPeer)
                .peer(&peer)
                .is_upstream_peer(is_upstream_peer));
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
            if is_new_peer && is_upstream_peer {
                tasks::execute_broadcast(peer, false, smp, scheduled_broadcasts, executor.clone());
            }
        }
        Event::LostPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["lost_peer".to_string().deref()])
                .inc();
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            debug!(LogSchema::new(LogEntry::LostPeer)
                .peer(&peer)
                .is_upstream_peer(
                    smp.peer_manager
                        .is_upstream_peer(&peer, Some(metadata.origin))
                ));
            smp.peer_manager.disable_peer(peer);
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
        }
        Event::Message(peer_id, msg) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["message".to_string().deref()])
                .inc();
            match msg {
                MempoolSyncMsg::BroadcastTransactionsRequest {
                    request_id,
                    transactions,
                } => {
                    let smp_clone = smp.clone();
                    let peer = PeerNetworkId(network_id, peer_id);
                    let timeline_state = match smp.peer_manager.is_upstream_peer(&peer, None) {
                        true => TimelineState::NonQualified,
                        false => TimelineState::NotReady,
                    };
                    // This timer measures how long it took for the bounded executor to
                    // *schedule* the task.
                    let _timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::SPAWN_LABEL,
                        ])
                        .start_timer();
                    // This timer measures how long it took for the task to go from scheduled
                    // to started.
                    let task_start_timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::START_LABEL,
                        ])
                        .start_timer();
                    bounded_executor
                        .spawn(tasks::process_transaction_broadcast(
                            smp_clone,
                            transactions,
                            request_id,
                            timeline_state,
                            peer,
                            task_start_timer,
                        ))
                        .await;
                }
                MempoolSyncMsg::BroadcastTransactionsResponse {
                    request_id,
                    retry,
                    backoff,
                } => {
                    let ack_timestamp = SystemTime::now();
                    smp.peer_manager.process_broadcast_ack(
                        PeerNetworkId(network_id, peer_id),
                        request_id,
                        retry,
                        backoff,
                        ack_timestamp,
                    );
                }
            }
        }
        Event::RpcRequest(peer_id, _msg, _res_tx) => {
            counters::UNEXPECTED_NETWORK_MSG_COUNT
                .with_label_values(&[&network_id.network_id().to_string(), &peer_id.to_string()])
                .inc();
            sample!(
                SampleRate::Duration(Duration::from_secs(60)),
                warn!(LogSchema::new(LogEntry::UnexpectedNetworkMsg)
                    .peer(&PeerNetworkId(network_id, peer_id)))
            );
        }
    }
}

/// Garbage collect all expired transactions by SystemTTL.
pub(crate) async fn gc_coordinator(mempool: Arc<Mutex<CoreMempool>>, gc_interval_ms: u64) {
    info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Start));
    let mut interval = IntervalStream::new(interval(Duration::from_millis(gc_interval_ms)));
    while let Some(_interval) = interval.next().await {
        sample!(
            SampleRate::Duration(Duration::from_secs(60)),
            info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Live))
        );
        mempool.lock().gc();
    }

    error!(LogSchema::event_log(
        LogEntry::GCRuntime,
        LogEvent::Terminated
    ));
}

/// Periodically logs a snapshot of transactions in core mempool.
/// In the future we may want an interactive way to directly query mempool's internal state.
/// For now, we will rely on this periodic snapshot to observe the internal state.
pub(crate) async fn snapshot_job(mempool: Arc<Mutex<CoreMempool>>, snapshot_interval_secs: u64) {
    let mut interval = IntervalStream::new(interval(Duration::from_secs(snapshot_interval_secs)));
    while let Some(_interval) = interval.next().await {
        let snapshot = mempool.lock().gen_snapshot();
        debug!(LogSchema::new(LogEntry::MempoolSnapshot).txns(snapshot));
    }
}
<commit_msg>[mempool] Move event handling into separate functions<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Processes that are directly spawned by shared mempool runtime initialization

use crate::{
    core_mempool::{CoreMempool, TimelineState},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{MempoolNetworkEvents, MempoolSyncMsg},
    shared_mempool::{
        tasks,
        types::{notify_subscribers, ScheduledBroadcast, SharedMempool, SharedMempoolNotification},
    },
    CommitNotification, ConsensusRequest, SubmissionStatus,
};
use ::network::protocols::network::Event;
use anyhow::Result;
use bounded_executor::BoundedExecutor;
use channel::diem_channel;
use diem_config::{config::PeerNetworkId, network_id::NodeNetworkId};
use diem_infallible::Mutex;
use diem_logger::prelude::*;
use diem_trace::prelude::*;
use diem_types::{
    mempool_status::MempoolStatus, on_chain_config::OnChainConfigPayload,
    transaction::SignedTransaction, vm_status::DiscardedVMStatus,
};
use futures::{
    channel::{mpsc, oneshot},
    stream::{select_all, FuturesUnordered},
    StreamExt,
};
use std::{
    ops::Deref,
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::{runtime::Handle, time::interval};
use tokio_stream::wrappers::IntervalStream;
use vm_validator::vm_validator::TransactionValidation;

/// Coordinator that handles inbound network events and outbound txn broadcasts.
pub(crate) async fn coordinator<V>(
    mut smp: SharedMempool<V>,
    executor: Handle,
    network_events: Vec<(NodeNetworkId, MempoolNetworkEvents)>,
    mut client_events: mpsc::Receiver<(
        SignedTransaction,
        oneshot::Sender<Result<SubmissionStatus>>,
    )>,
    mut consensus_requests: mpsc::Receiver<ConsensusRequest>,
    mut state_sync_requests: mpsc::Receiver<CommitNotification>,
    mut mempool_reconfig_events: diem_channel::Receiver<(), OnChainConfigPayload>,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Start
    ));
    let smp_events: Vec<_> = network_events
        .into_iter()
        .map(|(network_id, events)| events.map(move |e| (network_id.clone(), e)))
        .collect();
    let mut events = select_all(smp_events).fuse();
    let mempool = smp.mempool.clone();
    let mut scheduled_broadcasts = FuturesUnordered::new();

    // Use a BoundedExecutor to restrict only `workers_available` concurrent
    // worker tasks that can process incoming transactions.
    let workers_available = smp.config.shared_mempool_max_concurrent_inbound_syncs;
    let bounded_executor = BoundedExecutor::new(workers_available, executor.clone());

    loop {
        let _timer = counters::MAIN_LOOP.start_timer();
        ::futures::select! {
            (msg, callback) = client_events.select_next_some() => {
                handle_client_event(&mut smp, &bounded_executor, msg, callback).await;
            },
            msg = consensus_requests.select_next_some() => {
                tasks::process_consensus_request(&mempool, msg).await;
            }
            msg = state_sync_requests.select_next_some() => {
                handle_state_sync_request(&mut smp, msg);
            }
            config_update = mempool_reconfig_events.select_next_some() => {
                handle_mempool_reconfig_event(&mut smp, &bounded_executor, config_update).await;
            },
            (peer, backoff) = scheduled_broadcasts.select_next_some() => {
                tasks::execute_broadcast(peer, backoff, &mut smp, &mut scheduled_broadcasts, executor.clone());
            },
            (network_id, event) = events.select_next_some() => {
                handle_event(&executor, &bounded_executor, &mut scheduled_broadcasts, &mut smp, network_id, event).await;
            },
            complete => break,
        }
    }
    error!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Terminated
    ));
}

async fn handle_client_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    msg: SignedTransaction,
    callback: oneshot::Sender<anyhow::Result<(MempoolStatus, Option<DiscardedVMStatus>)>>,
) where
    V: TransactionValidation,
{
    trace_event!("mempool::client_event", {"txn", msg.sender(), msg.sequence_number()});
    // This timer measures how long it took for the bounded executor to *schedule* the
    // task.
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    // This timer measures how long it took for the task to go from scheduled to started.
    let task_start_timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::START_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_client_transaction_submission(
            smp.clone(),
            msg,
            callback,
            task_start_timer,
        ))
        .await;
}

fn handle_state_sync_request<V>(smp: &mut SharedMempool<V>, msg: CommitNotification)
where
    V: TransactionValidation,
{
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::STATE_SYNC_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    tokio::spawn(tasks::process_state_sync_request(smp.mempool.clone(), msg));
}

async fn handle_mempool_reconfig_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    config_update: OnChainConfigPayload,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::ReconfigUpdate,
        LogEvent::Received
    ));
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::RECONFIG_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_config_update(
            config_update,
            smp.validator.clone(),
        ))
        .await;
}

async fn handle_event<V>(
    executor: &Handle,
    bounded_executor: &BoundedExecutor,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    smp: &mut SharedMempool<V>,
    network_id: NodeNetworkId,
    event: Event<MempoolSyncMsg>,
) where
    V: TransactionValidation,
{
    match event {
        Event::NewPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["new_peer".to_string().deref()])
                .inc();
            let origin = metadata.origin;
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            let is_new_peer = smp.peer_manager.add_peer(peer.clone(), origin);
            let is_upstream_peer = smp.peer_manager.is_upstream_peer(&peer, Some(origin));
            debug!(LogSchema::new(LogEntry::NewPeer)
                .peer(&peer)
                .is_upstream_peer(is_upstream_peer));
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
            if is_new_peer && is_upstream_peer {
                tasks::execute_broadcast(peer, false, smp, scheduled_broadcasts, executor.clone());
            }
        }
        Event::LostPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["lost_peer".to_string().deref()])
                .inc();
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            debug!(LogSchema::new(LogEntry::LostPeer)
                .peer(&peer)
                .is_upstream_peer(
                    smp.peer_manager
                        .is_upstream_peer(&peer, Some(metadata.origin))
                ));
            smp.peer_manager.disable_peer(peer);
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
        }
        Event::Message(peer_id, msg) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["message".to_string().deref()])
                .inc();
            match msg {
                MempoolSyncMsg::BroadcastTransactionsRequest {
                    request_id,
                    transactions,
                } => {
                    let smp_clone = smp.clone();
                    let peer = PeerNetworkId(network_id, peer_id);
                    let timeline_state = match smp.peer_manager.is_upstream_peer(&peer, None) {
                        true => TimelineState::NonQualified,
                        false => TimelineState::NotReady,
                    };
                    // This timer measures how long it took for the bounded executor to
                    // *schedule* the task.
                    let _timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::SPAWN_LABEL,
                        ])
                        .start_timer();
                    // This timer measures how long it took for the task to go from scheduled
                    // to started.
                    let task_start_timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::START_LABEL,
                        ])
                        .start_timer();
                    bounded_executor
                        .spawn(tasks::process_transaction_broadcast(
                            smp_clone,
                            transactions,
                            request_id,
                            timeline_state,
                            peer,
                            task_start_timer,
                        ))
                        .await;
                }
                MempoolSyncMsg::BroadcastTransactionsResponse {
                    request_id,
                    retry,
                    backoff,
                } => {
                    let ack_timestamp = SystemTime::now();
                    smp.peer_manager.process_broadcast_ack(
                        PeerNetworkId(network_id, peer_id),
                        request_id,
                        retry,
                        backoff,
                        ack_timestamp,
                    );
                }
            }
        }
        Event::RpcRequest(peer_id, _msg, _res_tx) => {
            counters::UNEXPECTED_NETWORK_MSG_COUNT
                .with_label_values(&[&network_id.network_id().to_string(), &peer_id.to_string()])
                .inc();
            sample!(
                SampleRate::Duration(Duration::from_secs(60)),
                warn!(LogSchema::new(LogEntry::UnexpectedNetworkMsg)
                    .peer(&PeerNetworkId(network_id, peer_id)))
            );
        }
    }
}

/// Garbage collect all expired transactions by SystemTTL.
pub(crate) async fn gc_coordinator(mempool: Arc<Mutex<CoreMempool>>, gc_interval_ms: u64) {
    info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Start));
    let mut interval = IntervalStream::new(interval(Duration::from_millis(gc_interval_ms)));
    while let Some(_interval) = interval.next().await {
        sample!(
            SampleRate::Duration(Duration::from_secs(60)),
            info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Live))
        );
        mempool.lock().gc();
    }

    error!(LogSchema::event_log(
        LogEntry::GCRuntime,
        LogEvent::Terminated
    ));
}

/// Periodically logs a snapshot of transactions in core mempool.
/// In the future we may want an interactive way to directly query mempool's internal state.
/// For now, we will rely on this periodic snapshot to observe the internal state.
pub(crate) async fn snapshot_job(mempool: Arc<Mutex<CoreMempool>>, snapshot_interval_secs: u64) {
    let mut interval = IntervalStream::new(interval(Duration::from_secs(snapshot_interval_secs)));
    while let Some(_interval) = interval.next().await {
        let snapshot = mempool.lock().gen_snapshot();
        debug!(LogSchema::new(LogEntry::MempoolSnapshot).txns(snapshot));
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct EqPair<T = Data>(PhantomData<T>);

impl<T> Construct for EqPair<T> {
    fn new() -> EqPair<T> { EqPair(PhantomData) }
}

impl Count<usize> for EqPair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim + 1) / 2 }
}

impl<T, U> Count<U> for EqPair<Of<T>>
    where
        T: Construct + Count<U, N = usize>
{
    type N = usize;
    fn count(&self, dim: &U) -> usize {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for EqPair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for EqPair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max + 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for EqPair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize;
        let min = index - max * (max + 1) / 2;
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<EqPair, usize, (usize, usize)>();
        is_complete::<EqPair<Of<EqPair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn test_eq_pair() {
        // 1 0 0 0
        // 2 3 0 0
        // 4 5 6 0
        // 7 8 9 10

        let eq_pair: EqPair = Construct::new();
        let ref n = 4;
        let count = eq_pair.count(n);
        assert_eq!(count, 10);

        let mut pos = (0, 0);
        for x in 0..count {
            eq_pair.to_pos(n, x, &mut pos);
            println!("{:?}", pos);
            assert_eq!(eq_pair.to_index(n, &pos), x);
        }
    }
}
<commit_msg>Impl `Count<BigUint>` for `EqPair`<commit_after>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct EqPair<T = Data>(PhantomData<T>);

impl<T> Construct for EqPair<T> {
    fn new() -> EqPair<T> { EqPair(PhantomData) }
}

impl Count<usize> for EqPair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim + 1) / 2 }
}

impl Count<BigUint> for EqPair<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        let _1: BigUint = 1usize.into();
        let _2: BigUint = 2usize.into();
        dim * (dim + _1) / _2
    }
}

impl<T, U> Count<U> for EqPair<Of<T>>
    where
        T: Construct + Count<U>,
        EqPair: Count<<T as Count<U>>::N, N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for EqPair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for EqPair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max + 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for EqPair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize;
        let min = index - max * (max + 1) / 2;
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for EqPair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: EqPair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<EqPair, usize, (usize, usize)>();
        is_complete::<EqPair<Of<EqPair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn test_eq_pair() {
        // 1 0 0 0
        // 2 3 0 0
        // 4 5 6 0
        // 7 8 9 10

        let eq_pair: EqPair = Construct::new();
        let ref n = 4;
        let count = eq_pair.count(n);
        assert_eq!(count, 10);

        let mut pos = (0, 0);
        for x in 0..count {
            eq_pair.to_pos(n, x, &mut pos);
            println!("{:?}", pos);
            assert_eq!(eq_pair.to_index(n, &pos), x);
        }
    }
}
<|endoftext|>