<commit_before>use super::internal_prelude::*;

fn copy_rect_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.copy_rect_to_canvas",
        name: "copy_rect",
        inbound_edges: EdgesIn::OneInputOneCanvas,
        description: "Copy Rect",
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_canvas),
        fn_execute: Some({

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

                if let s::Node::CopyRectToCanvas { from_x, from_y, width, height, x, y } =
                       ctx.get_json_params(ix).unwrap() {
                    let input: *mut ::ffi::BitmapBgra =
                        ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    let canvas: *mut ::ffi::BitmapBgra =
                        ctx.first_parent_result_frame(ix, EdgeKind::Canvas).unwrap();

                    unsafe {
                        if (*input).fmt != (*canvas).fmt {
                            panic!("Can't copy between bitmaps with different pixel formats")
                        }
                        if input == canvas{
                            panic!("Canvas and input must be different bitmaps for CopyRect to work!")
                        }

                        // TODO: Implement faster path for common (full clone) path
                        //    if (info->x == 0 && info->from_x == 0 && info->from_y == 0 && info->y == 0 && info->width == input->w
                        //        && info->width == canvas->w && info->height == input->h && info->height == canvas->h
                        //        && canvas->stride == input->stride) {
                        //        memcpy(canvas->pixels, input->pixels, input->stride * input->h);
                        //        canvas->alpha_meaningful = input->alpha_meaningful;

                        if (*input).w <= from_x || (*input).h <= from_y ||
                           (*input).w < from_x + width ||
                           (*input).h < from_y + height ||
                           (*canvas).w < x + width ||
                           (*canvas).h < y + height {
                            println!("canvas {}x{}, input {}x{}, command {:?}",
                                     (*canvas).w,
                                     (*canvas).h,
                                     (*input).w,
                                     (*input).h,
                                     ctx.get_json_params(ix).unwrap());
                            panic!("Out of bounds")
                        }

                        let bytes_pp = match (*input).fmt {
                            PixelFormat::Gray8 => 1,
                            PixelFormat::Bgra32 => 4,
                            PixelFormat::Bgr24 => 3,
                        };
                        if from_x == 0 && x == 0 && width == (*input).w && width == (*canvas).w  &&
                            (*input).stride == (*canvas).stride && !(*canvas).borrowed_pixels {
                            //This optimization has the side effect of copying irrelevant data, so we don't want to do it if windowed, only
                            // if padded or permanently cropped.
                            let from_offset = (*input).stride * from_y;
                            let from_ptr = (*input).pixels.offset(from_offset as isize);
                            let to_offset = (*canvas).stride * y;
                            let to_ptr = (*canvas).pixels.offset(to_offset as isize);
                            ptr::copy_nonoverlapping(from_ptr, to_ptr, ((*input).stride * height) as usize);
                        }else {
                            for row in 0..height {
                                let from_offset = (*input).stride * (from_y + row) + bytes_pp * from_x;
                                let from_ptr = (*input).pixels.offset(from_offset as isize);
                                let to_offset = (*canvas).stride * (y + row) + bytes_pp * x;
                                let to_ptr = (*canvas).pixels.offset(to_offset as isize);
                                ptr::copy_nonoverlapping(from_ptr, to_ptr, (width * bytes_pp) as usize);
                            }
                        }

                        ctx.weight_mut(ix).result = NodeResult::Frame(canvas);
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn fill_rect_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.fill_rect_mutate",
        name: "fill_rect",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),
        fn_execute: Some({

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

                if let s::Node::FillRect { x1, x2, y1, y2, color } = ctx.get_json_params(ix)
                    .unwrap() {

                    let input = ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    unsafe {

                        if !ffi::flow_bitmap_bgra_fill_rect(ctx.c.flow_c(),
                                                            input,
                                                            x1,
                                                            y1,
                                                            x2,
                                                            y2,
                                                            color.to_u32_bgra().unwrap()) {
                            panic!("failed to fill rect. epic.");
                        }

                        ctx.weight_mut(ix).result = NodeResult::Frame(input);
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn clone_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.clone",
        name: "Clone",
        description: "Clone",
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.first_parent_input_weight(ix).unwrap().frame_est {
                    FrameEstimate::Some(FrameInfo { w, h, fmt, alpha_meaningful }) => {
                        let canvas_params = s::Node::CreateCanvas {
                            w: w as usize,
                            h: h as usize,
                            format: s::PixelFormat::from(fmt),
                            color: s::Color::Transparent,
                        };
                        let copy_params = s::Node::CopyRectToCanvas {
                            from_x: 0,
                            from_y: 0,
                            x: 0,
                            y: 0,
                            width: w as u32,
                            height: h as u32,
                        };
                        let canvas = ctx.graph
                            .add_node(Node::new(&CREATE_CANVAS, NodeParams::Json(canvas_params)));
                        let copy = ctx.graph
                            .add_node(Node::new(&COPY_RECT, NodeParams::Json(copy_params)));
                        ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
                        ctx.replace_node_with_existing(ix, copy);
                    }
                    _ => panic!(""),
                }

            }
            f
        }),
        ..Default::default()
    }
}
fn expand_canvas_size(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

    let input_info = ctx.first_parent_frame_info_some(ix).unwrap();

    let weight = &mut ctx.weight_mut(ix);
    match weight.params {
        NodeParams::Json(s::Node::ExpandCanvas { ref left,
                                                 ref top,
                                                 ref bottom,
                                                 ref right,
                                                 ref color }) => {
            weight.frame_est = FrameEstimate::Some(FrameInfo {
                w: input_info.w + *left as i32 + *right as i32,
                h: input_info.h + *top as i32 + *bottom as i32,
                fmt: ffi::PixelFormat::from(input_info.fmt),
                alpha_meaningful: input_info.alpha_meaningful,
            }); //TODO: May change if color has alpha
        }
        _ => {
            panic!("Node params missing");
        }
    }
}

fn expand_canvas_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.expand_canvas",
        name: "expand canvas",
        inbound_edges: EdgesIn::OneInput,
        description: "Expand Canvas",
        fn_estimate: Some(expand_canvas_size),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.first_parent_input_weight(ix).unwrap().frame_est {
                    FrameEstimate::Some(FrameInfo { w, h, fmt, alpha_meaningful }) => {
                        if let s::Node::ExpandCanvas { left, top, right, bottom, color } =
                               ctx.get_json_params(ix).unwrap() {
                            let new_w = w as usize + left as usize + right as usize;
                            let new_h = h as usize + top as usize + bottom as usize;
                            let canvas_params = s::Node::CreateCanvas {
                                w: new_w as usize,
                                h: new_h as usize,
                                format: s::PixelFormat::from(fmt),
                                color: color,
                            };
                            let copy_params = s::Node::CopyRectToCanvas {
                                from_x: 0,
                                from_y: 0,
                                x: left,
                                y: top,
                                width: w as u32,
                                height: h as u32,
                            };
                            let canvas = ctx.graph
                                .add_node(Node::new(&CREATE_CANVAS,
                                                    NodeParams::Json(canvas_params)));
                            let copy = ctx.graph
                                .add_node(Node::new(&COPY_RECT, NodeParams::Json(copy_params)));
                            ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
                            ctx.replace_node_with_existing(ix, copy);
                        }
                    }
                    _ => panic!(""),
                }
            }
            f
        }),
        ..Default::default()
    }
}

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

    let input_info = ctx.first_parent_frame_info_some(ix).unwrap_or_else(|| {
        println!("{:?}", ctx.graph_to_str());
        panic!("");
    });

    let weight = &mut ctx.weight_mut(ix);
    match weight.params {
        NodeParams::Json(s::Node::Crop { ref x1, ref y1, ref x2, ref y2 }) => {
            weight.frame_est = FrameEstimate::Some(FrameInfo {
                w: *x2 as i32 - *x1 as i32,
                h: *y2 as i32 - *y1 as i32,
                fmt: ffi::PixelFormat::from(input_info.fmt),
                alpha_meaningful: input_info.alpha_meaningful,
            });
        }
        _ => {
            panic!("Node params missing");
        }
    }
}
fn crop_mutate_def() -> NodeDefinition {
    NodeDefinition {
        // TODO: As a mutating node, shouldn't this verify no siblings exist? 'Consumed' might be non-deterministic
        fqn: "imazen.crop_mutate",
        name: "crop_mutate",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(crop_size),
        fn_execute: Some({

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

                if let s::Node::Crop { x1, x2, y1, y2 } = ctx.get_json_params(ix).unwrap() {

                    let input = ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    unsafe {
                        // println!("Cropping {}x{} to ({},{}) ({},{})", (*input).w, (*input).h, x1, y1, x2, y2);

                        let bytes_pp = match (*input).fmt {
                            PixelFormat::Gray8 => 1,
                            PixelFormat::Bgra32 => 4,
                            PixelFormat::Bgr24 => 3,
                        };
                        let offset = (*input).stride as isize * y1 as isize +
                                     bytes_pp * x1 as isize;
                        (*input).pixels = (*input).pixels.offset(offset);
                        (*input).w = x2 - x1;
                        (*input).h = y2 - y1;
                        // println!("Changing pointer by {}, w{}, h{}", offset, (*input).w, (*input).h);

                        ctx.weight_mut(ix).result = NodeResult::Frame(input);
                        ctx.first_parent_input_weight_mut(ix).unwrap().result =
                            NodeResult::Consumed;
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn crop_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.crop",
        name: "crop",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(crop_size),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                let mut new_nodes = Vec::with_capacity(2);
                if ctx.has_other_children(ctx.first_parent_input(ix).unwrap(), ix) {
                    new_nodes.push(Node::new(&CLONE, NodeParams::None));
                }
                new_nodes.push(Node::new(&CROP_MUTATE,
                                         NodeParams::Json(ctx.get_json_params(ix).unwrap())));
                ctx.replace_node(ix, new_nodes);
            }
            f
        }),
        ..Default::default()
    }
}

fn crop_whitespace_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.crop_whitespace",
        name: "crop_whitespace",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                ctx.weight_mut(ix).frame_est = FrameEstimate::Impossible;
            }
            f
        }),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

                // detect bounds, increase, and replace with crop
                if let s::Node::CropWhitespace {threshold, percent_padding} = ctx.get_json_params(ix).unwrap() {
                    let (x1, y1, x2, y2) = match ctx.first_parent_input_weight(ix).unwrap().result {
                        NodeResult::Frame(b) => {
                            unsafe {
                                let rect = ::ffi::detect_content(ctx.c.flow_c(), b, threshold);
                                let padding = (percent_padding * (rect.x2 - rect.x1 + rect.y2 - rect.y1) as f32 / 2f32).ceil() as i32;
                                (cmp::max(0, rect.x1 - padding) as u32, cmp::max(0, rect.y1 - padding) as u32,
                                 cmp::min((*b).w as i32, rect.x2 + padding) as u32, cmp::min((*b).h as i32, rect.y2 + padding) as u32)
                            }
                        },
                        _ => { panic!("") }
                    };

                    ctx.replace_node(ix, vec![
                        Node::new(&CROP,
                                  NodeParams::Json(s::Node::Crop{ x1: x1, y1: y1, x2: x2, y2: y2 }))
                    ]);
                }
            }
            f
        }),
        ..Default::default()
    }
}
lazy_static! {
    pub static ref CLONE: NodeDefinition = clone_def();
    pub static ref CROP_MUTATE: NodeDefinition = crop_mutate_def();
    pub static ref CROP: NodeDefinition = crop_def();
    pub static ref CROP_WHITESPACE: NodeDefinition = crop_whitespace_def();
    pub static ref EXPAND_CANVAS: NodeDefinition = expand_canvas_def();

    pub static ref COPY_RECT: NodeDefinition = copy_rect_def();
    pub static ref FILL_RECT: NodeDefinition = fill_rect_def();
}
<commit_msg>Check crop coordinates<commit_after>use super::internal_prelude::*;

