<commit_before>//! Tests the derived `Parcel` implementations and ensures
//! various invariants are followed.

use protocol::{Error, Parcel, Settings};
use protocol::hint;
use std::io;

/// Wraps another Parcel and saves the hints at read time.
#[derive(Debug, PartialEq)]
pub struct SaveHints<T> where T: Parcel {
    pub inner: T,
    saved_hints: Option<hint::Hints>,
}

impl<T> SaveHints<T>
    where T: Parcel {
    pub fn hints(&self) -> &hint::Hints {
        self.saved_hints.as_ref()
            .expect("there are no saved hints for manually built values")
    }
}

impl<T> Parcel for SaveHints<T>
    where T: Parcel {
    const TYPE_NAME: &'static str = "SaveHints";

    fn read(read: &mut io::Read, settings: &Settings,
            hints: &mut hint::Hints) -> Result<Self, Error> {
        let saved_hints = Some(hints.clone());
        let inner = T::read(read, settings, hints)?;
        Ok(SaveHints { inner, saved_hints })
    }

    fn write(&self, write: &mut io::Write,
             settings: &Settings) -> Result<(), Error> {
        self.inner.write(write, settings)
    }
}

impl<T> From<T> for SaveHints<T> where T: Parcel {
    fn from(v: T) -> Self {
        SaveHints {
            inner: v,
            saved_hints: None,
        }
    }
}

trait HasSavedHints: Parcel {
    fn saved_hints_after_reading(&self) -> &hint::Hints;
}

/// Writes a value to a stream, reads it back with the given hints,
/// and returns the hint state after the read.
fn get_hints_after_read<P>(mut input_hints: hint::Hints,
                           input_value: P)
    -> hint::Hints
    where P: HasSavedHints + Default {
    let mut parcel_stream = input_value.into_stream(&Settings::default()).unwrap();
    let v = P::read(&mut parcel_stream, &Settings::default(), &mut input_hints).unwrap();

    v.saved_hints_after_reading().clone()
}

/// Use this macro in places where we should probably
/// add new tests when adding new hints.
///
/// It triggers an unmentioned field in struct pattern error
/// until the new field is mentioned in the callsite.
macro_rules! force_contributor_to_acknowledge_new_hints {
    ( $( $field:ident ),* ) => {
        {
            // This is here so new hints must have tests added due
            // to exhaustive pattern matching.
            #[allow(unused_variables)]
            let hint::Hints { $( $field ),* } = hint::Hints::default();
        }
    };
}

/// Defines a bunch of test functions that test invariants
/// true for hints on every type.
macro_rules! define_common_hint_invariant_tests {
    ($parcel_description:ident => $parcel_ty:ty : $parcel_value:expr) => {
        mod $parcel_description {
            use super::*;
            use hints::*;
            use protocol::hint;

            const PRETTY_LARGE_NUMBER: usize = 10_000;

            /// Whenever any automatically derived type is read,
            #[test]
            fn all_prior_hints_are_ignored_when_reading() {

                let mut hints = hint::Hints::default();

                force_contributor_to_acknowledge_new_hints!(
                    current_field_index, known_field_lengths
                );

                // Set current field index to its maximum value, so that
                // if the system is actually incremented, it'll panic.
                hints.current_field_index = Some(usize::max_value());
                // Insert three bullshit field lengths.
                hints.known_field_lengths = (0..PRETTY_LARGE_NUMBER).into_iter().map(|i| {
                    (i, protocol::hint::FieldLength { length: i+i/2, kind: protocol::hint::LengthPrefixKind::Bytes })
                }).collect();

                let hints_afterwards = get_hints_after_read::<$parcel_ty>(hints, $parcel_value);

                assert!(hints_afterwards.current_field_index.unwrap() < PRETTY_LARGE_NUMBER);
                assert!(hints_afterwards.known_field_lengths.len() < PRETTY_LARGE_NUMBER);
            }
        }
    };
}

pub mod enums;
pub mod strukt;

<commit_msg>[test] Fix the 'hints' SaveHints Parcel implementation<commit_after>//! Tests the derived `Parcel` implementations and ensures
//! various invariants are followed.

use protocol::{Error, Parcel, Settings};
use protocol::hint;
use std::io;

/// Wraps another Parcel and saves the hints at read time.
#[derive(Debug, PartialEq)]
pub struct SaveHints<T> where T: Parcel {
    pub inner: T,
    saved_hints: Option<hint::Hints>,
}

impl<T> SaveHints<T>
    where T: Parcel {
    pub fn hints(&self) -> &hint::Hints {
        self.saved_hints.as_ref()
            .expect("there are no saved hints for manually built values")
    }
}

impl<T> Parcel for SaveHints<T>
    where T: Parcel {
    const TYPE_NAME: &'static str = "SaveHints";

    fn read(read: &mut io::Read, settings: &Settings,
            hints: &mut hint::Hints) -> Result<Self, Error> {
        let saved_hints = Some(hints.clone());
        let inner = T::read(read, settings, hints)?;
        Ok(SaveHints { inner, saved_hints })
    }

    fn write(&self, write: &mut io::Write,
             settings: &Settings,
             hints: &mut hint::Hints) -> Result<(), Error> {
        self.inner.write(write, settings, hints)
    }
}

impl<T> From<T> for SaveHints<T> where T: Parcel {
    fn from(v: T) -> Self {
        SaveHints {
            inner: v,
            saved_hints: None,
        }
    }
}

trait HasSavedHints: Parcel {
    fn saved_hints_after_reading(&self) -> &hint::Hints;
}

/// Writes a value to a stream, reads it back with the given hints,
/// and returns the hint state after the read.
fn get_hints_after_read<P>(mut input_hints: hint::Hints,
                           input_value: P)
    -> hint::Hints
    where P: HasSavedHints + Default {
    let mut parcel_stream = input_value.into_stream(&Settings::default()).unwrap();
    let v = P::read(&mut parcel_stream, &Settings::default(), &mut input_hints).unwrap();

    v.saved_hints_after_reading().clone()
}

/// Use this macro in places where we should probably
/// add new tests when adding new hints.
///
/// It triggers an unmentioned field in struct pattern error
/// until the new field is mentioned in the callsite.
macro_rules! force_contributor_to_acknowledge_new_hints {
    ( $( $field:ident ),* ) => {
        {
            // This is here so new hints must have tests added due
            // to exhaustive pattern matching.
            #[allow(unused_variables)]
            let hint::Hints { $( $field ),* } = hint::Hints::default();
        }
    };
}

/// Defines a bunch of test functions that test invariants
/// true for hints on every type.
macro_rules! define_common_hint_invariant_tests {
    ($parcel_description:ident => $parcel_ty:ty : $parcel_value:expr) => {
        mod $parcel_description {
            use super::*;
            use hints::*;
            use protocol::hint;

            const PRETTY_LARGE_NUMBER: usize = 10_000;

            /// Whenever any automatically derived type is read,
            #[test]
            fn all_prior_hints_are_ignored_when_reading() {

                let mut hints = hint::Hints::default();

                force_contributor_to_acknowledge_new_hints!(
                    current_field_index, known_field_lengths
                );

                // Set current field index to its maximum value, so that
                // if the system is actually incremented, it'll panic.
                hints.current_field_index = Some(usize::max_value());
                // Insert three bullshit field lengths.
                hints.known_field_lengths = (0..PRETTY_LARGE_NUMBER).into_iter().map(|i| {
                    (i, protocol::hint::FieldLength { length: i+i/2, kind: protocol::hint::LengthPrefixKind::Bytes })
                }).collect();

                let hints_afterwards = get_hints_after_read::<$parcel_ty>(hints, $parcel_value);

                assert!(hints_afterwards.current_field_index.unwrap() < PRETTY_LARGE_NUMBER);
                assert!(hints_afterwards.known_field_lengths.len() < PRETTY_LARGE_NUMBER);
            }
        }
    };
}

pub mod enums;
pub mod strukt;

<|endoftext|>


<commit_before>//! Tests with reference images.
//!
//! This is the bulk of librsvg's black-box tests.  In principle, each test takes an SVG file, renders
//! it to a raster image, and compares that image to a reference image stored on disk.  If the images
//! are "too different", the test fails.  We allow for minor differences in rendering to account for
//! antialiasing artifacts, floating-point variations, and such.
//!

#![cfg(test)]
use crate::test_compare_render_output;
use test_generator::test_resources;

use cairo;
use librsvg::{
    surface_utils::shared_surface::{SharedImageSurface, SurfaceType},
    CairoRenderer, IntrinsicDimensions, Length, Loader,
};
use std::path::PathBuf;

