<commit_before>extern crate imageflow_serde as s;
use daggy::{Dag, EdgeIndex, NodeIndex};
use ffi;
use ffi::{Context, Job, EdgeKind, BitmapBgra};
use flow::definitions::*;
use petgraph;
use petgraph::EdgeDirection;
use std::ptr;
use super::*;
use super::NodeDefHelpers;

fn bitmap_bgra_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.bitmap_bgra_pointer",
        name: "bitmap_bgra_pointer",
        outbound_edges: true,
        inbound_edges: EdgesIn::OneOptionalInput,

        fn_estimate: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.weight(ix).params {
                    NodeParams::Json(s::Node::FlowBitmapBgraPtr{ptr_to_flow_bitmap_bgra_ptr}) => {
                        let ptr: *mut *mut BitmapBgra = ptr_to_flow_bitmap_bgra_ptr as *mut *mut BitmapBgra;
                        unsafe {
                            if ptr == ptr::null_mut() {
                                panic!("Must be a valid pointer to a pointer to BitmapBgra");
                            }

                            if *ptr == ptr::null_mut() {
                                NodeDefHelpers::copy_frame_est_from_first_input(ctx, ix);
                            } else {
                                let ref mut weight = ctx.weight_mut(ix);
                                let ref b = **ptr;
                                weight.frame_est = FrameEstimate::Some(FrameInfo {
                                    w: b.w as i32,
                                    h: b.h as i32,
                                    fmt: b.fmt,
                                    alpha_meaningful: b.alpha_meaningful
                                });
                            }
                        }

                    }
                    _ => {
                        panic!("Node params missing");
                    }
                }
            }
            f
        }),
        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                // let ref mut weight = ctx.weight_mut(ix);
                match ctx.weight(ix).params {
                    NodeParams::Json(s::Node::FlowBitmapBgraPtr{ptr_to_flow_bitmap_bgra_ptr}) => {
                        let ptr: *mut *mut BitmapBgra = ptr_to_flow_bitmap_bgra_ptr as *mut *mut BitmapBgra;
                        unsafe {
                            if ptr == ptr::null_mut() {
                                panic!("Must be a valid pointer to a pointer to BitmapBgra");
                            }

                            let frame =     ctx.first_parent_result_frame(ix, EdgeKind::Input);
                            let ref mut weight = ctx.weight_mut(ix);
                            match frame {
                                Some(input_ptr) => {
                                    *ptr = input_ptr;
                                    weight.result = NodeResult::Frame(input_ptr);
                                },
                                None => {
                                    if *ptr == ptr::null_mut() {
                                        panic!("When serving as an input node, FlowBitmapBgraPtr must point to a valid BitmapBgra. Found null.");
                                    }
                                    weight.result = NodeResult::Frame(*ptr);
                                }
                            }
                        }
                    }
                    _ => {
                        panic!("Node params missing");
                    }
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn decoder_encoder_io_id(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) -> Option<i32> {
    match ctx.weight(ix).params {
        NodeParams::Json(s::Node::Decode { io_id }) => Some(io_id),
        NodeParams::Json(s::Node::Encode { io_id, .. }) => Some(io_id),
        _ => None,
    }
}

fn decoder_estimate(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

    let codec = ctx.weight(ix).custom_state as *mut ffi::CodecInstance;

    let io_id = decoder_encoder_io_id(ctx, ix).unwrap();
    let mut frame_info: ffi::DecoderInfo = Default::default();
    unsafe {
        if !ffi::flow_job_get_decoder_info(ctx.c,
                                           ctx.job,
                                           io_id,
                                           &mut frame_info as *mut ffi::DecoderInfo) {
            ctx.assert_ok();
        }
    }

    ctx.weight_mut(ix).frame_est = FrameEstimate::Some(FrameInfo {
        fmt: frame_info.frame0_post_decode_format,
        w: frame_info.frame0_width,
        h: frame_info.frame0_height,
        alpha_meaningful: true, // WRONG
    });
}

// Todo list codec name in stringify

fn decoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.decoder",
        name: "decoder",
        outbound_edges: true,
        inbound_edges: EdgesIn::NoInput,
        fn_estimate: Some(decoder_estimate),

        // Allow link-up
        fn_link_state_to_this_io_id: Some(decoder_encoder_io_id),
        fn_flatten_pre_optimize: {
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

                // Mutate instead of replace (custom_state is populated)
                ctx.weight_mut(ix).def = &PRIMITIVE_DECODER;

                let exif_flag = unsafe {ffi::flow_codecs_jpg_decoder_get_exif(ctx.c, ctx.weight(ix).custom_state as *mut ffi::CodecInstance) };
                if exif_flag > 0 {
                    let new_node = ctx.graph
                        .add_node(Node::new(&APPLY_ORIENTATION,
                                            NodeParams::Json(s::Node::ApplyOrientation {
                                                flag: exif_flag,
                                            })));
                    ctx.copy_edges_to(ix, new_node, EdgeDirection::Outgoing);
                    ctx.delete_child_edges_for(ix);
                    ctx.graph.add_edge(ix, new_node, EdgeKind::Input).unwrap();
                }
            }
            Some(f)
        },
        ..Default::default()
    }
}
fn primitive_decoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.primitive_decoder",
        name: "primitive_decoder",
        outbound_edges: true,
        inbound_edges: EdgesIn::NoInput,
        fn_estimate: Some(decoder_estimate),
        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                //TODO______
                let codec = ctx.weight(ix).custom_state as *mut ffi::CodecInstance;

                unsafe {
                    let result = ffi::flow_codec_execute_read_frame(ctx.c, codec);
                    if result == ptr::null_mut() {
                        ctx.assert_ok();
                    } else {
                        ctx.weight_mut(ix).result = NodeResult::Frame(result);
                    }
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn encoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.primitive_encoder",
        name: "primitive_encoder",
        outbound_edges: false,
        inbound_edges: EdgesIn::OneInput,
        // Allow link-up
        fn_link_state_to_this_io_id: Some(decoder_encoder_io_id),
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),

        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                if let Some(input_bitmap) = ctx.first_parent_result_frame(ix, EdgeKind::Input) {
                    {
                        let weight = ctx.weight(ix);
                        if let NodeParams::Json(s::Node::Encode { ref preset, .. }) = weight.params {
                            let codec = weight.custom_state as *mut ffi::CodecInstance;

                            if codec == ptr::null_mut() { panic!("") }

                            let (wanted_id, hints) = match *preset {
                                s::EncoderPreset::LibjpegTurbo { quality } =>
                                (ffi::CodecType::EncodeJpeg as i64,
                                 ffi::EncoderHints {
                                    jpeg_encode_quality: quality.unwrap_or(90),
                                    disable_png_alpha: false,
                                 }),
                                s::EncoderPreset::Libpng { ref matte, zlib_compression, ref depth } =>
                                    (ffi::CodecType::EncodePng as i64,
                                     ffi::EncoderHints {
                                         jpeg_encode_quality: -1,
                                         disable_png_alpha: match *depth {
                                             Some(s::PngBitDepth::Png24) => false,
                                             _ => true },
                                     })
                            };

                            unsafe {
                                (*codec).codec_id = wanted_id;
                                if !ffi::flow_codec_initialize(ctx.c, codec) {
                                    ctx.assert_ok();
                                }
                                let codec_def = ffi::flow_codec_get_definition(ctx.c, wanted_id);
                                if codec_def == ptr::null_mut() {
                                    ctx.assert_ok();
                                }
                                let write_fn = (*codec_def).write_frame;
                                if write_fn == None {
                                    panic!("Codec didn't implement write_frame");
                                }

                                if !write_fn.unwrap()(ctx.c, (*codec).codec_state, input_bitmap, &hints as *const ffi::EncoderHints) {
                                    ctx.assert_ok();
                                }
                            }
                        } else {
                            panic!("");
                        }
                    }
                    {
                        ctx.weight_mut(ix).result = NodeResult::Frame(input_bitmap);
                    }
                }else {
                    panic!("");
                }

            }
            f
        }),

        ..Default::default()
    }
}

lazy_static! {
    pub static ref BITMAP_BGRA_POINTER: NodeDefinition = bitmap_bgra_def();
    pub static ref DECODER: NodeDefinition = decoder_def();
    pub static ref ENCODE: NodeDefinition = encoder_def();
    pub static ref PRIMITIVE_DECODER: NodeDefinition = primitive_decoder_def();
}
<commit_msg>Fix accidental swap of png32/png24<commit_after>extern crate imageflow_serde as s;
use daggy::{Dag, EdgeIndex, NodeIndex};
use ffi;
use ffi::{Context, Job, EdgeKind, BitmapBgra};
use flow::definitions::*;
use petgraph;
use petgraph::EdgeDirection;
use std::ptr;
use super::*;
use super::NodeDefHelpers;