fn copy_rect_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.copy_rect_to_canvas",
        name: "copy_rect",
        inbound_edges: EdgesIn::OneInputOneCanvas,
        description: "Copy Rect",
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_canvas),
        fn_execute: Some({

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

                if let s::Node::CopyRectToCanvas { from_x, from_y, width, height, x, y } =
                       ctx.get_json_params(ix).unwrap() {
                    let input: *mut ::ffi::BitmapBgra =
                        ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    let canvas: *mut ::ffi::BitmapBgra =
                        ctx.first_parent_result_frame(ix, EdgeKind::Canvas).unwrap();

                    unsafe {
                        if (*input).fmt != (*canvas).fmt {
                            panic!("Can't copy between bitmaps with different pixel formats")
                        }
                        if input == canvas{
                            panic!("Canvas and input must be different bitmaps for CopyRect to work!")
                        }

                        // TODO: Implement faster path for common (full clone) path
                        //    if (info->x == 0 && info->from_x == 0 && info->from_y == 0 && info->y == 0 && info->width == input->w
                        //        && info->width == canvas->w && info->height == input->h && info->height == canvas->h
                        //        && canvas->stride == input->stride) {
                        //        memcpy(canvas->pixels, input->pixels, input->stride * input->h);
                        //        canvas->alpha_meaningful = input->alpha_meaningful;

                        if (*input).w <= from_x || (*input).h <= from_y ||
                           (*input).w < from_x + width ||
                           (*input).h < from_y + height ||
                           (*canvas).w < x + width ||
                           (*canvas).h < y + height {
                            println!("canvas {}x{}, input {}x{}, command {:?}",
                                     (*canvas).w,
                                     (*canvas).h,
                                     (*input).w,
                                     (*input).h,
                                     ctx.get_json_params(ix).unwrap());
                            panic!("Out of bounds")
                        }

                        let bytes_pp = match (*input).fmt {
                            PixelFormat::Gray8 => 1,
                            PixelFormat::Bgra32 => 4,
                            PixelFormat::Bgr24 => 3,
                        };
                        if from_x == 0 && x == 0 && width == (*input).w && width == (*canvas).w  &&
                            (*input).stride == (*canvas).stride && !(*canvas).borrowed_pixels {
                            //This optimization has the side effect of copying irrelevant data, so we don't want to do it if windowed, only
                            // if padded or permanently cropped.
                            let from_offset = (*input).stride * from_y;
                            let from_ptr = (*input).pixels.offset(from_offset as isize);
                            let to_offset = (*canvas).stride * y;
                            let to_ptr = (*canvas).pixels.offset(to_offset as isize);
                            ptr::copy_nonoverlapping(from_ptr, to_ptr, ((*input).stride * height) as usize);
                        }else {
                            for row in 0..height {
                                let from_offset = (*input).stride * (from_y + row) + bytes_pp * from_x;
                                let from_ptr = (*input).pixels.offset(from_offset as isize);
                                let to_offset = (*canvas).stride * (y + row) + bytes_pp * x;
                                let to_ptr = (*canvas).pixels.offset(to_offset as isize);
                                ptr::copy_nonoverlapping(from_ptr, to_ptr, (width * bytes_pp) as usize);
                            }
                        }

                        ctx.weight_mut(ix).result = NodeResult::Frame(canvas);
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn fill_rect_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.fill_rect_mutate",
        name: "fill_rect",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),
        fn_execute: Some({

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

                if let s::Node::FillRect { x1, x2, y1, y2, color } = ctx.get_json_params(ix)
                    .unwrap() {

                    let input = ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    unsafe {

                        if !ffi::flow_bitmap_bgra_fill_rect(ctx.c.flow_c(),
                                                            input,
                                                            x1,
                                                            y1,
                                                            x2,
                                                            y2,
                                                            color.to_u32_bgra().unwrap()) {
                            panic!("failed to fill rect. epic.");
                        }

                        ctx.weight_mut(ix).result = NodeResult::Frame(input);
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn clone_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.clone",
        name: "Clone",
        description: "Clone",
        fn_estimate: Some(NodeDefHelpers::copy_frame_est_from_first_input),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.first_parent_input_weight(ix).unwrap().frame_est {
                    FrameEstimate::Some(FrameInfo { w, h, fmt, alpha_meaningful }) => {
                        let canvas_params = s::Node::CreateCanvas {
                            w: w as usize,
                            h: h as usize,
                            format: s::PixelFormat::from(fmt),
                            color: s::Color::Transparent,
                        };
                        let copy_params = s::Node::CopyRectToCanvas {
                            from_x: 0,
                            from_y: 0,
                            x: 0,
                            y: 0,
                            width: w as u32,
                            height: h as u32,
                        };
                        let canvas = ctx.graph
                            .add_node(Node::new(&CREATE_CANVAS, NodeParams::Json(canvas_params)));
                        let copy = ctx.graph
                            .add_node(Node::new(&COPY_RECT, NodeParams::Json(copy_params)));
                        ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
                        ctx.replace_node_with_existing(ix, copy);
                    }
                    _ => panic!(""),
                }

            }
            f
        }),
        ..Default::default()
    }
}
fn expand_canvas_size(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

    let input_info = ctx.first_parent_frame_info_some(ix).unwrap();

    let weight = &mut ctx.weight_mut(ix);
    match weight.params {
        NodeParams::Json(s::Node::ExpandCanvas { ref left,
                                                 ref top,
                                                 ref bottom,
                                                 ref right,
                                                 ref color }) => {
            weight.frame_est = FrameEstimate::Some(FrameInfo {
                w: input_info.w + *left as i32 + *right as i32,
                h: input_info.h + *top as i32 + *bottom as i32,
                fmt: ffi::PixelFormat::from(input_info.fmt),
                alpha_meaningful: input_info.alpha_meaningful,
            }); //TODO: May change if color has alpha
        }
        _ => {
            panic!("Node params missing");
        }
    }
}

fn expand_canvas_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.expand_canvas",
        name: "expand canvas",
        inbound_edges: EdgesIn::OneInput,
        description: "Expand Canvas",
        fn_estimate: Some(expand_canvas_size),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                match ctx.first_parent_input_weight(ix).unwrap().frame_est {
                    FrameEstimate::Some(FrameInfo { w, h, fmt, alpha_meaningful }) => {
                        if let s::Node::ExpandCanvas { left, top, right, bottom, color } =
                               ctx.get_json_params(ix).unwrap() {
                            let new_w = w as usize + left as usize + right as usize;
                            let new_h = h as usize + top as usize + bottom as usize;
                            let canvas_params = s::Node::CreateCanvas {
                                w: new_w as usize,
                                h: new_h as usize,
                                format: s::PixelFormat::from(fmt),
                                color: color,
                            };
                            let copy_params = s::Node::CopyRectToCanvas {
                                from_x: 0,
                                from_y: 0,
                                x: left,
                                y: top,
                                width: w as u32,
                                height: h as u32,
                            };
                            let canvas = ctx.graph
                                .add_node(Node::new(&CREATE_CANVAS,
                                                    NodeParams::Json(canvas_params)));
                            let copy = ctx.graph
                                .add_node(Node::new(&COPY_RECT, NodeParams::Json(copy_params)));
                            ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
                            ctx.replace_node_with_existing(ix, copy);
                        }
                    }
                    _ => panic!(""),
                }
            }
            f
        }),
        ..Default::default()
    }
}

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

    let input_info = ctx.first_parent_frame_info_some(ix).unwrap_or_else(|| {
        println!("{:?}", ctx.graph_to_str());
        panic!("");
    });

    let weight = &mut ctx.weight_mut(ix);
    match weight.params {
        NodeParams::Json(s::Node::Crop { ref x1, ref y1, ref x2, ref y2 }) => {
            weight.frame_est = FrameEstimate::Some(FrameInfo {
                w: *x2 as i32 - *x1 as i32,
                h: *y2 as i32 - *y1 as i32,
                fmt: ffi::PixelFormat::from(input_info.fmt),
                alpha_meaningful: input_info.alpha_meaningful,
            });
        }
        _ => {
            panic!("Node params missing");
        }
    }
}
fn crop_mutate_def() -> NodeDefinition {
    NodeDefinition {
        // TODO: As a mutating node, shouldn't this verify no siblings exist? 'Consumed' might be non-deterministic
        fqn: "imazen.crop_mutate",
        name: "crop_mutate",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(crop_size),
        fn_execute: Some({

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

                if let s::Node::Crop { x1, x2, y1, y2 } = ctx.get_json_params(ix).unwrap() {

                    let input = ctx.first_parent_result_frame(ix, EdgeKind::Input).unwrap();
                    unsafe {
                        // println!("Cropping {}x{} to ({},{}) ({},{})", (*input).w, (*input).h, x1, y1, x2, y2);

                        let (w,h) = ((*input).w, (*input).h);
                        if x2 <= x1 || y2 <= y1 || x2 > w || y2 > h{
                            panic!("Invalid crop bounds {:?} (image {}x{})", ((x1,y1),(x2,y2)), w,h);
                        }

                        let bytes_pp = match (*input).fmt {
                            PixelFormat::Gray8 => 1,
                            PixelFormat::Bgra32 => 4,
                            PixelFormat::Bgr24 => 3,
                        };
                        let offset = (*input).stride as isize * y1 as isize +
                                     bytes_pp * x1 as isize;
                        (*input).pixels = (*input).pixels.offset(offset);
                        (*input).w = x2 - x1;
                        (*input).h = y2 - y1;
                        // println!("Changing pointer by {}, w{}, h{}", offset, (*input).w, (*input).h);

                        ctx.weight_mut(ix).result = NodeResult::Frame(input);
                        ctx.first_parent_input_weight_mut(ix).unwrap().result =
                            NodeResult::Consumed;
                    }

                } else {
                    panic!("Missing params")
                }
            }
            f
        }),
        ..Default::default()
    }
}

