<commit_before>/// this file tests a different backtracking behaviour. With the current
/// `error!` macro, an early return is done in the current function, but
/// backtracking continues normally outside of that function.
///
/// The solution here wraps `IResult` in a `Result`: a `Ok` indicates usual
/// backtracking, `Err` indicates that we must "cut".

#[macro_use]
extern crate nom;

#[cfg(feature = "verbose_errors")]
macro_rules! n (
    ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i,$o,u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, $e>, nom::Err<$i, $e>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name<'a>( i: &'a[u8] ) -> std::result::Result<nom::IResult<&'a [u8], $o, u32>, nom::Err<&'a [u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: &[u8] ) -> std::result::Result<nom::IResult<&[u8], &[u8], u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i,$o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, $e>, nom::Err<$i, $e>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: &[u8] ) -> std::result::Result<nom::IResult<&[u8], $o, u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident, $submac:ident!( $($args:tt)* )) => (
        pub fn $name<'a>( i: &'a [u8] ) -> std::result::Result<nom::IResult<&[u8], &[u8], u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
);

#[cfg(feature = "verbose_errors")]
macro_rules! cut (
  ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let cl = || {
        Ok($submac!($i, $($args)*))
      };

      match cl() {
        std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x),
        std::result::Result::Ok(nom::IResult::Done(i, o))    => nom::IResult::Done(i, o),
        std::result::Result::Ok(nom::IResult::Error(e)) | std::result::Result::Err(e)  => {
          return std::result::Result::Err(nom::Err::NodePosition($code, $i, Box::new(e)))
        }
      }
    }
  );
  ($i:expr, $code:expr, $f:expr) => (
    cut!($i, $code, call!($f));
  );
);

#[cfg(feature = "verbose_errors")]
macro_rules! c (
  ($i:expr, $f:expr) => (
    {
      match $f($i) {
        std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x),
        std::result::Result::Ok(nom::IResult::Done(i, o))    => nom::IResult::Done(i, o),
        std::result::Result::Ok(nom::IResult::Error(e))      => nom::IResult::Error(e),
        std::result::Result::Err(e)     => {
          return std::result::Result::Err(e)
        }
      }
    }
  );
);

#[cfg(feature = "verbose_errors")]
n!(pub foo< bool >,
    chain!(
        tag!("a") ~
        cut!(nom::ErrorKind::Custom(42),dbg_dmp!(tag!("b"))) ,
        || { true }
    )
);

#[cfg(feature = "verbose_errors")]
n!(pub foos< Vec<bool> >,
    delimited!(
        tag!("("),
        many0!(c!(foo)),
        tag!(")")
    )
);

#[cfg(feature = "verbose_errors")]
#[test]
fn test_ok() {
    let r = foos(b"(abab)");
    println!("result: {:?}", r);
    match r {
        Ok(nom::IResult::Done(_,result)) => assert_eq!(result,vec![true,true]),
        res => panic!("Oops {:?}.",res)
    }
}

#[cfg(feature = "verbose_errors")]
#[test]
fn test_err() {
    let input = b"(ac)";
    let r = foos(&input[..]);
    println!("result: {:?}", r);
    match r {
        //Ok(nom::IResult::Error(nom::Err::Position(kind,_))) => assert_eq!(kind,nom::ErrorKind::Custom(42)),
        Err(nom::Err::NodePosition(kind, position, _)) => {
          assert_eq!(kind, nom::ErrorKind::Custom(42));
          assert_eq!(position, &input[2..]);
        }
        res => panic!("Oops, {:?}",res)
    }
}

<commit_msg>tests/cross_function_backtracking: don't use chain!<commit_after>/// this file tests a different backtracking behaviour. With the current
/// `error!` macro, an early return is done in the current function, but
/// backtracking continues normally outside of that function.
///
/// The solution here wraps `IResult` in a `Result`: a `Ok` indicates usual
/// backtracking, `Err` indicates that we must "cut".

#[macro_use]
extern crate nom;

#[cfg(feature = "verbose_errors")]
macro_rules! n (
    ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i,$o,u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, $e>, nom::Err<$i, $e>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
        fn $name<'a>( i: &'a[u8] ) -> std::result::Result<nom::IResult<&'a [u8], $o, u32>, nom::Err<&'a [u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    ($name:ident, $submac:ident!( $($args:tt)* )) => (
        fn $name( i: &[u8] ) -> std::result::Result<nom::IResult<&[u8], &[u8], u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i,$o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, $e>, nom::Err<$i, $e>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: $i ) -> std::result::Result<nom::IResult<$i, $o, u32>, nom::Err<$i, u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
        pub fn $name( i: &[u8] ) -> std::result::Result<nom::IResult<&[u8], $o, u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
    (pub $name:ident, $submac:ident!( $($args:tt)* )) => (
        pub fn $name<'a>( i: &'a [u8] ) -> std::result::Result<nom::IResult<&[u8], &[u8], u32>, nom::Err<&[u8], u32>> {
            std::result::Result::Ok($submac!(i, $($args)*))
        }
    );
);

#[cfg(feature = "verbose_errors")]
macro_rules! cut (
  ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let cl = || {
        Ok($submac!($i, $($args)*))
      };

      match cl() {
        std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x),
        std::result::Result::Ok(nom::IResult::Done(i, o))    => nom::IResult::Done(i, o),
        std::result::Result::Ok(nom::IResult::Error(e)) | std::result::Result::Err(e)  => {
          return std::result::Result::Err(nom::Err::NodePosition($code, $i, Box::new(e)))
        }
      }
    }
  );
  ($i:expr, $code:expr, $f:expr) => (
    cut!($i, $code, call!($f));
  );
);

#[cfg(feature = "verbose_errors")]
macro_rules! c (
  ($i:expr, $f:expr) => (
    {
      match $f($i) {
        std::result::Result::Ok(nom::IResult::Incomplete(x)) => nom::IResult::Incomplete(x),
        std::result::Result::Ok(nom::IResult::Done(i, o))    => nom::IResult::Done(i, o),
        std::result::Result::Ok(nom::IResult::Error(e))      => nom::IResult::Error(e),
        std::result::Result::Err(e)     => {
          return std::result::Result::Err(e)
        }
      }
    }
  );
);

#[cfg(feature = "verbose_errors")]
n!(pub foo< bool >,
    do_parse!(
        tag!("a") >>
        cut!(nom::ErrorKind::Custom(42),dbg_dmp!(tag!("b"))) >>
        (true)
    )
);

#[cfg(feature = "verbose_errors")]
n!(pub foos< Vec<bool> >,
    delimited!(
        tag!("("),
        many0!(c!(foo)),
        tag!(")")
    )
);

#[cfg(feature = "verbose_errors")]
#[test]
fn test_ok() {
    let r = foos(b"(abab)");
    println!("result: {:?}", r);
    match r {
        Ok(nom::IResult::Done(_,result)) => assert_eq!(result,vec![true,true]),
        res => panic!("Oops {:?}.",res)
    }
}

