<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use context::BlockOffset;
use context::BLOCK_TO_PLANE_SHIFT;
use context::MI_SIZE;
use partition::*;
use plane::*;
use FrameInvariants;
use FrameState;

#[inline(always)]
pub fn get_sad(
  plane_org: &mut PlaneSlice, plane_ref: &mut PlaneSlice, blk_h: usize,
  blk_w: usize
) -> u32 {
  let mut sum = 0 as u32;

  for _r in 0..blk_h {
    {
      let slice_org = plane_org.as_slice_w_width(blk_w);
      let slice_ref = plane_ref.as_slice_w_width(blk_w);
      sum += slice_org
        .iter()
        .zip(slice_ref)
        .map(|(&a, &b)| (a as i32 - b as i32).abs() as u32)
        .sum::<u32>();
    }
    plane_org.y += 1;
    plane_ref.y += 1;
  }

  sum
}

pub fn motion_estimation(
  fi: &FrameInvariants, fs: &mut FrameState, bsize: BlockSize,
  bo: &BlockOffset, ref_frame: usize, pmv: &MotionVector
) -> MotionVector {
  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
    Some(ref rec) => {
      let po = PlaneOffset {
        x: (bo.x as isize) << BLOCK_TO_PLANE_SHIFT,
        y: (bo.y as isize) << BLOCK_TO_PLANE_SHIFT
      };
      let range = 32 as isize;
      let blk_w = bsize.width();
      let blk_h = bsize.height();
      let border_w = 128 + blk_w as isize * 8;
      let border_h = 128 + blk_h as isize * 8;
      let mvx_min = -(bo.x as isize) * (8 * MI_SIZE) as isize - border_w;
      let mvx_max = (fi.w_in_b - bo.x - blk_w / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_w;
      let mvy_min = -(bo.y as isize) * (8 * MI_SIZE) as isize - border_h;
      let mvy_max = (fi.h_in_b - bo.y - blk_h / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_h;
      let x_lo = po.x + ((-range + (pmv.col / 8) as isize).max(mvx_min / 8));
      let x_hi = po.x + ((range + (pmv.col / 8) as isize).min(mvx_max / 8));
      let y_lo = po.y + ((-range + (pmv.row / 8) as isize).max(mvy_min / 8));
      let y_hi = po.y + ((range + (pmv.row / 8) as isize).min(mvy_max / 8));

      let mut lowest_sad = 128 * 128 * 4096 as u32;
      let mut best_mv = MotionVector { row: 0, col: 0 };

      for y in (y_lo..y_hi).step_by(2) {
        for x in (x_lo..x_hi).step_by(2) {
          let mut plane_org = fs.input.planes[0].slice(&po);
          let mut plane_ref = rec.frame.planes[0].slice(&PlaneOffset { x, y });

          let sad = get_sad(&mut plane_org, &mut plane_ref, blk_h, blk_w);

          if sad < lowest_sad {
            lowest_sad = sad;
            best_mv = MotionVector {
              row: 8 * (y as i16 - po.y as i16),
              col: 8 * (x as i16 - po.x as i16)
            }
          }
        }
      }

      let mode = PredictionMode::NEWMV;
      let mut tmp_plane = Plane::new(blk_w, blk_h, 0, 0, 0, 0);

      let mut steps = vec![8, 4, 2];
      if fi.allow_high_precision_mv {
        steps.push(1);
      }

      for step in steps {
        let center_mv_h = best_mv;
        for i in 0..3 {
          for j in 0..3 {
            // Skip the center point that was already tested
            if i == 1 && j == 1 {
              continue;
            }

            let cand_mv = MotionVector {
              row: center_mv_h.row + step * (i as i16 - 1),
              col: center_mv_h.col + step * (j as i16 - 1)
            };

            if (cand_mv.col as isize) < mvx_min || (cand_mv.col as isize) > mvx_max {
              continue;
            }
            if (cand_mv.row as isize) < mvy_min || (cand_mv.row as isize) > mvy_max {
              continue;
            }

            {
              let tmp_slice =
                &mut tmp_plane.mut_slice(&PlaneOffset { x: 0, y: 0 });

              mode.predict_inter(
                fi, 0, &po, tmp_slice, blk_w, blk_h, ref_frame, &cand_mv, 8,
              );
            }

            let mut plane_org = fs.input.planes[0].slice(&po);
            let mut plane_ref = tmp_plane.slice(&PlaneOffset { x: 0, y: 0 });

            let sad = get_sad(&mut plane_org, &mut plane_ref, blk_h, blk_w);

            if sad < lowest_sad {
              lowest_sad = sad;
              best_mv = cand_mv;
            }
          }
        }
      }

      best_mv
    }

    None => MotionVector { row: 0, col: 0 }
  }
}
<commit_msg>Drop spurious mut in motion_estimation<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use context::BlockOffset;
use context::BLOCK_TO_PLANE_SHIFT;
use context::MI_SIZE;
use partition::*;
use plane::*;
use FrameInvariants;
use FrameState;

#[inline(always)]
pub fn get_sad(
  plane_org: &mut PlaneSlice, plane_ref: &mut PlaneSlice, blk_h: usize,
  blk_w: usize
) -> u32 {
  let mut sum = 0 as u32;

  for _r in 0..blk_h {
    {
      let slice_org = plane_org.as_slice_w_width(blk_w);
      let slice_ref = plane_ref.as_slice_w_width(blk_w);
      sum += slice_org
        .iter()
        .zip(slice_ref)
        .map(|(&a, &b)| (a as i32 - b as i32).abs() as u32)
        .sum::<u32>();
    }
    plane_org.y += 1;
    plane_ref.y += 1;
  }

  sum
}

pub fn motion_estimation(
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize,
  bo: &BlockOffset, ref_frame: usize, pmv: &MotionVector
) -> MotionVector {
  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
    Some(ref rec) => {
      let po = PlaneOffset {
        x: (bo.x as isize) << BLOCK_TO_PLANE_SHIFT,
        y: (bo.y as isize) << BLOCK_TO_PLANE_SHIFT
      };
      let range = 32 as isize;
      let blk_w = bsize.width();
      let blk_h = bsize.height();
      let border_w = 128 + blk_w as isize * 8;
      let border_h = 128 + blk_h as isize * 8;
      let mvx_min = -(bo.x as isize) * (8 * MI_SIZE) as isize - border_w;
      let mvx_max = (fi.w_in_b - bo.x - blk_w / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_w;
      let mvy_min = -(bo.y as isize) * (8 * MI_SIZE) as isize - border_h;
      let mvy_max = (fi.h_in_b - bo.y - blk_h / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_h;
      let x_lo = po.x + ((-range + (pmv.col / 8) as isize).max(mvx_min / 8));
      let x_hi = po.x + ((range + (pmv.col / 8) as isize).min(mvx_max / 8));
      let y_lo = po.y + ((-range + (pmv.row / 8) as isize).max(mvy_min / 8));
      let y_hi = po.y + ((range + (pmv.row / 8) as isize).min(mvy_max / 8));

      let mut lowest_sad = 128 * 128 * 4096 as u32;
      let mut best_mv = MotionVector { row: 0, col: 0 };

      for y in (y_lo..y_hi).step_by(2) {
        for x in (x_lo..x_hi).step_by(2) {
          let mut plane_org = fs.input.planes[0].slice(&po);
          let mut plane_ref = rec.frame.planes[0].slice(&PlaneOffset { x, y });

          let sad = get_sad(&mut plane_org, &mut plane_ref, blk_h, blk_w);

          if sad < lowest_sad {
            lowest_sad = sad;
            best_mv = MotionVector {
              row: 8 * (y as i16 - po.y as i16),
              col: 8 * (x as i16 - po.x as i16)
            }
          }
        }
      }

      let mode = PredictionMode::NEWMV;
      let mut tmp_plane = Plane::new(blk_w, blk_h, 0, 0, 0, 0);

      let mut steps = vec![8, 4, 2];
      if fi.allow_high_precision_mv {
        steps.push(1);
      }

      for step in steps {
        let center_mv_h = best_mv;
        for i in 0..3 {
          for j in 0..3 {
            // Skip the center point that was already tested
            if i == 1 && j == 1 {
              continue;
            }

            let cand_mv = MotionVector {
              row: center_mv_h.row + step * (i as i16 - 1),
              col: center_mv_h.col + step * (j as i16 - 1)
            };

            if (cand_mv.col as isize) < mvx_min || (cand_mv.col as isize) > mvx_max {
              continue;
            }
            if (cand_mv.row as isize) < mvy_min || (cand_mv.row as isize) > mvy_max {
              continue;
            }

            {
              let tmp_slice =
                &mut tmp_plane.mut_slice(&PlaneOffset { x: 0, y: 0 });

              mode.predict_inter(
                fi, 0, &po, tmp_slice, blk_w, blk_h, ref_frame, &cand_mv, 8,
              );
            }

            let mut plane_org = fs.input.planes[0].slice(&po);
            let mut plane_ref = tmp_plane.slice(&PlaneOffset { x: 0, y: 0 });

            let sad = get_sad(&mut plane_org, &mut plane_ref, blk_h, blk_w);

            if sad < lowest_sad {
              lowest_sad = sad;
              best_mv = cand_mv;
            }
          }
        }
      }

      best_mv
    }

    None => MotionVector { row: 0, col: 0 }
  }
}
<|endoftext|>


<commit_before>use cairo::{self, ImageSurface};
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::{AttributeResultExt, NodeError};
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers;
use crate::property_bag::PropertyBag;
use crate::surface_utils::{iterators::Pixels, shared_surface::SharedImageSurface};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, PrimitiveWithInput};

/// Enumeration of the color channels the displacement map can source.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum ColorChannel {
    R,
    G,
    B,
    A,
}