fn bitmap_bgra_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.bitmap_bgra_pointer",
        name: "bitmap_bgra_pointer",
        outbound_edges: true,
        inbound_edges: EdgesIn::OneOptionalInput,

        fn_estimate: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.weight(ix).params {
                    NodeParams::Json(s::Node::FlowBitmapBgraPtr{ptr_to_flow_bitmap_bgra_ptr}) => {
                        let ptr: *mut *mut BitmapBgra = ptr_to_flow_bitmap_bgra_ptr as *mut *mut BitmapBgra;
                        unsafe {
                            if ptr == ptr::null_mut() {
                                panic!("Must be a valid pointer to a pointer to BitmapBgra");
                            }

                            if *ptr == ptr::null_mut() {
                                NodeDefHelpers::copy_frame_est_from_first_input(ctx, ix);
                            } else {
                                let ref mut weight = ctx.weight_mut(ix);
                                let ref b = **ptr;
                                weight.frame_est = FrameEstimate::Some(FrameInfo {
                                    w: b.w as i32,
                                    h: b.h as i32,
                                    fmt: b.fmt,
                                    alpha_meaningful: b.alpha_meaningful
                                });
                            }
                        }

                    }
                    _ => {
                        panic!("Node params missing");
                    }
                }
            }
            f
        }),
        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                // let ref mut weight = ctx.weight_mut(ix);
                match ctx.weight(ix).params {
                    NodeParams::Json(s::Node::FlowBitmapBgraPtr{ptr_to_flow_bitmap_bgra_ptr}) => {
                        let ptr: *mut *mut BitmapBgra = ptr_to_flow_bitmap_bgra_ptr as *mut *mut BitmapBgra;
                        unsafe {
                            if ptr == ptr::null_mut() {
                                panic!("Must be a valid pointer to a pointer to BitmapBgra");
                            }

                            let frame =     ctx.first_parent_result_frame(ix, EdgeKind::Input);
                            let ref mut weight = ctx.weight_mut(ix);
                            match frame {
                                Some(input_ptr) => {
                                    *ptr = input_ptr;
                                    weight.result = NodeResult::Frame(input_ptr);
                                },
                                None => {
                                    if *ptr == ptr::null_mut() {
                                        panic!("When serving as an input node, FlowBitmapBgraPtr must point to a valid BitmapBgra. Found null.");
                                    }
                                    weight.result = NodeResult::Frame(*ptr);
                                }
                            }
                        }
                    }
                    _ => {
                        panic!("Node params missing");
                    }
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn decoder_encoder_io_id(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) -> Option<i32> {
    match ctx.weight(ix).params {
        NodeParams::Json(s::Node::Decode { io_id }) => Some(io_id),
        NodeParams::Json(s::Node::Encode { io_id, .. }) => Some(io_id),
        _ => None,
    }
}

fn decoder_estimate(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

    let codec = ctx.weight(ix).custom_state as *mut ffi::CodecInstance;

    let io_id = decoder_encoder_io_id(ctx, ix).unwrap();
    let mut frame_info: ffi::DecoderInfo = Default::default();
    unsafe {
        if !ffi::flow_job_get_decoder_info(ctx.c,
                                           ctx.job,
                                           io_id,
                                           &mut frame_info as *mut ffi::DecoderInfo) {
            ctx.assert_ok();
        }
    }

    ctx.weight_mut(ix).frame_est = FrameEstimate::Some(FrameInfo {
        fmt: frame_info.frame0_post_decode_format,
        w: frame_info.frame0_width,
        h: frame_info.frame0_height,
        alpha_meaningful: true, // WRONG
    });
}

// Todo list codec name in stringify

fn decoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.decoder",
        name: "decoder",
        outbound_edges: true,
        inbound_edges: EdgesIn::NoInput,
        fn_estimate: Some(decoder_estimate),

        // Allow link-up
        fn_link_state_to_this_io_id: Some(decoder_encoder_io_id),
        fn_flatten_pre_optimize: {
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

                // Mutate instead of replace (custom_state is populated)
                ctx.weight_mut(ix).def = &PRIMITIVE_DECODER;

                let exif_flag = unsafe {ffi::flow_codecs_jpg_decoder_get_exif(ctx.c, ctx.weight(ix).custom_state as *mut ffi::CodecInstance) };
                if exif_flag > 0 {
                    let new_node = ctx.graph
                        .add_node(Node::new(&APPLY_ORIENTATION,
                                            NodeParams::Json(s::Node::ApplyOrientation {
                                                flag: exif_flag,
                                            })));
                    ctx.copy_edges_to(ix, new_node, EdgeDirection::Outgoing);
                    ctx.delete_child_edges_for(ix);
                    ctx.graph.add_edge(ix, new_node, EdgeKind::Input).unwrap();
                }
            }
            Some(f)
        },
        ..Default::default()
    }
}
fn primitive_decoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.primitive_decoder",
        name: "primitive_decoder",
        outbound_edges: true,
        inbound_edges: EdgesIn::NoInput,
        fn_estimate: Some(decoder_estimate),
        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                //TODO______
                let codec = ctx.weight(ix).custom_state as *mut ffi::CodecInstance;

                unsafe {
                    let result = ffi::flow_codec_execute_read_frame(ctx.c, codec);
                    if result == ptr::null_mut() {
                        ctx.assert_ok();
                    } else {
                        ctx.weight_mut(ix).result = NodeResult::Frame(result);
                    }
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn encoder_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.primitive_encoder",
        name: "primitive_encoder",
        outbound_edges: false,
        inbound_edges: EdgesIn::OneInput,
        // Allow link-up
        fn_link_state_to_this_io_id: Some(decoder_encoder_io_id),
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),

        fn_execute: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                if let Some(input_bitmap) = ctx.first_parent_result_frame(ix, EdgeKind::Input) {
                    {
                        let weight = ctx.weight(ix);
                        if let NodeParams::Json(s::Node::Encode { ref preset, .. }) = weight.params {
                            let codec = weight.custom_state as *mut ffi::CodecInstance;

                            if codec == ptr::null_mut() { panic!("") }

                            let (wanted_id, hints) = match *preset {
                                s::EncoderPreset::LibjpegTurbo { quality } =>
                                (ffi::CodecType::EncodeJpeg as i64,
                                 ffi::EncoderHints {
                                    jpeg_encode_quality: quality.unwrap_or(90),
                                    disable_png_alpha: false,
                                 }),
                                s::EncoderPreset::Libpng { ref matte, zlib_compression, ref depth } =>
                                    (ffi::CodecType::EncodePng as i64,
                                     ffi::EncoderHints {
                                         jpeg_encode_quality: -1,
                                         disable_png_alpha: match *depth {
                                             Some(s::PngBitDepth::Png24) => true,
                                             _ => false },
                                     })
                            };

                            unsafe {
                                (*codec).codec_id = wanted_id;
                                if !ffi::flow_codec_initialize(ctx.c, codec) {
                                    ctx.assert_ok();
                                }
                                let codec_def = ffi::flow_codec_get_definition(ctx.c, wanted_id);
                                if codec_def == ptr::null_mut() {
                                    ctx.assert_ok();
                                }
                                let write_fn = (*codec_def).write_frame;
                                if write_fn == None {
                                    panic!("Codec didn't implement write_frame");
                                }

                                if !write_fn.unwrap()(ctx.c, (*codec).codec_state, input_bitmap, &hints as *const ffi::EncoderHints) {
                                    ctx.assert_ok();
                                }
                            }
                        } else {
                            panic!("");
                        }
                    }
                    {
                        ctx.weight_mut(ix).result = NodeResult::Frame(input_bitmap);
                    }
                }else {
                    panic!("");
                }

            }
            f
        }),

        ..Default::default()
    }
}