#[cfg(feature = "verbose_errors")]
#[test]
fn test_err() {
    let input = b"(ac)";
    let r = foos(&input[..]);
    println!("result: {:?}", r);
    match r {
        //Ok(nom::IResult::Error(nom::Err::Position(kind,_))) => assert_eq!(kind,nom::ErrorKind::Custom(42)),
        Err(nom::Err::NodePosition(kind, position, _)) => {
          assert_eq!(kind, nom::ErrorKind::Custom(42));
          assert_eq!(position, &input[2..]);
        }
        res => panic!("Oops, {:?}",res)
    }
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use style;

#[test]
fn size_of_specified_values() {
    use std::mem::size_of;
    let threshold = 24;

    let mut bad_properties = vec![];

    macro_rules! check_property {
        ( $( { $name: ident, $boxed: expr } )+ ) => {
            $(
                let size = size_of::<style::properties::longhands::$name::SpecifiedValue>();
                let is_boxed = $boxed;
                if (!is_boxed && size > threshold) || (is_boxed && size <= threshold) {
                    bad_properties.push(("$name", size, is_boxed));
                }
            )+
        }
    }

    longhand_properties_idents!(check_property);

    let mut failing_messages = vec![];

    for bad_prop in bad_properties {
        if !bad_prop.2 {
            failing_messages.push(
                format!("Your changes have increased the size of {} SpecifiedValue to {}. The threshold is \
                        currently {}. SpecifiedValues affect size of PropertyDeclaration enum and \
                        increasing the size may negative affect style system performance. Please consider \
                        using `boxed=\"True\"` in this longhand.",
                        bad_prop.0, bad_prop.1, threshold));
        } else if bad_prop.2 {
            failing_messages.push(
                format!("Your changes have decreased the size of {} SpecifiedValue to {}. Good work! \
                        The threshold is currently {}. Please consider removing `boxed=\"True\"` from this longhand.",
                        bad_prop.0, bad_prop.1, threshold));
        }
    }

    if !failing_messages.is_empty() {
        panic!("{}", failing_messages.join("\n\n"));
    }
}
<commit_msg>use the proper property name in specified_values tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use style;

#[test]
fn size_of_specified_values() {
    use std::mem::size_of;
    let threshold = 24;

    let mut bad_properties = vec![];

    macro_rules! check_property {
        ( $( { $name: ident, $boxed: expr } )+ ) => {
            $(
                let size = size_of::<style::properties::longhands::$name::SpecifiedValue>();
                let is_boxed = $boxed;
                if (!is_boxed && size > threshold) || (is_boxed && size <= threshold) {
                    bad_properties.push((stringify!($name), size, is_boxed));
                }
            )+
        }
    }

    longhand_properties_idents!(check_property);

    let mut failing_messages = vec![];

    for bad_prop in bad_properties {
        if !bad_prop.2 {
            failing_messages.push(
                format!("Your changes have increased the size of {} SpecifiedValue to {}. The threshold is \
                        currently {}. SpecifiedValues affect size of PropertyDeclaration enum and \
                        increasing the size may negative affect style system performance. Please consider \
                        using `boxed=\"True\"` in this longhand.",
                        bad_prop.0, bad_prop.1, threshold));
        } else if bad_prop.2 {
            failing_messages.push(
                format!("Your changes have decreased the size of {} SpecifiedValue to {}. Good work! \
                        The threshold is currently {}. Please consider removing `boxed=\"True\"` from this longhand.",
                        bad_prop.0, bad_prop.1, threshold));
        }
    }

    if !failing_messages.is_empty() {
        panic!("{}", failing_messages.join("\n\n"));
    }
}
<|endoftext|>


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

use gdk_pixbuf::{Colorspace, Pixbuf};
use glib::translate::*;
use librsvg::{CairoRenderer, Loader};
use rgb::FromSlice;

use crate::c_api::checked_i32;
use crate::dpi::Dpi;
use crate::sizing::LegacySize;

use rsvg_internals::{
    surface_utils::PixelOps, Pixel, RenderingError, SharedImageSurface, SurfaceType,
};

use crate::c_api::set_gerror;

fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
    assert!(width > 0 && height > 0);

    Pixbuf::new(Colorspace::Rgb, true, 8, width, height).ok_or(RenderingError::OutOfMemory)
}

pub fn empty_pixbuf() -> Result<Pixbuf, RenderingError> {
    // GdkPixbuf does not allow zero-sized pixbufs, but Cairo allows zero-sized
    // surfaces.  In this case, return a 1-pixel transparent pixbuf.

    let pixbuf = pixbuf_new(1, 1)?;
    pixbuf.put_pixel(0, 0, 0, 0, 0, 0);

    Ok(pixbuf)
}

pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, RenderingError> {
    let width = surface.width();
    let height = surface.height();

    let pixbuf = pixbuf_new(width, height)?;
    assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
    assert!(pixbuf.get_bits_per_sample() == 8);
    assert!(pixbuf.get_n_channels() == 4);

    let pixels = unsafe { pixbuf.get_pixels() };
    let stride = pixbuf.get_rowstride() as usize;

    // We use chunks_mut(), not chunks_exact_mut(), because gdk-pixbuf tends
    // to make the last row *not* have the full stride (i.e. it is
    // only as wide as the pixels in that row).
    let pixbuf_rows = pixels.chunks_mut(stride).take(height as usize);

    for (src_row, dest_row) in surface.rows().zip(pixbuf_rows) {
        let row: &mut [Pixel] = dest_row.as_rgba_mut();

        for (src, dest) in src_row.iter().zip(row.iter_mut()) {
            *dest = Pixel::from(*src).unpremultiply();
        }
    }

    Ok(pixbuf)
}

enum SizeKind {
    Zoom,
    WidthHeight,
    WidthHeightMax,
    ZoomMax,
}

struct SizeMode {
    kind: SizeKind,
    x_zoom: f64,
    y_zoom: f64,
    width: i32,
    height: i32,
}

fn get_final_size(in_width: f64, in_height: f64, size_mode: &SizeMode) -> (f64, f64) {
    if in_width == 0.0 || in_height == 0.0 {
        return (0.0, 0.0);
    }

    let mut out_width;
    let mut out_height;

    match size_mode.kind {
        SizeKind::Zoom => {
            out_width = size_mode.x_zoom * in_width;
            out_height = size_mode.y_zoom * in_height;
        }

        SizeKind::ZoomMax => {
            out_width = size_mode.x_zoom * in_width;
            out_height = size_mode.y_zoom * in_height;

            if out_width > f64::from(size_mode.width) || out_height > f64::from(size_mode.height) {
                let zoom_x = f64::from(size_mode.width) / out_width;
                let zoom_y = f64::from(size_mode.height) / out_height;
                let zoom = zoom_x.min(zoom_y);

                out_width *= zoom;
                out_height *= zoom;
            }
        }

        SizeKind::WidthHeightMax => {
            let zoom_x = f64::from(size_mode.width) / in_width;
            let zoom_y = f64::from(size_mode.height) / in_height;

            let zoom = zoom_x.min(zoom_y);

            out_width = zoom * in_width;
            out_height = zoom * in_height;
        }

        SizeKind::WidthHeight => {
            if size_mode.width != -1 {
                out_width = f64::from(size_mode.width);
            } else {
                out_width = in_width;
            }

            if size_mode.height != -1 {
                out_height = f64::from(size_mode.height);
            } else {
                out_height = in_height;
            }
        }
    }

    (out_width, out_height)
}

fn render_to_pixbuf_at_size(
    renderer: &CairoRenderer,
    document_width: f64,
    document_height: f64,
    desired_width: f64,
    desired_height: f64,
) -> Result<Pixbuf, RenderingError> {
    if desired_width == 0.0
        || desired_height == 0.0
        || document_width == 0.0
        || document_height == 0.0
    {
        return empty_pixbuf();
    }

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        checked_i32(desired_width.round())?,
        checked_i32(desired_height.round())?,
    )?;

    {
        let cr = cairo::Context::new(&surface);
        cr.scale(
            desired_width / document_width,
            desired_height / document_height,
        );

        let viewport = cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: document_width,
            height: document_height,
        };

        // We do it with a cr transform so we can scale non-proportionally.
        renderer.render_document(&cr, &viewport)?;
    }

    let shared_surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;

    pixbuf_from_surface(&shared_surface)
}