fn crop_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.crop",
        name: "crop",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some(crop_size),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                let mut new_nodes = Vec::with_capacity(2);
                if ctx.has_other_children(ctx.first_parent_input(ix).unwrap(), ix) {
                    new_nodes.push(Node::new(&CLONE, NodeParams::None));
                }
                new_nodes.push(Node::new(&CROP_MUTATE,
                                         NodeParams::Json(ctx.get_json_params(ix).unwrap())));
                ctx.replace_node(ix, new_nodes);
            }
            f
        }),
        ..Default::default()
    }
}

fn crop_whitespace_def() -> NodeDefinition {
    NodeDefinition {
        fqn: "imazen.crop_whitespace",
        name: "crop_whitespace",
        inbound_edges: EdgesIn::OneInput,
        fn_estimate: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {
                ctx.weight_mut(ix).frame_est = FrameEstimate::Impossible;
            }
            f
        }),
        fn_flatten_pre_optimize: Some({
            fn f(ctx: &mut OpCtxMut, ix: NodeIndex<u32>) {

                // detect bounds, increase, and replace with crop
                if let s::Node::CropWhitespace {threshold, percent_padding} = ctx.get_json_params(ix).unwrap() {
                    let (x1, y1, x2, y2) = match ctx.first_parent_input_weight(ix).unwrap().result {
                        NodeResult::Frame(b) => {
                            unsafe {
                                let rect = ::ffi::detect_content(ctx.c.flow_c(), b, threshold);
                                let padding = (percent_padding * (rect.x2 - rect.x1 + rect.y2 - rect.y1) as f32 / 2f32).ceil() as i32;
                                (cmp::max(0, rect.x1 - padding) as u32, cmp::max(0, rect.y1 - padding) as u32,
                                 cmp::min((*b).w as i32, rect.x2 + padding) as u32, cmp::min((*b).h as i32, rect.y2 + padding) as u32)
                            }
                        },
                        _ => { panic!("") }
                    };

                    ctx.replace_node(ix, vec![
                        Node::new(&CROP,
                                  NodeParams::Json(s::Node::Crop{ x1: x1, y1: y1, x2: x2, y2: y2 }))
                    ]);
                }
            }
            f
        }),
        ..Default::default()
    }
}
lazy_static! {
    pub static ref CLONE: NodeDefinition = clone_def();
    pub static ref CROP_MUTATE: NodeDefinition = crop_mutate_def();
    pub static ref CROP: NodeDefinition = crop_def();
    pub static ref CROP_WHITESPACE: NodeDefinition = crop_whitespace_def();
    pub static ref EXPAND_CANVAS: NodeDefinition = expand_canvas_def();

    pub static ref COPY_RECT: NodeDefinition = copy_rect_def();
    pub static ref FILL_RECT: NodeDefinition = fill_rect_def();
}
<|endoftext|>