lazy_static! {
    pub static ref BITMAP_BGRA_POINTER: NodeDefinition = bitmap_bgra_def();
    pub static ref DECODER: NodeDefinition = decoder_def();
    pub static ref ENCODE: NodeDefinition = encoder_def();
    pub static ref PRIMITIVE_DECODER: NodeDefinition = primitive_decoder_def();
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::str::Utf8Error;
use std::num::{ParseIntError, ParseFloatError};
use quick_error::ResultExt;

use vsl::{VslRecord, VslRecordTag, VslIdent};

use nom::{self, IResult};

pub type TimeStamp = f64;

#[derive(Debug, Clone)]
pub struct AccessRecord {
    pub ident: VslIdent,
    pub start: TimeStamp,
    pub end: TimeStamp,
    pub transaction_type: TransactionType,
    pub transaction: HttpTransaction,
}

#[derive(Debug, Clone)]
pub enum TransactionType {
    Client,
    Backend {
        parent: VslIdent,
        reason: String,
    },
}

impl TransactionType {
    #[allow(dead_code)]
    pub fn is_backend(&self) -> bool {
        match self {
            &TransactionType::Backend { parent: _, reason: _ } => true,
            _ => false
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_parent(&self) -> VslIdent {
        match self {
            &TransactionType::Backend { ref parent, reason: _ } => *parent,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_reason(&self) -> &str {
        match self {
            &TransactionType::Backend { parent: _, ref reason } => reason,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }
}

#[derive(Debug, Clone)]
pub struct HttpTransaction {
    pub request: HttpRequest,
    pub response: HttpResponse,
}

#[derive(Debug, Clone)]
pub struct HttpRequest {
    pub method: String,
    pub url: String,
    pub protocol: String,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct HttpResponse {
    pub status_name: String,
    pub status_code: u32,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
struct RecordBuilder {
    ident: VslIdent,
    transaction_type: Option<TransactionType>,
    start: Option<TimeStamp>,
    end: Option<TimeStamp>,
    method: Option<String>,
    url: Option<String>,
    protocol: Option<String>,
    status_name: Option<String>,
    status_code: Option<u32>,
    headers: HashMap<String, String>,
}

#[derive(Debug)]
enum RecordBuilderResult {
    Building(RecordBuilder),
    Ready(AccessRecord),
}

trait IResultExt<O, E> {
    fn into_result(self) -> Result<O, E>;
}

impl<I, O, E> IResultExt<O, nom::Err<I, E>> for IResult<I, O, E> {
    fn into_result(self) -> Result<O, nom::Err<I, E>> {
        match self {
            IResult::Done(_, o) => Ok(o),
            IResult::Error(err) => Err(err),
            IResult::Incomplete(_) => panic!("got Incomplete IResult!"),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum RecordBuilderError {
        NonUtf8VslMessage(err: Utf8Error) {
            display("VSL record message is not valid UTF-8 encoded string: {}", err)
            cause(err)
        }
        InvalidMessageFormat(message: String, err: String) {
            display("Failed to parse message '{}': {}", message, err)
            context(message: &'a str, err: nom::Err<&'a str>)
                -> (message.to_string(), format!("Nom parser failed: {}", err))
        }
        InvalidMessageFieldFormat(message: String, field_name: &'static str, err: String) {
            display("Failed to parse field '{}' from message '{}': {}", field_name, message, err)
            context(field_info: (&'a str, &'static str), err: ParseFloatError)
                -> (field_info.0.to_string(), field_info.1, format!("Float parsing error: {}", err))
            context(field_info: (&'a str, &'static str), err: ParseIntError)
                -> (field_info.0.to_string(), field_info.1, format!("Integer parsing error: {}", err))
        }
        UnimplementedTransactionType(message: String, transaction_type: String) {
            display("Unimplemented transaction type '{}' in message: {}", transaction_type, message)
        }
    }
}

use nom::{space, eof};
named!(label<&str, &str>, terminated!(take_until_s!(": "), tag_s!(": ")));
named!(space_terminated<&str, &str>, terminated!(is_not_s!(" "), space));
named!(space_terminated_eof<&str, &str>, terminated!(is_not_s!(" "), eof));

named!(slt_begin<&str, (&str, &str, &str)>, complete!(tuple!(
        space_terminated,           // Type ("sess", "req" or "bereq")
        space_terminated,           // Parent vxid
        space_terminated_eof)));    // Reason

named!(slt_timestamp<&str, (&str, &str, &str, &str)>, complete!(tuple!(
        label,                      // Event label
        space_terminated,           // Absolute time of event
        space_terminated,           // Time since start of work unit
        space_terminated_eof)));    // Time since last timestamp

impl RecordBuilder {
    fn new(ident: VslIdent) -> RecordBuilder {
        RecordBuilder {
            ident: ident,
            transaction_type: None,
            start: None,
            end: None,
            method: None,
            url: None,
            protocol: None,
            status_name: None,
            status_code: None,
            headers: HashMap::new()
        }
    }

    fn apply<'r>(self, vsl: &'r VslRecord) -> Result<RecordBuilderResult, RecordBuilderError> {
        let builder = match vsl.message() {
            Ok(message) => match vsl.tag {
                VslRecordTag::SLT_Begin => {
                    let (transaction_type, parent, reason) = try!(slt_begin(message).into_result().context(message));
                    let parent = try!(parent.parse().context((message, "parent vxid")));

                    let transaction_type = match transaction_type {
                        "bereq" => TransactionType::Backend {
                            parent: parent,
                            reason: reason.to_owned()
                        },
                        _ => return Err(RecordBuilderError::UnimplementedTransactionType(message.to_string(), transaction_type.to_string()))
                    };

                    RecordBuilder { transaction_type: Some(transaction_type), .. self }
                }
                VslRecordTag::SLT_Timestamp => {
                    let (label, timestamp, _sice_work_start, _since_last_timestamp) = try!(slt_timestamp(message).into_result().context(message));
                    match label {
                        "Start" => RecordBuilder {
                            start: Some(try!(timestamp.parse().context((message, "timestamp")))),
                            .. self },
                            _ => {
                                warn!("Ignoring unknown SLT_Timestamp label variant: {}", label);
                                self
                            }
                    }
                }
                _ => {
                    warn!("Ignoring unknown VSL tag: {:?}", vsl.tag);
                    self
                }
            },
            Err(err) => return Err(RecordBuilderError::NonUtf8VslMessage(err))
        };

        Ok(RecordBuilderResult::Building(builder))
    }
}

#[derive(Debug)]
pub struct State {
    builders: HashMap<VslIdent, RecordBuilder>
}

impl State {
    pub fn new() -> State {
        State { builders: HashMap::new() }
    }

    pub fn apply(&mut self, vsl: &VslRecord) -> Option<AccessRecord> {
        //TODO: use entry API
        let builder = match self.builders.remove(&vsl.ident) {
            Some(builder) => builder,
            None => RecordBuilder::new(vsl.ident),
        };

        match builder.apply(vsl) {
            Ok(result) => match result {
                RecordBuilderResult::Building(builder) => {
                    self.builders.insert(vsl.ident, builder);
                    return None
                }
                RecordBuilderResult::Ready(record) => return Some(record),
            },
            Err(err) => {
                println!("Error while building record with ident {}: {}", vsl.ident, err);
                return None
            }
        }
    }

    #[cfg(test)]
    fn get(&self, ident: VslIdent) -> Option<&RecordBuilder> {
        self.builders.get(&ident)
    }
}

#[cfg(test)]
mod access_log_state_tests {
    pub use super::*;
    use vsl::{VslRecord, VslRecordTag};

    #[test]
    fn apply_non_utf8() {
        let mut state = State::new();

        state.apply(&VslRecord {
            tag: VslRecordTag::SLT_Begin,
            marker: 0,
            ident: 123,
            data: &[255, 0, 1, 2, 3]
        });

        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq 321 fetch"));

        let builder = state.get(123).unwrap().clone();
        let transaction_type = builder.transaction_type.unwrap();

        assert_eq!(transaction_type.get_backend_parent(), 321);
        assert_eq!(transaction_type.get_backend_reason(), "fetch");
    }

    #[test]
    fn apply_begin_unimpl_transaction_type() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo 231 fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_parser_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo bar"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_float_parse_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq bar fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_timestamp() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
    }
}
<commit_msg>cleanup<commit_after>use std::collections::HashMap;
use std::str::Utf8Error;
use std::num::{ParseIntError, ParseFloatError};
use quick_error::ResultExt;

use vsl::{VslRecord, VslRecordTag, VslIdent};

use nom::{self, IResult};

pub type TimeStamp = f64;

#[derive(Debug, Clone)]
pub struct AccessRecord {
    pub ident: VslIdent,
    pub start: TimeStamp,
    pub end: TimeStamp,
    pub transaction_type: TransactionType,
    pub transaction: HttpTransaction,
}

#[derive(Debug, Clone)]
pub enum TransactionType {
    Client,
    Backend {
        parent: VslIdent,
        reason: String,
    },
}

impl TransactionType {
    #[allow(dead_code)]
    pub fn is_backend(&self) -> bool {
        match self {
            &TransactionType::Backend { parent: _, reason: _ } => true,
            _ => false
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_parent(&self) -> VslIdent {
        match self {
            &TransactionType::Backend { ref parent, reason: _ } => *parent,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_reason(&self) -> &str {
        match self {
            &TransactionType::Backend { parent: _, ref reason } => reason,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }
}

#[derive(Debug, Clone)]
pub struct HttpTransaction {
    pub request: HttpRequest,
    pub response: HttpResponse,
}

#[derive(Debug, Clone)]
pub struct HttpRequest {
    pub method: String,
    pub url: String,
    pub protocol: String,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct HttpResponse {
    pub status_name: String,
    pub status_code: u32,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
struct RecordBuilder {
    ident: VslIdent,
    transaction_type: Option<TransactionType>,
    start: Option<TimeStamp>,
    end: Option<TimeStamp>,
    method: Option<String>,
    url: Option<String>,
    protocol: Option<String>,
    status_name: Option<String>,
    status_code: Option<u32>,
    headers: HashMap<String, String>,
}

#[derive(Debug)]
enum RecordBuilderResult {
    Building(RecordBuilder),
    Ready(AccessRecord),
}

trait IResultExt<O, E> {
    fn into_result(self) -> Result<O, E>;
}

impl<I, O, E> IResultExt<O, nom::Err<I, E>> for IResult<I, O, E> {
    fn into_result(self) -> Result<O, nom::Err<I, E>> {
        match self {
            IResult::Done(_, o) => Ok(o),
            IResult::Error(err) => Err(err),
            IResult::Incomplete(_) => panic!("got Incomplete IResult!"),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum RecordBuilderError {
        NonUtf8VslMessage(err: Utf8Error) {
            display("VSL record message is not valid UTF-8 encoded string: {}", err)
            cause(err)
        }
        UnimplementedTransactionType(transaction_type: String) {
            display("Unimplemented transaction type '{}'", transaction_type)
        }
        InvalidMessageFormat(err: String) {
            display("Failed to parse message: {}", err)
            // Note: using context() since from() does not support lifetimes
            context(tag: VslRecordTag ,err: nom::Err<&'a str>)
                -> (format!("Nom parser failed on VSL record {:?}: {}", tag, err))
        }
        InvalidMessageFieldFormat(field_name: &'static str, err: String) {
            display("Failed to parse message field '{}': {}", field_name, err)
            context(field_name: &'static str, err: ParseFloatError)
                -> (field_name, format!("Float parsing error: {}", err))
            context(field_name: &'static str, err: ParseIntError)
                -> (field_name, format!("Integer parsing error: {}", err))
        }
    }
}

use nom::{space, eof};
named!(label<&str, &str>, terminated!(take_until_s!(": "), tag_s!(": ")));
named!(space_terminated<&str, &str>, terminated!(is_not_s!(" "), space));
named!(space_terminated_eof<&str, &str>, terminated!(is_not_s!(" "), eof));

named!(slt_begin<&str, (&str, &str, &str)>, complete!(tuple!(
        space_terminated,           // Type ("sess", "req" or "bereq")
        space_terminated,           // Parent vxid
        space_terminated_eof)));    // Reason

named!(slt_timestamp<&str, (&str, &str, &str, &str)>, complete!(tuple!(
        label,                      // Event label
        space_terminated,           // Absolute time of event
        space_terminated,           // Time since start of work unit
        space_terminated_eof)));    // Time since last timestamp

impl RecordBuilder {
    fn new(ident: VslIdent) -> RecordBuilder {
        RecordBuilder {
            ident: ident,
            transaction_type: None,
            start: None,
            end: None,
            method: None,
            url: None,
            protocol: None,
            status_name: None,
            status_code: None,
            headers: HashMap::new()
        }
    }

    fn apply<'r>(self, vsl: &'r VslRecord) -> Result<RecordBuilderResult, RecordBuilderError> {
        let builder = match vsl.message() {
            Ok(message) => match vsl.tag {
                VslRecordTag::SLT_Begin => {
                    let (transaction_type, parent, reason) = try!(slt_begin(message).into_result().context(vsl.tag));
                    let parent = try!(parent.parse().context("parent vxid"));

                    let transaction_type = match transaction_type {
                        "bereq" => TransactionType::Backend {
                            parent: parent,
                            reason: reason.to_owned()
                        },
                        _ => return Err(RecordBuilderError::UnimplementedTransactionType(transaction_type.to_string()))
                    };

                    RecordBuilder { transaction_type: Some(transaction_type), .. self }
                }
                VslRecordTag::SLT_Timestamp => {
                    let (label, timestamp, _sice_work_start, _since_last_timestamp) = try!(slt_timestamp(message).into_result().context(vsl.tag));
                    match label {
                        "Start" => RecordBuilder {
                            start: Some(try!(timestamp.parse().context("timestamp"))),
                            .. self },
                            _ => {
                                warn!("Ignoring unknown SLT_Timestamp label variant: {}", label);
                                self
                            }
                    }
                }
                _ => {
                    warn!("Ignoring unknown VSL tag: {:?}", vsl.tag);
                    self
                }
            },
            Err(err) => return Err(RecordBuilderError::NonUtf8VslMessage(err))
        };

        Ok(RecordBuilderResult::Building(builder))
    }
}

#[derive(Debug)]
pub struct State {
    builders: HashMap<VslIdent, RecordBuilder>
}

impl State {
    pub fn new() -> State {
        State { builders: HashMap::new() }
    }

    pub fn apply(&mut self, vsl: &VslRecord) -> Option<AccessRecord> {
        //TODO: use entry API
        let builder = match self.builders.remove(&vsl.ident) {
            Some(builder) => builder,
            None => RecordBuilder::new(vsl.ident),
        };

        match builder.apply(vsl) {
            Ok(result) => match result {
                RecordBuilderResult::Building(builder) => {
                    self.builders.insert(vsl.ident, builder);
                    return None
                }
                RecordBuilderResult::Ready(record) => return Some(record),
            },
            Err(err) => {
                println!("Error while building record with ident {} while applying VSL record with tag {:?} and message {:?}: {}", vsl.ident, vsl.tag, vsl.message(), err);
                return None
            }
        }
    }

    #[cfg(test)]
    fn get(&self, ident: VslIdent) -> Option<&RecordBuilder> {
        self.builders.get(&ident)
    }
}

#[cfg(test)]
mod access_log_state_tests {
    pub use super::*;
    use vsl::{VslRecord, VslRecordTag};

    #[test]
    fn apply_non_utf8() {
        let mut state = State::new();

        state.apply(&VslRecord {
            tag: VslRecordTag::SLT_Begin,
            marker: 0,
            ident: 123,
            data: &[255, 0, 1, 2, 3]
        });

        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq 321 fetch"));

        let builder = state.get(123).unwrap().clone();
        let transaction_type = builder.transaction_type.unwrap();

        assert_eq!(transaction_type.get_backend_parent(), 321);
        assert_eq!(transaction_type.get_backend_reason(), "fetch");
    }

    #[test]
    fn apply_begin_unimpl_transaction_type() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo 231 fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_parser_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo bar"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_float_parse_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq bar fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_timestamp() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};

use {Actor, ActorRef, ActorSystem, CanReceive, Message, Props};

pub struct ActorCell<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    // We have an inner structure in order to be able to generate new ActorCell easily.
    inner_cell: Arc<InnerActorCell<Args, A>>,
}

impl<Args:  Copy + Sync + Send, A: Actor> Clone for ActorCell<Args, A> {
    fn clone(&self) -> ActorCell<Args, A> {
        ActorCell {
            inner_cell: self.inner_cell.clone()
        }
    }
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> ActorCell<Args, A> {
    pub fn new(actor: A, props: Props<Args, A>, system: ActorSystem) -> ActorCell<Args, A> {
        ActorCell {
            inner_cell: Arc::new(InnerActorCell::new(actor, props, system)),
        }
    }

    pub fn receive_message(&self, message: Message, sender: Arc<CanReceive + Sync>) {
        self.inner_cell.receive_message(message, sender);
        self.enqueue_actor_ref();
    }

    fn enqueue_actor_ref(&self) {
        self.inner_cell.system.enqueue_actor(self.actor_ref());
    }

    pub fn handle_envelope(&self) {
        self.inner_cell.handle_envelope(self.clone());
    }
}

/// This is the API that actors are supposed to see.
pub trait ActorContext<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    fn actor_ref(&self) -> ActorRef<Args, A>;
    fn actor_of(&self, props: Props<Args, A>) -> ActorRef<Args, A>;
    fn tell<T: CanReceive>(&self, to: T, message: Message);
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> ActorContext<Args, A> for ActorCell<Args, A> {
    fn actor_ref(&self) -> ActorRef<Args, A> {
        ActorRef::with_cell(self.clone())
    }

    fn actor_of(&self, props: Props<Args, A>) -> ActorRef<Args, A> {
        let actor = props.create();
        let actor_cell  = ActorCell {
            inner_cell: Arc::new(InnerActorCell::new(actor, props, self.inner_cell.system.clone())),
        };
        ActorRef::with_cell(actor_cell)
    }

    fn tell<T: CanReceive>(&self, to: T, message: Message) {
        to.receive(message, Arc::new(self.actor_ref()));
    }
}

struct InnerActorCell<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    actor: A,
    mailbox: Mutex<VecDeque<Envelope>>,
    props: Props<Args, A>,
    system: ActorSystem,
    //current_sender: RwLock<Option<Arc<CanReceive + Sync>>>,
    busy: Mutex<()>,
}

struct Envelope {
    message: Message,
    sender: Arc<CanReceive + Sync>,
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> InnerActorCell<Args, A> {
    fn new(actor: A, props: Props<Args, A>, system: ActorSystem) -> InnerActorCell<Args, A> {
        InnerActorCell {
            actor: actor,
            mailbox: Mutex::new(VecDeque::new()),
            props: props,
            system: system,
            //current_sender: RwLock::new(None),
            busy: Mutex::new(()),
        }
    }

    fn receive_envelope(&self, envelope: Envelope) {
        self.mailbox.lock().unwrap().push_back(envelope);
    }

    fn receive_message(&self, message: Message, sender: Arc<CanReceive + Sync>) {
        self.receive_envelope(Envelope{message: message, sender: sender});
    }

    fn handle_envelope(&self, context: ActorCell<Args, A>) {
        // Allows to have a single thread working on an actor at a time, only issue is that threads
        // still enter this function and block.
        // TODO(gamazeps): fix this, obviously.
        let _lock = self.busy.lock();
        let envelope = match self.mailbox.lock().unwrap().pop_front() {
            Some(envelope) => envelope,
            None => {
                println!("no envelope in mailbox");
                return;
            }
        };
        //{
        //    let mut current_sender = self.current_sender.write().unwrap();
        //    *current_envelope = Some(envelope.sender.clone());
        //}
        self.actor.receive(envelope.message, context);
    }

}
<commit_msg>ActorContext gives access to sender information.<commit_after>use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};

use {Actor, ActorRef, ActorSystem, CanReceive, Message, Props};

pub struct ActorCell<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    // We have an inner structure in order to be able to generate new ActorCell easily.
    inner_cell: Arc<InnerActorCell<Args, A>>,
}

impl<Args:  Copy + Sync + Send, A: Actor> Clone for ActorCell<Args, A> {
    fn clone(&self) -> ActorCell<Args, A> {
        ActorCell {
            inner_cell: self.inner_cell.clone()
        }
    }
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> ActorCell<Args, A> {
    pub fn new(actor: A, props: Props<Args, A>, system: ActorSystem) -> ActorCell<Args, A> {
        ActorCell {
            inner_cell: Arc::new(InnerActorCell::new(actor, props, system)),
        }
    }

    pub fn receive_message(&self, message: Message, sender: Arc<CanReceive + Sync>) {
        self.inner_cell.receive_message(message, sender);
        self.enqueue_actor_ref();
    }

    fn enqueue_actor_ref(&self) {
        self.inner_cell.system.enqueue_actor(self.actor_ref());
    }

    pub fn handle_envelope(&self) {
        self.inner_cell.handle_envelope(self.clone());
    }
}

/// This is the API that actors are supposed to see.
pub trait ActorContext<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    fn actor_ref(&self) -> ActorRef<Args, A>;
    fn actor_of(&self, props: Props<Args, A>) -> ActorRef<Args, A>;
    fn tell<T: CanReceive>(&self, to: T, message: Message);
    fn sender(&self) -> Arc<CanReceive + Sync>;
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> ActorContext<Args, A> for ActorCell<Args, A> {
    fn actor_ref(&self) -> ActorRef<Args, A> {
        ActorRef::with_cell(self.clone())
    }

    fn actor_of(&self, props: Props<Args, A>) -> ActorRef<Args, A> {
        let actor = props.create();
        let actor_cell  = ActorCell {
            inner_cell: Arc::new(InnerActorCell::new(actor, props, self.inner_cell.system.clone())),
        };
        ActorRef::with_cell(actor_cell)
    }

    fn tell<T: CanReceive>(&self, to: T, message: Message) {
        to.receive(message, Arc::new(self.actor_ref()));
    }

    fn sender(&self) -> Arc<CanReceive + Sync> {
        self.inner_cell.current_sender.read().unwrap().as_ref().unwrap().clone()
    }
}

struct InnerActorCell<Args: Copy + Sync + Send + 'static, A: Actor + 'static> {
    actor: A,
    mailbox: Mutex<VecDeque<Envelope>>,
    props: Props<Args, A>,
    system: ActorSystem,
    current_sender: RwLock<Option<Arc<CanReceive + Sync>>>,
    busy: Mutex<()>,
}

struct Envelope {
    message: Message,
    sender: Arc<CanReceive + Sync>,
}

impl<Args: Copy + Sync + Send + 'static, A: Actor + 'static> InnerActorCell<Args, A> {
    fn new(actor: A, props: Props<Args, A>, system: ActorSystem) -> InnerActorCell<Args, A> {
        InnerActorCell {
            actor: actor,
            mailbox: Mutex::new(VecDeque::new()),
            props: props,
            system: system,
            current_sender: RwLock::new(None),
            busy: Mutex::new(()),
        }
    }

    fn receive_envelope(&self, envelope: Envelope) {
        self.mailbox.lock().unwrap().push_back(envelope);
    }

    fn receive_message(&self, message: Message, sender: Arc<CanReceive + Sync>) {
        self.receive_envelope(Envelope{message: message, sender: sender});
    }

    fn handle_envelope(&self, context: ActorCell<Args, A>) {
        // Allows to have a single thread working on an actor at a time, only issue is that threads
        // still enter this function and block.
        // TODO(gamazeps): fix this, obviously.
        let _lock = self.busy.lock();
        let envelope = match self.mailbox.lock().unwrap().pop_front() {
            Some(envelope) => envelope,
            None => {
                println!("no envelope in mailbox");
                return;
            }
        };
        {
            let mut current_sender = self.current_sender.write().unwrap();
            *current_sender = Some(envelope.sender.clone());
        };
        self.actor.receive(envelope.message, context);
    }

}
<|endoftext|>


<commit_before>use ansi_term::Colour::Red;
use ansi_term::Colour::Green;

pub fn info<S>(message: S)
    where S: Into<String>
{
    println!("{}", Green.paint(message.into()));
}

pub fn error<S>(message: S)
    where S: Into<String>
{
    println!("{}", Red.paint(message.into()));
}
<commit_msg>Improve logger output<commit_after>use ansi_term::Colour::Red;
use ansi_term::Colour::Green;
use ansi_term::Style;

pub fn info<S>(message: S)
    where S: Into<String>
{
    let message = message.into();
    if !message.is_empty() {
        println!("{} {}", Style::new().bold().fg(Green).paint("Info:"), message);
    }
}

pub fn error<S>(message: S)
    where S: Into<String>
{
    let message = message.into();
    if !message.is_empty() {
        println!("{} {}", Style::new().bold().fg(Red).paint("Error:"), message);
    }
}
<|endoftext|>


<commit_before>use std::{fmt, str};

use nom::{
    branch::alt,
    bytes::complete::{tag, tag_no_case},
    character::complete::{multispace0, multispace1},
    combinator::{map, opt},
    lib::std::fmt::Formatter,
    multi::many0,
    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
    Err::Error,
    IResult,
};

use crate::{
    column::Column,
    common::{
        as_alias, column_identifier_no_alias, integer_literal, type_identifier, Literal, SqlType,
    },
};

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
    Bracketed(Box<Arithmetic>),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticItem {
    Base(ArithmeticBase),
    Expr(Box<Arithmetic>),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct Arithmetic {
    pub op: ArithmeticOperator,
    pub left: ArithmeticItem,
    pub right: ArithmeticItem,
}

impl Arithmetic {
    pub fn new(op: ArithmeticOperator, left: ArithmeticBase, right: ArithmeticBase) -> Self {
        Self {
            op,
            left: ArithmeticItem::Base(left),
            right: ArithmeticItem::Base(right),
        }
    }
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub ari: Arithmetic,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            ari: Arithmetic {
                op,
                left: ArithmeticItem::Base(left),
                right: ArithmeticItem::Base(right),
            },
            alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
            ArithmeticBase::Bracketed(ref ari) => write!(f, "({})", ari),
        }
    }
}

impl fmt::Display for ArithmeticItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticItem::Base(ref b) => write!(f, "{}", b),
            ArithmeticItem::Expr(ref expr) => write!(f, "{}", expr),
        }
    }
}

impl fmt::Display for Arithmetic {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} {} {}", self.left, self.op, self.right)
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} AS {}", self.ari, alias),
            None => write!(f, "{}", self.ari),
        }
    }
}

fn arithmetic_cast_helper(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    let (remaining_input, (_, _, _, _, a_base, _, _, _, _sign, sql_type, _, _)) = tuple((
        tag_no_case("cast"),
        multispace0,
        tag("("),
        multispace0,
        // TODO(malte): should be arbitrary expr
        arithmetic_base,
        multispace1,
        tag_no_case("as"),
        multispace1,
        opt(terminated(tag_no_case("signed"), multispace1)),
        type_identifier,
        multispace0,
        tag(")"),
    ))(i)?;

    Ok((remaining_input, (a_base, Some(sql_type))))
}

pub fn arithmetic_cast(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    alt((arithmetic_cast_helper, map(arithmetic_base, |v| (v, None))))(i)
}

pub fn add_sub_operator(i: &[u8]) -> IResult<&[u8], ArithmeticOperator> {
    alt((
        map(tag("+"), |_| ArithmeticOperator::Add),
        map(tag("-"), |_| ArithmeticOperator::Subtract),
    ))(i)
}

pub fn mul_div_operator(i: &[u8]) -> IResult<&[u8], ArithmeticOperator> {
    alt((
        map(tag("*"), |_| ArithmeticOperator::Multiply),
        map(tag("/"), |_| ArithmeticOperator::Divide),
    ))(i)
}

// Base case for nested arithmetic expressions: column name or literal.
pub fn arithmetic_base(i: &[u8]) -> IResult<&[u8], ArithmeticBase> {
    alt((
        map(integer_literal, ArithmeticBase::Scalar),
        map(column_identifier_no_alias, ArithmeticBase::Column),
        map(
            delimited(
                terminated(tag("("), multispace0),
                arithmetic,
                preceded(multispace0, tag(")")),
            ),
            |ari| ArithmeticBase::Bracketed(Box::new(ari)),
        ),
    ))(i)
}

fn arithmetic(i: &[u8]) -> IResult<&[u8], Arithmetic> {
    let res = expr(i)?;
    match res.1 {
        ArithmeticItem::Base(ArithmeticBase::Column(_))
        | ArithmeticItem::Base(ArithmeticBase::Scalar(_)) => {
            Err(Error((res.0, nom::error::ErrorKind::Tag)))
        } // no operator
        ArithmeticItem::Base(ArithmeticBase::Bracketed(expr)) => Ok((res.0, *expr)),
        ArithmeticItem::Expr(expr) => Ok((res.0, *expr)),
    }
}

fn expr(i: &[u8]) -> IResult<&[u8], ArithmeticItem> {
    map(pair(term, many0(expr_rest)), |(item, rs)| {
        rs.into_iter().fold(item, |acc, (o, r)| {
            ArithmeticItem::Expr(Box::new(Arithmetic {
                op: o,
                left: acc,
                right: r,
            }))
        })
    })(i)
}

fn expr_rest(i: &[u8]) -> IResult<&[u8], (ArithmeticOperator, ArithmeticItem)> {
    separated_pair(preceded(multispace0, add_sub_operator), multispace0, term)(i)
}

fn term(i: &[u8]) -> IResult<&[u8], ArithmeticItem> {
    map(pair(arithmetic_cast, many0(term_rest)), |(b, rs)| {
        rs.into_iter()
            .fold(ArithmeticItem::Base(b.0), |acc, (o, r)| {
                ArithmeticItem::Expr(Box::new(Arithmetic {
                    op: o,
                    left: acc,
                    right: r,
                }))
            })
    })(i)
}

fn term_rest(i: &[u8]) -> IResult<&[u8], (ArithmeticOperator, ArithmeticItem)> {
    separated_pair(
        preceded(multispace0, mul_div_operator),
        multispace0,
        map(arithmetic_cast, |b| ArithmeticItem::Base(b.0)),
    )(i)
}

// Parse simple arithmetic expressions combining literals, and columns and literals.
pub fn arithmetic_expression(i: &[u8]) -> IResult<&[u8], ArithmeticExpression> {
    map(pair(arithmetic, opt(as_alias)), |(ari, opt_alias)| {
        ArithmeticExpression {
            ari,
            alias: opt_alias.map(String::from),
        }
    })(i)
}

#[cfg(test)]
mod tests {
    use crate::arithmetic::{
        ArithmeticBase::Scalar,
        ArithmeticOperator::{Add, Divide, Multiply, Subtract},
    };

    use super::*;

    #[test]
    fn it_parses_arithmetic_expressions() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };
        use crate::column::{FunctionArguments, FunctionExpression};

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max(
                        FunctionArguments::Column("foo".into()),
                    ))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
            "CAST(5 AS bigint) - foo AS 5_minus_foo",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Subtract,
                Scalar(5.into()),
                ABColumn("foo".into()),
                Some("5_minus_foo".into()),
            ),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }

    #[test]
    fn nested_arithmetic() {
        let qs = [
            "1 + 1",
            "1 + 2 - 3",
            "1 + 2 * 3",
            "2 * 3 - 1 / 3",
            "3 * (1 + 2)",
        ];

        let expects =
            [
                Arithmetic::new(Add, Scalar(1.into()), Scalar(1.into())),
                Arithmetic {
                    op: Subtract,
                    left: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Add,
                        Scalar(1.into()),
                        Scalar(2.into()),
                    ))),
                    right: ArithmeticItem::Base(Scalar(3.into())),
                },
                Arithmetic {
                    op: Add,
                    left: ArithmeticItem::Base(Scalar(1.into())),
                    right: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Multiply,
                        Scalar(2.into()),
                        Scalar(3.into()),
                    ))),
                },
                Arithmetic {
                    op: Subtract,
                    left: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Multiply,
                        Scalar(2.into()),
                        Scalar(3.into()),
                    ))),
                    right: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Divide,
                        Scalar(1.into()),
                        Scalar(3.into()),
                    ))),
                },
                Arithmetic {
                    op: Multiply,
                    left: ArithmeticItem::Base(Scalar(3.into())),
                    right: ArithmeticItem::Base(ArithmeticBase::Bracketed(Box::new(
                        Arithmetic::new(Add, Scalar(1.into()), Scalar(2.into())),
                    ))),
                },
            ];

        for (i, e) in qs.iter().enumerate() {
            let res = arithmetic(e.as_bytes());
            let ari = res.unwrap().1;
            assert_eq!(ari, expects[i]);
            assert_eq!(format!("{}", ari), qs[i]);
        }
    }
}
<commit_msg>Fix minor bugs.<commit_after>use std::{fmt, str};