unsafe fn pixbuf_from_file_with_size_mode(
    filename: *const libc::c_char,
    size_mode: &SizeMode,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    let path = PathBuf::from_glib_none(filename);

    let handle = match Loader::new().read_path(path) {
        Ok(handle) => handle,
        Err(e) => {
            set_gerror(error, 0, &format!("{}", e));
            return ptr::null_mut();
        }
    };

    let dpi = Dpi::default();
    let renderer = CairoRenderer::new(&handle).with_dpi(dpi.x(), dpi.y());

    let (document_width, document_height) = match renderer.legacy_document_size_in_pixels() {
        Ok(dim) => dim,
        Err(e) => {
            set_gerror(error, 0, &format!("{}", e));
            return ptr::null_mut();
        }
    };

    let (desired_width, desired_height) =
        get_final_size(document_width, document_height, size_mode);

    render_to_pixbuf_at_size(
        &renderer,
        document_width,
        document_height,
        desired_width,
        desired_height,
    )
    .map(|pixbuf| pixbuf.to_glib_full())
    .unwrap_or_else(|e| {
        set_gerror(error, 0, &format!("{}", e));
        ptr::null_mut()
    })
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file(
    filename: *const libc::c_char,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file => ptr::null_mut();

        !filename.is_null(),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: -1,
            height: -1,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_size(
    filename: *const libc::c_char,
    width: libc::c_int,
    height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_size => ptr::null_mut();

        !filename.is_null(),
        (width >= 1 && height >= 1) || (width == -1 && height == -1),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width,
            height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom(
    filename: *const libc::c_char,
    x_zoom: libc::c_double,
    y_zoom: libc::c_double,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::Zoom,
            x_zoom,
            y_zoom,
            width: 0,
            height: 0,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom_with_max(
    filename: *const libc::c_char,
    x_zoom: libc::c_double,
    y_zoom: libc::c_double,
    max_width: libc::c_int,
    max_height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom_with_max => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::ZoomMax,
            x_zoom,
            y_zoom,
            width: max_width,
            height: max_height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_max_size(
    filename: *const libc::c_char,
    max_width: libc::c_int,
    max_height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_max_size => ptr::null_mut();

        !filename.is_null(),
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeightMax,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: max_width,
            height: max_height,
        },
        error,
    )
}
<commit_msg>Toplevel module docs for pixbuf_utils<commit_after>//! Legacy C API for functions that render directly to a `GdkPixbuf`.
//!
//! This is the implementation of the `rsvg_pixbuf_*` family of functions.

use std::path::PathBuf;
use std::ptr;

use gdk_pixbuf::{Colorspace, Pixbuf};
use glib::translate::*;
use librsvg::{CairoRenderer, Loader};
use rgb::FromSlice;

use crate::c_api::checked_i32;
use crate::dpi::Dpi;
use crate::sizing::LegacySize;

use rsvg_internals::{
    surface_utils::PixelOps, Pixel, RenderingError, SharedImageSurface, SurfaceType,
};

use crate::c_api::set_gerror;

fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
    assert!(width > 0 && height > 0);

    Pixbuf::new(Colorspace::Rgb, true, 8, width, height).ok_or(RenderingError::OutOfMemory)
}

pub fn empty_pixbuf() -> Result<Pixbuf, RenderingError> {
    // GdkPixbuf does not allow zero-sized pixbufs, but Cairo allows zero-sized
    // surfaces.  In this case, return a 1-pixel transparent pixbuf.

    let pixbuf = pixbuf_new(1, 1)?;
    pixbuf.put_pixel(0, 0, 0, 0, 0, 0);

    Ok(pixbuf)
}

pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, RenderingError> {
    let width = surface.width();
    let height = surface.height();

    let pixbuf = pixbuf_new(width, height)?;
    assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
    assert!(pixbuf.get_bits_per_sample() == 8);
    assert!(pixbuf.get_n_channels() == 4);

    let pixels = unsafe { pixbuf.get_pixels() };
    let stride = pixbuf.get_rowstride() as usize;

    // We use chunks_mut(), not chunks_exact_mut(), because gdk-pixbuf tends
    // to make the last row *not* have the full stride (i.e. it is
    // only as wide as the pixels in that row).
    let pixbuf_rows = pixels.chunks_mut(stride).take(height as usize);

    for (src_row, dest_row) in surface.rows().zip(pixbuf_rows) {
        let row: &mut [Pixel] = dest_row.as_rgba_mut();

        for (src, dest) in src_row.iter().zip(row.iter_mut()) {
            *dest = Pixel::from(*src).unpremultiply();
        }
    }

    Ok(pixbuf)
}

enum SizeKind {
    Zoom,
    WidthHeight,
    WidthHeightMax,
    ZoomMax,
}

struct SizeMode {
    kind: SizeKind,
    x_zoom: f64,
    y_zoom: f64,
    width: i32,
    height: i32,
}

fn get_final_size(in_width: f64, in_height: f64, size_mode: &SizeMode) -> (f64, f64) {
    if in_width == 0.0 || in_height == 0.0 {
        return (0.0, 0.0);
    }

    let mut out_width;
    let mut out_height;

    match size_mode.kind {
        SizeKind::Zoom => {
            out_width = size_mode.x_zoom * in_width;
            out_height = size_mode.y_zoom * in_height;
        }

        SizeKind::ZoomMax => {
            out_width = size_mode.x_zoom * in_width;
            out_height = size_mode.y_zoom * in_height;

            if out_width > f64::from(size_mode.width) || out_height > f64::from(size_mode.height) {
                let zoom_x = f64::from(size_mode.width) / out_width;
                let zoom_y = f64::from(size_mode.height) / out_height;
                let zoom = zoom_x.min(zoom_y);

                out_width *= zoom;
                out_height *= zoom;
            }
        }

        SizeKind::WidthHeightMax => {
            let zoom_x = f64::from(size_mode.width) / in_width;
            let zoom_y = f64::from(size_mode.height) / in_height;

            let zoom = zoom_x.min(zoom_y);

            out_width = zoom * in_width;
            out_height = zoom * in_height;
        }

        SizeKind::WidthHeight => {
            if size_mode.width != -1 {
                out_width = f64::from(size_mode.width);
            } else {
                out_width = in_width;
            }

            if size_mode.height != -1 {
                out_height = f64::from(size_mode.height);
            } else {
                out_height = in_height;
            }
        }
    }

    (out_width, out_height)
}

fn render_to_pixbuf_at_size(
    renderer: &CairoRenderer,
    document_width: f64,
    document_height: f64,
    desired_width: f64,
    desired_height: f64,
) -> Result<Pixbuf, RenderingError> {
    if desired_width == 0.0
        || desired_height == 0.0
        || document_width == 0.0
        || document_height == 0.0
    {
        return empty_pixbuf();
    }

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        checked_i32(desired_width.round())?,
        checked_i32(desired_height.round())?,
    )?;

    {
        let cr = cairo::Context::new(&surface);
        cr.scale(
            desired_width / document_width,
            desired_height / document_height,
        );

        let viewport = cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: document_width,
            height: document_height,
        };

        // We do it with a cr transform so we can scale non-proportionally.
        renderer.render_document(&cr, &viewport)?;
    }

    let shared_surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;

    pixbuf_from_surface(&shared_surface)
}