/// The `feDisplacementMap` filter primitive.
pub struct FeDisplacementMap {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    scale: f64,
    x_channel_selector: ColorChannel,
    y_channel_selector: ColorChannel,
}

impl Default for FeDisplacementMap {
    /// Constructs a new `DisplacementMap` with empty properties.
    #[inline]
    fn default() -> FeDisplacementMap {
        FeDisplacementMap {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            scale: 0.0,
            x_channel_selector: ColorChannel::A,
            y_channel_selector: ColorChannel::A,
        }
    }
}

impl NodeTrait for FeDisplacementMap {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "in2") => self.in2 = Some(Input::parse(attr, value)?),
                expanded_name!(svg "scale") => self.scale = parsers::number(value).attribute(attr)?,
                expanded_name!(svg "xChannelSelector") => {
                    self.x_channel_selector = ColorChannel::parse(attr, value)?
                }
                expanded_name!(svg "yChannelSelector") => {
                    self.y_channel_selector = ColorChannel::parse(attr, value)?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeDisplacementMap {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let displacement_input = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&displacement_input)
            .into_irect(draw_ctx);

        // Displacement map's values need to be non-premultiplied.
        let displacement_surface = displacement_input.surface().unpremultiply(bounds)?;

        let (sx, sy) = ctx.paffine().transform_distance(self.scale, self.scale);

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        {
            let cr = cairo::Context::new(&output_surface);

            for (x, y, displacement_pixel) in Pixels::new(&displacement_surface, bounds) {
                let get_value = |channel| match channel {
                    ColorChannel::R => displacement_pixel.r,
                    ColorChannel::G => displacement_pixel.g,
                    ColorChannel::B => displacement_pixel.b,
                    ColorChannel::A => displacement_pixel.a,
                };

                let process = |x| f64::from(x) / 255.0 - 0.5;

                let dx = process(get_value(self.x_channel_selector));
                let dy = process(get_value(self.y_channel_selector));

                let x = f64::from(x);
                let y = f64::from(y);
                let ox = sx * dx;
                let oy = sy * dy;

                // Doing this in a loop doesn't look too bad performance wise, and allows not to
                // manually implement bilinear or other interpolation.
                cr.rectangle(x, y, 1.0, 1.0);
                cr.reset_clip();
                cr.clip();

                input.surface().set_as_source_surface(&cr, -ox, -oy);
                cr.paint();
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        // Performance TODO: this converts in back and forth to linear RGB while technically it's
        // only needed for in2.
        true
    }
}

impl ColorChannel {
    fn parse(attr: QualName, s: &str) -> Result<Self, NodeError> {
        match s {
            "R" => Ok(ColorChannel::R),
            "G" => Ok(ColorChannel::G),
            "B" => Ok(ColorChannel::B),
            "A" => Ok(ColorChannel::A),
            _ => Err(NodeError::parse_error(attr, "invalid value")),
        }
    }
}
<commit_msg>displacement_map.rs: Don't create a NodeError directly<commit_after>use cairo::{self, ImageSurface};
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers;
use crate::property_bag::PropertyBag;
use crate::surface_utils::{iterators::Pixels, shared_surface::SharedImageSurface};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, PrimitiveWithInput};

/// Enumeration of the color channels the displacement map can source.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum ColorChannel {
    R,
    G,
    B,
    A,
}

/// The `feDisplacementMap` filter primitive.
pub struct FeDisplacementMap {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    scale: f64,
    x_channel_selector: ColorChannel,
    y_channel_selector: ColorChannel,
}

impl Default for FeDisplacementMap {
    /// Constructs a new `DisplacementMap` with empty properties.
    #[inline]
    fn default() -> FeDisplacementMap {
        FeDisplacementMap {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            scale: 0.0,
            x_channel_selector: ColorChannel::A,
            y_channel_selector: ColorChannel::A,
        }
    }
}