use nom::{
    branch::alt,
    bytes::complete::{tag, tag_no_case},
    character::complete::{multispace0, multispace1},
    combinator::{map, opt},
    lib::std::fmt::Formatter,
    multi::many0,
    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
    Err::Error,
    IResult,
};

use crate::{
    column::Column,
    common::{
        as_alias, column_identifier_no_alias, integer_literal, type_identifier, Literal, SqlType,
    },
};

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
    Bracketed(Box<Arithmetic>),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticItem {
    Base(ArithmeticBase),
    Expr(Box<Arithmetic>),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct Arithmetic {
    pub op: ArithmeticOperator,
    pub left: ArithmeticItem,
    pub right: ArithmeticItem,
}

impl Arithmetic {
    pub fn new(op: ArithmeticOperator, left: ArithmeticBase, right: ArithmeticBase) -> Self {
        Self {
            op,
            left: ArithmeticItem::Base(left),
            right: ArithmeticItem::Base(right),
        }
    }
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub ari: Arithmetic,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            ari: Arithmetic {
                op,
                left: ArithmeticItem::Base(left),
                right: ArithmeticItem::Base(right),
            },
            alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
            ArithmeticBase::Bracketed(ref ari) => write!(f, "({})", ari),
        }
    }
}

impl fmt::Display for ArithmeticItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticItem::Base(ref b) => write!(f, "{}", b),
            ArithmeticItem::Expr(ref expr) => write!(f, "{}", expr),
        }
    }
}