unsafe fn pixbuf_from_file_with_size_mode(
    filename: *const libc::c_char,
    size_mode: &SizeMode,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    let path = PathBuf::from_glib_none(filename);

    let handle = match Loader::new().read_path(path) {
        Ok(handle) => handle,
        Err(e) => {
            set_gerror(error, 0, &format!("{}", e));
            return ptr::null_mut();
        }
    };

    let dpi = Dpi::default();
    let renderer = CairoRenderer::new(&handle).with_dpi(dpi.x(), dpi.y());

    let (document_width, document_height) = match renderer.legacy_document_size_in_pixels() {
        Ok(dim) => dim,
        Err(e) => {
            set_gerror(error, 0, &format!("{}", e));
            return ptr::null_mut();
        }
    };

    let (desired_width, desired_height) =
        get_final_size(document_width, document_height, size_mode);

    render_to_pixbuf_at_size(
        &renderer,
        document_width,
        document_height,
        desired_width,
        desired_height,
    )
    .map(|pixbuf| pixbuf.to_glib_full())
    .unwrap_or_else(|e| {
        set_gerror(error, 0, &format!("{}", e));
        ptr::null_mut()
    })
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file(
    filename: *const libc::c_char,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file => ptr::null_mut();

        !filename.is_null(),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: -1,
            height: -1,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_size(
    filename: *const libc::c_char,
    width: libc::c_int,
    height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_size => ptr::null_mut();

        !filename.is_null(),
        (width >= 1 && height >= 1) || (width == -1 && height == -1),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width,
            height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom(
    filename: *const libc::c_char,
    x_zoom: libc::c_double,
    y_zoom: libc::c_double,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::Zoom,
            x_zoom,
            y_zoom,
            width: 0,
            height: 0,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom_with_max(
    filename: *const libc::c_char,
    x_zoom: libc::c_double,
    y_zoom: libc::c_double,
    max_width: libc::c_int,
    max_height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom_with_max => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::ZoomMax,
            x_zoom,
            y_zoom,
            width: max_width,
            height: max_height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_max_size(
    filename: *const libc::c_char,
    max_width: libc::c_int,
    max_height: libc::c_int,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_max_size => ptr::null_mut();

        !filename.is_null(),
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeightMax,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: max_width,
            height: max_height,
        },
        error,
    )
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

#[derive(Debug, Eq, PartialEq)]
enum MatchType {
    Prefix,
    Fuzzy,
}

fn build_query(q: &str,
               match_type: MatchType,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(10000).build();

    let main_match_type = match match_type {
        MatchType::Prefix => "label.prefix",
        MatchType::Fuzzy => "label.ngram",
    };

    let boost_match_query = rs_q::build_multi_match(vec![main_match_type.to_string(),
                                                         "zip_codes.prefix".to_string()],
                                                    q.to_string())
        .with_boost(100)
        .build();

    let mut should_query = vec![boost_addr, boost_match_query];

    // for fuzzy search we also search by the prefix index (with a greater boost than ngram)
    // to have better results
    if match_type == MatchType::Fuzzy {
        should_query.push(rs_q::build_match("label.prefix", q.to_string())
            .with_boost(1000)
            .build());
    }

    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    use rs_es::query::{CombinationMinimumShouldMatch, MinimumShouldMatch};
    let min_match = |min, threshold| {
        CombinationMinimumShouldMatch::new(MinimumShouldMatch::from(min),
                                           MinimumShouldMatch::from(threshold))
    };

    let minimum_should_match = match match_type {
        MatchType::Prefix => {
            // when we search [0, 2] fields, we need to match 100% of them
            // when we search [3, 4] fields, we need to match 90% of them
            // when we search [5, +] fields, we only need to match 70% on them
            // this way if the input has more fields than the documents
            // (additional information like the country, the region, ...)
            // they can be ignored
            MinimumShouldMatch::from(vec![min_match(2, 90f64), min_match(4, 70f64)])
        }
        // for fuzzy search we lower our expectation and we accept 50% of token match
        MatchType::Fuzzy => MinimumShouldMatch::from(50f64),
    };

    let mut must = vec![rs_q::build_multi_match(vec![main_match_type.to_string(),
                                                     "zip_codes.prefix".to_string()],
                                                q.to_string())
                            .with_minimum_should_match(minimum_should_match)
                            .build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn query(q: &str,
         cnx: &str,
         match_type: MatchType,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&["munin"])
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

pub fn autocomplete(q: &str,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    // First we try a prety exact match on the prefix.
    // If there are no results then we do a new fuzzy search (matching ngrams)
    let results = try!(query(&q,
                             cnx,
                             MatchType::Prefix,
                             offset,
                             limit,
                             &coord,
                             make_shape(&shape)));
    if results.is_empty() {
        query(&q,
              cnx,
              MatchType::Fuzzy,
              offset,
              limit,
              &coord,
              make_shape(&shape))
    } else {
        Ok(results)
    }
}
<commit_msg>change the query<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

#[derive(Debug, Eq, PartialEq)]
enum MatchType {
    Prefix,
    Fuzzy,
}

fn build_query(q: &str,
               match_type: MatchType,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    // we order the type of object we want
    // Note: the addresses are boosted more because even if we don't want them first
    // because they are more severely filtered
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(5000).build();
    let boost_admin = rs_q::build_term("_type", "admin").with_boost(3000).build();
    let boost_stop = rs_q::build_term("_type", "stop").with_boost(2000).build();

    let main_match_type = match match_type {
        MatchType::Prefix => "label.prefix",
        MatchType::Fuzzy => "label.ngram",
    };

    let boost_main_match_query = rs_q::build_multi_match(vec![main_match_type.to_string()],
                                                         q.to_string())
        .with_boost(100)
        .build();
    let boost_zipcode_match_query = rs_q::build_multi_match(vec!["zip_codes.prefix".to_string()],
                                                            q.to_string())
        .with_boost(500)
        .build();

    let mut should_query = vec![boost_addr,
                                boost_admin,
                                boost_stop,
                                boost_main_match_query,
                                boost_zipcode_match_query];

    // for fuzzy search we also search by the prefix index (with a greater boost than ngram)
    // to have better results
    if match_type == MatchType::Fuzzy {
        should_query.push(rs_q::build_match("label.prefix", q.to_string())
            .with_boost(1000)
            .build());
    }

    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    use rs_es::query::{CombinationMinimumShouldMatch, MinimumShouldMatch};
    let min_match = |min, threshold| {
        CombinationMinimumShouldMatch::new(MinimumShouldMatch::from(min),
                                           MinimumShouldMatch::from(threshold))
    };

    let minimum_should_match = match match_type {
        MatchType::Prefix => {
            // when we search [0, 2] fields, we need to match 100% of them
            // when we search [3, 4] fields, we need to match 90% of them
            // when we search [5, +] fields, we only need to match 70% on them
            // this way if the input has more fields than the documents
            // (additional information like the country, the region, ...)
            // they can be ignored
            MinimumShouldMatch::from(vec![min_match(2, 90f64), min_match(4, 70f64)])
        }
        // for fuzzy search we lower our expectation and we accept 50% of token match
        MatchType::Fuzzy => MinimumShouldMatch::from(50f64),
    };

    let mut must = vec![rs_q::build_multi_match(vec![main_match_type.to_string(),
                                                     "zip_codes.prefix".to_string()],
                                                q.to_string())
                            .with_minimum_should_match(minimum_should_match)
                            .build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn query(q: &str,
         cnx: &str,
         match_type: MatchType,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&["munin"])
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

pub fn autocomplete(q: &str,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    // First we try a prety exact match on the prefix.
    // If there are no results then we do a new fuzzy search (matching ngrams)
    let results = try!(query(&q,
                             cnx,
                             MatchType::Prefix,
                             offset,
                             limit,
                             &coord,
                             make_shape(&shape)));
    if results.is_empty() {
        query(&q,
              cnx,
              MatchType::Fuzzy,
              offset,
              limit,
              &coord,
              make_shape(&shape))
    } else {
        Ok(results)
    }
}
<|endoftext|>


<commit_before>//! Instruction Set Architectures.
//!
//! The sub-modules of this `isa` module provide definitions for the instruction sets that Cretonne
//! can target.

pub mod riscv;
<commit_msg>Scaffold implementation of the TargetIsa trait.<commit_after>//! Instruction Set Architectures.
//!
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
//! by the ISA-independent code generator.
//!
//! The sub-modules of this module provide definitions for the instruction sets that Cretonne
//! can target. Each sub-module has it's own implementation of `TargetIsa`.

pub mod riscv;

use ir::dfg::DataFlowGraph;
use ir::entities::Inst;

pub trait TargetIsa {
    /// Encode an instruction after determining it is legal.
    ///
    /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
    /// Otherwise, return `None`.
    ///
    /// This is also the main entry point for determining if an instruction is legal.
    fn encode(&self, dfg: &DataFlowGraph, inst: &Inst) -> Option<Encoding>;
}

/// Bits needed to encode an instruction as binary machine code.
///
/// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
/// encoding *bits*. The recipe determines the native instruction format and the mapping of
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
/// typically parts of the opcode.
pub struct Encoding(u32);

impl Encoding {
    /// Create a new `Encoding` containing `(recipe, bits)`. The `num_bits` parameter is the
    /// ISA-dependent size of `bits`.
    pub fn new(recipe: u32, bits: u32, num_bits: u8) -> Encoding {
        Encoding((recipe << num_bits) | bits)
    }

    /// Split the encoding into two parts: `(recipe, bits)`. Only the target ISA knows how many
    /// bits are in each part.
    pub fn split(&self, num_bits: u8) -> (u32, u32) {
        (self.0 >> num_bits, self.0 & ((1 << num_bits) - 1))
    }
}
<|endoftext|>


<commit_before>use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

/// This must be used by the kernel to ensure that context switches are done atomically
/// Compare and exchange this to true when beginning a context switch on any CPU
/// The Context::switch_to function will set it back to false, allowing other CPU's to switch
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;

#[derive(Clone, Debug)]
pub struct Context {
    /// FX valid?
    loadable: bool,
    /// FX location
    fx: usize,
    /// Page table pointer
    cr3: usize,
    /// RFLAGS register
    rflags: usize,
    /// RBX register
    rbx: usize,
    /// R12 register
    r12: usize,
    /// R13 register
    r13: usize,
    /// R14 register
    r14: usize,
    /// R15 register
    r15: usize,
    /// Base pointer
    rbp: usize,
    /// Stack pointer
    rsp: usize
}

impl Context {
    pub fn new() -> Context {
        Context {
            loadable: false,
            fx: 0,
            cr3: 0,
            rflags: 0,
            rbx: 0,
            r12: 0,
            r13: 0,
            r14: 0,
            r15: 0,
            rbp: 0,
            rsp: 0
        }
    }

    pub fn get_page_table(&self) -> usize {
        self.cr3
    }

    pub fn set_fx(&mut self, address: usize) {
        self.fx = address;
    }

    pub fn set_page_table(&mut self, address: usize) {
        self.cr3 = address;
    }

    pub fn set_stack(&mut self, address: usize) {
        self.rsp = address;
    }

    /// Switch to the next context by restoring its stack and registers
    #[cold]
    #[inline(never)]
    #[naked]
    pub unsafe fn switch_to(&mut self, next: &mut Context) {
        /*
        asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile");
        self.loadable = true;
        if next.loadable {
            asm!("fxrstor [$0]" : : "r"(next.fx) : "memory" : "intel", "volatile");
        }else{
            asm!("fninit" : : : "memory" : "intel", "volatile");
        }
        */

        asm!("mov $0, cr3" : "=r"(self.cr3) : : "memory" : "intel", "volatile");
        if next.cr3 != self.cr3 {
            asm!("mov cr3, $0" : : "r"(next.cr3) : "memory" : "intel", "volatile");
        }

        asm!("pushfq ; pop $0" : "=r"(self.rflags) : : "memory" : "intel", "volatile");
        asm!("push $0 ; popfq" : : "r"(next.rflags) : "memory" : "intel", "volatile");

        asm!("mov $0, rbx" : "=r"(self.rbx) : : "memory" : "intel", "volatile");
        asm!("mov rbx, $0" : : "r"(next.rbx) : "memory" : "intel", "volatile");

        asm!("mov $0, r12" : "=r"(self.r12) : : "memory" : "intel", "volatile");
        asm!("mov r12, $0" : : "r"(next.r12) : "memory" : "intel", "volatile");

        asm!("mov $0, r13" : "=r"(self.r13) : : "memory" : "intel", "volatile");
        asm!("mov r13, $0" : : "r"(next.r13) : "memory" : "intel", "volatile");

        asm!("mov $0, r14" : "=r"(self.r14) : : "memory" : "intel", "volatile");
        asm!("mov r14, $0" : : "r"(next.r14) : "memory" : "intel", "volatile");

        asm!("mov $0, r15" : "=r"(self.r15) : : "memory" : "intel", "volatile");
        asm!("mov r15, $0" : : "r"(next.r15) : "memory" : "intel", "volatile");

        asm!("mov $0, rsp" : "=r"(self.rsp) : : "memory" : "intel", "volatile");
        asm!("mov rsp, $0" : : "r"(next.rsp) : "memory" : "intel", "volatile");

        asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile");
        asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile");

        asm!("call context_switch_unlock" : : : "memory" : "intel", "volatile");
    }
}

/// Unset global lock, set inside of kernel
#[no_mangle]
pub extern fn context_switch_unlock(){
    CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
}
<commit_msg>Reenable fx<commit_after>use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

/// This must be used by the kernel to ensure that context switches are done atomically
/// Compare and exchange this to true when beginning a context switch on any CPU
/// The Context::switch_to function will set it back to false, allowing other CPU's to switch
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;

#[derive(Clone, Debug)]
pub struct Context {
    /// FX valid?
    loadable: bool,
    /// FX location
    fx: usize,
    /// Page table pointer
    cr3: usize,
    /// RFLAGS register
    rflags: usize,
    /// RBX register
    rbx: usize,
    /// R12 register
    r12: usize,
    /// R13 register
    r13: usize,
    /// R14 register
    r14: usize,
    /// R15 register
    r15: usize,
    /// Base pointer
    rbp: usize,
    /// Stack pointer
    rsp: usize
}

impl Context {
    pub fn new() -> Context {
        Context {
            loadable: false,
            fx: 0,
            cr3: 0,
            rflags: 0,
            rbx: 0,
            r12: 0,
            r13: 0,
            r14: 0,
            r15: 0,
            rbp: 0,
            rsp: 0
        }
    }

    pub fn get_page_table(&self) -> usize {
        self.cr3
    }

    pub fn set_fx(&mut self, address: usize) {
        self.fx = address;
    }

    pub fn set_page_table(&mut self, address: usize) {
        self.cr3 = address;
    }

    pub fn set_stack(&mut self, address: usize) {
        self.rsp = address;
    }

    /// Switch to the next context by restoring its stack and registers
    #[cold]
    #[inline(never)]
    #[naked]
    pub unsafe fn switch_to(&mut self, next: &mut Context) {
        asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile");
        self.loadable = true;
        if next.loadable {
            asm!("fxrstor [$0]" : : "r"(next.fx) : "memory" : "intel", "volatile");
        }else{
            asm!("fninit" : : : "memory" : "intel", "volatile");
        }

        asm!("mov $0, cr3" : "=r"(self.cr3) : : "memory" : "intel", "volatile");
        if next.cr3 != self.cr3 {
            asm!("mov cr3, $0" : : "r"(next.cr3) : "memory" : "intel", "volatile");
        }

        asm!("pushfq ; pop $0" : "=r"(self.rflags) : : "memory" : "intel", "volatile");
        asm!("push $0 ; popfq" : : "r"(next.rflags) : "memory" : "intel", "volatile");

        asm!("mov $0, rbx" : "=r"(self.rbx) : : "memory" : "intel", "volatile");
        asm!("mov rbx, $0" : : "r"(next.rbx) : "memory" : "intel", "volatile");

        asm!("mov $0, r12" : "=r"(self.r12) : : "memory" : "intel", "volatile");
        asm!("mov r12, $0" : : "r"(next.r12) : "memory" : "intel", "volatile");

        asm!("mov $0, r13" : "=r"(self.r13) : : "memory" : "intel", "volatile");
        asm!("mov r13, $0" : : "r"(next.r13) : "memory" : "intel", "volatile");

        asm!("mov $0, r14" : "=r"(self.r14) : : "memory" : "intel", "volatile");
        asm!("mov r14, $0" : : "r"(next.r14) : "memory" : "intel", "volatile");

        asm!("mov $0, r15" : "=r"(self.r15) : : "memory" : "intel", "volatile");
        asm!("mov r15, $0" : : "r"(next.r15) : "memory" : "intel", "volatile");

        asm!("mov $0, rsp" : "=r"(self.rsp) : : "memory" : "intel", "volatile");
        asm!("mov rsp, $0" : : "r"(next.rsp) : "memory" : "intel", "volatile");

        asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile");
        asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile");

        asm!("call context_switch_unlock" : : : "memory" : "intel", "volatile");
    }
}

/// Unset global lock, set inside of kernel
#[no_mangle]
pub extern fn context_switch_unlock(){
    CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
}
<|endoftext|>


<commit_before>
pub struct ProcessorInterface;

impl ProcessorInterface {

    pub fn new() -> ProcessorInterface {
        ProcessorInterface
    }

    pub fn read_u32(&self, register: u32) -> u32 {
        println!("READ PI");
        0
    }

    pub fn write_u32(&mut self, register: u32, val: u32) {
        println!("WRITE PI");
    }

}
<commit_msg>processor interface updates<commit_after>
const INTERRUPT_CAUSE: u32 = 0x00;
const INTERRUPT_MASK:  u32 = 0x04;
const RESET_CODE:      u32 = 0x24;
const REVISION:        u32 = 0x2C;
const UNKNOWN:         u32 = 0x30;

pub struct ProcessorInterface {
    interrupt_mask: u32,
    reset_code: u32,
    revision: u32
}

impl ProcessorInterface {

    pub fn new() -> ProcessorInterface {
        ProcessorInterface {
            interrupt_mask: 0,
            reset_code: 0,
            revision: 0x246500B1 // revision C
        }
    }

    pub fn read_u32(&self, register: u32) -> u32 {
        match register {
            RESET_CODE => self.reset_code,
            REVISION => self.revision,
            _ => panic!("unrecognized pi register {:#x}", register)
        }
    }

    pub fn write_u32(&mut self, register: u32, val: u32) {
        match register {
            INTERRUPT_CAUSE => panic!("PI: Interrupt {}", val),
            INTERRUPT_MASK => self.interrupt_mask = val,
            RESET_CODE => self.reset_code = val,
            UNKNOWN => {}, // ignore value written to unknown reg
            _ => panic!("unrecognized pi register {:#x} {:#x}", register, val)
        }
    }
}
<|endoftext|>


<commit_before>//! The project module takes care of muxed related initialization. Locating the
//! users home directory. Finding the desired config files, and reading the
//! configs in.
pub mod parser;

use command::{Attach, Commands, SwitchClient};
use common::project_paths::ProjectPaths;
use first_run::check_first_run;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use tmux::has_session;
use yaml_rust::{Yaml, YamlLoader};

static TMUX_ENV_VAR: &str = "TMUX";

/// Using the provided project name, locate the path to that project file. It
/// should be something similar to: `~/.muxed/my_project.yml`
/// Read in the contents of the config (which should be Yaml), and parse the
/// contents as yaml.
///
/// # Examples
///
/// Given the project name "compiler" and a project file found at:
/// `~/.muxed/compiler.yml`.
///
/// ```
/// let yaml: Result<Vec<Yaml>, String> = read("compiler".to_string());
/// ```
///
/// `project_name`: The name of the project, corresponding to the project config
/// file.
pub fn read(project_name: &str, project_paths: &ProjectPaths) -> Result<Vec<Yaml>, String> {
    check_first_run(&project_paths.project_directory)?;

    let mut file = File::open(&project_paths.project_file).map_err(|e| format!("No project configuration file was found with the name `{}` in the directory `{}`. Received error: {}", project_name, &project_paths.project_directory.display(), e.to_string()))?;
    let mut contents = String::new();

    file.read_to_string(&mut contents)
        .map_err(|e| e.to_string())?;

    let parsed_yaml = YamlLoader::load_from_str(&contents).map_err(|e| e.to_string())?;

    Ok(parsed_yaml)
}

/// Find out if a tmux session is already active with this name. If it is active
/// return `Some<Commands::Attach>` with a command to attach to the session. If a
/// session is not active return None and let the app carry on.
pub fn session_exists(project_name: &str) -> Option<Commands> {
    if has_session(project_name).success() {
        Some(open(project_name))
    } else {
        None
    }
}

/// Check to see how we want to open the project. Do we need to attach to a new
/// tmux session or can we switch the client from a running session.
pub fn open(project_name: &str) -> Commands {
    if env::var_os(TMUX_ENV_VAR).is_some() {
        SwitchClient::new(&project_name).into()
    } else {
        Attach::new(&project_name, None).into()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use common::rand_names;
    use std::fs;

    #[test]
    fn missing_file_returns_err() {
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", "");
        let result = read(&String::from("not_a_file"), &project_paths);
        assert!(result.is_err())
    }

    #[test]
    fn poorly_formatted_file_returns_err() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(b"mix: [1,2,3]: muxed");
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_err());
    }

    #[test]
    fn good_file_returns_ok() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(
            b"---
    windows: ['cargo', 'vim', 'git']
    ",
        );
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_ok());
    }
}
<commit_msg>test: Add unit test for project open<commit_after>//! The project module takes care of muxed related initialization. Locating the
//! users home directory. Finding the desired config files, and reading the
//! configs in.
pub mod parser;

use command::{Attach, Commands, SwitchClient};
use common::project_paths::ProjectPaths;
use first_run::check_first_run;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use tmux::has_session;
use yaml_rust::{Yaml, YamlLoader};

static TMUX_ENV_VAR: &str = "TMUX";

/// Using the provided project name, locate the path to that project file. It
/// should be something similar to: `~/.muxed/my_project.yml`
/// Read in the contents of the config (which should be Yaml), and parse the
/// contents as yaml.
///
/// # Examples
///
/// Given the project name "compiler" and a project file found at:
/// `~/.muxed/compiler.yml`.
///
/// ```
/// let yaml: Result<Vec<Yaml>, String> = read("compiler".to_string());
/// ```
///
/// `project_name`: The name of the project, corresponding to the project config
/// file.
pub fn read(project_name: &str, project_paths: &ProjectPaths) -> Result<Vec<Yaml>, String> {
    check_first_run(&project_paths.project_directory)?;

    let mut file = File::open(&project_paths.project_file).map_err(|e| format!("No project configuration file was found with the name `{}` in the directory `{}`. Received error: {}", project_name, &project_paths.project_directory.display(), e.to_string()))?;
    let mut contents = String::new();

    file.read_to_string(&mut contents)
        .map_err(|e| e.to_string())?;

    let parsed_yaml = YamlLoader::load_from_str(&contents).map_err(|e| e.to_string())?;

    Ok(parsed_yaml)
}

/// Find out if a tmux session is already active with this name. If it is active
/// return `Some<Commands::Attach>` with a command to attach to the session. If a
/// session is not active return None and let the app carry on.
pub fn session_exists(project_name: &str) -> Option<Commands> {
    if has_session(project_name).success() {
        Some(open(project_name))
    } else {
        None
    }
}

/// Check to see how we want to open the project. Do we need to attach to a new
/// tmux session or can we switch the client from a running session.
pub fn open(project_name: &str) -> Commands {
    if env::var_os(TMUX_ENV_VAR).is_some() {
        SwitchClient::new(&project_name).into()
    } else {
        Attach::new(&project_name, None).into()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use common::rand_names;
    use std::fs;

    #[test]
    fn missing_file_returns_err() {
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", "");
        let result = read(&String::from("not_a_file"), &project_paths);
        assert!(result.is_err())
    }

    #[test]
    fn poorly_formatted_file_returns_err() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(b"mix: [1,2,3]: muxed");
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_err());
    }

    #[test]
    fn good_file_returns_ok() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(
            b"---
    windows: ['cargo', 'vim', 'git']
    ",
        );
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_ok());
    }

    #[test]
    fn open_returns_attach_in_bare_context() {
        let attach_command = match open("muxed") {
            Commands::Attach(_) => true,
            _ => false,
        };

        assert!(attach_command);
    }

    #[test]
    fn open_returns_switch_client_in_nested_context() {
        let _ = env::set_var(TMUX_ENV_VAR, "somestring");
        let switch_command = match open("muxed") {
            Commands::SwitchClient(_) => true,
            _ => false,
        };
        let _ = env::remove_var(TMUX_ENV_VAR);

        assert!(switch_command);
    }
}
<|endoftext|>


<commit_before>pub struct Parser {
    pub id: u64
}

impl Parser {
    pub fn new(id: u64) -> Parser {
        Parser { id: id }
    }
}
<commit_msg>Removed 'parser.rs'<commit_after><|endoftext|>


<commit_before>//!
//! Combined environment
//!
//! This is used to merge several separate environments into one.
//!

use std::result::Result;
use std::sync::*;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;
use super::list_tools::*;
use super::empty_environment::*;
use super::functional_tool::*;

struct EnvironmentCollection {
    environments: Vec<Box<Environment>>
}

impl EnvironmentCollection {
    fn new(environments: Vec<Box<Environment>>) -> EnvironmentCollection {
        EnvironmentCollection { environments: environments }
    }
}

#[derive(Clone)]
pub struct CombinedEnvironment {
    collection: Arc<Mutex<EnvironmentCollection>>
}

impl CombinedEnvironment {
    ///
    /// Creates a new combined environment
    ///
    /// The first environment to define a tool is the one that is used in the event that more than
    /// one environment defines one. The `list-tools` tool will be changed to one that combines the
    /// results across all environments.
    ///
    pub fn from_environments(environments: Vec<Box<Environment>>) -> CombinedEnvironment {
        CombinedEnvironment { collection: Arc::new(Mutex::new(EnvironmentCollection::new(environments))) }
    }

    ///
    /// Combines the results of listing the tools across all of the environments
    ///
    pub fn list_tools(&self) -> ListToolsResult {
        let collection = self.collection.lock().unwrap();

        // List all of the tools in all the environments
        let tools = collection.environments.iter()
            .map(|env| env.get_json_tool(super::tool_name::LIST_TOOLS))
            .filter(|tool| tool.is_ok())
            .map(|tool| tool.unwrap());

        let results = tools.map(|tool| tool.invoke_json(Value::Null, &EmptyEnvironment::new()))
            .filter(|result| result.is_ok())
            .map(|result| result.unwrap());

        let decoded = results.map(|result| from_value::<ListToolsResult>(result).unwrap_or(ListToolsResult::with_names(vec![])).names);

        // Concatentate the results
        let mut final_result = vec![];
        for list in decoded {
            for name in list {
                final_result.push(name.clone());
            }
        }

        final_result.sort();
        final_result.dedup();

        ListToolsResult::with_name_strings(final_result)
    }
}

impl Environment for CombinedEnvironment {
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError> {
        if name == super::tool_name::LIST_TOOLS {
            // Generate a list-tools implementation (we use a copy of this object, which will reference
            // our environments as the collection is reference counted)
            let list_environment    = self.clone();
            let list_tools          = make_pure_tool(move |_: ()| list_environment.list_tools());

            Ok(Box::new(list_tools))
        } else {
            // Return the first item in the collection that implements the specified tool name
            let collection  = self.collection.lock().unwrap();
            let item        = collection.environments.iter()
                .map(|env| env.get_json_tool(name).ok())
                .find(|env| env.is_some())
                .map(|env| env.unwrap());

            item.ok_or(RetrieveToolError::not_found())
        }
    }
}

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

    #[test]
    fn can_find_tool_in_first_environment() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ Box::new(first), Box::new(second) ]);

        assert!(combined.get_json_tool("first-tool").is_ok());
        assert!(combined.get_typed_tool("first-tool").unwrap().invoke(2, &combined) == Ok(3));
    }

    #[test]
    fn can_find_tool_in_second_environment() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ Box::new(first), Box::new(second) ]);

        assert!(combined.get_json_tool("second-tool").is_ok());
        assert!(combined.get_typed_tool("second-tool").unwrap().invoke(2, &combined) == Ok(4));
    }

    #[test]
    fn first_environment_overrides_second() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ Box::new(first), Box::new(second) ]);

        assert!(combined.get_json_tool("tool").is_ok());
        assert!(combined.get_typed_tool("tool").unwrap().invoke(2, &combined) == Ok(3));
    }

    #[test]
    fn can_list_tools() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ Box::new(first), Box::new(second) ]);

        assert!(combined.get_json_tool("list-tools").is_ok());
        assert!(combined.get_typed_tool("list-tools").unwrap().invoke((), &combined) == Ok(ListToolsResult::with_names(vec![ "define-tool", "first-tool", "list-tools", "second-tool", "undefine-tool" ])));
    }

    #[test]
    fn list_tools_does_not_generate_duplicates() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ Box::new(first), Box::new(second) ]);

        assert!(combined.get_json_tool("list-tools").is_ok());
        assert!(combined.get_typed_tool("list-tools").unwrap().invoke((), &combined) == Ok(ListToolsResult::with_names(vec![ "define-tool", "list-tools", "tool", "undefine-tool" ])));
    }
}
<commit_msg>Change CombinedEnvironment to combine environment references instead of boxed environments<commit_after>//!
//! Combined environment
//!
//! This is used to merge several separate environments into one.
//!