impl NodeTrait for FeDisplacementMap {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "in2") => self.in2 = Some(Input::parse(attr, value)?),
                expanded_name!(svg "scale") => self.scale = parsers::number(value).attribute(attr)?,
                expanded_name!(svg "xChannelSelector") => {
                    self.x_channel_selector = ColorChannel::parse(attr, value)?
                }
                expanded_name!(svg "yChannelSelector") => {
                    self.y_channel_selector = ColorChannel::parse(attr, value)?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeDisplacementMap {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let displacement_input = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&displacement_input)
            .into_irect(draw_ctx);

        // Displacement map's values need to be non-premultiplied.
        let displacement_surface = displacement_input.surface().unpremultiply(bounds)?;

        let (sx, sy) = ctx.paffine().transform_distance(self.scale, self.scale);

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        {
            let cr = cairo::Context::new(&output_surface);

            for (x, y, displacement_pixel) in Pixels::new(&displacement_surface, bounds) {
                let get_value = |channel| match channel {
                    ColorChannel::R => displacement_pixel.r,
                    ColorChannel::G => displacement_pixel.g,
                    ColorChannel::B => displacement_pixel.b,
                    ColorChannel::A => displacement_pixel.a,
                };

                let process = |x| f64::from(x) / 255.0 - 0.5;

                let dx = process(get_value(self.x_channel_selector));
                let dy = process(get_value(self.y_channel_selector));

                let x = f64::from(x);
                let y = f64::from(y);
                let ox = sx * dx;
                let oy = sy * dy;

                // Doing this in a loop doesn't look too bad performance wise, and allows not to
                // manually implement bilinear or other interpolation.
                cr.rectangle(x, y, 1.0, 1.0);
                cr.reset_clip();
                cr.clip();

                input.surface().set_as_source_surface(&cr, -ox, -oy);
                cr.paint();
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        // Performance TODO: this converts in back and forth to linear RGB while technically it's
        // only needed for in2.
        true
    }
}

impl ColorChannel {
    fn parse(attr: QualName, s: &str) -> Result<Self, NodeError> {
        match s {
            "R" => Ok(ColorChannel::R),
            "G" => Ok(ColorChannel::G),
            "B" => Ok(ColorChannel::B),
            "A" => Ok(ColorChannel::A),
            _ => Err(ValueErrorKind::parse_error("invalid value")).attribute(attr),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file= OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut u32,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>change Peripheral base address<commit_after>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x3F000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file= OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut u32,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>


<commit_before>use sdl2;
use sdl2_gfx;
use ttf = sdl2_ttf;
use sdl2::video;
use sdl2::render;
use sdl2::{event, keycode};
// for Renderer trait
use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::{Color, RGB, RGBA};
use sdl2::rwops;
use sdl2_ttf::LoaderRWops;

static SCREEN_WIDTH : int = 800;
static SCREEN_HEIGHT : int = 600;

mod game;

// hadle the annoying Rect i32
macro_rules! rect(
    ($x:expr, $y:expr, $w:expr, $h:expr) => (
        sdl2::rect::Rect::new($x as i32, $y as i32, $w as i32, $h as i32)
    )
)

// colors
static BG_COLOR: Color = RGB(0xee, 0xe4, 0xda);
static FG_COLOR: Color = RGB(0x77, 0x6e, 0x65);
static CHAR_COLOR: Color = RGB(0xee, 0x33, 0x66);
static CONTAINER_COLOR: Color = RGBA(0x77, 0x6e, 0x65, 200);
static CELL_COLORS: &'static [Color] = &'static [
    RGBA(0xee, 0xe4, 0xda, 120), RGB(0xed, 0xe0, 0xc8), RGB(0xf2, 0xb1, 0x79),
    RGB(0xf5, 0x95, 0x64), RGB(0xf6, 0x7c, 0x5f), RGB(0xf6, 0x5e, 0x3b),
    RGB(0xed, 0xcf, 0x72), RGB(0xed, 0xcc, 0x61), RGB(0xed, 0xc8, 0x50),
    RGB(0xed, 0xc5, 0x3f), RGB(0xed, 0xc2, 0x2e), RGB(0x3c, 0x3a, 0x32), ];

// Font
static TTF_FONT_RAW_BYTES: &'static [u8] = include_bin!("./res/OpenDyslexic-Regular.ttf");

#[allow(uppercase_variables, unused_must_use)]
fn draw_game(gm: &mut game::GameManager, ren: &render::Renderer, font: &ttf::Font,
             (x,y,w,h): (int,int,int,int)) -> Result<(), ~str> {
    assert_eq!(w, h);
    // BEST in 500x500
    let SIZE = gm.size;
    let CONTAINER_PADDING: int = 50  / (SIZE as int + 1);
    let CELL_WIDTH = (w - CONTAINER_PADDING * (SIZE as int + 1)) / SIZE as int ;
    assert!(CELL_WIDTH > 40); // Min width
    try!(ren.box_(x as i16, y as i16, (x+w) as i16, (y+h) as i16, CONTAINER_COLOR));
    gm.grid.each_cell(|j, i, tile_opt| {
        let i = i as int;
        let j = j as int;
        let val = match tile_opt {
            Some(&tile) => tile.value,
            None        => 0,
        };
        let c = if val == 0 {
            0           // or will be +Infinity
        } else {
            (val as f64).log2() as uint
        };
        let bx = (x + CONTAINER_PADDING * (j + 1) + CELL_WIDTH * j) as i16;
        let by = (y + CONTAINER_PADDING * (i + 1) + CELL_WIDTH * i) as i16;
        ren.box_(bx, by, bx + CELL_WIDTH as i16, by + CELL_WIDTH as i16, CELL_COLORS[c]);
        // ren.string(bx, by, format!("({}, {})", j, i), CHAR_COLOR); // DEBUG
        if val != 0 {
            let (tex, tw, th) = {
                let wd = format!("{}", val);
                let (w, h) = font.size_of_str(wd).ok().expect("size of str");
                let text = font.render_str_blended(wd, FG_COLOR).ok().expect("renderred surface");
                (ren.create_texture_from_surface(text).ok().expect("create texture"), w, h)
            };

            let ratio = if tw > CELL_WIDTH {
                CELL_WIDTH as f64 / tw as f64
            } else if th > CELL_WIDTH {
                CELL_WIDTH as f64 / th as f64
            } else { 1.0 };

            let tw = (tw as f64 * ratio) as int;
            let th = (th as f64 * ratio) as int;

            ren.copy(tex, None, Some(rect!(bx as int + CELL_WIDTH / 2 - tw/2, by as int + CELL_WIDTH / 2 - th/2,
                                               tw, th)));
        }
    });
    Ok(())
}

fn draw_title(ren: &render::Renderer, font: &ttf::Font) -> Result<(), ~str> {
    let (tex2, w, h) = {
        let wd = "Rust - 2048";
        //font.set_style([ttf::StyleBold]);
        let (w, h) = try!(font.size_of_str(wd));
        let text = try!(font.render_str_blended(wd, FG_COLOR));
        (try!(ren.create_texture_from_surface(text)), w, h)
    };
    try!(ren.copy(tex2, None, Some(rect!(SCREEN_WIDTH / 2 - w / 2, 20, w, h))));
    Ok(())
}

// FIXME: tooooooo many type convertion
fn draw_popup(ren: &render::Renderer, font: &ttf::Font, msg: &str) -> Result<(), ~str> {
    let (tex, w, h) = {
        //font.set_style([ttf::StyleBold]);
        let (w, h) = try!(font.size_of_str(msg));
        let text = try!(font.render_str_blended(msg, FG_COLOR));
        (try!(ren.create_texture_from_surface(text)), w, h)
    };
    try!(ren.rounded_box((SCREEN_WIDTH / 2 - w / 2) as i16,
                         (SCREEN_HEIGHT / 2 - h / 2) as i16,
                         (SCREEN_WIDTH / 2 + w / 2) as i16,
                         (SCREEN_HEIGHT / 2 + h / 2) as i16,
                         5,
                         BG_COLOR));
    try!(ren.rounded_rectangle((SCREEN_WIDTH / 2 - w / 2) as i16,
                               (SCREEN_HEIGHT / 2 - h / 2) as i16,
                               (SCREEN_WIDTH / 2 + w / 2) as i16,
                               (SCREEN_HEIGHT / 2 + h / 2) as i16,
                               5,
                               FG_COLOR));
    try!(ren.copy(tex, None, Some(rect!(SCREEN_WIDTH / 2 - w / 2,
                                        SCREEN_HEIGHT / 2 - h / 2,
                                        w,
                                        h))));
    Ok(())
}

pub fn run(game_size: uint) -> Result<(), ~str> {
    let win = try!(video::Window::new(
        "Rust - 2048", video::PosCentered, video::PosCentered, SCREEN_WIDTH, SCREEN_HEIGHT,
        [video::Shown]));
    let ren = try!(render::Renderer::from_window(
        win, render::DriverAuto, [render::Accelerated]));

    let mut fpsm = sdl2_gfx::framerate::FPSManager::new();
    try!(fpsm.set_framerate(50));

    let font : ~ttf::Font = {
        let raw = try!(rwops::RWops::from_bytes(TTF_FONT_RAW_BYTES));
        // or try!(ttf::Font::from_file(&Path::new("./OpenDyslexic-Regular.ttf"), 48));
        try!(raw.load_font(48))
    };
    let mut gm = game::GameManager::new(game_size);

    let mut playing = false;
    let mut celebrating = false;

    'main : loop {
        'event : loop {
            fpsm.delay();
            try!(ren.set_draw_color(BG_COLOR));
            try!(ren.clear());
            // == main drawing ==
            try!(draw_title(&*ren, &*font));
            try!(ren.string(0i16, 0i16, format!("frames: {}", fpsm.get_frame_count()), CHAR_COLOR));

            try!(ren.string(200, 90, format!("your score: {}", gm.score), CHAR_COLOR));

            try!(draw_game(&mut gm, &*ren, &*font, (SCREEN_WIDTH / 2 - 400 / 2, 100, 400, 400)));

            if celebrating || (playing && !gm.moves_available()) { // can't move
                try!(draw_popup(&*ren, &*font, format!("Score: {}! Max Cell: {}", gm.score, "NaN")));
                playing = false;
                celebrating = true;

            } else if !playing && !celebrating {
                try!(draw_popup(&*ren, &*font, "Press SPACE to start!"));
            }

            // == main drawing ends ==
            ren.present();

            match event::poll_event() {
                event::QuitEvent(_) => break 'main,
                event::KeyDownEvent(_, _, keycode::LeftKey, _, _) if playing => {
                    gm.move(game::Left);
                }
                event::KeyDownEvent(_, _, keycode::RightKey, _, _) if playing => {
                    gm.move(game::Right);
                }
                event::KeyDownEvent(_, _, keycode::UpKey, _, _) if playing => {
                    gm.move(game::Up);
                }
                event::KeyDownEvent(_, _, keycode::DownKey, _, _) if playing => {
                    gm.move(game::Down);
                }
                event::KeyDownEvent(_, _, key, _, _) => {
                    if key == keycode::EscapeKey {
                        break 'main
                    } else if key == keycode::SpaceKey {
                        if !playing {
                            playing = true;
                            celebrating = false;
                            gm.setup();
                        }
                    }

                }
                event::MouseButtonDownEvent(_, _, _, _, x, y) => {
                    println!("mouse btn down at ({},{})", x, y);
                }

                _ => {}
            }
        }
    }
    Ok(())
}
<commit_msg>use super cell color, avoid index out range<commit_after>use sdl2;
use sdl2_gfx;
use ttf = sdl2_ttf;
use sdl2::video;
use sdl2::render;
use sdl2::{event, keycode};
// for Renderer trait
use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::{Color, RGB, RGBA};
use sdl2::rwops;
use sdl2_ttf::LoaderRWops;

static SCREEN_WIDTH : int = 800;
static SCREEN_HEIGHT : int = 600;

mod game;

// hadle the annoying Rect i32
macro_rules! rect(
    ($x:expr, $y:expr, $w:expr, $h:expr) => (
        sdl2::rect::Rect::new($x as i32, $y as i32, $w as i32, $h as i32)
    )
)

// colors
static BG_COLOR: Color = RGB(0xee, 0xe4, 0xda);
static FG_COLOR: Color = RGB(0x77, 0x6e, 0x65);
static CHAR_COLOR: Color = RGB(0xee, 0x33, 0x66);
static CONTAINER_COLOR: Color = RGBA(0x77, 0x6e, 0x65, 200);
static CELL_COLORS: &'static [Color] = &'static [
    RGBA(0xee, 0xe4, 0xda, 120), RGB(0xed, 0xe0, 0xc8), RGB(0xf2, 0xb1, 0x79),
    RGB(0xf5, 0x95, 0x64), RGB(0xf6, 0x7c, 0x5f), RGB(0xf6, 0x5e, 0x3b),
    RGB(0xed, 0xcf, 0x72), RGB(0xed, 0xcc, 0x61), RGB(0xed, 0xc8, 0x50),
    RGB(0xed, 0xc5, 0x3f), RGB(0xed, 0xc2, 0x2e), RGB(0x3c, 0x3a, 0x32), ];
static SUPER_CELL_COLOR: Color = RGB(0xcc, 0x33, 0xff);

// Font
static TTF_FONT_RAW_BYTES: &'static [u8] = include_bin!("./res/OpenDyslexic-Regular.ttf");

#[allow(uppercase_variables, unused_must_use)]
fn draw_game(gm: &mut game::GameManager, ren: &render::Renderer, font: &ttf::Font,
             (x,y,w,h): (int,int,int,int)) -> Result<(), ~str> {
    assert_eq!(w, h);
    // BEST in 500x500
    let SIZE = gm.size;
    let CONTAINER_PADDING: int = 50  / (SIZE as int + 1);
    let CELL_WIDTH = (w - CONTAINER_PADDING * (SIZE as int + 1)) / SIZE as int ;
    assert!(CELL_WIDTH > 40); // Min width
    try!(ren.box_(x as i16, y as i16, (x+w) as i16, (y+h) as i16, CONTAINER_COLOR));
    gm.grid.each_cell(|j, i, tile_opt| {
        let i = i as int;
        let j = j as int;
        let val = match tile_opt {
            Some(&tile) => tile.value,
            None        => 0,
        };
        let c = if val == 0 {
            0           // or will be +Infinity
        } else {
            (val as f64).log2() as uint
        };
        let color = CELL_COLORS.get(c).map(|&co| co).unwrap_or(SUPER_CELL_COLOR);
        let bx = (x + CONTAINER_PADDING * (j + 1) + CELL_WIDTH * j) as i16;
        let by = (y + CONTAINER_PADDING * (i + 1) + CELL_WIDTH * i) as i16;
        ren.box_(bx, by, bx + CELL_WIDTH as i16, by + CELL_WIDTH as i16, color);
        // ren.string(bx, by, format!("({}, {})", j, i), CHAR_COLOR); // DEBUG
        if val != 0 {
            let (tex, tw, th) = {
                let wd = format!("{}", val);
                let (w, h) = font.size_of_str(wd).ok().expect("size of str");
                let text = font.render_str_blended(wd, FG_COLOR).ok().expect("renderred surface");
                (ren.create_texture_from_surface(text).ok().expect("create texture"), w, h)
            };

            let ratio = if tw > CELL_WIDTH {
                CELL_WIDTH as f64 / tw as f64
            } else if th > CELL_WIDTH {
                CELL_WIDTH as f64 / th as f64
            } else { 1.0 };

            let tw = (tw as f64 * ratio) as int;
            let th = (th as f64 * ratio) as int;

            ren.copy(tex, None, Some(rect!(bx as int + CELL_WIDTH / 2 - tw/2, by as int + CELL_WIDTH / 2 - th/2,
                                               tw, th)));
        }
    });
    Ok(())
}

fn draw_title(ren: &render::Renderer, font: &ttf::Font) -> Result<(), ~str> {
    let (tex2, w, h) = {
        let wd = "Rust - 2048";
        //font.set_style([ttf::StyleBold]);
        let (w, h) = try!(font.size_of_str(wd));
        let text = try!(font.render_str_blended(wd, FG_COLOR));
        (try!(ren.create_texture_from_surface(text)), w, h)
    };
    try!(ren.copy(tex2, None, Some(rect!(SCREEN_WIDTH / 2 - w / 2, 20, w, h))));
    Ok(())
}

// FIXME: tooooooo many type convertion
fn draw_popup(ren: &render::Renderer, font: &ttf::Font, msg: &str) -> Result<(), ~str> {
    let (tex, w, h) = {
        //font.set_style([ttf::StyleBold]);
        let (w, h) = try!(font.size_of_str(msg));
        let text = try!(font.render_str_blended(msg, FG_COLOR));
        (try!(ren.create_texture_from_surface(text)), w, h)
    };
    try!(ren.rounded_box((SCREEN_WIDTH / 2 - w / 2) as i16,
                         (SCREEN_HEIGHT / 2 - h / 2) as i16,
                         (SCREEN_WIDTH / 2 + w / 2) as i16,
                         (SCREEN_HEIGHT / 2 + h / 2) as i16,
                         5,
                         BG_COLOR));
    try!(ren.rounded_rectangle((SCREEN_WIDTH / 2 - w / 2) as i16,
                               (SCREEN_HEIGHT / 2 - h / 2) as i16,
                               (SCREEN_WIDTH / 2 + w / 2) as i16,
                               (SCREEN_HEIGHT / 2 + h / 2) as i16,
                               5,
                               FG_COLOR));
    try!(ren.copy(tex, None, Some(rect!(SCREEN_WIDTH / 2 - w / 2,
                                        SCREEN_HEIGHT / 2 - h / 2,
                                        w,
                                        h))));
    Ok(())
}

pub fn run(game_size: uint) -> Result<(), ~str> {
    let win = try!(video::Window::new(
        "Rust - 2048", video::PosCentered, video::PosCentered, SCREEN_WIDTH, SCREEN_HEIGHT,
        [video::Shown]));
    let ren = try!(render::Renderer::from_window(
        win, render::DriverAuto, [render::Accelerated]));

    let mut fpsm = sdl2_gfx::framerate::FPSManager::new();
    try!(fpsm.set_framerate(50));

    let font : ~ttf::Font = {
        let raw = try!(rwops::RWops::from_bytes(TTF_FONT_RAW_BYTES));
        // or try!(ttf::Font::from_file(&Path::new("./OpenDyslexic-Regular.ttf"), 48));
        try!(raw.load_font(48))
    };
    let mut gm = game::GameManager::new(game_size);

    let mut playing = false;
    let mut celebrating = false;

    'main : loop {
        'event : loop {
            fpsm.delay();
            try!(ren.set_draw_color(BG_COLOR));
            try!(ren.clear());
            // == main drawing ==
            try!(draw_title(&*ren, &*font));
            try!(ren.string(0i16, 0i16, format!("frames: {}", fpsm.get_frame_count()), CHAR_COLOR));

            try!(ren.string(200, 90, format!("your score: {}", gm.score), CHAR_COLOR));

            try!(draw_game(&mut gm, &*ren, &*font, (SCREEN_WIDTH / 2 - 400 / 2, 100, 400, 400)));

            if celebrating || (playing && !gm.moves_available()) { // can't move
                try!(draw_popup(&*ren, &*font, format!("Score: {}! Max Cell: {}", gm.score, "NaN")));
                playing = false;
                celebrating = true;

            } else if !playing && !celebrating {
                try!(draw_popup(&*ren, &*font, "Press SPACE to start!"));
            }

            // == main drawing ends ==
            ren.present();

            match event::poll_event() {
                event::QuitEvent(_) => break 'main,
                event::KeyDownEvent(_, _, keycode::LeftKey, _, _) if playing => {
                    gm.move(game::Left);
                }
                event::KeyDownEvent(_, _, keycode::RightKey, _, _) if playing => {
                    gm.move(game::Right);
                }
                event::KeyDownEvent(_, _, keycode::UpKey, _, _) if playing => {
                    gm.move(game::Up);
                }
                event::KeyDownEvent(_, _, keycode::DownKey, _, _) if playing => {
                    gm.move(game::Down);
                }
                event::KeyDownEvent(_, _, key, _, _) => {
                    if key == keycode::EscapeKey {
                        break 'main
                    } else if key == keycode::SpaceKey {
                        if !playing {
                            playing = true;
                            celebrating = false;
                            gm.setup();
                        }
                    }

                }
                event::MouseButtonDownEvent(_, _, _, _, x, y) => {
                    println!("mouse btn down at ({},{})", x, y);
                }

                _ => {}
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate game_of_life_parsers;

use std::fs::File;
use game_of_life_parsers::GameDescriptor;
use game_of_life_parsers::Coord;
use game_of_life_parsers::Parser;
use game_of_life_parsers::Life105Parser;

#[test]
fn fail() {
	let file = File::open("tests/life_1_05/glider.life").unwrap();
	let mut parser = Life105Parser::new();

	let gd: Box<GameDescriptor> = parser.parse(file).unwrap();
	assert_eq!(&[2, 3], gd.survival());
	assert_eq!(&[1], gd.birth());
	assert_eq!(&[
		// block 1
		Coord { x:  0, y: -1 },
		Coord { x:  1, y: 0 },
		Coord { x: -1, y: 1 }, Coord { x: 0, y: 1 }, Coord { x: 1, y: 1 },
		// block 2
		Coord { x: 3, y: 2 }, Coord { x: 4, y: 3 }, Coord { x: 5, y: 4 }
	], gd.live_cells());
}
<commit_msg>renamed test<commit_after>extern crate game_of_life_parsers;

use std::fs::File;
use game_of_life_parsers::GameDescriptor;
use game_of_life_parsers::Coord;
use game_of_life_parsers::Parser;
use game_of_life_parsers::Life105Parser;

#[test]
fn parse_file() {
	let file = File::open("tests/life_1_05/glider.life").unwrap();
	let mut parser = Life105Parser::new();

	let gd: Box<GameDescriptor> = parser.parse(file).unwrap();
	assert_eq!(&[2, 3], gd.survival());
	assert_eq!(&[1], gd.birth());
	assert_eq!(&[
		// block 1
		Coord { x:  0, y: -1 },
		Coord { x:  1, y: 0 },
		Coord { x: -1, y: 1 }, Coord { x: 0, y: 1 }, Coord { x: 1, y: 1 },
		// block 2
		Coord { x: 3, y: 2 }, Coord { x: 4, y: 3 }, Coord { x: 5, y: 4 }
	], gd.live_cells());
}
<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// Weak memory emulation tests. All of the following test if
// our weak memory emulation produces any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.
//
// Note that we can't effectively test whether our weak memory emulation
// can produce *all* consistent execution outcomes. This may be possible
// if Miri's scheduler is sufficiently random and explores all possible
// interleavings of our small test cases after a reasonable number of runs.
// However, since Miri's scheduler is not even pre-emptive, there will
// always be possible interleavings (and possible execution outcomes),
// that can never be observed regardless of how weak memory emulation is
// implemented.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicUsize};
use std::thread::{spawn, yield_now};

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple tests
fn static_atomic(val: usize) -> &'static AtomicUsize {
    let ret = Box::leak(Box::new(AtomicUsize::new(val)));
    // A workaround to put the initialisation value in the store buffer
    ret.store(val, Relaxed);
    ret
}

// Spins and yields until until acquires a pre-determined value
fn acquires_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Acquire) != val {
        yield_now();
    }
    val
}

fn reads_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Relaxed) != val {
        yield_now();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    //                                               |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    //                                               |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    //                                               |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    //                                               |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

// 2.2 Second Problem: SC Fences are Too Weak
// This test should pass under the C++20 model Rust is using.
// Unfortunately, Miri's weak memory emulation only follows C++11 model
// as we don't know how to correctly emulate C++20's revised SC semantics
#[allow(dead_code)]
fn test_cpp20_rwc_syncs() {
    /*
    int main() {
        atomic_int x = 0;
        atomic_int y = 0;

        {{{ x.store(1,mo_relaxed);
        ||| { r1=x.load(mo_relaxed).readsvalue(1);
              fence(mo_seq_cst);
              r2=y.load(mo_relaxed); }
        ||| { y.store(1,mo_relaxed);
              fence(mo_seq_cst);
              r3=x.load(mo_relaxed); }
        }}}
        return 0;
    }
    */
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
    });

    let j2 = spawn(move || {
        reads_value(&x, 1);
        fence(SeqCst);
        y.load(Relaxed)
    });

    let j3 = spawn(move || {
        y.store(1, Relaxed);
        fence(SeqCst);
        x.load(Relaxed)
    });

    j1.join().unwrap();
    let b = j2.join().unwrap();
    let c = j3.join().unwrap();

    assert_ne!((b, c), (0, 0));
}