<commit_before>use gitlib::{GitRepo, GitError};
use Manifest;

use std::fs::ReadDir;
use std::path::{Path, PathBuf};

struct ExploratoryMode {
    read_dir: Option<ReadDir>,
    pending: Vec<PathBuf>,
}

impl Iterator for ExploratoryMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        while self.pending.len() > 0 || self.read_dir.is_some() {
            {
                let iter = match self.read_dir {
                    Some(ref mut it) => it,
                    None => {
                        let current_dir = match self.pending.pop() {
                            Some(p) => p,
                            None => continue,
                        };

                        let read_result = current_dir.read_dir();

                        if let Err(_) = read_result {
                            continue;
                        }

                        let it = read_result.unwrap();
                        self.read_dir = Some(it);
                        self.read_dir.as_mut().unwrap()
                    }
                };

                while let Some(dir_entry) = iter.next() {
                    let entry = {
                        if !dir_entry.is_ok() {
                            continue;
                        }

                        dir_entry.unwrap()
                    };

                    match entry.file_type() {
                        Ok(t) => {
                            if !t.is_dir() {
                                continue;
                            }
                        }
                        Err(_) => continue,
                    }

                    let path = entry.path();

                    match path.file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    if name_str.starts_with(".") || name_str.starts_with("$") {
                                        continue;
                                    }
                                }
                                None => continue,
                            }
                        }
                        None => continue,
                    };

                    let repo = match GitRepo::new(&path) {
                        Ok(r) => r,
                        Err(GitError::OpenRepo) => {
                            self.pending.push(path.to_path_buf());
                            continue;
                        }
                        Err(_) => continue,
                    };

                    return Some(repo);
                }
            }

            self.read_dir = None;
        }

        None
    }
}

struct ManifestMode {}

impl Iterator for ManifestMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

enum RepoMode {
    Exploratory(ExploratoryMode),
    Manifest(ManifestMode),
}

impl Iterator for RepoMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            RepoMode::Exploratory(ref mut em) => em.next(),
            RepoMode::Manifest(ref mut mm) => mm.next(),
        }
    }
}

pub struct GitRepositories {
    mode: RepoMode,
}

impl GitRepositories {
    pub fn new(path: &Path) -> Self {
        let exp = ExploratoryMode {
            read_dir: None,
            pending: vec![path.to_owned()],
        };

        GitRepositories { mode: RepoMode::Exploratory(exp) }
    }

    pub fn from_manifest(manifest: &Manifest) -> Self {
        let man = ManifestMode {};

        GitRepositories { mode: RepoMode::Manifest(man) }
    }
}

impl Iterator for GitRepositories {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        self.mode.next()
    }
}<commit_msg>Removed extra layer of iterator abstraction<commit_after>use gitlib::{GitRepo, GitError};
use Manifest;

use std::fs::ReadDir;
use std::path::{Path, PathBuf};

struct ExploratoryMode {
    read_dir: Option<ReadDir>,
    pending: Vec<PathBuf>,
}

impl Iterator for ExploratoryMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        while self.pending.len() > 0 || self.read_dir.is_some() {
            {
                let iter = match self.read_dir {
                    Some(ref mut it) => it,
                    None => {
                        let current_dir = match self.pending.pop() {
                            Some(p) => p,
                            None => continue,
                        };

                        let read_result = current_dir.read_dir();

                        if let Err(_) = read_result {
                            continue;
                        }

                        let it = read_result.unwrap();
                        self.read_dir = Some(it);
                        self.read_dir.as_mut().unwrap()
                    }
                };

                while let Some(dir_entry) = iter.next() {
                    let entry = {
                        if !dir_entry.is_ok() {
                            continue;
                        }

                        dir_entry.unwrap()
                    };

                    match entry.file_type() {
                        Ok(t) => {
                            if !t.is_dir() {
                                continue;
                            }
                        }
                        Err(_) => continue,
                    }

                    let path = entry.path();

                    match path.file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    if name_str.starts_with(".") || name_str.starts_with("$") {
                                        continue;
                                    }
                                }
                                None => continue,
                            }
                        }
                        None => continue,
                    };

                    let repo = match GitRepo::new(&path) {
                        Ok(r) => r,
                        Err(GitError::OpenRepo) => {
                            self.pending.push(path.to_path_buf());
                            continue;
                        }
                        Err(_) => continue,
                    };

                    return Some(repo);
                }
            }

            self.read_dir = None;
        }

        None
    }
}

struct ManifestMode {}

impl Iterator for ManifestMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

enum RepoMode {
    Exploratory(ExploratoryMode),
    Manifest(ManifestMode),
}

pub struct GitRepositories {
    mode: RepoMode,
}

impl GitRepositories {
    pub fn new(path: &Path) -> Self {
        let exp = ExploratoryMode {
            read_dir: None,
            pending: vec![path.to_owned()],
        };

        GitRepositories { mode: RepoMode::Exploratory(exp) }
    }

    pub fn from_manifest(manifest: &Manifest) -> Self {
        let man = ManifestMode {};

        GitRepositories { mode: RepoMode::Manifest(man) }
    }
}

impl Iterator for GitRepositories {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        match self.mode {
            RepoMode::Exploratory(ref mut em) => em.next(),
            RepoMode::Manifest(ref mut mm) => mm.next(),
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use super::path_expr::{
    PathExpression, PathLeg, PATH_EXPR_ARRAY_INDEX_ASTERISK, PATH_EXPR_ASTERISK,
};
use super::Json;

impl Json {
    // extract receives several path expressions as arguments, matches them in j, and returns
    // the target JSON matched any path expressions, which may be autowrapped as an array.
    // If there is no any expression matched, it returns None.
    pub fn extract(&self, path_expr_list: &[PathExpression]) -> Option<Json> {
        let mut elem_list = Vec::with_capacity(path_expr_list.len());
        for path_expr in path_expr_list {
            elem_list.append(&mut extract_json(self, &path_expr.legs))
        }
        if elem_list.is_empty() {
            return None;
        }
        if path_expr_list.len() == 1 && elem_list.len() == 1 {
            // If path_expr contains asterisks, elem_list.len() won't be 1
            // even if path_expr_list.len() equals to 1.
            return Some(elem_list.remove(0));
        }
        Some(Json::Array(elem_list))
    }
}

// extract_json is used by JSON::extract().
pub fn extract_json(j: &Json, path_legs: &[PathLeg]) -> Vec<Json> {
    if path_legs.is_empty() {
        return vec![j.clone()];
    }
    let (current_leg, sub_path_legs) = (&path_legs[0], &path_legs[1..]);
    let mut ret = vec![];
    match *current_leg {
        PathLeg::Index(i) => match *j {
            Json::Array(ref array) => {
                if i == PATH_EXPR_ARRAY_INDEX_ASTERISK {
                    for child in array {
                        ret.append(&mut extract_json(child, sub_path_legs))
                    }
                } else if (i as usize) < array.len() {
                    ret.append(&mut extract_json(&array[i as usize], sub_path_legs))
                }
            }
            _ => {
                if (i == PATH_EXPR_ARRAY_INDEX_ASTERISK) || (i as usize == 0) {
                    ret.append(&mut extract_json(j, sub_path_legs))
                }
            }
        },
        PathLeg::Key(ref key) => {
            if let Json::Object(ref map) = *j {
                if key == PATH_EXPR_ASTERISK {
                    for key in map.keys() {
                        ret.append(&mut extract_json(&map[key], sub_path_legs))
                    }
                } else if map.contains_key(key) {
                    ret.append(&mut extract_json(&map[key], sub_path_legs))
                }
            }
        }
        PathLeg::DoubleAsterisk => {
            ret.append(&mut extract_json(j, sub_path_legs));
            match *j {
                Json::Array(ref array) => {
                    for child in array {
                        ret.append(&mut extract_json(child, path_legs))
                    }
                }
                Json::Object(ref map) => {
                    for key in map.keys() {
                        ret.append(&mut extract_json(&map[key], path_legs))
                    }
                }
                _ => {}
            }
        }
    }
    ret
}

#[cfg(test)]
mod tests {
    use super::super::path_expr::{
        PathExpressionFlag, PATH_EXPRESSION_CONTAINS_ASTERISK,
        PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK, PATH_EXPR_ARRAY_INDEX_ASTERISK,
    };
    use super::*;
    use std::str::FromStr;