use std::result::Result;
use std::sync::*;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;
use super::list_tools::*;
use super::empty_environment::*;
use super::functional_tool::*;

struct EnvironmentCollection<'a> {
    environments: Vec<&'a Environment>
}

impl<'a> EnvironmentCollection<'a> {
    fn new(environments: Vec<&'a Environment>) -> EnvironmentCollection<'a> {
        EnvironmentCollection { environments: environments }
    }
}

#[derive(Clone)]
pub struct CombinedEnvironment<'a> {
    collection: Arc<Mutex<EnvironmentCollection<'a>>>
}

impl<'a> CombinedEnvironment<'a> {
    ///
    /// Creates a new combined environment
    ///
    /// The first environment to define a tool is the one that is used in the event that more than
    /// one environment defines one. The `list-tools` tool will be changed to one that combines the
    /// results across all environments.
    ///
    pub fn from_environments(environments: Vec<&'a Environment>) -> CombinedEnvironment {
        CombinedEnvironment { collection: Arc::new(Mutex::new(EnvironmentCollection::new(environments))) }
    }

    ///
    /// Combines the results of listing the tools across all of the environments
    ///
    pub fn list_tools(&self) -> ListToolsResult {
        let collection = self.collection.lock().unwrap();

        // List all of the tools in all the environments
        let tools: Vec<Box<Tool>> = collection.environments.iter()
            .map(|env| env.get_json_tool(super::tool_name::LIST_TOOLS))
            .filter(|tool| tool.is_ok())
            .map(|tool| tool.unwrap())
            .collect();

        CombinedEnvironment::collect_tool_list(tools.iter())
    }