pub fn main() {
    // TODO: does this make chances of spurious success
    // "sufficiently low"? This also takes a long time to run,
    // prehaps each function should be its own test case so they
    // can be run in parallel
    for _ in 0..500 {
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
        // test_cpp20_rwc_syncs();
    }
}
<commit_msg>Add imperfectly overlapping test<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// Weak memory emulation tests. All of the following test if
// our weak memory emulation produces any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.
//
// Note that we can't effectively test whether our weak memory emulation
// can produce *all* consistent execution outcomes. This may be possible
// if Miri's scheduler is sufficiently random and explores all possible
// interleavings of our small test cases after a reasonable number of runs.
// However, since Miri's scheduler is not even pre-emptive, there will
// always be possible interleavings (and possible execution outcomes),
// that can never be observed regardless of how weak memory emulation is
// implemented.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.
#![feature(atomic_from_mut)]

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicU16, AtomicU32, AtomicUsize};
use std::thread::{spawn, yield_now};

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple tests
fn static_atomic(val: usize) -> &'static AtomicUsize {
    let ret = Box::leak(Box::new(AtomicUsize::new(val)));
    // A workaround to put the initialisation value in the store buffer
    ret.store(val, Relaxed);
    ret
}

// Spins and yields until until acquires a pre-determined value
fn acquires_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Acquire) != val {
        yield_now();
    }
    val
}