impl fmt::Display for Arithmetic {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} {} {}", self.left, self.op, self.right)
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} AS {}", self.ari, alias),
            None => write!(f, "{}", self.ari),
        }
    }
}

fn arithmetic_cast_helper(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    let (remaining_input, (_, _, _, _, a_base, _, _, _, _sign, sql_type, _, _)) = tuple((
        tag_no_case("cast"),
        multispace0,
        tag("("),
        multispace0,
        // TODO(malte): should be arbitrary expr
        arithmetic_base,
        multispace1,
        tag_no_case("as"),
        multispace1,
        opt(terminated(tag_no_case("signed"), multispace1)),
        type_identifier,
        multispace0,
        tag(")"),
    ))(i)?;

    Ok((remaining_input, (a_base, Some(sql_type))))
}

pub fn arithmetic_cast(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    alt((arithmetic_cast_helper, map(arithmetic_base, |v| (v, None))))(i)
}

pub fn add_sub_operator(i: &[u8]) -> IResult<&[u8], ArithmeticOperator> {
    alt((
        map(tag("+"), |_| ArithmeticOperator::Add),
        map(tag("-"), |_| ArithmeticOperator::Subtract),
    ))(i)
}

pub fn mul_div_operator(i: &[u8]) -> IResult<&[u8], ArithmeticOperator> {
    alt((
        map(tag("*"), |_| ArithmeticOperator::Multiply),
        map(tag("/"), |_| ArithmeticOperator::Divide),
    ))(i)
}