    ///
    /// Given a collection of list-tools implementations, returns the result of combining them all
    ///
    fn collect_tool_list<'b, T: Iterator<Item=&'b Box<Tool>>>(tools: T) -> ListToolsResult {
        let results = tools.map(|tool| tool.invoke_json(Value::Null, &EmptyEnvironment::new()))
            .filter(|result| result.is_ok())
            .map(|result| result.unwrap());

        let decoded = results.map(|result| from_value::<ListToolsResult>(result).unwrap_or(ListToolsResult::with_names(vec![])).names);

        // Concatentate the results
        let mut final_result = vec![];
        for list in decoded {
            for name in list {
                final_result.push(name.clone());
            }
        }

        final_result.sort();
        final_result.dedup();

        ListToolsResult::with_name_strings(final_result)
    }
}

impl<'a> Environment for CombinedEnvironment<'a> {
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError> {
        if name == super::tool_name::LIST_TOOLS {
            // Get all the list-tools implementations from our environments
            let collection              = self.collection.lock().unwrap();
            let tools: Vec<Box<Tool>>   = collection.environments.iter()
                .map(|env| env.get_json_tool(super::tool_name::LIST_TOOLS))
                .filter(|tool| tool.is_ok())
                .map(|tool| tool.unwrap())
                .collect();

            // Create a combined list-tools implementation
            let list_tools = make_pure_tool(move |_: ()| CombinedEnvironment::collect_tool_list(tools.iter()));

            Ok(Box::new(list_tools))
        } else {
            // Return the first item in the collection that implements the specified tool name
            let collection  = self.collection.lock().unwrap();
            let item        = collection.environments.iter()
                .map(|env| env.get_json_tool(name).ok())
                .find(|env| env.is_some())
                .map(|env| env.unwrap());

            item.ok_or(RetrieveToolError::not_found())
        }
    }
}

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

    #[test]
    fn can_find_tool_in_first_environment() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ &first, &second ]);

        assert!(combined.get_json_tool("first-tool").is_ok());
        assert!(combined.get_typed_tool("first-tool").unwrap().invoke(2, &combined) == Ok(3));
    }

    #[test]
    fn can_find_tool_in_second_environment() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ &first, &second ]);

        assert!(combined.get_json_tool("second-tool").is_ok());
        assert!(combined.get_typed_tool("second-tool").unwrap().invoke(2, &combined) == Ok(4));
    }

    #[test]
    fn first_environment_overrides_second() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ &first, &second ]);

        assert!(combined.get_json_tool("tool").is_ok());
        assert!(combined.get_typed_tool("tool").unwrap().invoke(2, &combined) == Ok(3));
    }

    #[test]
    fn can_list_tools() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("first-tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("second-tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ &first, &second ]);

        assert!(combined.get_json_tool("list-tools").is_ok());
        assert!(combined.get_typed_tool("list-tools").unwrap().invoke((), &combined) == Ok(ListToolsResult::with_names(vec![ "define-tool", "first-tool", "list-tools", "second-tool", "undefine-tool" ])));
    }

    #[test]
    fn list_tools_does_not_generate_duplicates() {
        let first   = DynamicEnvironment::new();
        let second  = DynamicEnvironment::new();

        first.define("tool", Box::new(make_pure_tool(|x:i32| x+1)));
        second.define("tool", Box::new(make_pure_tool(|x:i32| x+2)));

        let combined = CombinedEnvironment::from_environments(vec![ &first, &second ]);

        assert!(combined.get_json_tool("list-tools").is_ok());
        assert!(combined.get_typed_tool("list-tools").unwrap().invoke((), &combined) == Ok(ListToolsResult::with_names(vec![ "define-tool", "list-tools", "tool", "undefine-tool" ])));
    }
}
<|endoftext|>


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