use crate::reference_utils::{Compare, Evaluate, Reference};
use crate::utils::{load_svg, render_document, setup_font_map, setup_language, SurfaceSize};

// The original reference images from the SVG1.1 test suite are at 72 DPI.
const TEST_SUITE_DPI: f64 = 72.0;

// https://gitlab.gnome.org/GNOME/librsvg/issues/91
//
// We were computing some offsets incorrectly if the initial transformation matrix
// passed to rsvg_handle_render_cairo() was not the identity matrix.  So,
// we create a surface with a "frame" around the destination for the image,
// and then only consider the pixels inside the frame.  This will require us
// to have a non-identity transformation (i.e. a translation matrix), which
// will test for this bug.
//
// The frame size is meant to be a ridiculous number to simulate an arbitrary
// offset.
const FRAME_SIZE: i32 = 47;

fn reference_test(path: &str) {
    setup_language();
    setup_font_map();

    let path = PathBuf::from(path);
    let path_base_name = path.file_stem().unwrap().to_string_lossy().to_owned();
    if path_base_name.starts_with("ignore") {
        return;
    }

    let reference = reference_path(&path);

    let handle = Loader::new()
        .read_path(&path)
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let renderer = CairoRenderer::new(&handle)
        .test_mode()
        .with_dpi(TEST_SUITE_DPI, TEST_SUITE_DPI);
    let (width, height) = image_size(renderer.intrinsic_dimensions(), TEST_SUITE_DPI);

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        width + 2 * FRAME_SIZE,
        height + 2 * FRAME_SIZE,
    )
    .unwrap();

    {
        let cr = cairo::Context::new(&surface).expect("Failed to create a cairo context");
        cr.translate(f64::from(FRAME_SIZE), f64::from(FRAME_SIZE));
        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: f64::from(width),
                    height: f64::from(height),
                },
            )
            .unwrap();
    }

    let surface = extract_rectangle(&surface, FRAME_SIZE, FRAME_SIZE, width, height).unwrap();

    let output_surf = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();

    Reference::from_png(&reference)
        .compare(&output_surf)
        .evaluate(&output_surf, &path_base_name);
}

/// Turns `/foo/bar/baz.svg` into `/foo/bar/baz-ref.svg`.
fn reference_path(path: &PathBuf) -> PathBuf {
    let basename = path.file_stem().unwrap();

    let mut reference_filename = basename.to_string_lossy().into_owned();
    reference_filename.push_str("-ref.png");

    path.with_file_name(reference_filename)
}

fn extract_rectangle(
    source: &cairo::ImageSurface,
    x: i32,
    y: i32,
    w: i32,
    h: i32,
) -> Result<cairo::ImageSurface, cairo::Error> {
    let dest = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
    let cr = cairo::Context::new(&dest).expect("Failed to create a cairo context");
    cr.set_source_surface(&source, f64::from(-x), f64::from(-y))
        .unwrap();
    cr.paint().unwrap();
    Ok(dest)
}

/// Computes the (width, height) pixel size at which an SVG should be rendered, based on its intrinsic dimensions.
///
/// # Panics:
///
/// Will panic if none of the following conditions are met:
///
/// * Width and height both exist
/// * Width and height do not exist, but viewBox exists.
fn image_size(dim: IntrinsicDimensions, dpi: f64) -> (i32, i32) {
    let IntrinsicDimensions {
        width,
        height,
        vbox,
    } = dim;

    use librsvg::LengthUnit::*;

    if let (Some(width), Some(height)) = (width, height) {
        if !(has_supported_unit(&width) && has_supported_unit(&height)) {
            panic!("SVG has unsupported unit type in width or height");
        }
    }

    #[rustfmt::skip]
    let (width, height) = match (width, height, vbox) {
        (Some(Length { length: w, unit: Percent }),
         Some(Length { length: h, unit: Percent }), vbox) if w == 1.0 && h == 1.0 => {
            if let Some(vbox) = vbox {
                (vbox.width, vbox.height)
            } else {
                panic!("SVG with percentage width/height must have a viewBox");
            }
        }

        (Some(Length { length: _, unit: Percent }),
         Some(Length { length: _, unit: Percent }), _) => {
            panic!("Test suite only supports percentage width/height at 100%");
        }

        (Some(w), Some(h), _) => {
            (normalize(&w, dpi), normalize(&h, dpi))
        }

        (None, None, Some(vbox)) => (vbox.width, vbox.height),

        (_, _, _) => panic!("Test suite does not support the dimensions of this file"),
    };

    // Keep in sync with c_api.rs
    let width = checked_i32(width.round());
    let height = checked_i32(height.round());

    (width, height)
}

// Keep in sync with c_api.rs
fn checked_i32(x: f64) -> i32 {
    cast::i32(x).expect("overflow when converting f64 to i32")
}

fn has_supported_unit(l: &Length) -> bool {
    use librsvg::LengthUnit::*;

    match l.unit {
        Percent | Px | In | Cm | Mm | Pt | Pc => true,
        _ => false,
    }
}

const POINTS_PER_INCH: f64 = 72.0;
const CM_PER_INCH: f64 = 2.54;
const MM_PER_INCH: f64 = 25.4;
const PICA_PER_INCH: f64 = 6.0;

fn normalize(l: &Length, dpi: f64) -> f64 {
    use librsvg::LengthUnit::*;

    match l.unit {
        Px => l.length,
        In => l.length * dpi,
        Cm => l.length * dpi / CM_PER_INCH,
        Mm => l.length * dpi / MM_PER_INCH,
        Pt => l.length * dpi / POINTS_PER_INCH,
        Pc => l.length * dpi / PICA_PER_INCH,
        _ => panic!("unsupported length unit"),
    }
}