    #[test]
    fn test_json_extract() {
        let mut test_cases = vec![
            // no path expression
            ("null", vec![], None),
            // Index
            (
                "[true, 2017]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("true"),
            ),
            (
                "[true, 2017]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PATH_EXPRESSION_CONTAINS_ASTERISK,
                }],
                Some("[true, 2017]"),
            ),
            (
                "[true, 2107]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(2)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                "6.18",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("6.18"),
            ),
            // Key
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from("c"))],
                    flags: PathExpressionFlag::default(),
                }],
                Some("false"),
            ),
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from(PATH_EXPR_ASTERISK))],
                    flags: PATH_EXPRESSION_CONTAINS_ASTERISK,
                }],
                Some(r#"["a1", 20.08, false]"#),
            ),
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from("d"))],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            // Double asterisks
            (
                "21",
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                None,
            ),
            (
                r#"{"g": {"a": "a1", "b": 20.08, "c": false}}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                Some("false"),
            ),
            (
                r#"[{"a": "a1", "b": 20.08, "c": false}, true]"#,
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                Some("false"),
            ),
        ];
        for (i, (js, exprs, expected)) in test_cases.drain(..).enumerate() {
            let j = js.parse();
            assert!(j.is_ok(), "#{} expect parse ok but got {:?}", i, j);
            let j: Json = j.unwrap();
            let expected = match expected {
                Some(es) => {
                    let e = Json::from_str(es);
                    assert!(e.is_ok(), "#{} expect parse json ok but got {:?}", i, e);
                    Some(e.unwrap())
                }
                None => None,
            };
            let got = j.extract(&exprs[..]);
            assert_eq!(
                got, expected,
                "#{} expect {:?}, but got {:?}",
                i, expected, got
            );
        }
    }
}
<commit_msg>copr: fix json_extract with PathLeg::Index (#5837)<commit_after>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use super::path_expr::{
    PathExpression, PathLeg, PATH_EXPR_ARRAY_INDEX_ASTERISK, PATH_EXPR_ASTERISK,
};
use super::Json;

impl Json {
    // extract receives several path expressions as arguments, matches them in j, and returns
    // the target JSON matched any path expressions, which may be autowrapped as an array.
    // If there is no any expression matched, it returns None.
    pub fn extract(&self, path_expr_list: &[PathExpression]) -> Option<Json> {
        let mut elem_list = Vec::with_capacity(path_expr_list.len());
        for path_expr in path_expr_list {
            elem_list.append(&mut extract_json(self, &path_expr.legs))
        }
        if elem_list.is_empty() {
            return None;
        }
        if path_expr_list.len() == 1 && elem_list.len() == 1 {
            // If path_expr contains asterisks, elem_list.len() won't be 1
            // even if path_expr_list.len() equals to 1.
            return Some(elem_list.remove(0));
        }
        Some(Json::Array(elem_list))
    }
}

// extract_json is used by JSON::extract().
pub fn extract_json(j: &Json, path_legs: &[PathLeg]) -> Vec<Json> {
    if path_legs.is_empty() {
        return vec![j.clone()];
    }
    let (current_leg, sub_path_legs) = (&path_legs[0], &path_legs[1..]);
    let mut ret = vec![];
    match *current_leg {
        PathLeg::Index(i) => match *j {
            Json::Array(ref array) => {
                if i == PATH_EXPR_ARRAY_INDEX_ASTERISK {
                    for child in array {
                        ret.append(&mut extract_json(child, sub_path_legs))
                    }
                } else if (i as usize) < array.len() {
                    ret.append(&mut extract_json(&array[i as usize], sub_path_legs))
                }
            }
            _ => {
                if i as usize == 0 {
                    ret.append(&mut extract_json(j, sub_path_legs))
                }
            }
        },
        PathLeg::Key(ref key) => {
            if let Json::Object(ref map) = *j {
                if key == PATH_EXPR_ASTERISK {
                    for key in map.keys() {
                        ret.append(&mut extract_json(&map[key], sub_path_legs))
                    }
                } else if map.contains_key(key) {
                    ret.append(&mut extract_json(&map[key], sub_path_legs))
                }
            }
        }
        PathLeg::DoubleAsterisk => {
            ret.append(&mut extract_json(j, sub_path_legs));
            match *j {
                Json::Array(ref array) => {
                    for child in array {
                        ret.append(&mut extract_json(child, path_legs))
                    }
                }
                Json::Object(ref map) => {
                    for key in map.keys() {
                        ret.append(&mut extract_json(&map[key], path_legs))
                    }
                }
                _ => {}
            }
        }
    }
    ret
}

#[cfg(test)]
mod tests {
    use super::super::path_expr::{
        PathExpressionFlag, PATH_EXPRESSION_CONTAINS_ASTERISK,
        PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK, PATH_EXPR_ARRAY_INDEX_ASTERISK,
    };
    use super::*;
    use std::str::FromStr;

    #[test]
    fn test_json_extract() {
        let mut test_cases = vec![
            // no path expression
            ("null", vec![], None),
            // Index
            (
                "[true, 2017]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("true"),
            ),
            (
                "[true, 2017]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PATH_EXPRESSION_CONTAINS_ASTERISK,
                }],
                Some("[true, 2017]"),
            ),
            (
                "[true, 2107]",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(2)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                "6.18",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("6.18"),
            ),
            (
                "6.18",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                "true",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("true"),
            ),
            (
                "true",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                "6",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("6"),
            ),
            (
                "6",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                "-6",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some("-6"),
            ),
            (
                "-6",
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                r#"{"a": [1, 2, {"aa": "xx"}]}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Index(PATH_EXPR_ARRAY_INDEX_ASTERISK)],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            (
                r#"{"a": [1, 2, {"aa": "xx"}]}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Index(0)],
                    flags: PathExpressionFlag::default(),
                }],
                Some(r#"{"a": [1, 2, {"aa": "xx"}]}"#),
            ),
            // Key
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from("c"))],
                    flags: PathExpressionFlag::default(),
                }],
                Some("false"),
            ),
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from(PATH_EXPR_ASTERISK))],
                    flags: PATH_EXPRESSION_CONTAINS_ASTERISK,
                }],
                Some(r#"["a1", 20.08, false]"#),
            ),
            (
                r#"{"a": "a1", "b": 20.08, "c": false}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::Key(String::from("d"))],
                    flags: PathExpressionFlag::default(),
                }],
                None,
            ),
            // Double asterisks
            (
                "21",
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                None,
            ),
            (
                r#"{"g": {"a": "a1", "b": 20.08, "c": false}}"#,
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                Some("false"),
            ),
            (
                r#"[{"a": "a1", "b": 20.08, "c": false}, true]"#,
                vec![PathExpression {
                    legs: vec![PathLeg::DoubleAsterisk, PathLeg::Key(String::from("c"))],
                    flags: PATH_EXPRESSION_CONTAINS_DOUBLE_ASTERISK,
                }],
                Some("false"),
            ),
        ];
        for (i, (js, exprs, expected)) in test_cases.drain(..).enumerate() {
            let j = js.parse();
            assert!(j.is_ok(), "#{} expect parse ok but got {:?}", i, j);
            let j: Json = j.unwrap();
            let expected = match expected {
                Some(es) => {
                    let e = Json::from_str(es);
                    assert!(e.is_ok(), "#{} expect parse json ok but got {:?}", i, e);
                    Some(e.unwrap())
                }
                None => None,
            };
            let got = j.extract(&exprs[..]);
            assert_eq!(
                got, expected,
                "#{} expect {:?}, but got {:?}",
                i, expected, got
            );
        }
    }
}
<|endoftext|>