fn reads_value(loc: &AtomicUsize, val: usize) -> usize {
    while loc.load(Relaxed) != val {
        yield_now();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    //                                               |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    //                                               |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    //                                               |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    //                                               |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// Strictly speaking, atomic accesses that imperfectly overlap with existing
// atomic objects are UB. Nonetheless we'd like to provide a sane value when
// the access is not racy.
fn test_imperfectly_overlapping_access() {
    let mut qword = AtomicU32::new(42);
    assert_eq!(qword.load(Relaxed), 42);
    qword.store(u32::to_be(0xabbafafa), Relaxed);

    let qword_mut = qword.get_mut();

    let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) };

    let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1);

    let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0]));

    assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba);
    assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

// 2.2 Second Problem: SC Fences are Too Weak
// This test should pass under the C++20 model Rust is using.
// Unfortunately, Miri's weak memory emulation only follows C++11 model
// as we don't know how to correctly emulate C++20's revised SC semantics
#[allow(dead_code)]
fn test_cpp20_rwc_syncs() {
    /*
    int main() {
        atomic_int x = 0;
        atomic_int y = 0;

        {{{ x.store(1,mo_relaxed);
        ||| { r1=x.load(mo_relaxed).readsvalue(1);
              fence(mo_seq_cst);
              r2=y.load(mo_relaxed); }
        ||| { y.store(1,mo_relaxed);
              fence(mo_seq_cst);
              r3=x.load(mo_relaxed); }
        }}}
        return 0;
    }
    */
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
    });

    let j2 = spawn(move || {
        reads_value(&x, 1);
        fence(SeqCst);
        y.load(Relaxed)
    });

    let j3 = spawn(move || {
        y.store(1, Relaxed);
        fence(SeqCst);
        x.load(Relaxed)
    });

    j1.join().unwrap();
    let b = j2.join().unwrap();
    let c = j3.join().unwrap();

    assert_ne!((b, c), (0, 0));
}