// A few contrived examples where lifetime should (or should not) be parsed as an object type.
// Lifetimes parsed as types are still rejected later by semantic checks.

// compile-flags: -Z continue-parse-after-error

struct S<'a, T>(&'a u8, T);

fn main() {
    // `'static` is a lifetime argument, `'static +` is a type argument
    let _: S<'static, u8>;
    let _: S<'static, 'static +>;
    //~^ at least one non-builtin trait is required for an object type
    let _: S<'static, 'static>;
    //~^ ERROR wrong number of lifetime parameters: expected 1, found 2
    //~| ERROR wrong number of type arguments: expected 1, found 0
    let _: S<'static +, 'static>;
    //~^ ERROR lifetime parameters must be declared prior to type parameters
    //~| ERROR at least one non-builtin trait is required for an object type
}
<commit_msg>"Fix" annoying test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// A few contrived examples where lifetime should (or should not) be parsed as an object type.
// Lifetimes parsed as types are still rejected later by semantic checks.

// compile-flags: -Z continue-parse-after-error

struct S<'a, T>(&'a u8, T);

fn main() {
    // `'static` is a lifetime argument, `'static +` is a type argument
    let _: S<'static, u8>;
    let _: S<'static, 'static +>;
    //~^ at least one non-builtin trait is required for an object type
    let _: S<'static, 'static>;
    //~^ ERROR wrong number of lifetime parameters: expected 1, found 2
    //~| ERROR wrong number of type arguments: expected 1, found 0
    let _: S<'static +, 'static>;
    //~^ ERROR lifetime parameters must be declared prior to type parameters
}
<|endoftext|>