<commit_before>#![allow(missing_docs)] // for downcast.

use downcast_rs::Downcast;
use na::RealField;

use crate::object::BodySet;
use crate::solver::IntegrationParameters;

/// The handle of a force generator.
pub type ForceGeneratorHandle = usize;

/// A persistent force generator.
///
/// A force generator applies a force to one or several bodies at each step of the simulation.
pub trait ForceGenerator<N: RealField>: Downcast + Send + Sync {
    /// Apply forces to some bodies.
    fn apply(&mut self, params: &IntegrationParameters<N>, bodies: &mut BodySet<N>) -> bool;
}

impl_downcast!(ForceGenerator<N> where N: RealField);
<commit_msg>Update documentation for `ForceGenerator` trait<commit_after>#![allow(missing_docs)] // for downcast.

use downcast_rs::Downcast;
use na::RealField;

use crate::object::BodySet;
use crate::solver::IntegrationParameters;

/// The handle of a force generator.
pub type ForceGeneratorHandle = usize;

/// A persistent force generator.
///
/// A force generator applies a force to one or several bodies at each step of the simulation.
pub trait ForceGenerator<N: RealField>: Downcast + Send + Sync {
    /// Apply forces to some bodies. Returns false to indicate that the force generator should be
    /// removed from the simulation.
    fn apply(&mut self, params: &IntegrationParameters<N>, bodies: &mut BodySet<N>) -> bool;
}

impl_downcast!(ForceGenerator<N> where N: RealField);
<|endoftext|>


<commit_before>pub mod data;
pub mod entity;
pub mod function;
pub mod globals;
pub mod memory;
pub mod opcode;
pub mod state;
pub mod table;
pub mod traps;

mod name;

pub use self::name::Name;

use crate::compiler::traps::write_trap_manifest;
use crate::program::{Function, Program, TableDef};
use byteorder::{LittleEndian, WriteBytesExt};
use cranelift_codegen::settings::{self, Configurable};
use cranelift_codegen::{ir, isa, print_errors::pretty_error, CodegenError};
use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
use cranelift_module::{DataContext, Linkage, Module, ModuleError};
use cranelift_native;
use faerie::Artifact;
use failure::{format_err, Error, ResultExt};
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy)]
pub enum OptLevel {
    Default,
    Best,
    Fastest,
}

impl OptLevel {
    fn to_flag(&self) -> &str {
        match self {
            OptLevel::Default => "default",
            OptLevel::Best => "best",
            OptLevel::Fastest => "fastest",
        }
    }
}

fn isa(opt_level: OptLevel) -> Box<isa::TargetIsa> {
    let mut flags_builder = settings::builder();
    let isa_builder = cranelift_native::builder().expect("host machine is not a supported target");
    flags_builder.enable("enable_verifier").unwrap();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("opt_level", opt_level.to_flag()).unwrap();
    isa_builder.finish(settings::Flags::new(flags_builder))
}

pub struct Compiler<'p> {
    pub prog: &'p Program,
    funcs: HashMap<Name, ir::Function>,
    module: Module<FaerieBackend>,
    opt_level: OptLevel,
}

impl<'p> Compiler<'p> {
    pub fn new(name: String, prog: &'p Program, opt_level: OptLevel) -> Result<Self, Error> {
        let libcalls = Box::new(move |libcall| match libcall {
            ir::LibCall::Probestack => "lucet_probestack".to_owned(),
            _ => (FaerieBuilder::default_libcall_names())(libcall),
        });

        let mut compiler = Self {
            funcs: HashMap::new(),
            module: Module::new(FaerieBuilder::new(
                isa(opt_level),
                name,
                FaerieTrapCollection::Enabled,
                libcalls,
            )?),
            prog: prog,
            opt_level: opt_level,
        };

        for f in prog.import_functions() {
            compiler.declare_function(f)?;
        }

        let start_section = prog.module().start_section();
        for f in prog.defined_functions() {
            let name = compiler.declare_function(f)?;
            if Some(f.wasmidx) == start_section {
                compiler.define_start_symbol(&name)?;
            }
        }

        for f in prog.runtime_functions() {
            compiler.declare_function(f)?;
        }

        for t in prog.tables() {
            compiler.declare_table(t)?;
        }
        Ok(compiler)
    }

    pub fn isa(&self) -> Box<isa::TargetIsa> {
        isa(self.opt_level)
    }

    /// Add a `guest_start` data symbol pointing to the `start` section.
    ///
    /// We want to have the symbol `guest_start` point to the function
    /// designated in the `start` section of the wasm module, but we
    /// also want whatever function that is to be callable by its
    /// normal symbol. Since ELF doesn't support aliasing function
    /// symbols, we add a data symbol with a reloc pointer to the
    /// function's normal symbol.
    pub fn define_start_symbol(&mut self, start_func: &Name) -> Result<(), Error> {
        let name = self.declare_data("guest_start", Linkage::Export, false)?;
        let mut ctx = DataContext::new();
        ctx.define_zeroinit(8);
        let fid = start_func
            .into_funcid()
            .ok_or(format_err!("start index pointed to a non-function"))?;
        let fref = self.module.declare_func_in_data(fid, &mut ctx);
        ctx.write_function_addr(0, fref);
        self.define_data(name, &ctx)
    }

    pub fn declare_function(&mut self, func: &Function) -> Result<Name, Error> {
        let funcid = self
            .module
            .declare_function(&func.symbol(), func.linkage(), &func.signature())
            .context(format!("declaration of {}", func.symbol()))?;
        Ok(Name::new_func(func.symbol().to_owned(), funcid))
    }

    pub fn declare_table(&mut self, table: &TableDef) -> Result<Name, Error> {
        let mut serialized_len: Vec<u8> = Vec::new();
        serialized_len
            .write_u64::<LittleEndian>(table.len() as u64)
            .unwrap();
        let mut len_ctx = DataContext::new();
        len_ctx.define(serialized_len.into_boxed_slice());
        let len_decl = self
            .module
            .declare_data(&table.len_symbol(), Linkage::Export, false)?;
        self.module.define_data(len_decl, &len_ctx)?;

        let dataid = self
            .module
            .declare_data(&table.symbol(), Linkage::Export, false)?;
        Ok(Name::new_data(table.symbol(), dataid))
    }

    pub fn declare_data(
        &mut self,
        sym: &str,
        linkage: Linkage,
        mutable: bool,
    ) -> Result<Name, Error> {
        let dataid = self.module.declare_data(sym, linkage, mutable)?;
        Ok(Name::new_data(sym.to_owned(), dataid))
    }