// Base case for nested arithmetic expressions: column name or literal.
pub fn arithmetic_base(i: &[u8]) -> IResult<&[u8], ArithmeticBase> {
    alt((
        map(integer_literal, ArithmeticBase::Scalar),
        map(column_identifier_no_alias, ArithmeticBase::Column),
        map(
            delimited(
                terminated(tag("("), multispace0),
                arithmetic,
                preceded(multispace0, tag(")")),
            ),
            |ari| ArithmeticBase::Bracketed(Box::new(ari)),
        ),
    ))(i)
}

fn arithmetic(i: &[u8]) -> IResult<&[u8], Arithmetic> {
    let res = expr(i)?;
    match res.1 {
        ArithmeticItem::Base(ArithmeticBase::Column(_))
        | ArithmeticItem::Base(ArithmeticBase::Scalar(_)) => {
            Err(Error((i, nom::error::ErrorKind::Tag)))
        } // no operator
        ArithmeticItem::Base(ArithmeticBase::Bracketed(expr)) => Ok((res.0, *expr)),
        ArithmeticItem::Expr(expr) => Ok((res.0, *expr)),
    }
}

fn expr(i: &[u8]) -> IResult<&[u8], ArithmeticItem> {
    map(pair(term, many0(expr_rest)), |(item, rs)| {
        rs.into_iter().fold(item, |acc, (o, r)| {
            ArithmeticItem::Expr(Box::new(Arithmetic {
                op: o,
                left: acc,
                right: r,
            }))
        })
    })(i)
}