<commit_before>//! Simple access to Amazon Web Service's (AWS) Simple Storage Service (S3)
#[macro_use]
extern crate serde_derive;
use serde_xml_rs as serde_xml;

pub use awsregion;
pub use awscreds;

pub mod bucket;
pub mod command;
pub mod request;
pub mod serde_types;
pub mod signing;
pub mod deserializer;

simpl::err!(S3Error, {
    Xml@serde_xml::Error;
    Req@reqwest::Error;
    InvalidHeaderName@reqwest::header::InvalidHeaderName;
    InvalidHeaderValue@reqwest::header::InvalidHeaderValue;
    Hmac@hmac::crypto_mac::InvalidKeyLength;
    Utf8@std::str::Utf8Error;
    Io@std::io::Error;
    Region@awsregion::AwsRegionError;
    Creds@awscreds::AwsCredsError;
});

const LONG_DATE: &str = "%Y%m%dT%H%M%SZ";
const EMPTY_PAYLOAD_SHA: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
<commit_msg>friendlier names<commit_after>//! Simple access to Amazon Web Service's (AWS) Simple Storage Service (S3)
#[macro_use]
extern crate serde_derive;
use serde_xml_rs as serde_xml;

pub use awsregion as region;
pub use awscreds as creds;

pub mod bucket;
pub mod command;
pub mod request;
pub mod serde_types;
pub mod signing;
pub mod deserializer;

simpl::err!(S3Error, {
    Xml@serde_xml::Error;
    Req@reqwest::Error;
    InvalidHeaderName@reqwest::header::InvalidHeaderName;
    InvalidHeaderValue@reqwest::header::InvalidHeaderValue;
    Hmac@hmac::crypto_mac::InvalidKeyLength;
    Utf8@std::str::Utf8Error;
    Io@std::io::Error;
    Region@awsregion::AwsRegionError;
    Creds@awscreds::AwsCredsError;
});

const LONG_DATE: &str = "%Y%m%dT%H%M%SZ";
const EMPTY_PAYLOAD_SHA: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]
#![feature(trace_macros)]

extern crate syntax;
extern crate rustc_plugin;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::fold::Folder;
use syntax::codemap::Span;
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::token::intern;
use syntax::tokenstream::TokenTree;

mod parser;
mod compiler;
mod x64data;
mod serialize;

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        intern("dynasm"),
        SyntaxExtension::NormalTT(
            Box::new(main),
            None,
            false
        )
    );
}

fn main<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm
    let token_tree = ecx.expander().fold_tts(token_tree.to_vec());

    let mut parser = ecx.new_parser_from_tts(&token_tree);

    // construct an ast of assembly nodes
    let (name, ast) = match parser::parse(ecx, &mut parser) {
        Ok(ast) => ast,
        Err(mut e) => {e.emit(); return DummyResult::any(span)}
    };

    // println!("{:?}", ast);

    let stmts = if let Ok(stmts) = compiler::compile(ecx, ast) {
        stmts
    } else {
        return DummyResult::any(span)
    };

    let stmts = serialize::serialize(ecx, name, stmts);

    Box::new(DynAsm {stmts: SmallVector::many(stmts)})
}

struct DynAsm {
    stmts: SmallVector<ast::Stmt>
}

impl MacResult for DynAsm {
    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(self.stmts)
    }
}
<commit_msg>Small change to match the new nightlies<commit_after>#![feature(plugin_registrar, rustc_private)]
#![feature(trace_macros)]

extern crate syntax;
extern crate rustc_plugin;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::fold::Folder;
use syntax::codemap::Span;
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::token::intern;
use syntax::tokenstream::TokenTree;

mod parser;
mod compiler;
mod x64data;
mod serialize;

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        intern("dynasm"),
        SyntaxExtension::NormalTT(
            Box::new(main),
            None,
            false
        )
    );
}

fn main<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm
    let token_tree = ecx.expander().fold_tts(token_tree);

    let mut parser = ecx.new_parser_from_tts(&token_tree);

    // construct an ast of assembly nodes
    let (name, ast) = match parser::parse(ecx, &mut parser) {
        Ok(ast) => ast,
        Err(mut e) => {e.emit(); return DummyResult::any(span)}
    };

    // println!("{:?}", ast);

    let stmts = if let Ok(stmts) = compiler::compile(ecx, ast) {
        stmts
    } else {
        return DummyResult::any(span)
    };

    let stmts = serialize::serialize(ecx, name, stmts);

    Box::new(DynAsm {stmts: SmallVector::many(stmts)})
}

struct DynAsm {
    stmts: SmallVector<ast::Stmt>
}

impl MacResult for DynAsm {
    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(self.stmts)
    }
}
<|endoftext|>