    pub fn get_function(&self, func: &Function) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(&func.symbol())
            .ok_or(format_err!("function named {} undeclared", func.symbol()))?;
        Ok(Name::new(func.symbol().to_owned(), ident))
    }

    pub fn get_table(&self, table: &TableDef) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(&table.symbol())
            .ok_or(format_err!("table named {} undeclared", table.symbol()))?;
        Ok(Name::new(table.symbol(), ident))
    }

    pub fn get_data(&self, name: &str) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(name)
            .ok_or(format_err!("data named {} undeclared", name,))?;
        Ok(Name::new(name.to_owned(), ident))
    }

    pub fn define_function(&mut self, name: Name, func: ir::Function) -> Result<(), Error> {
        use std::collections::hash_map::Entry;
        match self.funcs.entry(name.clone()) {
            Entry::Occupied(_entry) => {
                return Err(format_err!(
                    "function {} has duplicate definition",
                    name.symbol()
                ))
            }
            Entry::Vacant(entry) => {
                entry.insert(func);
            }
        }
        Ok(())
    }

    pub fn define_data(&mut self, name: Name, data: &DataContext) -> Result<(), Error> {
        let id = name
            .into_dataid()
            .ok_or(format_err!("data defined with invalid name {:?}", name))?;
        self.module.define_data(id, data)?;
        Ok(())
    }

    pub fn cranelift_funcs(self) -> CraneliftFuncs {
        CraneliftFuncs {
            funcs: self.funcs,
            isa: self.isa(),
        }
    }

    pub fn codegen(self) -> Result<ObjectFile, Error> {
        use cranelift_codegen::Context;

        let mut ctx = Context::new();
        let mut module = self.module;

        for (name, func) in self.funcs.iter() {
            ctx.func = func.clone();
            let id = name
                .into_funcid()
                .ok_or(format_err!("function defined with invalid name {:?}", name,))?;
            module.define_function(id, &mut ctx).map_err(|e| match e {
                ModuleError::Compilation(ce) => match ce {
                    CodegenError::Verifier(_) =>
                    // Verifier errors are never recoverable. This is the last
                    // time we'll have enough information still around to pretty-print
                    {
                        format_err!(
                            "code generation error:\n{}",
                            pretty_error(func, Some(&*self.isa()), ce)
                        )
                    }
                    _ => ModuleError::Compilation(ce).into(),
                },
                _ => e.into(),
            })?;
            ctx.clear();
        }

        ObjectFile::new(module.finish())
    }
}

pub struct CraneliftFuncs {
    funcs: HashMap<Name, ir::Function>,
    isa: Box<isa::TargetIsa>,
}

impl CraneliftFuncs {
    /// This outputs a .clif file
    pub fn write(&self, path: &PathBuf) -> Result<(), Error> {
        use cranelift_codegen::write_function;
        let mut buffer = String::new();
        for (n, func) in self.funcs.iter() {
            buffer.push_str(&format!("; {}\n", n.symbol()));
            write_function(&mut buffer, func, Some(self.isa.as_ref()))
                .context(format_err!("writing func {:?}", n))?
        }
        let mut file = File::create(path)?;
        file.write_all(buffer.as_bytes())?;
        Ok(())
    }
}

pub struct ObjectFile {
    artifact: Artifact,
}
impl ObjectFile {
    pub fn new(mut product: FaerieProduct) -> Result<Self, Error> {
        let trap_manifest = &product
            .trap_manifest
            .expect("trap manifest will be present");
        write_trap_manifest(trap_manifest, &mut product.artifact)?;
        Ok(Self {
            artifact: product.artifact,
        })
    }
    pub fn write(&self, path: &PathBuf) -> Result<(), Error> {
        let _ = path.file_name().ok_or(format_err!(
            "path {:?} needs to have filename",
            path.clone()
        ));
        let file = File::create(path)?;
        self.artifact.write(file)?;
        Ok(())
    }
}
<commit_msg>make the borrow checker happy<commit_after>pub mod data;
pub mod entity;
pub mod function;
pub mod globals;
pub mod memory;
pub mod opcode;
pub mod state;
pub mod table;
pub mod traps;

mod name;

pub use self::name::Name;

use crate::compiler::traps::write_trap_manifest;
use crate::program::{Function, Program, TableDef};
use byteorder::{LittleEndian, WriteBytesExt};
use cranelift_codegen::settings::{self, Configurable};
use cranelift_codegen::{ir, isa, print_errors::pretty_error, CodegenError};
use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
use cranelift_module::{DataContext, Linkage, Module, ModuleError};
use cranelift_native;
use faerie::Artifact;
use failure::{format_err, Error, ResultExt};
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy)]
pub enum OptLevel {
    Default,
    Best,
    Fastest,
}

impl OptLevel {
    fn to_flag(&self) -> &str {
        match self {
            OptLevel::Default => "default",
            OptLevel::Best => "best",
            OptLevel::Fastest => "fastest",
        }
    }
}

fn isa(opt_level: OptLevel) -> Box<isa::TargetIsa> {
    let mut flags_builder = settings::builder();
    let isa_builder = cranelift_native::builder().expect("host machine is not a supported target");
    flags_builder.enable("enable_verifier").unwrap();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("opt_level", opt_level.to_flag()).unwrap();
    isa_builder.finish(settings::Flags::new(flags_builder))
}

pub struct Compiler<'p> {
    pub prog: &'p Program,
    funcs: HashMap<Name, ir::Function>,
    module: Module<FaerieBackend>,
    opt_level: OptLevel,
}

impl<'p> Compiler<'p> {
    pub fn new(name: String, prog: &'p Program, opt_level: OptLevel) -> Result<Self, Error> {
        let libcalls = Box::new(move |libcall| match libcall {
            ir::LibCall::Probestack => "lucet_probestack".to_owned(),
            _ => (FaerieBuilder::default_libcall_names())(libcall),
        });

        let mut compiler = Self {
            funcs: HashMap::new(),
            module: Module::new(FaerieBuilder::new(
                isa(opt_level),
                name,
                FaerieTrapCollection::Enabled,
                libcalls,
            )?),
            prog: prog,
            opt_level: opt_level,
        };

        for f in prog.import_functions() {
            compiler.declare_function(f)?;
        }

        let start_section = prog.module().start_section();
        for f in prog.defined_functions() {
            let name = compiler.declare_function(f)?;
            if Some(f.wasmidx) == start_section {
                compiler.define_start_symbol(&name)?;
            }
        }

        for f in prog.runtime_functions() {
            compiler.declare_function(f)?;
        }

        for t in prog.tables() {
            compiler.declare_table(t)?;
        }
        Ok(compiler)
    }

    pub fn isa(&self) -> Box<isa::TargetIsa> {
        isa(self.opt_level)
    }

    /// Add a `guest_start` data symbol pointing to the `start` section.
    ///
    /// We want to have the symbol `guest_start` point to the function
    /// designated in the `start` section of the wasm module, but we
    /// also want whatever function that is to be callable by its
    /// normal symbol. Since ELF doesn't support aliasing function
    /// symbols, we add a data symbol with a reloc pointer to the
    /// function's normal symbol.
    pub fn define_start_symbol(&mut self, start_func: &Name) -> Result<(), Error> {
        let name = self.declare_data("guest_start", Linkage::Export, false)?;
        let mut ctx = DataContext::new();
        ctx.define_zeroinit(8);
        let fid = start_func
            .into_funcid()
            .ok_or(format_err!("start index pointed to a non-function"))?;
        let fref = self.module.declare_func_in_data(fid, &mut ctx);
        ctx.write_function_addr(0, fref);
        self.define_data(name, &ctx)
    }

    pub fn declare_function(&mut self, func: &Function) -> Result<Name, Error> {
        let funcid = self
            .module
            .declare_function(&func.symbol(), func.linkage(), &func.signature())
            .context(format!("declaration of {}", func.symbol()))?;
        Ok(Name::new_func(func.symbol().to_owned(), funcid))
    }

    pub fn declare_table(&mut self, table: &TableDef) -> Result<Name, Error> {
        let mut serialized_len: Vec<u8> = Vec::new();
        serialized_len
            .write_u64::<LittleEndian>(table.len() as u64)
            .unwrap();
        let mut len_ctx = DataContext::new();
        len_ctx.define(serialized_len.into_boxed_slice());
        let len_decl = self
            .module
            .declare_data(&table.len_symbol(), Linkage::Export, false)?;
        self.module.define_data(len_decl, &len_ctx)?;

        let dataid = self
            .module
            .declare_data(&table.symbol(), Linkage::Export, false)?;
        Ok(Name::new_data(table.symbol(), dataid))
    }

    pub fn declare_data(
        &mut self,
        sym: &str,
        linkage: Linkage,
        mutable: bool,
    ) -> Result<Name, Error> {
        let dataid = self.module.declare_data(sym, linkage, mutable)?;
        Ok(Name::new_data(sym.to_owned(), dataid))
    }