pub fn main() {
    test_imperfectly_overlapping_access();
    // TODO: does this make chances of spurious success
    // "sufficiently low"? This also takes a long time to run,
    // prehaps each function should be its own test case so they
    // can be run in parallel
    for _ in 0..500 {
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
        // test_cpp20_rwc_syncs();
    }
}
<|endoftext|>


<commit_before>use error::AttributeError;
use parsers::{Parse, ParseError};

/// Defines the units to be used for things that can consider a
/// coordinate system in terms of the current transformation, or in
/// terms of the current object's bounding box.
///
/// Keep in sync with rsvg-private.h:RsvgCoordUnits
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CoordUnits {
    UserSpaceOnUse,
    ObjectBoundingBox
}

impl Parse for CoordUnits {
    type Data = ();
    type Err = AttributeError;

    fn parse (s: &str, _: ()) -> Result<CoordUnits, AttributeError> {
        match s {
            "userSpaceOnUse"    => Ok (CoordUnits::UserSpaceOnUse),
            "objectBoundingBox" => Ok (CoordUnits::ObjectBoundingBox),
            _                   => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'")))
        }
    }
}

/// Creates a newtype around `CoordUnits`, with a default value.
///
/// SVG attributes that can take `userSpaceOnUse` or
/// `objectBoundingBox` values often have different default values
/// depending on the type of SVG element.  We use this macro to create
/// a newtype for each SVG element and attribute that requires values
/// of this type.  The newtype provides an `impl Default` with the
/// specified `$default` value.
#[macro_export]
macro_rules! coord_units {
    ($name:ident, $default:expr) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        struct $name(CoordUnits);

        impl Default for $name {
            fn default() -> Self {
                $name($default)
            }
        }

        impl From<$name> for CoordUnits {
            fn from(u: $name) -> Self {
                u.0
            }
        }

        impl $crate::parsers::Parse for $name {
            type Data = ();
            type Err = $crate::error::AttributeError;

            fn parse(s: &str, _: ()) -> Result<Self, $crate::error::AttributeError> {
                Ok($name($crate::coord_units::CoordUnits::parse(s, ())?))
            }
        }
    }
}

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

    coord_units!(MyUnits, CoordUnits::ObjectBoundingBox);

    #[test]
    fn parsing_invalid_strings_yields_error () {
        assert! (MyUnits::parse ("", ()).is_err ());
        assert! (MyUnits::parse ("foo", ()).is_err ());
    }

    #[test]
    fn parses_paint_server_units () {
        assert_eq! (MyUnits::parse ("userSpaceOnUse", ()), Ok (MyUnits(CoordUnits::UserSpaceOnUse)));
        assert_eq! (MyUnits::parse ("objectBoundingBox", ()), Ok (MyUnits(CoordUnits::ObjectBoundingBox)));
    }
}
<commit_msg>coord_units.rs: Test the default value and converter<commit_after>use error::AttributeError;
use parsers::{Parse, ParseError};