#[test_resources("tests/fixtures/reftests/*.svg")]
fn reftests(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/adwaita/*.svg")]
fn adwaita(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/bugs/*.svg")]
fn bugs(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg1.1/*.svg")]
fn svg_1_1(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg2/*.svg")]
fn svg_2(name: &str) {
    reference_test(name);
}

test_compare_render_output!(
    marker_orient_auto_start_reverse,
    100,
    100,
    br##"<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
    <defs>
      <marker id="marker" orient="auto-start-reverse" viewBox="0 0 10 10"
              refX="0" refY="5" markerWidth="10" markerHeight="10"
              markerUnits="userSpaceOnUse">
        <path d="M0,0 L10,5 L0,10 Z" fill="green"/>
      </marker>
    </defs>

    <path d="M20,50 L80,50" marker-start="url(#marker)" marker-end="url(#marker)" stroke-width="10" stroke="black"/>
  </svg>"##,

    br##"<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
      <path
         d="M 20,55 10,50 20,45 Z"
         id="triangle1" fill="green"/>
      <path
         d="m 80,45 10,5 -10,5 z"
         id="triangle2" fill="green"/>
      <rect
         id="rectangle"
         width="60"
         height="10"
         x="20"
         y="45" fill="black"/>
    </svg>"##,
);

test_compare_render_output!(
    marker_context_stroke,
    400,
    400,
    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
      <style>
        .path1 {
          fill: none;
          stroke-width: 4px;
          marker: url(#marker1);
        }

        .path2 {
          fill: darkblue;
          stroke: mediumseagreen;
          stroke-width: 4px;
          marker: url(#marker2);
        }
      </style>

      <path class="path1" d="M20,20 L200,20 L380,20" stroke="lime"/>

      <path class="path2" d="M20,40 h360 v320 h-360 v-320 Z"/>

      <marker id="marker1" markerWidth="12" markerHeight="12" refX="6" refY="6"
              markerUnits="userSpaceOnUse">
        <circle cx="6" cy="6" r="3"
                fill="white" stroke="context-stroke" stroke-width="2"/>
      </marker>

      <marker id="marker2" markerWidth="12" markerHeight="12" refX="6" refY="6"
              markerUnits="userSpaceOnUse">
        <!-- Note that here the paint is reversed:
             fill=context-stroke,
             stroke=context-fill
        -->
        <circle cx="6" cy="6" r="3"
                fill="context-stroke" stroke="context-fill" stroke-width="2"/>
      </marker>
    </svg>
    "##,
    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
      <path d="M20,20 L200,20 L380,20" stroke="lime" stroke-width="4"/>
      <circle cx="20" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>
      <circle cx="200" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>
      <circle cx="380" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>

      <path class="path2" d="M20,40 h360 v320 h-360 v-320 Z" fill="darkblue"
            stroke="mediumseagreen" stroke-width="4"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="380" cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="380" cy="360" r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="360" r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
    </svg>
    "##,
);
<commit_msg>Rename test<commit_after>//! Tests with reference images.
//!
//! This is the bulk of librsvg's black-box tests.  In principle, each test takes an SVG file, renders
//! it to a raster image, and compares that image to a reference image stored on disk.  If the images
//! are "too different", the test fails.  We allow for minor differences in rendering to account for
//! antialiasing artifacts, floating-point variations, and such.
//!

#![cfg(test)]
use crate::test_compare_render_output;
use test_generator::test_resources;

use cairo;
use librsvg::{
    surface_utils::shared_surface::{SharedImageSurface, SurfaceType},
    CairoRenderer, IntrinsicDimensions, Length, Loader,
};
use std::path::PathBuf;

use crate::reference_utils::{Compare, Evaluate, Reference};
use crate::utils::{load_svg, render_document, setup_font_map, setup_language, SurfaceSize};

// The original reference images from the SVG1.1 test suite are at 72 DPI.
const TEST_SUITE_DPI: f64 = 72.0;

// https://gitlab.gnome.org/GNOME/librsvg/issues/91
//
// We were computing some offsets incorrectly if the initial transformation matrix
// passed to rsvg_handle_render_cairo() was not the identity matrix.  So,
// we create a surface with a "frame" around the destination for the image,
// and then only consider the pixels inside the frame.  This will require us
// to have a non-identity transformation (i.e. a translation matrix), which
// will test for this bug.
//
// The frame size is meant to be a ridiculous number to simulate an arbitrary
// offset.
const FRAME_SIZE: i32 = 47;

fn reference_test(path: &str) {
    setup_language();
    setup_font_map();

    let path = PathBuf::from(path);
    let path_base_name = path.file_stem().unwrap().to_string_lossy().to_owned();
    if path_base_name.starts_with("ignore") {
        return;
    }

    let reference = reference_path(&path);

    let handle = Loader::new()
        .read_path(&path)
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let renderer = CairoRenderer::new(&handle)
        .test_mode()
        .with_dpi(TEST_SUITE_DPI, TEST_SUITE_DPI);
    let (width, height) = image_size(renderer.intrinsic_dimensions(), TEST_SUITE_DPI);

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        width + 2 * FRAME_SIZE,
        height + 2 * FRAME_SIZE,
    )
    .unwrap();

    {
        let cr = cairo::Context::new(&surface).expect("Failed to create a cairo context");
        cr.translate(f64::from(FRAME_SIZE), f64::from(FRAME_SIZE));
        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: f64::from(width),
                    height: f64::from(height),
                },
            )
            .unwrap();
    }

    let surface = extract_rectangle(&surface, FRAME_SIZE, FRAME_SIZE, width, height).unwrap();

    let output_surf = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();

    Reference::from_png(&reference)
        .compare(&output_surf)
        .evaluate(&output_surf, &path_base_name);
}

/// Turns `/foo/bar/baz.svg` into `/foo/bar/baz-ref.svg`.
fn reference_path(path: &PathBuf) -> PathBuf {
    let basename = path.file_stem().unwrap();

    let mut reference_filename = basename.to_string_lossy().into_owned();
    reference_filename.push_str("-ref.png");

    path.with_file_name(reference_filename)
}

fn extract_rectangle(
    source: &cairo::ImageSurface,
    x: i32,
    y: i32,
    w: i32,
    h: i32,
) -> Result<cairo::ImageSurface, cairo::Error> {
    let dest = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
    let cr = cairo::Context::new(&dest).expect("Failed to create a cairo context");
    cr.set_source_surface(&source, f64::from(-x), f64::from(-y))
        .unwrap();
    cr.paint().unwrap();
    Ok(dest)
}

/// Computes the (width, height) pixel size at which an SVG should be rendered, based on its intrinsic dimensions.
///
/// # Panics:
///
/// Will panic if none of the following conditions are met:
///
/// * Width and height both exist
/// * Width and height do not exist, but viewBox exists.
fn image_size(dim: IntrinsicDimensions, dpi: f64) -> (i32, i32) {
    let IntrinsicDimensions {
        width,
        height,
        vbox,
    } = dim;

    use librsvg::LengthUnit::*;

    if let (Some(width), Some(height)) = (width, height) {
        if !(has_supported_unit(&width) && has_supported_unit(&height)) {
            panic!("SVG has unsupported unit type in width or height");
        }
    }

    #[rustfmt::skip]
    let (width, height) = match (width, height, vbox) {
        (Some(Length { length: w, unit: Percent }),
         Some(Length { length: h, unit: Percent }), vbox) if w == 1.0 && h == 1.0 => {
            if let Some(vbox) = vbox {
                (vbox.width, vbox.height)
            } else {
                panic!("SVG with percentage width/height must have a viewBox");
            }
        }

        (Some(Length { length: _, unit: Percent }),
         Some(Length { length: _, unit: Percent }), _) => {
            panic!("Test suite only supports percentage width/height at 100%");
        }

        (Some(w), Some(h), _) => {
            (normalize(&w, dpi), normalize(&h, dpi))
        }

        (None, None, Some(vbox)) => (vbox.width, vbox.height),

        (_, _, _) => panic!("Test suite does not support the dimensions of this file"),
    };

    // Keep in sync with c_api.rs
    let width = checked_i32(width.round());
    let height = checked_i32(height.round());

    (width, height)
}

// Keep in sync with c_api.rs
fn checked_i32(x: f64) -> i32 {
    cast::i32(x).expect("overflow when converting f64 to i32")
}

fn has_supported_unit(l: &Length) -> bool {
    use librsvg::LengthUnit::*;

    match l.unit {
        Percent | Px | In | Cm | Mm | Pt | Pc => true,
        _ => false,
    }
}

const POINTS_PER_INCH: f64 = 72.0;
const CM_PER_INCH: f64 = 2.54;
const MM_PER_INCH: f64 = 25.4;
const PICA_PER_INCH: f64 = 6.0;

fn normalize(l: &Length, dpi: f64) -> f64 {
    use librsvg::LengthUnit::*;

    match l.unit {
        Px => l.length,
        In => l.length * dpi,
        Cm => l.length * dpi / CM_PER_INCH,
        Mm => l.length * dpi / MM_PER_INCH,
        Pt => l.length * dpi / POINTS_PER_INCH,
        Pc => l.length * dpi / PICA_PER_INCH,
        _ => panic!("unsupported length unit"),
    }
}

#[test_resources("tests/fixtures/reftests/*.svg")]
fn reftests(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/adwaita/*.svg")]
fn adwaita(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/bugs/*.svg")]
fn bugs(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg1.1/*.svg")]
fn svg_1_1(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg2/*.svg")]
fn svg_2(name: &str) {
    reference_test(name);
}

test_compare_render_output!(
    marker_orient_auto_start_reverse,
    100,
    100,
    br##"<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
    <defs>
      <marker id="marker" orient="auto-start-reverse" viewBox="0 0 10 10"
              refX="0" refY="5" markerWidth="10" markerHeight="10"
              markerUnits="userSpaceOnUse">
        <path d="M0,0 L10,5 L0,10 Z" fill="green"/>
      </marker>
    </defs>

    <path d="M20,50 L80,50" marker-start="url(#marker)" marker-end="url(#marker)" stroke-width="10" stroke="black"/>
  </svg>"##,

    br##"<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
      <path
         d="M 20,55 10,50 20,45 Z"
         id="triangle1" fill="green"/>
      <path
         d="m 80,45 10,5 -10,5 z"
         id="triangle2" fill="green"/>
      <rect
         id="rectangle"
         width="60"
         height="10"
         x="20"
         y="45" fill="black"/>
    </svg>"##,
);

test_compare_render_output!(
    marker_context_stroke_fill,
    400,
    400,
    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
      <style>
        .path1 {
          fill: none;
          stroke-width: 4px;
          marker: url(#marker1);
        }

        .path2 {
          fill: darkblue;
          stroke: mediumseagreen;
          stroke-width: 4px;
          marker: url(#marker2);
        }
      </style>

      <path class="path1" d="M20,20 L200,20 L380,20" stroke="lime"/>

      <path class="path2" d="M20,40 h360 v320 h-360 v-320 Z"/>

      <marker id="marker1" markerWidth="12" markerHeight="12" refX="6" refY="6"
              markerUnits="userSpaceOnUse">
        <circle cx="6" cy="6" r="3"
                fill="white" stroke="context-stroke" stroke-width="2"/>
      </marker>

      <marker id="marker2" markerWidth="12" markerHeight="12" refX="6" refY="6"
              markerUnits="userSpaceOnUse">
        <!-- Note that here the paint is reversed:
             fill=context-stroke,
             stroke=context-fill
        -->
        <circle cx="6" cy="6" r="3"
                fill="context-stroke" stroke="context-fill" stroke-width="2"/>
      </marker>
    </svg>"##,

    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
      <path d="M20,20 L200,20 L380,20" stroke="lime" stroke-width="4"/>
      <circle cx="20" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>
      <circle cx="200" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>
      <circle cx="380" cy="20" r="3" stroke-width="2" fill="white" stroke="lime"/>

      <path class="path2" d="M20,40 h360 v320 h-360 v-320 Z" fill="darkblue"
            stroke="mediumseagreen" stroke-width="4"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="380" cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="380" cy="360" r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="360" r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
      <circle cx="20"  cy="40"  r="3" fill="mediumseagreen" stroke="darkblue" stroke-width="2"/>
    </svg>
    "##,
);
<|endoftext|>


<commit_before>use ::anyhow::Result;
use ::async_std::net::{TcpListener, TcpStream};
use ::async_std::prelude::*;
use ::async_std::task;

use ::pueue::message::{create_success_message, Message};
use ::pueue::protocol::*;

#[async_std::test]
async fn test_single_huge_payload() -> Result<()> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let addr = listener.local_addr()?;

    // The message that should be sent
    let payload = "a".repeat(100_000);
    let message = create_success_message(payload);
    let original_bytes = bincode::serialize(&message).expect("Failed to serialize message.");

    // Spawn a sub thread that:
    // 1. Accepts a new connection
    // 2. Reads a message
    // 3. Sends the same message back
    task::spawn(async move {
        let mut incoming = listener.incoming();
        let mut socket = incoming.next().await.unwrap().unwrap();
        let message_bytes = receive_bytes(&mut socket).await.unwrap();

        let message: Message = bincode::deserialize(&message_bytes).unwrap();

        send_message(message, &mut socket).await.unwrap();
    });

    let mut client = TcpStream::connect(&addr).await?;
    // Create a client that sends a message and instantly receives it
    send_message(message, &mut client).await?;
    let response_bytes = receive_bytes(&mut client).await?;
    let _message: Message = bincode::deserialize(&response_bytes)?;

    assert_eq!(response_bytes, original_bytes);

    Ok(())
}
<commit_msg>Fix test imports<commit_after>use anyhow::Result;
use async_std::net::{TcpListener, TcpStream};
use async_std::prelude::*;
use async_std::task;

use pueue::message::{create_success_message, Message};
use pueue::protocol::*;

#[async_std::test]
async fn test_single_huge_payload() -> Result<()> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let addr = listener.local_addr()?;

    // The message that should be sent
    let payload = "a".repeat(100_000);
    let message = create_success_message(payload);
    let original_bytes = bincode::serialize(&message).expect("Failed to serialize message.");

    // Spawn a sub thread that:
    // 1. Accepts a new connection
    // 2. Reads a message
    // 3. Sends the same message back
    task::spawn(async move {
        let mut incoming = listener.incoming();
        let mut socket = incoming.next().await.unwrap().unwrap();
        let message_bytes = receive_bytes(&mut socket).await.unwrap();

        let message: Message = bincode::deserialize(&message_bytes).unwrap();

        send_message(message, &mut socket).await.unwrap();
    });

    let mut client = TcpStream::connect(&addr).await?;
    // Create a client that sends a message and instantly receives it
    send_message(message, &mut client).await?;
    let response_bytes = receive_bytes(&mut client).await?;
    let _message: Message = bincode::deserialize(&response_bytes)?;

    assert_eq!(response_bytes, original_bytes);

    Ok(())
}
<|endoftext|>


<commit_before>extern crate serde;

use self::serde::ser::Serialize;

#[derive(Debug, Clone, Serialize)]
pub enum OpCode {
    Greeting,
    Connect,
    Disconnect,
    WorldUpdate,
}

#[derive(Debug, Clone, Serialize)]
pub struct Message<T>
where
    T: Serialize,
{
    pub opcode: OpCode,
    pub payload: T,
}

#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
pub enum Key {
    ArrowUp,
    ArrowDown,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct KeyState {
    pub key: Key,
    pub pressed: bool,
}
<commit_msg>Core: Add debug constraint<commit_after>extern crate serde;

use self::serde::ser::Serialize;
use std::fmt::Debug;

#[derive(Debug, Clone, Serialize)]
pub enum OpCode {
    Greeting,
    Connect,
    Disconnect,
    WorldUpdate,
}

#[derive(Debug, Clone, Serialize)]
pub struct Message<T>
where
    T: Serialize + Debug,
{
    pub opcode: OpCode,
    pub payload: T,
}

#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
pub enum Key {
    ArrowUp,
    ArrowDown,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct KeyState {
    pub key: Key,
    pub pressed: bool,
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::dynamic_set::{Entry, DYNAMIC_SET};
use crate::static_sets::StaticAtomSet;
use debug_unreachable::debug_unreachable;
use phf_shared;
use std::borrow::Cow;
use std::cmp::Ordering::{self, Equal};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::num::NonZeroU64;
use std::ops;
use std::slice;
use std::str;
use std::sync::atomic::Ordering::SeqCst;

const DYNAMIC_TAG: u8 = 0b_00;
const INLINE_TAG: u8 = 0b_01; // len in upper nybble
const STATIC_TAG: u8 = 0b_10;
const TAG_MASK: u64 = 0b_11;
const LEN_OFFSET: u64 = 4;
const LEN_MASK: u64 = 0xF0;

const MAX_INLINE_LEN: usize = 7;
const STATIC_SHIFT_BITS: usize = 32;

/// Represents a string that has been interned.
///
/// While the type definition for `Atom` indicates that it generic on a particular
/// implementation of an atom set, you don't need to worry about this.  Atoms can be static
/// and come from a `StaticAtomSet` generated by the `string_cache_codegen` crate, or they
/// can be dynamic and created by you on an `EmptyStaticAtomSet`.
///
/// `Atom` implements `Clone` but not `Copy`, since internally atoms are reference-counted;
/// this means that you may need to `.clone()` an atom to keep copies to it in different
/// places, or when passing it to a function that takes an `Atom` rather than an `&Atom`.
///
/// ## Creating an atom at runtime
///
/// If you use `string_cache_codegen` to generate a precomputed list of atoms, your code
/// may then do something like read data from somewhere and extract tokens that need to be
/// compared to the atoms.  In this case, you can use `Atom::from(&str)` or
/// `Atom::from(String)`.  These create a reference-counted atom which will be
/// automatically freed when all references to it are dropped.
///
/// This means that your application can safely have a loop which tokenizes data, creates
/// atoms from the tokens, and compares the atoms to a predefined set of keywords, without
/// running the risk of arbitrary memory consumption from creating large numbers of atoms —
/// as long as your application does not store clones of the atoms it creates along the
/// way.
///
/// For example, the following is safe and will not consume arbitrary amounts of memory:
///
/// ```ignore
/// let untrusted_data = "large amounts of text ...";
///
/// for token in untrusted_data.split_whitespace() {
///     let atom = Atom::from(token); // interns the string
///
///     if atom == Atom::from("keyword") {
///         // handle that keyword
///     } else if atom == Atom::from("another_keyword") {
///         // handle that keyword
///     } else {
///         println!("unknown keyword");
///     }
/// } // atom is dropped here, so it is not kept around in memory
/// ```
#[derive(PartialEq, Eq)]
// NOTE: Deriving PartialEq requires that a given string must always be interned the same way.
pub struct Atom<Static> {
    unsafe_data: NonZeroU64,
    phantom: PhantomData<Static>,
}

// FIXME: bound removed from the struct definition before of this error for pack_static:
// "error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable"
// https://github.com/rust-lang/rust/issues/57563
impl<Static> Atom<Static> {
    /// For the atom!() macros
    #[inline(always)]
    #[doc(hidden)]
    pub const fn pack_static(n: u32) -> Self {
        Self {
            unsafe_data: unsafe {
                // STATIC_TAG ensures this is non-zero
                NonZeroU64::new_unchecked((STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS))
            },
            phantom: PhantomData,
        }
    }

    fn tag(&self) -> u8 {
        (self.unsafe_data.get() & TAG_MASK) as u8
    }
}

impl<Static: StaticAtomSet> Atom<Static> {
    /// Return the internal repersentation. For testing.
    #[doc(hidden)]
    pub fn unsafe_data(&self) -> u64 {
        self.unsafe_data.get()
    }

    /// Return true if this is a static Atom. For testing.
    #[doc(hidden)]
    pub fn is_static(&self) -> bool {
        self.tag() == STATIC_TAG
    }

    /// Return true if this is a dynamic Atom. For testing.
    #[doc(hidden)]
    pub fn is_dynamic(&self) -> bool {
        self.tag() == DYNAMIC_TAG
    }

    /// Return true if this is an inline Atom. For testing.
    #[doc(hidden)]
    pub fn is_inline(&self) -> bool {
        self.tag() == INLINE_TAG
    }

    fn static_index(&self) -> u64 {
        self.unsafe_data.get() >> STATIC_SHIFT_BITS
    }

    /// Get the hash of the string as it is stored in the set.
    pub fn get_hash(&self) -> u32 {
        match self.tag() {
            DYNAMIC_TAG => {
                let entry = self.unsafe_data.get() as *const Entry;
                unsafe { (*entry).hash }
            }
            STATIC_TAG => Static::get().hashes[self.static_index() as usize],
            INLINE_TAG => {
                let data = self.unsafe_data.get();
                // This may or may not be great...
                ((data >> 32) ^ data) as u32
            }
            _ => unsafe { debug_unreachable!() },
        }
    }

    pub fn try_static(string_to_add: &str) -> Option<Self> {
        Self::try_static_internal(string_to_add).ok()
    }

    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
        let static_set = Static::get();
        let hash = phf_shared::hash(&*string_to_add, &static_set.key);
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());

        if static_set.atoms[index as usize] == string_to_add {
            Ok(Self::pack_static(index))
        } else {
            Err(hash)
        }
    }
}

impl<Static: StaticAtomSet> Default for Atom<Static> {
    #[inline]
    fn default() -> Self {
        Atom::pack_static(Static::empty_string_index())
    }
}

impl<Static: StaticAtomSet> Hash for Atom<Static> {
    #[inline]
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        state.write_u32(self.get_hash())
    }
}

impl<'a, Static: StaticAtomSet> From<Cow<'a, str>> for Atom<Static> {
    fn from(string_to_add: Cow<'a, str>) -> Self {
        Self::try_static_internal(&*string_to_add).unwrap_or_else(|hash| {
            let len = string_to_add.len();
            if len <= MAX_INLINE_LEN {
                let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
                {
                    let dest = inline_atom_slice_mut(&mut data);
                    dest[..len].copy_from_slice(string_to_add.as_bytes())
                }
                Atom {
                    // INLINE_TAG ensures this is never zero
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
                    phantom: PhantomData,
                }
            } else {
                let ptr: std::ptr::NonNull<Entry> =
                    DYNAMIC_SET.lock().insert(string_to_add, hash.g);
                let data = ptr.as_ptr() as u64;
                debug_assert!(0 == data & TAG_MASK);
                Atom {
                    // The address of a ptr::NonNull is non-zero
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
                    phantom: PhantomData,
                }
            }
        })
    }
}

impl<Static: StaticAtomSet> Clone for Atom<Static> {
    #[inline(always)]
    fn clone(&self) -> Self {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            unsafe { &*entry }.ref_count.fetch_add(1, SeqCst);
        }
        Atom { ..*self }
    }
}

impl<Static> Drop for Atom<Static> {
    #[inline]
    fn drop(&mut self) {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
                drop_slow(self)
            }
        }

        // Out of line to guide inlining.
        fn drop_slow<Static>(this: &mut Atom<Static>) {
            DYNAMIC_SET
                .lock()
                .remove(this.unsafe_data.get() as *mut Entry);
        }
    }
}

impl<Static: StaticAtomSet> ops::Deref for Atom<Static> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        unsafe {
            match self.tag() {
                DYNAMIC_TAG => {
                    let entry = self.unsafe_data.get() as *const Entry;
                    &(*entry).string
                }
                INLINE_TAG => {
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
                    let src = inline_atom_slice(&self.unsafe_data);
                    str::from_utf8_unchecked(&src[..(len as usize)])
                }
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
                _ => debug_unreachable!(),
            }
        }
    }
}

impl<Static: StaticAtomSet> fmt::Debug for Atom<Static> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ty_str = unsafe {
            match self.tag() {
                DYNAMIC_TAG => "dynamic",
                INLINE_TAG => "inline",
                STATIC_TAG => "static",
                _ => debug_unreachable!(),
            }
        };

        write!(f, "Atom('{}' type={})", &*self, ty_str)
    }
}

impl<Static: StaticAtomSet> PartialOrd for Atom<Static> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.unsafe_data == other.unsafe_data {
            return Some(Equal);
        }
        self.as_ref().partial_cmp(other.as_ref())
    }
}

impl<Static: StaticAtomSet> Ord for Atom<Static> {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        if self.unsafe_data == other.unsafe_data {
            return Equal;
        }
        self.as_ref().cmp(other.as_ref())
    }
}

// AsciiExt requires mutating methods, so we just implement the non-mutating ones.
// We don't need to implement is_ascii because there's no performance improvement
// over the one from &str.
impl<Static: StaticAtomSet> Atom<Static> {
    fn from_mutated_str<F: FnOnce(&mut str)>(s: &str, f: F) -> Self {
        let mut buffer = mem::MaybeUninit::<[u8; 64]>::uninit();
        let buffer = unsafe { &mut *buffer.as_mut_ptr() };

        if let Some(buffer_prefix) = buffer.get_mut(..s.len()) {
            buffer_prefix.copy_from_slice(s.as_bytes());
            let as_str = unsafe { ::std::str::from_utf8_unchecked_mut(buffer_prefix) };
            f(as_str);
            Atom::from(&*as_str)
        } else {
            let mut string = s.to_owned();
            f(&mut string);
            Atom::from(string)
        }
    }

    /// Like [`to_ascii_uppercase`].
    ///
    /// [`to_ascii_uppercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_uppercase
    pub fn to_ascii_uppercase(&self) -> Self {
        for (i, b) in self.bytes().enumerate() {
            if let b'a'..=b'z' = b {
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_uppercase());
            }
        }
        self.clone()
    }

    /// Like [`to_ascii_lowercase`].
    ///
    /// [`to_ascii_lowercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_lowercase
    pub fn to_ascii_lowercase(&self) -> Self {
        for (i, b) in self.bytes().enumerate() {
            if let b'A'..=b'Z' = b {
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_lowercase());
            }
        }
        self.clone()
    }

    /// Like [`eq_ignore_ascii_case`].
    ///
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        (self == other) || self.eq_str_ignore_ascii_case(&**other)
    }

    /// Like [`eq_ignore_ascii_case`], but takes an unhashed string as `other`.
    ///
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        (&**self).eq_ignore_ascii_case(other)
    }
}

#[inline(always)]
fn inline_atom_slice(x: &NonZeroU64) -> &[u8] {
    unsafe {
        let x: *const NonZeroU64 = x;
        let mut data = x as *const u8;
        // All except the lowest byte, which is first in little-endian, last in big-endian.
        if cfg!(target_endian = "little") {
            data = data.offset(1);
        }
        let len = 7;
        slice::from_raw_parts(data, len)
    }
}

#[inline(always)]
fn inline_atom_slice_mut(x: &mut u64) -> &mut [u8] {
    unsafe {
        let x: *mut u64 = x;
        let mut data = x as *mut u8;
        // All except the lowest byte, which is first in little-endian, last in big-endian.
        if cfg!(target_endian = "little") {
            data = data.offset(1);
        }
        let len = 7;
        slice::from_raw_parts_mut(data, len)
    }
}
<commit_msg>Remove redundant `use` line<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::dynamic_set::{Entry, DYNAMIC_SET};
use crate::static_sets::StaticAtomSet;
use debug_unreachable::debug_unreachable;

use std::borrow::Cow;
use std::cmp::Ordering::{self, Equal};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::num::NonZeroU64;
use std::ops;
use std::slice;
use std::str;
use std::sync::atomic::Ordering::SeqCst;

const DYNAMIC_TAG: u8 = 0b_00;
const INLINE_TAG: u8 = 0b_01; // len in upper nybble
const STATIC_TAG: u8 = 0b_10;
const TAG_MASK: u64 = 0b_11;
const LEN_OFFSET: u64 = 4;
const LEN_MASK: u64 = 0xF0;

const MAX_INLINE_LEN: usize = 7;
const STATIC_SHIFT_BITS: usize = 32;

/// Represents a string that has been interned.
///
/// While the type definition for `Atom` indicates that it generic on a particular
/// implementation of an atom set, you don't need to worry about this.  Atoms can be static
/// and come from a `StaticAtomSet` generated by the `string_cache_codegen` crate, or they
/// can be dynamic and created by you on an `EmptyStaticAtomSet`.
///
/// `Atom` implements `Clone` but not `Copy`, since internally atoms are reference-counted;
/// this means that you may need to `.clone()` an atom to keep copies to it in different
/// places, or when passing it to a function that takes an `Atom` rather than an `&Atom`.
///
/// ## Creating an atom at runtime
///
/// If you use `string_cache_codegen` to generate a precomputed list of atoms, your code
/// may then do something like read data from somewhere and extract tokens that need to be
/// compared to the atoms.  In this case, you can use `Atom::from(&str)` or
/// `Atom::from(String)`.  These create a reference-counted atom which will be
/// automatically freed when all references to it are dropped.
///
/// This means that your application can safely have a loop which tokenizes data, creates
/// atoms from the tokens, and compares the atoms to a predefined set of keywords, without
/// running the risk of arbitrary memory consumption from creating large numbers of atoms —
/// as long as your application does not store clones of the atoms it creates along the
/// way.
///
/// For example, the following is safe and will not consume arbitrary amounts of memory:
///
/// ```ignore
/// let untrusted_data = "large amounts of text ...";
///
/// for token in untrusted_data.split_whitespace() {
///     let atom = Atom::from(token); // interns the string
///
///     if atom == Atom::from("keyword") {
///         // handle that keyword
///     } else if atom == Atom::from("another_keyword") {
///         // handle that keyword
///     } else {
///         println!("unknown keyword");
///     }
/// } // atom is dropped here, so it is not kept around in memory
/// ```
#[derive(PartialEq, Eq)]
// NOTE: Deriving PartialEq requires that a given string must always be interned the same way.
pub struct Atom<Static> {
    unsafe_data: NonZeroU64,
    phantom: PhantomData<Static>,
}

// FIXME: bound removed from the struct definition before of this error for pack_static:
// "error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable"
// https://github.com/rust-lang/rust/issues/57563
impl<Static> Atom<Static> {
    /// For the atom!() macros
    #[inline(always)]
    #[doc(hidden)]
    pub const fn pack_static(n: u32) -> Self {
        Self {
            unsafe_data: unsafe {
                // STATIC_TAG ensures this is non-zero
                NonZeroU64::new_unchecked((STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS))
            },
            phantom: PhantomData,
        }
    }

    fn tag(&self) -> u8 {
        (self.unsafe_data.get() & TAG_MASK) as u8
    }
}

impl<Static: StaticAtomSet> Atom<Static> {
    /// Return the internal repersentation. For testing.
    #[doc(hidden)]
    pub fn unsafe_data(&self) -> u64 {
        self.unsafe_data.get()
    }

    /// Return true if this is a static Atom. For testing.
    #[doc(hidden)]
    pub fn is_static(&self) -> bool {
        self.tag() == STATIC_TAG
    }

    /// Return true if this is a dynamic Atom. For testing.
    #[doc(hidden)]
    pub fn is_dynamic(&self) -> bool {
        self.tag() == DYNAMIC_TAG
    }

    /// Return true if this is an inline Atom. For testing.
    #[doc(hidden)]
    pub fn is_inline(&self) -> bool {
        self.tag() == INLINE_TAG
    }

    fn static_index(&self) -> u64 {
        self.unsafe_data.get() >> STATIC_SHIFT_BITS
    }

    /// Get the hash of the string as it is stored in the set.
    pub fn get_hash(&self) -> u32 {
        match self.tag() {
            DYNAMIC_TAG => {
                let entry = self.unsafe_data.get() as *const Entry;
                unsafe { (*entry).hash }
            }
            STATIC_TAG => Static::get().hashes[self.static_index() as usize],
            INLINE_TAG => {
                let data = self.unsafe_data.get();
                // This may or may not be great...
                ((data >> 32) ^ data) as u32
            }
            _ => unsafe { debug_unreachable!() },
        }
    }

    pub fn try_static(string_to_add: &str) -> Option<Self> {
        Self::try_static_internal(string_to_add).ok()
    }

    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
        let static_set = Static::get();
        let hash = phf_shared::hash(&*string_to_add, &static_set.key);
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());

        if static_set.atoms[index as usize] == string_to_add {
            Ok(Self::pack_static(index))
        } else {
            Err(hash)
        }
    }
}

impl<Static: StaticAtomSet> Default for Atom<Static> {
    #[inline]
    fn default() -> Self {
        Atom::pack_static(Static::empty_string_index())
    }
}

impl<Static: StaticAtomSet> Hash for Atom<Static> {
    #[inline]
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        state.write_u32(self.get_hash())
    }
}

impl<'a, Static: StaticAtomSet> From<Cow<'a, str>> for Atom<Static> {
    fn from(string_to_add: Cow<'a, str>) -> Self {
        Self::try_static_internal(&*string_to_add).unwrap_or_else(|hash| {
            let len = string_to_add.len();
            if len <= MAX_INLINE_LEN {
                let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
                {
                    let dest = inline_atom_slice_mut(&mut data);
                    dest[..len].copy_from_slice(string_to_add.as_bytes())
                }
                Atom {
                    // INLINE_TAG ensures this is never zero
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
                    phantom: PhantomData,
                }
            } else {
                let ptr: std::ptr::NonNull<Entry> =
                    DYNAMIC_SET.lock().insert(string_to_add, hash.g);
                let data = ptr.as_ptr() as u64;
                debug_assert!(0 == data & TAG_MASK);
                Atom {
                    // The address of a ptr::NonNull is non-zero
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
                    phantom: PhantomData,
                }
            }
        })
    }
}

impl<Static: StaticAtomSet> Clone for Atom<Static> {
    #[inline(always)]
    fn clone(&self) -> Self {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            unsafe { &*entry }.ref_count.fetch_add(1, SeqCst);
        }
        Atom { ..*self }
    }
}

impl<Static> Drop for Atom<Static> {
    #[inline]
    fn drop(&mut self) {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
                drop_slow(self)
            }
        }

        // Out of line to guide inlining.
        fn drop_slow<Static>(this: &mut Atom<Static>) {
            DYNAMIC_SET
                .lock()
                .remove(this.unsafe_data.get() as *mut Entry);
        }
    }
}

impl<Static: StaticAtomSet> ops::Deref for Atom<Static> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        unsafe {
            match self.tag() {
                DYNAMIC_TAG => {
                    let entry = self.unsafe_data.get() as *const Entry;
                    &(*entry).string
                }
                INLINE_TAG => {
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
                    let src = inline_atom_slice(&self.unsafe_data);
                    str::from_utf8_unchecked(&src[..(len as usize)])
                }
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
                _ => debug_unreachable!(),
            }
        }
    }
}

impl<Static: StaticAtomSet> fmt::Debug for Atom<Static> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ty_str = unsafe {
            match self.tag() {
                DYNAMIC_TAG => "dynamic",
                INLINE_TAG => "inline",
                STATIC_TAG => "static",
                _ => debug_unreachable!(),
            }
        };

        write!(f, "Atom('{}' type={})", &*self, ty_str)
    }
}

impl<Static: StaticAtomSet> PartialOrd for Atom<Static> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.unsafe_data == other.unsafe_data {
            return Some(Equal);
        }
        self.as_ref().partial_cmp(other.as_ref())
    }
}

impl<Static: StaticAtomSet> Ord for Atom<Static> {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        if self.unsafe_data == other.unsafe_data {
            return Equal;
        }
        self.as_ref().cmp(other.as_ref())
    }
}

// AsciiExt requires mutating methods, so we just implement the non-mutating ones.
// We don't need to implement is_ascii because there's no performance improvement
// over the one from &str.
impl<Static: StaticAtomSet> Atom<Static> {
    fn from_mutated_str<F: FnOnce(&mut str)>(s: &str, f: F) -> Self {
        let mut buffer = mem::MaybeUninit::<[u8; 64]>::uninit();
        let buffer = unsafe { &mut *buffer.as_mut_ptr() };

        if let Some(buffer_prefix) = buffer.get_mut(..s.len()) {
            buffer_prefix.copy_from_slice(s.as_bytes());
            let as_str = unsafe { ::std::str::from_utf8_unchecked_mut(buffer_prefix) };
            f(as_str);
            Atom::from(&*as_str)
        } else {
            let mut string = s.to_owned();
            f(&mut string);
            Atom::from(string)
        }
    }

    /// Like [`to_ascii_uppercase`].
    ///
    /// [`to_ascii_uppercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_uppercase
    pub fn to_ascii_uppercase(&self) -> Self {
        for (i, b) in self.bytes().enumerate() {
            if let b'a'..=b'z' = b {
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_uppercase());
            }
        }
        self.clone()
    }

    /// Like [`to_ascii_lowercase`].
    ///
    /// [`to_ascii_lowercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_lowercase
    pub fn to_ascii_lowercase(&self) -> Self {
        for (i, b) in self.bytes().enumerate() {
            if let b'A'..=b'Z' = b {
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_lowercase());
            }
        }
        self.clone()
    }

    /// Like [`eq_ignore_ascii_case`].
    ///
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        (self == other) || self.eq_str_ignore_ascii_case(&**other)
    }

    /// Like [`eq_ignore_ascii_case`], but takes an unhashed string as `other`.
    ///
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
        (&**self).eq_ignore_ascii_case(other)
    }
}

#[inline(always)]
fn inline_atom_slice(x: &NonZeroU64) -> &[u8] {
    unsafe {
        let x: *const NonZeroU64 = x;
        let mut data = x as *const u8;
        // All except the lowest byte, which is first in little-endian, last in big-endian.
        if cfg!(target_endian = "little") {
            data = data.offset(1);
        }
        let len = 7;
        slice::from_raw_parts(data, len)
    }
}

#[inline(always)]
fn inline_atom_slice_mut(x: &mut u64) -> &mut [u8] {
    unsafe {
        let x: *mut u64 = x;
        let mut data = x as *mut u8;
        // All except the lowest byte, which is first in little-endian, last in big-endian.
        if cfg!(target_endian = "little") {
            data = data.offset(1);
        }
        let len = 7;
        slice::from_raw_parts_mut(data, len)
    }
}
<|endoftext|>


<commit_before>//! Bit level parsers and combinators
//!
//! Bit parsing is handled by tweaking the input in most macros.
//! In byte level parsing, the input is generally a `&[u8]` passed from combinator
//! to combinator until the slices are manipulated.
//!
//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is an byte slice,
//! the second part is a bit offset in the first byte of the slice.
//!
//! By passing a pair like this, we can leverage most of the combinators, and avoid
//! transforming the whole slice to a vector of booleans. This should make it easy
//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length.

/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>`
/// transforms its byte slice input in a bit stream for the underlying parsers
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_3_bits<u8>, bits!( take_bits!( u8, 3 ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_3_bits( sl ), Done(&sl[1..], 5) );
/// # }
#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bits_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr) => (
    bits_impl!($i, call!($f));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let input = ($i, 0usize);
      match $submac!(input, $($args)*) {
        $crate::IResult::Error(e)                            => {
          let err = match e {
            $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k),
            $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => {
              $crate::Err::Position(k, &i[b/8..])
            }
          };
          $crate::IResult::Error(err)
        }
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => {
          //println!("bits parser returned Needed::Size({})", i);
          $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1))
        },
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
          //println!("bit index=={} => byte index=={}", bit_index, byte_index);
          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>`
/// generates a parser consuming the specified number of bits.
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_pair<(u8, u8)>, bits!( pair!( take_bits!( u8, 3 ), take_bits!(u8, 5) ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_pair( sl ),       Done(&sl[1..], (5, 10)) );
///  assert_eq!(take_pair( &sl[1..] ), Done(&sl[2..], (7, 16)) );
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  ($i:expr, $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      //println!("taking {} bits from {:?}", $count, $i);
      let (input, bit_offset) = $i;
      let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 {
        $crate::IResult::Done( (input, bit_offset), 0)
      } else {
        let cnt = ($count as usize + bit_offset).div(8);
        if input.len() * 8 < $count as usize + bit_offset {
          //println!("returning incomplete: {}", $count as usize + bit_offset);
          $crate::IResult::Incomplete($crate::Needed::Size($count as usize))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              input[it] as $t
            } else {
              ((input[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&input[cnt..], end_offset) , acc)
        }
      };
      res
    }
  );
);

/// matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified
#[macro_export]
macro_rules! tag_bits (
  ($i:expr, $t:ty, $count:expr, $p: pat) => (
    {
      match take_bits!($i, $t, $count) {
        $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
        $crate::IResult::Done(i, o)    => {
          if let $p = o {
            let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o);
            res
          } else {
            $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
          }
        },
        _                              => {
          $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
        }
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed,Err};
  use ErrorKind;

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 0), u8,   6 ), IResult::Done((&sl[0..], 6), 42));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22)));
  }

  #[test]
  fn tag_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(tag_bits!( (sl, 0), u8,   3, 0b101), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(tag_bits!( (sl, 0), u8,   4, 0b1010), IResult::Done((&sl[0..], 4), 10));
  }

  named!(ch<(&[u8],usize),(u8,u8)>,
    chain!(
      tag_bits!(u8, 3, 0b101) ~
      x: take_bits!(u8, 4)    ~
      y: take_bits!(u8, 5)    ,
      || { (x,y) }
    )
  );

  #[test]
  fn chain_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15)));
    assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16)));
    assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12)));
  }

  named!(ch_bytes<(u8,u8)>, bits!(ch));
  #[test]
  fn bits_to_bytes() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15)));
    assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2)));
    assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..])));
  }
}
<commit_msg>Fixed small typo in docs.<commit_after>//! Bit level parsers and combinators
//!
//! Bit parsing is handled by tweaking the input in most macros.
//! In byte level parsing, the input is generally a `&[u8]` passed from combinator
//! to combinator until the slices are manipulated.
//!
//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is an byte slice,
//! the second part is a bit offset in the first byte of the slice.
//!
//! By passing a pair like this, we can leverage most of the combinators, and avoid
//! transforming the whole slice to a vector of booleans. This should make it easy
//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length.

/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>`
/// transforms its byte slice input into a bit stream for the underlying parsers
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_3_bits<u8>, bits!( take_bits!( u8, 3 ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_3_bits( sl ), Done(&sl[1..], 5) );
/// # }
#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bits_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr) => (
    bits_impl!($i, call!($f));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let input = ($i, 0usize);
      match $submac!(input, $($args)*) {
        $crate::IResult::Error(e)                            => {
          let err = match e {
            $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k),
            $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => {
              $crate::Err::Position(k, &i[b/8..])
            }
          };
          $crate::IResult::Error(err)
        }
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => {
          //println!("bits parser returned Needed::Size({})", i);
          $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1))
        },
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
          //println!("bit index=={} => byte index=={}", bit_index, byte_index);
          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>`
/// generates a parser consuming the specified number of bits.
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_pair<(u8, u8)>, bits!( pair!( take_bits!( u8, 3 ), take_bits!(u8, 5) ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_pair( sl ),       Done(&sl[1..], (5, 10)) );
///  assert_eq!(take_pair( &sl[1..] ), Done(&sl[2..], (7, 16)) );
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  ($i:expr, $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      //println!("taking {} bits from {:?}", $count, $i);
      let (input, bit_offset) = $i;
      let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 {
        $crate::IResult::Done( (input, bit_offset), 0)
      } else {
        let cnt = ($count as usize + bit_offset).div(8);
        if input.len() * 8 < $count as usize + bit_offset {
          //println!("returning incomplete: {}", $count as usize + bit_offset);
          $crate::IResult::Incomplete($crate::Needed::Size($count as usize))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              input[it] as $t
            } else {
              ((input[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&input[cnt..], end_offset) , acc)
        }
      };
      res
    }
  );
);

/// matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified
#[macro_export]
macro_rules! tag_bits (
  ($i:expr, $t:ty, $count:expr, $p: pat) => (
    {
      match take_bits!($i, $t, $count) {
        $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
        $crate::IResult::Done(i, o)    => {
          if let $p = o {
            let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o);
            res
          } else {
            $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
          }
        },
        _                              => {
          $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
        }
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed,Err};
  use ErrorKind;

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 0), u8,   6 ), IResult::Done((&sl[0..], 6), 42));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22)));
  }

  #[test]
  fn tag_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(tag_bits!( (sl, 0), u8,   3, 0b101), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(tag_bits!( (sl, 0), u8,   4, 0b1010), IResult::Done((&sl[0..], 4), 10));
  }

  named!(ch<(&[u8],usize),(u8,u8)>,
    chain!(
      tag_bits!(u8, 3, 0b101) ~
      x: take_bits!(u8, 4)    ~
      y: take_bits!(u8, 5)    ,
      || { (x,y) }
    )
  );

  #[test]
  fn chain_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15)));
    assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16)));
    assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12)));
  }

  named!(ch_bytes<(u8,u8)>, bits!(ch));
  #[test]
  fn bits_to_bytes() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15)));
    assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2)));
    assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..])));
  }
}
<|endoftext|>


<commit_before>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// ((if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("((if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}
<commit_msg>Fix slightly wrong program in integration target<commit_after>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}
<|endoftext|>


<commit_before>use num::{Float, FromPrimitive};

/// A one-dimensional cubic bezier polynomial
#[derive(Debug, Clone)]
pub struct BezCubePoly<F> where F: Float + FromPrimitive {
    pub start: F,
    pub ctrl0: F,
    pub ctrl1: F,
    pub end: F
}

impl<F> BezCubePoly<F> where F: Float + FromPrimitive {
    pub fn new(start: F, ctrl0: F, ctrl1: F, end: F) -> BezCubePoly<F> {
        BezCubePoly {
            start: start,
            ctrl0: ctrl0,
            ctrl1: ctrl1,
            end: end
        }
    }

    pub fn interp(&self, t: F) -> F {
        let zero = F::from_f32(0.0).unwrap();
        let one  = F::from_f32(1.0).unwrap();
        assert!(zero <= t && t <= one);
        self.interp_unbounded(t)
    }

    pub fn interp_unbounded(&self, t: F) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        t1.powi(3)             * self.start                             +
        t1.powi(2) * t         * self.ctrl0 * F::from_f32(3.0).unwrap() +
        t1         * t.powi(2) * self.ctrl1 * F::from_f32(3.0).unwrap() +
                     t.powi(3) * self.end
    }

    pub fn derivative(&self, t: F) -> F {
        let zero = F::from_f32(0.0).unwrap();
        let one  = F::from_f32(1.0).unwrap();
        assert!(zero <= t && t <= one);
        self.derivative_unbounded(t)
    }

    pub fn derivative_unbounded(&self, t: F) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        t1.powi(2)     * (self.ctrl0 - self.start) * F::from_f32(3.0).unwrap() +
        t1 * t         * (self.ctrl1 - self.ctrl0) * F::from_f32(6.0).unwrap() +
             t.powi(2) * (self.end - self.ctrl1)   * F::from_f32(3.0).unwrap()
    }
}<commit_msg>Re-wrote Bezier curve polynomials to be created from macros<commit_after>use num::{Float, FromPrimitive};

macro_rules! count {
    ($idc:tt) => (1);
    ($($element:tt),*) => {{$(count!($element) +)* 0}};
}

macro_rules! n_bezier {
    ($name:ident {
        $($field:ident: $weight:expr),+
    } derived {
        $($dleft:ident - $dright:ident: $dweight:expr),+
    }) => {
        #[derive(Debug, Clone)]
        pub struct $name<F> where F: Float + FromPrimitive {
            $($field: F),+
        }

        impl<F> $name<F> where F: Float + FromPrimitive {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }

            pub fn interp(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.interp_unbounded(t)
            }

            pub fn interp_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $field =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        self.$field *
                        F::from_i32($weight).unwrap();
                )+
                $($field +)+ F::from_f32(0.0).unwrap()
            }

            pub fn derivative(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.derivative_unbounded(t)
            }

            pub fn derivative_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 2;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $dleft =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        (self.$dleft - self.$dright) *
                        F::from_i32($dweight).unwrap();
                )+
                $($dleft +)+ F::from_f32(0.0).unwrap()
            }
        }
    }
}

n_bezier!{BezCubePoly {
    start: 1,
    ctrl0: 3,
    ctrl1: 3,
    end:   1
} derived {
    ctrl0 - start: 1,
    ctrl1 - ctrl0: 2,
    end   - ctrl1: 1
}}<|endoftext|>


<commit_before>use std::io::TcpStream;

pub trait Data
{
    fn process_request_data(&self, mut request: TcpStream);
}
<commit_msg>Updated trait<commit_after>use std::io::TcpStream;

trait Data
{
    fn process_request_data(&self, mut request: TcpStream);
}
<|endoftext|>


<commit_before>extern crate config;
use self::config::types::{Config, ScalarValue, Value};

use std::env::home_dir;
use std::process::Command;

pub struct CommandLine {
    program: String,
    args: Vec<String>,
}

fn expand_home(path: &String) -> String {
    if path.starts_with("~/") {
        match home_dir() {
            Some(home) => format!("{}/{}", home.display(), &path[2..]),
            _ => path.clone(),
        }
    } else {
        path.clone()
    }
}

fn make_command_vec(vec: &Vec<Value>) -> Result<CommandLine, String> {
    if vec.is_empty() {
        return Err(format!("empty execution vector"));
    }

    let mut prog_args = vec![];
    for v in vec {
        match v {
            &Value::Svalue(ref sv) =>
                match sv {
                    &ScalarValue::Str(ref s) => prog_args.push(s),
                    _ => return Err(format!("non-string program value")),
                },
            _ => return Err(format!("non-string program value")),
        }
    }

    let (prog, args) = prog_args.split_at(1);
    Ok(CommandLine {
        program: expand_home(prog[0]),
        // XXX: Why does .cloned() not work?
        args: args.iter().map(|&arg| (*arg).clone()).collect(),
    })
}

fn make_command_str(string: &String) -> Result<CommandLine, String> {
    if string.is_empty() {
        Err(format!("empty execution string"))
    } else {
        Ok(CommandLine {
            program: expand_home(string),
            args: vec![],
        })
    }
}

pub fn read_command_line_from_config(conf: &Config, path: &str) -> Option<CommandLine> {
    conf.lookup(path).and_then(|val| {
        let cmd_line = match val {
            &Value::Array(ref a) => make_command_vec(a),
            &Value::Svalue(ref sv) =>
                match sv {
                    &ScalarValue::Str(ref s) => make_command_str(s),
                    _ => Err(format!("unsupported type for {}", path)),
                },
            _ => Err(format!("unsupported type for {}", path)),
        };

        cmd_line.map_err(|err| {
            println!("Failed to make a command line for '{}': {:?}", path, err);
        }).ok()
    })
}

pub fn run_command_line(cmd_line: &CommandLine) -> Result<(), String> {
    let cmd = Command::new(&cmd_line.program)
                .args(&cmd_line.args)
                .output();

    match cmd {
        Ok(output) =>
            if output.status.success() {
                Ok(())
            } else {
                Err(format!("failed to execute process ({:?}):\noutput:\n{}\nerror:{}",
                            output.status.code(),
                            String::from_utf8_lossy(&output.stdout),
                            String::from_utf8_lossy(&output.stderr)))
            },
        _ => Err(format!("failed to execute process")),
    }
}
<commit_msg>clippy: address match_ref_pats warnings<commit_after>extern crate config;
use self::config::types::{Config, ScalarValue, Value};

use std::env::home_dir;
use std::process::Command;

pub struct CommandLine {
    program: String,
    args: Vec<String>,
}

fn expand_home(path: &String) -> String {
    if path.starts_with("~/") {
        match home_dir() {
            Some(home) => format!("{}/{}", home.display(), &path[2..]),
            _ => path.clone(),
        }
    } else {
        path.clone()
    }
}

fn make_command_vec(vec: &Vec<Value>) -> Result<CommandLine, String> {
    if vec.is_empty() {
        return Err(format!("empty execution vector"));
    }

    let mut prog_args = vec![];
    for v in vec {
        match *v {
            Value::Svalue(ref sv) =>
                match *sv {
                    ScalarValue::Str(ref s) => prog_args.push(s),
                    _ => return Err(format!("non-string program value")),
                },
            _ => return Err(format!("non-string program value")),
        }
    }

    let (prog, args) = prog_args.split_at(1);
    Ok(CommandLine {
        program: expand_home(prog[0]),
        // XXX: Why does .cloned() not work?
        args: args.iter().map(|&arg| (*arg).clone()).collect(),
    })
}

fn make_command_str(string: &String) -> Result<CommandLine, String> {
    if string.is_empty() {
        Err(format!("empty execution string"))
    } else {
        Ok(CommandLine {
            program: expand_home(string),
            args: vec![],
        })
    }
}

pub fn read_command_line_from_config(conf: &Config, path: &str) -> Option<CommandLine> {
    conf.lookup(path).and_then(|val| {
        let cmd_line = match *val {
            Value::Array(ref a) => make_command_vec(a),
            Value::Svalue(ref sv) =>
                match *sv {
                    ScalarValue::Str(ref s) => make_command_str(s),
                    _ => Err(format!("unsupported type for {}", path)),
                },
            _ => Err(format!("unsupported type for {}", path)),
        };

        cmd_line.map_err(|err| {
            println!("Failed to make a command line for '{}': {:?}", path, err);
        }).ok()
    })
}

pub fn run_command_line(cmd_line: &CommandLine) -> Result<(), String> {
    let cmd = Command::new(&cmd_line.program)
                .args(&cmd_line.args)
                .output();

    match cmd {
        Ok(output) =>
            if output.status.success() {
                Ok(())
            } else {
                Err(format!("failed to execute process ({:?}):\noutput:\n{}\nerror:{}",
                            output.status.code(),
                            String::from_utf8_lossy(&output.stdout),
                            String::from_utf8_lossy(&output.stderr)))
            },
        _ => Err(format!("failed to execute process")),
    }
}
<|endoftext|>