    pub fn get_function(&self, func: &Function) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(&func.symbol())
            .ok_or(format_err!("function named {} undeclared", func.symbol()))?;
        Ok(Name::new(func.symbol().to_owned(), ident))
    }

    pub fn get_table(&self, table: &TableDef) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(&table.symbol())
            .ok_or(format_err!("table named {} undeclared", table.symbol()))?;
        Ok(Name::new(table.symbol(), ident))
    }

    pub fn get_data(&self, name: &str) -> Result<Name, Error> {
        let ident = self
            .module
            .get_name(name)
            .ok_or(format_err!("data named {} undeclared", name,))?;
        Ok(Name::new(name.to_owned(), ident))
    }

    pub fn define_function(&mut self, name: Name, func: ir::Function) -> Result<(), Error> {
        use std::collections::hash_map::Entry;
        match self.funcs.entry(name.clone()) {
            Entry::Occupied(_entry) => {
                return Err(format_err!(
                    "function {} has duplicate definition",
                    name.symbol()
                ))
            }
            Entry::Vacant(entry) => {
                entry.insert(func);
            }
        }
        Ok(())
    }

    pub fn define_data(&mut self, name: Name, data: &DataContext) -> Result<(), Error> {
        let id = name
            .into_dataid()
            .ok_or(format_err!("data defined with invalid name {:?}", name))?;
        self.module.define_data(id, data)?;
        Ok(())
    }

    pub fn cranelift_funcs(self) -> CraneliftFuncs {
        let isa = self.isa();
        CraneliftFuncs {
            funcs: self.funcs,
            isa: isa,
        }
    }

    pub fn codegen(self) -> Result<ObjectFile, Error> {
        use cranelift_codegen::Context;

        let isa = &*self.isa();
        let mut ctx = Context::new();
        let mut module = self.module;

        for (name, func) in self.funcs.iter() {
            ctx.func = func.clone();
            let id = name
                .into_funcid()
                .ok_or(format_err!("function defined with invalid name {:?}", name,))?;
            module.define_function(id, &mut ctx).map_err(|e| match e {
                ModuleError::Compilation(ce) => match ce {
                    CodegenError::Verifier(_) =>
                    // Verifier errors are never recoverable. This is the last
                    // time we'll have enough information still around to pretty-print
                    {
                        format_err!(
                            "code generation error:\n{}",
                            pretty_error(func, Some(isa), ce)
                        )
                    }
                    _ => ModuleError::Compilation(ce).into(),
                },
                _ => e.into(),
            })?;
            ctx.clear();
        }

        ObjectFile::new(module.finish())
    }
}

pub struct CraneliftFuncs {
    funcs: HashMap<Name, ir::Function>,
    isa: Box<isa::TargetIsa>,
}

impl CraneliftFuncs {
    /// This outputs a .clif file
    pub fn write(&self, path: &PathBuf) -> Result<(), Error> {
        use cranelift_codegen::write_function;
        let mut buffer = String::new();
        for (n, func) in self.funcs.iter() {
            buffer.push_str(&format!("; {}\n", n.symbol()));
            write_function(&mut buffer, func, Some(self.isa.as_ref()))
                .context(format_err!("writing func {:?}", n))?
        }
        let mut file = File::create(path)?;
        file.write_all(buffer.as_bytes())?;
        Ok(())
    }
}

pub struct ObjectFile {
    artifact: Artifact,
}
impl ObjectFile {
    pub fn new(mut product: FaerieProduct) -> Result<Self, Error> {
        let trap_manifest = &product
            .trap_manifest
            .expect("trap manifest will be present");
        write_trap_manifest(trap_manifest, &mut product.artifact)?;
        Ok(Self {
            artifact: product.artifact,
        })
    }
    pub fn write(&self, path: &PathBuf) -> Result<(), Error> {
        let _ = path.file_name().ok_or(format_err!(
            "path {:?} needs to have filename",
            path.clone()
        ));
        let file = File::create(path)?;
        self.artifact.write(file)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use bit_field::BitField;

use core::register::Reg;
use core::instruction::Instruction;

#[allow(non_snake_case)]
pub fn decode_LDRB_reg_t1(command: u16) -> Instruction {
    Instruction::LDRB_reg {
        rt: Reg::from_u16(command.get_bits(0..3)).unwrap(),
        rn: Reg::from_u16(command.get_bits(3..6)).unwrap(),
        rm: Reg::from_u16(command.get_bits(6..9)).unwrap(),
    }
}

#[allow(non_snake_case)]
pub fn decode_LDRB_imm_t1(command: u16) -> Instruction {
    Instruction::LDRB_imm {
        rt: Reg::from_u16(command.get_bits(0..3)).unwrap(),
        rn: Reg::from_u16(command.get_bits(3..6)).unwrap(),
        imm32: (command.get_bits(6..11) as u32) << 2,
    }
}
<commit_msg>bugfix: LDRB_imm value is not shifted<commit_after>use bit_field::BitField;

use core::register::Reg;
use core::instruction::Instruction;

#[allow(non_snake_case)]
pub fn decode_LDRB_reg_t1(command: u16) -> Instruction {
    Instruction::LDRB_reg {
        rt: Reg::from_u16(command.get_bits(0..3)).unwrap(),
        rn: Reg::from_u16(command.get_bits(3..6)).unwrap(),
        rm: Reg::from_u16(command.get_bits(6..9)).unwrap(),
    }
}

#[allow(non_snake_case)]
pub fn decode_LDRB_imm_t1(command: u16) -> Instruction {
    Instruction::LDRB_imm {
        rt: Reg::from_u16(command.get_bits(0..3)).unwrap(),
        rn: Reg::from_u16(command.get_bits(3..6)).unwrap(),
        imm32: command.get_bits(6..11) as u32,
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

#[test]
fn basic() {
    clap_app!(claptests =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );
}

#[test]
fn quoted_app_name() {
    let app = clap_app!(("app name with spaces-and-hyphens") =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );

    assert_eq!(app.p.meta.name, "app name with spaces-and-hyphens");

    let mut help_text = vec![];
    app.write_help(&mut help_text).expect("Could not write help text.");
    let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8");
    assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n"));
}

#[test]
fn quoted_arg_long_name() {
    let app = clap_app!(claptests =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );

    let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
        .expect("Expected to successfully match the given args.");
    assert!(matches.is_present("option2"));
}
<commit_msg>tests(clap_app!): adds tests for ("config-file") style positonal args<commit_after>#[macro_use]
extern crate clap;

#[test]
fn basic() {
    clap_app!(claptests =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );
}

#[test]
fn quoted_app_name() {
    let app = clap_app!(("app name with spaces-and-hyphens") =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );

    assert_eq!(app.p.meta.name, "app name with spaces-and-hyphens");

    let mut help_text = vec![];
    app.write_help(&mut help_text).expect("Could not write help text.");
    let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8");
    assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n"));
}

#[test]
fn quoted_arg_long_name() {
    let app = clap_app!(claptests =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg positional: index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg positional3: index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );

    let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
        .expect("Expected to successfully match the given args.");
    assert!(matches.is_present("option2"));
}

#[test]
fn quoted_arg_name() {
    let app = clap_app!(claptests =>
        (version: "0.1")
        (about: "tests clap library")
        (author: "Kevin K. <kbknapp@gmail.com>")
        (@arg opt: -o --option +takes_value ... "tests options")
        (@arg ("positional-arg"): index(1) "tests positionals")
        (@arg flag: -f --flag ... +global "tests flags")
        (@arg flag2: -F conflicts_with[flag] requires[option2]
            "tests flags with exclusions")
        (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
            "tests long options with exclusions")
        (@arg positional2: index(2) "tests positionals with exclusions")
        (@arg option3: -O --Option +takes_value possible_value[fast slow]
            "tests options with specific value sets")
        (@arg ("positional-3"): index(3) ... possible_value[vi emacs]
            "tests positionals with specific values")
        (@arg multvals: --multvals +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
            "Tests mutliple values, not mult occs")
        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
        (@subcommand subcmd =>
            (about: "tests subcommands")
            (version: "0.1")
            (author: "Kevin K. <kbknapp@gmail.com>")
            (@arg scoption: -o --option ... +takes_value "tests options")
            (@arg scpositional: index(1) "tests positionals"))
    );

    let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
        .expect("Expected to successfully match the given args.");
    assert!(matches.is_present("option2"));
}
<|endoftext|>