fn expr_rest(i: &[u8]) -> IResult<&[u8], (ArithmeticOperator, ArithmeticItem)> {
    separated_pair(preceded(multispace0, add_sub_operator), multispace0, term)(i)
}

fn term(i: &[u8]) -> IResult<&[u8], ArithmeticItem> {
    map(pair(arithmetic_cast, many0(term_rest)), |(b, rs)| {
        rs.into_iter()
            .fold(ArithmeticItem::Base(b.0), |acc, (o, r)| {
                ArithmeticItem::Expr(Box::new(Arithmetic {
                    op: o,
                    left: acc,
                    right: r,
                }))
            })
    })(i)
}

fn term_rest(i: &[u8]) -> IResult<&[u8], (ArithmeticOperator, ArithmeticItem)> {
    separated_pair(
        preceded(multispace0, mul_div_operator),
        multispace0,
        map(arithmetic_cast, |b| ArithmeticItem::Base(b.0)),
    )(i)
}

// Parse simple arithmetic expressions combining literals, and columns and literals.
pub fn arithmetic_expression(i: &[u8]) -> IResult<&[u8], ArithmeticExpression> {
    map(pair(arithmetic, opt(as_alias)), |(ari, opt_alias)| {
        ArithmeticExpression {
            ari,
            alias: opt_alias.map(String::from),
        }
    })(i)
}

#[cfg(test)]
mod tests {
    use crate::arithmetic::{
        ArithmeticBase::Scalar,
        ArithmeticOperator::{Add, Divide, Multiply, Subtract},
    };

    use super::*;
    use nom::error::ErrorKind;
    use nom::AsBytes;

    #[test]
    fn it_parses_arithmetic_expressions() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };
        use crate::column::{FunctionArguments, FunctionExpression};

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max(
                        FunctionArguments::Column("foo".into()),
                    ))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::{
            ArithmeticBase::{Column as ABColumn, Scalar},
            ArithmeticOperator::*,
        };

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
            "CAST(5 AS bigint) - foo AS 5_minus_foo",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Subtract,
                Scalar(5.into()),
                ABColumn("foo".into()),
                Some("5_minus_foo".into()),
            ),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }

    #[test]
    fn nested_arithmetic() {
        let qs = [
            "1 + 1",
            "1 + 2 - 3",
            "1 + 2 * 3",
            "2 * 3 - 1 / 3",
            "3 * (1 + 2)",
        ];

        let expects =
            [
                Arithmetic::new(Add, Scalar(1.into()), Scalar(1.into())),
                Arithmetic {
                    op: Subtract,
                    left: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Add,
                        Scalar(1.into()),
                        Scalar(2.into()),
                    ))),
                    right: ArithmeticItem::Base(Scalar(3.into())),
                },
                Arithmetic {
                    op: Add,
                    left: ArithmeticItem::Base(Scalar(1.into())),
                    right: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Multiply,
                        Scalar(2.into()),
                        Scalar(3.into()),
                    ))),
                },
                Arithmetic {
                    op: Subtract,
                    left: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Multiply,
                        Scalar(2.into()),
                        Scalar(3.into()),
                    ))),
                    right: ArithmeticItem::Expr(Box::new(Arithmetic::new(
                        Divide,
                        Scalar(1.into()),
                        Scalar(3.into()),
                    ))),
                },
                Arithmetic {
                    op: Multiply,
                    left: ArithmeticItem::Base(Scalar(3.into())),
                    right: ArithmeticItem::Base(ArithmeticBase::Bracketed(Box::new(
                        Arithmetic::new(Add, Scalar(1.into()), Scalar(2.into())),
                    ))),
                },
            ];

        for (i, e) in qs.iter().enumerate() {
            let res = arithmetic(e.as_bytes());
            let ari = res.unwrap().1;
            assert_eq!(ari, expects[i]);
            assert_eq!(format!("{}", ari), qs[i]);
        }
    }

    #[test]
    fn arithmetic_scalar(){
        let qs = "56";
        let res = arithmetic(qs.as_bytes());
        assert!(res.is_err());
        assert_eq!(nom::Err::Error((qs.as_bytes(), ErrorKind::Tag)), res.err().unwrap());
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate cargo_registry;
extern crate conduit_middleware;
extern crate civet;
extern crate git2;
extern crate env_logger;

use cargo_registry::env;
use civet::Server;
use std::env;
use std::fs::{self, File};
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::mpsc::channel;

#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();
    let url = env("GIT_REPO_URL");
    let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT"));

    let repo = match git2::Repository::open(&checkout) {
        Ok(r) => r,
        Err(..) => {
            let _ = fs::remove_dir_all(&checkout);
            fs::create_dir_all(&checkout).unwrap();
            let mut cb = git2::RemoteCallbacks::new();
            cb.credentials(cargo_registry::git::credentials);
            let mut opts = git2::FetchOptions::new();
            opts.remote_callbacks(cb);
            git2::build::RepoBuilder::new()
                                     .fetch_options(opts)
                                     .clone(&url, &checkout).unwrap()
        }
    };
    let mut cfg = repo.config().unwrap();
    cfg.set_str("user.name", "bors").unwrap();
    cfg.set_str("user.email", "bors@rust-lang.org").unwrap();

    let heroku = env::var("HEROKU").is_ok();
    let cargo_env = if heroku {
        cargo_registry::Env::Production
    } else {
        cargo_registry::Env::Development
    };
    let config = cargo_registry::Config {
        s3_bucket: env("S3_BUCKET"),
        s3_access_key: env("S3_ACCESS_KEY"),
        s3_secret_key: env("S3_SECRET_KEY"),
        s3_region: env::var("S3_REGION").ok(),
        s3_proxy: None,
        session_key: env("SESSION_KEY"),
        git_repo_checkout: checkout,
        gh_client_id: env("GH_CLIENT_ID"),
        gh_client_secret: env("GH_CLIENT_SECRET"),
        db_url: env("DATABASE_URL"),
        env: cargo_env,
        max_upload_size: 10 * 1024 * 1024,
        mirror: env::var("MIRROR").is_ok(),
    };
    let app = cargo_registry::App::new(&config);
    let app = cargo_registry::middleware(Arc::new(app));

    cargo_registry::categories::sync().unwrap();

    let port = if heroku {
        8888
    } else {
        env::var("PORT").ok().and_then(|s| s.parse().ok()).unwrap_or(8888)
    };
    let threads = if cargo_env == cargo_registry::Env::Development {1} else {50};
    let mut cfg = civet::Config::new();
    cfg.port(port).threads(threads).keep_alive(true);
    let _a = Server::start(cfg, app);
    println!("listening on port {}", port);
    if heroku {
        File::create("/tmp/app-initialized").unwrap();
    }

    // TODO: handle a graceful shutdown by just waiting for a SIG{INT,TERM}
    let (_tx, rx) = channel::<()>();
    rx.recv().unwrap();
}
<commit_msg>Disable categories sync temporarily<commit_after>#![deny(warnings)]