/// Defines the units to be used for things that can consider a
/// coordinate system in terms of the current transformation, or in
/// terms of the current object's bounding box.
///
/// Keep in sync with rsvg-private.h:RsvgCoordUnits
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CoordUnits {
    UserSpaceOnUse,
    ObjectBoundingBox
}

impl Parse for CoordUnits {
    type Data = ();
    type Err = AttributeError;

    fn parse (s: &str, _: ()) -> Result<CoordUnits, AttributeError> {
        match s {
            "userSpaceOnUse"    => Ok (CoordUnits::UserSpaceOnUse),
            "objectBoundingBox" => Ok (CoordUnits::ObjectBoundingBox),
            _                   => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'")))
        }
    }
}

/// Creates a newtype around `CoordUnits`, with a default value.
///
/// SVG attributes that can take `userSpaceOnUse` or
/// `objectBoundingBox` values often have different default values
/// depending on the type of SVG element.  We use this macro to create
/// a newtype for each SVG element and attribute that requires values
/// of this type.  The newtype provides an `impl Default` with the
/// specified `$default` value.
#[macro_export]
macro_rules! coord_units {
    ($name:ident, $default:expr) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        struct $name(CoordUnits);

        impl Default for $name {
            fn default() -> Self {
                $name($default)
            }
        }

        impl From<$name> for CoordUnits {
            fn from(u: $name) -> Self {
                u.0
            }
        }

        impl $crate::parsers::Parse for $name {
            type Data = ();
            type Err = $crate::error::AttributeError;

            fn parse(s: &str, _: ()) -> Result<Self, $crate::error::AttributeError> {
                Ok($name($crate::coord_units::CoordUnits::parse(s, ())?))
            }
        }
    }
}

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

    coord_units!(MyUnits, CoordUnits::ObjectBoundingBox);

    #[test]
    fn parsing_invalid_strings_yields_error () {
        assert! (MyUnits::parse ("", ()).is_err ());
        assert! (MyUnits::parse ("foo", ()).is_err ());
    }

    #[test]
    fn parses_paint_server_units () {
        assert_eq! (MyUnits::parse ("userSpaceOnUse", ()), Ok (MyUnits(CoordUnits::UserSpaceOnUse)));
        assert_eq! (MyUnits::parse ("objectBoundingBox", ()), Ok (MyUnits(CoordUnits::ObjectBoundingBox)));
    }

    #[test]
    fn has_correct_default() {
        assert_eq!(MyUnits::default(), MyUnits(CoordUnits::ObjectBoundingBox));
    }

    #[test]
    fn converts_to_coord_units() {
        assert_eq!(CoordUnits::from(MyUnits(CoordUnits::ObjectBoundingBox)), CoordUnits::ObjectBoundingBox);
    }
}
<|endoftext|>


<commit_before>use ::cairo;
use ::cairo_sys;
use ::glib_sys;
use ::glib::translate::*;
use ::libc;

use color::*;
use error::*;
use opacity::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_free (state: *mut RsvgState);
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_set_cond_true (state: *const RsvgState, cond_true: glib_sys::gboolean);
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity (state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);
    fn rsvg_render_surface (draw_ctx: *const RsvgDrawingCtx,
                            surface: *const cairo_sys::cairo_surface_t,
                            x: f64,
                            y: f64,
                            w: f64,
                            h: f64);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn render_surface (draw_ctx: *const RsvgDrawingCtx,
                       surface: &cairo::ImageSurface,
                       x: f64,
                       y: f64,
                       w: f64,
                       h: f64) {
    unsafe { rsvg_render_surface (draw_ctx, surface.to_raw_none(), x, y, w, h); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_free (state: *mut RsvgState) {
    unsafe { rsvg_state_free (state); }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_set_cond_true (state: *const RsvgState, cond_true: bool) {
    unsafe { rsvg_state_set_cond_true (state, cond_true.to_glib()); }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            Ok (None)
        } else {
            Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
        }
    }
}

pub fn state_get_stop_opacity (state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity (state);

        if opacity_ptr.is_null () {
            Ok (None)
        } else {
            Opacity::from_opacity_spec (&*opacity_ptr).map (|opacity| Some (opacity))
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color (state) };

    Color::from (argb)
}
<commit_msg>drawing_ctx.rs: Bind get_pango_context() to Rust<commit_after>use cairo;
use cairo_sys;
use glib_sys;
use glib::translate::*;
use libc;
use pango_sys;
use pango;

use color::*;
use error::*;
use opacity::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> *mut pango_sys::PangoContext;

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_free (state: *mut RsvgState);
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_set_cond_true (state: *const RsvgState, cond_true: glib_sys::gboolean);
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity (state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);
    fn rsvg_render_surface (draw_ctx: *const RsvgDrawingCtx,
                            surface: *const cairo_sys::cairo_surface_t,
                            x: f64,
                            y: f64,
                            w: f64,
                            h: f64);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn render_surface (draw_ctx: *const RsvgDrawingCtx,
                       surface: &cairo::ImageSurface,
                       x: f64,
                       y: f64,
                       w: f64,
                       h: f64) {
    unsafe { rsvg_render_surface (draw_ctx, surface.to_raw_none(), x, y, w, h); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> pango::Context {
    unsafe {
        from_glib_full(rsvg_drawing_ctx_get_pango_context(draw_ctx))
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_free (state: *mut RsvgState) {
    unsafe { rsvg_state_free (state); }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_set_cond_true (state: *const RsvgState, cond_true: bool) {
    unsafe { rsvg_state_set_cond_true (state, cond_true.to_glib()); }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            Ok (None)
        } else {
            Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
        }
    }
}

pub fn state_get_stop_opacity (state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity (state);

        if opacity_ptr.is_null () {
            Ok (None)
        } else {
            Opacity::from_opacity_spec (&*opacity_ptr).map (|opacity| Some (opacity))
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color (state) };

    Color::from (argb)
}
<|endoftext|>


<commit_before>use crate::task::JoinHandle;

cfg_rt_multi_thread! {
    /// Runs the provided blocking function on the current thread without
    /// blocking the executor.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is not okay, as it may prevent the executor from
    /// driving other futures forward.  This function runs the closure on the
    /// current thread by having the thread temporarily cease from being a core
    /// thread, and turns it into a blocking thread. See the [CPU-bound tasks
    /// and blocking code][blocking] section for more information.
    ///
    /// Although this function avoids starving other independently spawned
    /// tasks, any other code running concurrently in the same task will be
    /// suspended during the call to `block_in_place`. This can happen e.g. when
    /// using the [`join!`] macro. To avoid this issue, use [`spawn_blocking`]
    /// instead.
    ///
    /// Note that this function can only be used when using the `multi_thread` runtime.
    ///
    /// Code running behind `block_in_place` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations
    /// to finish. You can use [`shutdown_timeout`] to stop waiting for them
    /// after a certain timeout. Be aware that this will still not cancel the
    /// tasks — they are simply allowed to keep running after the method
    /// returns.
    ///
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
    /// [`join!`]: macro@join
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     // do some compute-heavy work or call synchronous code
    /// });
    /// # }
    /// ```
    pub fn block_in_place<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        crate::runtime::thread_pool::block_in_place(f)
    }
}

/// Runs the provided closure on a thread where blocking is acceptable.
///
/// In general, issuing a blocking call or performing a lot of compute in a
/// future without yielding is not okay, as it may prevent the executor from
/// driving other futures forward. This function runs the provided closure
/// on a thread dedicated to blocking operations. See the [CPU-bound tasks
/// and blocking code][blocking] section for more information.
///
/// Tokio will spawn more blocking threads when they are requested through
/// this function until the upper limit configured on the [`Builder`] is
/// reached.  This limit is very large by default, because `spawn_blocking` is
/// often used for various kinds of IO operations that cannot be performed
/// asynchronously. When you run CPU-bound code using `spawn_blocking`, you
/// should keep this large upper limit in mind; to run your CPU-bound
/// computations on only a few threads, you should use a separate thread
/// pool such as [rayon] rather than configuring the number of blocking
/// threads.
///
/// This function is intended for non-async operations that eventually
/// finish on their own. If you want to spawn an ordinary thread, you should
/// use [`thread::spawn`] instead.
///
/// Closures spawned using `spawn_blocking` cannot be cancelled. When you
/// shut down the executor, it will wait indefinitely for all blocking
/// operations to finish. You can use [`shutdown_timeout`] to stop waiting
/// for them after a certain timeout. Be aware that this will still not
/// cancel the tasks — they are simply allowed to keep running after the
/// method returns.
///
/// Note that if you are using the single threaded runtime, this function will
/// still spawn additional threads for blocking operations. The basic
/// scheduler's single thread is only used for asynchronous code.
///
/// [`Builder`]: struct@crate::runtime::Builder
/// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
/// [rayon]: https://docs.rs/rayon
/// [`thread::spawn`]: fn@std::thread::spawn
/// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
///
/// # Examples
///
/// ```
/// use tokio::task;
///
/// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
/// let res = task::spawn_blocking(move || {
///     // do some compute-heavy work or call synchronous code
///     "done computing"
/// }).await?;
///
/// assert_eq!(res, "done computing");
/// # Ok(())
/// # }
/// ```
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    #[cfg(feature = "tracing")]
    let f = {
        let span = tracing::trace_span!(
            target: "tokio::task",
            "task",
            kind = %"blocking",
            function = %std::any::type_name::<F>(),
        );
        move || {
            let _g = span.enter();
            f()
        }
    };
    crate::runtime::spawn_blocking(f)
}
<commit_msg>rt: tweak spawn_blocking docs (#2955)<commit_after>use crate::task::JoinHandle;

cfg_rt_multi_thread! {
    /// Runs the provided blocking function on the current thread without
    /// blocking the executor.
    ///
    /// In general, issuing a blocking call or performing a lot of compute in a
    /// future without yielding is not okay, as it may prevent the executor from
    /// driving other futures forward.  This function runs the closure on the
    /// current thread by having the thread temporarily cease from being a core
    /// thread, and turns it into a blocking thread. See the [CPU-bound tasks
    /// and blocking code][blocking] section for more information.
    ///
    /// Although this function avoids starving other independently spawned
    /// tasks, any other code running concurrently in the same task will be
    /// suspended during the call to `block_in_place`. This can happen e.g. when
    /// using the [`join!`] macro. To avoid this issue, use [`spawn_blocking`]
    /// instead.
    ///
    /// Note that this function can only be used when using the `multi_thread` runtime.
    ///
    /// Code running behind `block_in_place` cannot be cancelled. When you shut
    /// down the executor, it will wait indefinitely for all blocking operations
    /// to finish. You can use [`shutdown_timeout`] to stop waiting for them
    /// after a certain timeout. Be aware that this will still not cancel the
    /// tasks — they are simply allowed to keep running after the method
    /// returns.
    ///
    /// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
    /// [`spawn_blocking`]: fn@crate::task::spawn_blocking
    /// [`join!`]: macro@join
    /// [`thread::spawn`]: fn@std::thread::spawn
    /// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::task;
    ///
    /// # async fn docs() {
    /// task::block_in_place(move || {
    ///     // do some compute-heavy work or call synchronous code
    /// });
    /// # }
    /// ```
    pub fn block_in_place<F, R>(f: F) -> R
    where
        F: FnOnce() -> R,
    {
        crate::runtime::thread_pool::block_in_place(f)
    }
}

/// Runs the provided closure on a thread where blocking is acceptable.
///
/// In general, issuing a blocking call or performing a lot of compute in a
/// future without yielding is problematic, as it may prevent the executor from
/// driving other futures forward. This function runs the provided closure on a
/// thread dedicated to blocking operations. See the [CPU-bound tasks and
/// blocking code][blocking] section for more information.
///
/// Tokio will spawn more blocking threads when they are requested through this
/// function until the upper limit configured on the [`Builder`] is reached.
/// This limit is very large by default, because `spawn_blocking` is often used
/// for various kinds of IO operations that cannot be performed asynchronously.
/// When you run CPU-bound code using `spawn_blocking`, you should keep this
/// large upper limit in mind. When running many CPU-bound computations, a
/// semaphore or some other synchronization primitive should be used to limit
/// the number of computation executed in parallel. Specialized CPU-bound
/// executors, such as [rayon], may also be a good fit.
///
/// This function is intended for non-async operations that eventually finish on
/// their own. If you want to spawn an ordinary thread, you should use
/// [`thread::spawn`] instead.
///
/// Closures spawned using `spawn_blocking` cannot be cancelled. When you shut
/// down the executor, it will wait indefinitely for all blocking operations to
/// finish. You can use [`shutdown_timeout`] to stop waiting for them after a
/// certain timeout. Be aware that this will still not cancel the tasks — they
/// are simply allowed to keep running after the method returns.
///
/// Note that if you are using the single threaded runtime, this function will
/// still spawn additional threads for blocking operations. The basic
/// scheduler's single thread is only used for asynchronous code.
///
/// [`Builder`]: struct@crate::runtime::Builder
/// [blocking]: ../index.html#cpu-bound-tasks-and-blocking-code
/// [rayon]: https://docs.rs/rayon
/// [`thread::spawn`]: fn@std::thread::spawn
/// [`shutdown_timeout`]: fn@crate::runtime::Runtime::shutdown_timeout
///
/// # Examples
///
/// ```
/// use tokio::task;
///
/// # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
/// let res = task::spawn_blocking(move || {
///     // do some compute-heavy work or call synchronous code
///     "done computing"
/// }).await?;
///
/// assert_eq!(res, "done computing");
/// # Ok(())
/// # }
/// ```
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    #[cfg(feature = "tracing")]
    let f = {
        let span = tracing::trace_span!(
            target: "tokio::task",
            "task",
            kind = %"blocking",
            function = %std::any::type_name::<F>(),
        );
        move || {
            let _g = span.enter();
            f()
        }
    };
    crate::runtime::spawn_blocking(f)
}
<|endoftext|>