extern crate cargo_registry;
extern crate conduit_middleware;
extern crate civet;
extern crate git2;
extern crate env_logger;

use cargo_registry::env;
use civet::Server;
use std::env;
use std::fs::{self, File};
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::mpsc::channel;

#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();
    let url = env("GIT_REPO_URL");
    let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT"));

    let repo = match git2::Repository::open(&checkout) {
        Ok(r) => r,
        Err(..) => {
            let _ = fs::remove_dir_all(&checkout);
            fs::create_dir_all(&checkout).unwrap();
            let mut cb = git2::RemoteCallbacks::new();
            cb.credentials(cargo_registry::git::credentials);
            let mut opts = git2::FetchOptions::new();
            opts.remote_callbacks(cb);
            git2::build::RepoBuilder::new()
                                     .fetch_options(opts)
                                     .clone(&url, &checkout).unwrap()
        }
    };
    let mut cfg = repo.config().unwrap();
    cfg.set_str("user.name", "bors").unwrap();
    cfg.set_str("user.email", "bors@rust-lang.org").unwrap();

    let heroku = env::var("HEROKU").is_ok();
    let cargo_env = if heroku {
        cargo_registry::Env::Production
    } else {
        cargo_registry::Env::Development
    };
    let config = cargo_registry::Config {
        s3_bucket: env("S3_BUCKET"),
        s3_access_key: env("S3_ACCESS_KEY"),
        s3_secret_key: env("S3_SECRET_KEY"),
        s3_region: env::var("S3_REGION").ok(),
        s3_proxy: None,
        session_key: env("SESSION_KEY"),
        git_repo_checkout: checkout,
        gh_client_id: env("GH_CLIENT_ID"),
        gh_client_secret: env("GH_CLIENT_SECRET"),
        db_url: env("DATABASE_URL"),
        env: cargo_env,
        max_upload_size: 10 * 1024 * 1024,
        mirror: env::var("MIRROR").is_ok(),
    };
    let app = cargo_registry::App::new(&config);
    let app = cargo_registry::middleware(Arc::new(app));

    // cargo_registry::categories::sync().unwrap();

    let port = if heroku {
        8888
    } else {
        env::var("PORT").ok().and_then(|s| s.parse().ok()).unwrap_or(8888)
    };
    let threads = if cargo_env == cargo_registry::Env::Development {1} else {50};
    let mut cfg = civet::Config::new();
    cfg.port(port).threads(threads).keep_alive(true);
    let _a = Server::start(cfg, app);
    println!("listening on port {}", port);
    if heroku {
        File::create("/tmp/app-initialized").unwrap();
    }

    // TODO: handle a graceful shutdown by just waiting for a SIG{INT,TERM}
    let (_tx, rx) = channel::<()>();
    rx.recv().unwrap();
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::io::{self, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;
use std::fmt::Write as FmtWrite;
use std::env;

const MAN_PAGE: &'static str = /* @MANSTART{date} */ r#"
NAME
    uptime - show how long the system has been running

SYNOPSIS
    uptime [ -h | --help] [offset]

DESCRIPTION
    Prints the length of time the system has been up.

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

const SECONDS_PER_MINUTE: i64 = 60;
const SECONDS_PER_HOUR: i64 = 3600;
const SECONDS_PER_DAY: i64 = 86400;

fn main() {
   let stdout = io::stdout();
   let mut stdout = stdout.lock();
   let mut stderr = io::stderr();

   let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
   parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut uptime_str = String::new();

    let mut ts = syscall::TimeSpec::default();
    if syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut ts).is_ok() {
        let uptime = ts.tv_sec;
        let uptime_secs = uptime % 60;
        let uptime_mins = (uptime / SECONDS_PER_MINUTE) % 60;
        let uptime_hours = (uptime / SECONDS_PER_HOUR) % 24;
        let uptime_days = (uptime / SECONDS_PER_DAY) % 365;

        let fmt_result;
        if uptime_days > 0 {
            fmt_result = write!(&mut uptime_str, "{}d {}h {}m {}s\n", uptime_days,
                                uptime_hours, uptime_mins, uptime_secs);
        } else if uptime_hours > 0 {
            fmt_result = write!(&mut uptime_str, "{}h {}m {}s\n", uptime_hours,
                                uptime_mins, uptime_secs);
        } else if uptime_mins > 0 {
            fmt_result = write!(&mut uptime_str, "{}m {}s\n", uptime_mins,
                                uptime_secs);
        } else {
            fmt_result = write!(&mut uptime_str, "{}s\n", uptime_secs);
        }

        if fmt_result.is_err() {
            println!("error: couldn't parse uptime");
        }
    }

    stdout.write(uptime_str.as_bytes()).try(&mut stderr);
    stdout.flush().try(&mut stderr);
}
<commit_msg>We don't show years. Removing remainder in the days calculation.<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::io::{self, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;
use std::fmt::Write as FmtWrite;
use std::env;

const MAN_PAGE: &'static str = /* @MANSTART{date} */ r#"
NAME
    uptime - show how long the system has been running

SYNOPSIS
    uptime [ -h | --help] [offset]

DESCRIPTION
    Prints the length of time the system has been up.

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

const SECONDS_PER_MINUTE: i64 = 60;
const SECONDS_PER_HOUR: i64 = 3600;
const SECONDS_PER_DAY: i64 = 86400;

fn main() {
   let stdout = io::stdout();
   let mut stdout = stdout.lock();
   let mut stderr = io::stderr();

   let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
   parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut uptime_str = String::new();

    let mut ts = syscall::TimeSpec::default();
    if syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut ts).is_ok() {
        let uptime = ts.tv_sec;
        let uptime_secs = uptime % 60;
        let uptime_mins = (uptime / SECONDS_PER_MINUTE) % 60;
        let uptime_hours = (uptime / SECONDS_PER_HOUR) % 24;
        let uptime_days = uptime / SECONDS_PER_DAY;

        let fmt_result;
        if uptime_days > 0 {
            fmt_result = write!(&mut uptime_str, "{}d {}h {}m {}s\n", uptime_days,
                                uptime_hours, uptime_mins, uptime_secs);
        } else if uptime_hours > 0 {
            fmt_result = write!(&mut uptime_str, "{}h {}m {}s\n", uptime_hours,
                                uptime_mins, uptime_secs);
        } else if uptime_mins > 0 {
            fmt_result = write!(&mut uptime_str, "{}m {}s\n", uptime_mins,
                                uptime_secs);
        } else {
            fmt_result = write!(&mut uptime_str, "{}s\n", uptime_secs);
        }

        if fmt_result.is_err() {
            println!("error: couldn't parse uptime");
        }
    }

    stdout.write(uptime_str.as_bytes()).try(&mut stderr);
    stdout.flush().try(&mut stderr);
}
<|endoftext|>