<commit_before>// Copyright (c) 2020, 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 thiserror::Error;

use std::sync::Arc;

use crate::api::{ChromaSampling, Context, ContextInner};
use crate::cpu_features::CpuFeatureLevel;
use crate::rayon::{ThreadPool, ThreadPoolBuilder};
use crate::tiling::TilingInfo;
use crate::util::Pixel;

mod encoder;
pub use encoder::*;

mod rate;
pub use rate::Error as RateControlError;
pub use rate::{RateControlConfig, RateControlSummary};

mod speedsettings;
pub use speedsettings::*;

/// Enumeration of possible invalid configuration errors.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum InvalidConfig {
  /// The width is invalid.
  #[error("invalid width {0} (expected >= 16, <= 65535)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 65535)")]
  InvalidHeight(usize),
  /// Aspect ratio numerator is invalid.
  #[error("invalid aspect ratio numerator {0} (expected > 0)")]
  InvalidAspectRatioNum(usize),
  /// Aspect ratio denominator is invalid.
  #[error("invalid aspect ratio denominator {0} (expected > 0)")]
  InvalidAspectRatioDen(usize),
  /// The render width (width adjusted based on the aspect ratio) is invalid.
  #[error("invalid render width {0} (expected >= 1, <= 65535")]
  InvalidRenderWidth(usize),
  /// The render height (height adjusted based on the aspect ratio) is invalid.
  #[error("invalid render height {0} (expected >= 1, <= 65535")]
  InvalidRenderHeight(usize),
  /// RDO lookahead frame count is invalid.
  #[error(
    "invalid rdo lookahead frames {actual} (expected <= {max} and >= {min})"
  )]
  InvalidRdoLookaheadFrames {
    /// The actual value.
    actual: usize,
    /// The maximal supported value.
    max: usize,
    /// The minimal supported value.
    min: usize,
  },
  /// Maximal keyframe interval is invalid.
  #[error("invalid max keyframe interval {actual} (expected <= {max})")]
  InvalidMaxKeyFrameInterval {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Tile columns is invalid.
  #[error("invalid tile cols {0} (expected power of 2)")]
  InvalidTileCols(usize),
  /// Tile rows is invalid.
  #[error("invalid tile rows {0} (expected power of 2)")]
  InvalidTileRows(usize),
  /// Framerate numerator is invalid.
  #[error("invalid framerate numerator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateNum {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Framerate denominator is invalid.
  #[error("invalid framerate denominator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateDen {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Reservoir frame delay is invalid.
  #[error("invalid reservoir frame delay {0} (expected >= 12, <= 131072)")]
  InvalidReservoirFrameDelay(i32),
  /// Reservoir frame delay is invalid.
  #[error(
    "invalid switch frame interval {0} (must only be used with low latency mode)"
  )]
  InvalidSwitchFrameInterval(u64),

  /// An option unsupported in still picture mode was enabled along with it.
  #[error("invalid option {0} specified with still picture mode")]
  InvalidOptionWithStillPicture(&'static str),

  /// The rate control needs a target bitrate in order to produce results
  #[error("The rate control requires a target bitrate")]
  TargetBitrateNeeded,

  /// The configuration
  #[error("Mismatch in the rate control configuration")]
  RateControlConfigurationMismatch,
}

/// Contains the encoder configuration.
#[derive(Clone, Debug, Default)]
pub struct Config {
  /// Settings which impact the produced bitstream.
  pub(crate) enc: EncoderConfig,
  /// Rate control configuration
  pub(crate) rate_control: RateControlConfig,
  /// The number of threads in the threadpool.
  pub(crate) threads: usize,
  /// Shared thread pool
  pub(crate) pool: Option<Arc<ThreadPool>>,
}

impl Config {
  /// Create a default configuration
  ///
  /// same as Default::default()
  pub fn new() -> Self {
    Config::default()
  }

  /// Set the encoder configuration
  ///
  /// EncoderConfig contains the settings impacting the
  /// codec features used in the produced bitstream.
  pub fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
    self.enc = enc;
    self
  }

  /// Set the number of workers in the threadpool
  ///
  /// The threadpool is shared across all the different parallel
  /// components in the encoder.
  pub fn with_threads(mut self, threads: usize) -> Self {
    self.threads = threads;
    self
  }

  /// Set the rate control configuration
  ///
  /// The default configuration is single pass
  pub fn with_rate_control(mut self, rate_control: RateControlConfig) -> Self {
    self.rate_control = rate_control;
    self
  }

  #[cfg(feature = "unstable")]
  /// Use the provided threadpool
  pub fn with_thread_pool(mut self, pool: Arc<ThreadPool>) -> Self {
    self.pool = Some(pool);
    self
  }
}

fn check_tile_log2(n: usize) -> bool {
  let tile_log2 = TilingInfo::tile_log2(1, n);
  if tile_log2.is_none() {
    return false;
  }
  let tile_log2 = tile_log2.unwrap();

  ((1 << tile_log2) - n) == 0 || n == 0
}

impl Config {
  pub(crate) fn new_inner<T: Pixel>(
    &self,
  ) -> Result<ContextInner<T>, InvalidConfig> {
    assert!(
      8 * std::mem::size_of::<T>() >= self.enc.bit_depth,
      "The Pixel u{} does not match the Config bit_depth {}",
      8 * std::mem::size_of::<T>(),
      self.enc.bit_depth
    );

    self.validate()?;

    // Because we don't have a FrameInvariants yet,
    // this is the only way to get the CpuFeatureLevel in use.
    // Since we only call this once, this shouldn't cause
    // performance issues.
    info!("CPU Feature Level: {}", CpuFeatureLevel::default());

    let mut config = self.enc;
    config.set_key_frame_interval(
      config.min_key_frame_interval,
      config.max_key_frame_interval,
    );

    // FIXME: inter unsupported with 4:2:2 and 4:4:4 chroma sampling
    let chroma_sampling = config.chroma_sampling;

    // FIXME: tx partition for intra not supported for chroma 422
    if chroma_sampling == ChromaSampling::Cs422 {
      config.speed_settings.rdo_tx_decision = false;
    }

    let mut inner = ContextInner::new(&config);

    if self.rate_control.emit_pass_data {
      let params = inner.rc_state.get_twopass_out_params(&inner, 0);
      inner.rc_state.init_first_pass(params.pass1_log_base_q);
    }

    if let Some(ref s) = self.rate_control.summary {
      inner.rc_state.init_second_pass();
      inner.rc_state.setup_second_pass(s);
    }

    Ok(inner)
  }
  /// Creates a [`Context`] with this configuration.
  ///
  /// # Examples
  ///
  /// ```
  /// use rav1e::prelude::*;
  ///
  /// # fn main() -> Result<(), InvalidConfig> {
  /// let cfg = Config::default();
  /// let ctx: Context<u8> = cfg.new_context()?;
  /// # Ok(())
  /// # }
  /// ```
  ///
  /// [`Context`]: struct.Context.html
  pub fn new_context<T: Pixel>(&self) -> Result<Context<T>, InvalidConfig> {
    let inner = self.new_inner()?;
    let config = *inner.config;
    let pool = if let Some(ref p) = self.pool {
      p.clone()
    } else {
      let pool =
        ThreadPoolBuilder::new().num_threads(self.threads).build().unwrap();
      Arc::new(pool)
    };

    Ok(Context { is_flushing: false, inner, pool, config })
  }

  /// Validates the configuration.
  pub fn validate(&self) -> Result<(), InvalidConfig> {
    use InvalidConfig::*;

    let config = &self.enc;

    if (config.still_picture && config.width < 1)
      || (!config.still_picture && config.width < 16)
      || config.width > u16::max_value() as usize
    {
      return Err(InvalidWidth(config.width));
    }
    if (config.still_picture && config.height < 1)
      || (!config.still_picture && config.height < 16)
      || config.height > u16::max_value() as usize
    {
      return Err(InvalidHeight(config.height));
    }

    if config.sample_aspect_ratio.num == 0 {
      return Err(InvalidAspectRatioNum(
        config.sample_aspect_ratio.num as usize,
      ));
    }
    if config.sample_aspect_ratio.den == 0 {
      return Err(InvalidAspectRatioDen(
        config.sample_aspect_ratio.den as usize,
      ));
    }

    let (render_width, render_height) = config.render_size();
    if render_width == 0 || render_width > u16::max_value() as usize {
      return Err(InvalidRenderWidth(render_width));
    }
    if render_height == 0 || render_height > u16::max_value() as usize {
      return Err(InvalidRenderHeight(render_height));
    }

    if config.rdo_lookahead_frames > MAX_RDO_LOOKAHEAD_FRAMES
      || config.rdo_lookahead_frames < 1
    {
      return Err(InvalidRdoLookaheadFrames {
        actual: config.rdo_lookahead_frames,
        max: MAX_RDO_LOOKAHEAD_FRAMES,
        min: 1,
      });
    }
    if config.max_key_frame_interval > MAX_MAX_KEY_FRAME_INTERVAL {
      return Err(InvalidMaxKeyFrameInterval {
        actual: config.max_key_frame_interval,
        max: MAX_MAX_KEY_FRAME_INTERVAL,
      });
    }

    if !check_tile_log2(config.tile_cols) {
      return Err(InvalidTileCols(config.tile_cols));
    }
    if !check_tile_log2(config.tile_rows) {
      return Err(InvalidTileRows(config.tile_rows));
    }

    if config.time_base.num == 0
      || config.time_base.num > u32::max_value() as u64
    {
      return Err(InvalidFrameRateNum {
        actual: config.time_base.num,
        max: u32::max_value() as u64,
      });
    }
    if config.time_base.den == 0
      || config.time_base.den > u32::max_value() as u64
    {
      return Err(InvalidFrameRateDen {
        actual: config.time_base.den,
        max: u32::max_value() as u64,
      });
    }

    if let Some(delay) = config.reservoir_frame_delay {
      if !(12..=131_072).contains(&delay) {
        return Err(InvalidReservoirFrameDelay(delay));
      }
    }

    if config.switch_frame_interval > 0 && !config.low_latency {
      return Err(InvalidSwitchFrameInterval(config.switch_frame_interval));
    }

    if config.enable_timing_info && config.still_picture {
      return Err(InvalidOptionWithStillPicture("enable_timing_info"));
    }

    // TODO: add more validation
    let rc = &self.rate_control;

    if (rc.emit_pass_data || rc.summary.is_some()) && config.bitrate == 0 {
      return Err(TargetBitrateNeeded);
    }

    Ok(())
  }
}
<commit_msg>Reject mismatched color configurations<commit_after>// Copyright (c) 2020, 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 thiserror::Error;

use std::sync::Arc;

use crate::api::{ChromaSampling, Context, ContextInner, PixelRange};
use crate::cpu_features::CpuFeatureLevel;
use crate::rayon::{ThreadPool, ThreadPoolBuilder};
use crate::tiling::TilingInfo;
use crate::util::Pixel;

mod encoder;
pub use encoder::*;

mod rate;
pub use rate::Error as RateControlError;
pub use rate::{RateControlConfig, RateControlSummary};

mod speedsettings;
pub use speedsettings::*;

/// Enumeration of possible invalid configuration errors.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum InvalidConfig {
  /// The width is invalid.
  #[error("invalid width {0} (expected >= 16, <= 65535)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 65535)")]
  InvalidHeight(usize),
  /// Aspect ratio numerator is invalid.
  #[error("invalid aspect ratio numerator {0} (expected > 0)")]
  InvalidAspectRatioNum(usize),
  /// Aspect ratio denominator is invalid.
  #[error("invalid aspect ratio denominator {0} (expected > 0)")]
  InvalidAspectRatioDen(usize),
  /// The render width (width adjusted based on the aspect ratio) is invalid.
  #[error("invalid render width {0} (expected >= 1, <= 65535")]
  InvalidRenderWidth(usize),
  /// The render height (height adjusted based on the aspect ratio) is invalid.
  #[error("invalid render height {0} (expected >= 1, <= 65535")]
  InvalidRenderHeight(usize),
  /// RDO lookahead frame count is invalid.
  #[error(
    "invalid rdo lookahead frames {actual} (expected <= {max} and >= {min})"
  )]
  InvalidRdoLookaheadFrames {
    /// The actual value.
    actual: usize,
    /// The maximal supported value.
    max: usize,
    /// The minimal supported value.
    min: usize,
  },
  /// Maximal keyframe interval is invalid.
  #[error("invalid max keyframe interval {actual} (expected <= {max})")]
  InvalidMaxKeyFrameInterval {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Tile columns is invalid.
  #[error("invalid tile cols {0} (expected power of 2)")]
  InvalidTileCols(usize),
  /// Tile rows is invalid.
  #[error("invalid tile rows {0} (expected power of 2)")]
  InvalidTileRows(usize),
  /// Framerate numerator is invalid.
  #[error("invalid framerate numerator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateNum {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Framerate denominator is invalid.
  #[error("invalid framerate denominator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateDen {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Reservoir frame delay is invalid.
  #[error("invalid reservoir frame delay {0} (expected >= 12, <= 131072)")]
  InvalidReservoirFrameDelay(i32),
  /// Reservoir frame delay is invalid.
  #[error(
    "invalid switch frame interval {0} (must only be used with low latency mode)"
  )]
  InvalidSwitchFrameInterval(u64),

  /// An option unsupported in still picture mode was enabled along with it.
  #[error("invalid option {0} specified with still picture mode")]
  InvalidOptionWithStillPicture(&'static str),

  /// The rate control needs a target bitrate in order to produce results
  #[error("The rate control requires a target bitrate")]
  TargetBitrateNeeded,

  /// The configuration
  #[error("Mismatch in the rate control configuration")]
  RateControlConfigurationMismatch,

  /// The color configuration mismatches AV1 constraints.
  #[error("Mismatch in the color configuration")]
  ColorConfigurationMismatch,
}

/// Contains the encoder configuration.
#[derive(Clone, Debug, Default)]
pub struct Config {
  /// Settings which impact the produced bitstream.
  pub(crate) enc: EncoderConfig,
  /// Rate control configuration
  pub(crate) rate_control: RateControlConfig,
  /// The number of threads in the threadpool.
  pub(crate) threads: usize,
  /// Shared thread pool
  pub(crate) pool: Option<Arc<ThreadPool>>,
}

impl Config {
  /// Create a default configuration
  ///
  /// same as Default::default()
  pub fn new() -> Self {
    Config::default()
  }

  /// Set the encoder configuration
  ///
  /// EncoderConfig contains the settings impacting the
  /// codec features used in the produced bitstream.
  pub fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
    self.enc = enc;
    self
  }

  /// Set the number of workers in the threadpool
  ///
  /// The threadpool is shared across all the different parallel
  /// components in the encoder.
  pub fn with_threads(mut self, threads: usize) -> Self {
    self.threads = threads;
    self
  }

  /// Set the rate control configuration
  ///
  /// The default configuration is single pass
  pub fn with_rate_control(mut self, rate_control: RateControlConfig) -> Self {
    self.rate_control = rate_control;
    self
  }

  #[cfg(feature = "unstable")]
  /// Use the provided threadpool
  pub fn with_thread_pool(mut self, pool: Arc<ThreadPool>) -> Self {
    self.pool = Some(pool);
    self
  }
}

fn check_tile_log2(n: usize) -> bool {
  let tile_log2 = TilingInfo::tile_log2(1, n);
  if tile_log2.is_none() {
    return false;
  }
  let tile_log2 = tile_log2.unwrap();

  ((1 << tile_log2) - n) == 0 || n == 0
}

impl Config {
  pub(crate) fn new_inner<T: Pixel>(
    &self,
  ) -> Result<ContextInner<T>, InvalidConfig> {
    assert!(
      8 * std::mem::size_of::<T>() >= self.enc.bit_depth,
      "The Pixel u{} does not match the Config bit_depth {}",
      8 * std::mem::size_of::<T>(),
      self.enc.bit_depth
    );

    self.validate()?;

    // Because we don't have a FrameInvariants yet,
    // this is the only way to get the CpuFeatureLevel in use.
    // Since we only call this once, this shouldn't cause
    // performance issues.
    info!("CPU Feature Level: {}", CpuFeatureLevel::default());

    let mut config = self.enc;
    config.set_key_frame_interval(
      config.min_key_frame_interval,
      config.max_key_frame_interval,
    );

    // FIXME: inter unsupported with 4:2:2 and 4:4:4 chroma sampling
    let chroma_sampling = config.chroma_sampling;

    // FIXME: tx partition for intra not supported for chroma 422
    if chroma_sampling == ChromaSampling::Cs422 {
      config.speed_settings.rdo_tx_decision = false;
    }

    let mut inner = ContextInner::new(&config);

    if self.rate_control.emit_pass_data {
      let params = inner.rc_state.get_twopass_out_params(&inner, 0);
      inner.rc_state.init_first_pass(params.pass1_log_base_q);
    }

    if let Some(ref s) = self.rate_control.summary {
      inner.rc_state.init_second_pass();
      inner.rc_state.setup_second_pass(s);
    }

    Ok(inner)
  }
  /// Creates a [`Context`] with this configuration.
  ///
  /// # Examples
  ///
  /// ```
  /// use rav1e::prelude::*;
  ///
  /// # fn main() -> Result<(), InvalidConfig> {
  /// let cfg = Config::default();
  /// let ctx: Context<u8> = cfg.new_context()?;
  /// # Ok(())
  /// # }
  /// ```
  ///
  /// [`Context`]: struct.Context.html
  pub fn new_context<T: Pixel>(&self) -> Result<Context<T>, InvalidConfig> {
    let inner = self.new_inner()?;
    let config = *inner.config;
    let pool = if let Some(ref p) = self.pool {
      p.clone()
    } else {
      let pool =
        ThreadPoolBuilder::new().num_threads(self.threads).build().unwrap();
      Arc::new(pool)
    };

    Ok(Context { is_flushing: false, inner, pool, config })
  }

  /// Validates the configuration.
  pub fn validate(&self) -> Result<(), InvalidConfig> {
    use InvalidConfig::*;

    let config = &self.enc;

    if (config.still_picture && config.width < 1)
      || (!config.still_picture && config.width < 16)
      || config.width > u16::max_value() as usize
    {
      return Err(InvalidWidth(config.width));
    }
    if (config.still_picture && config.height < 1)
      || (!config.still_picture && config.height < 16)
      || config.height > u16::max_value() as usize
    {
      return Err(InvalidHeight(config.height));
    }

    if config.sample_aspect_ratio.num == 0 {
      return Err(InvalidAspectRatioNum(
        config.sample_aspect_ratio.num as usize,
      ));
    }
    if config.sample_aspect_ratio.den == 0 {
      return Err(InvalidAspectRatioDen(
        config.sample_aspect_ratio.den as usize,
      ));
    }

    let (render_width, render_height) = config.render_size();
    if render_width == 0 || render_width > u16::max_value() as usize {
      return Err(InvalidRenderWidth(render_width));
    }
    if render_height == 0 || render_height > u16::max_value() as usize {
      return Err(InvalidRenderHeight(render_height));
    }

    if config.rdo_lookahead_frames > MAX_RDO_LOOKAHEAD_FRAMES
      || config.rdo_lookahead_frames < 1
    {
      return Err(InvalidRdoLookaheadFrames {
        actual: config.rdo_lookahead_frames,
        max: MAX_RDO_LOOKAHEAD_FRAMES,
        min: 1,
      });
    }
    if config.max_key_frame_interval > MAX_MAX_KEY_FRAME_INTERVAL {
      return Err(InvalidMaxKeyFrameInterval {
        actual: config.max_key_frame_interval,
        max: MAX_MAX_KEY_FRAME_INTERVAL,
      });
    }

    if !check_tile_log2(config.tile_cols) {
      return Err(InvalidTileCols(config.tile_cols));
    }
    if !check_tile_log2(config.tile_rows) {
      return Err(InvalidTileRows(config.tile_rows));
    }

    if config.time_base.num == 0
      || config.time_base.num > u32::max_value() as u64
    {
      return Err(InvalidFrameRateNum {
        actual: config.time_base.num,
        max: u32::max_value() as u64,
      });
    }
    if config.time_base.den == 0
      || config.time_base.den > u32::max_value() as u64
    {
      return Err(InvalidFrameRateDen {
        actual: config.time_base.den,
        max: u32::max_value() as u64,
      });
    }

    if let Some(delay) = config.reservoir_frame_delay {
      if !(12..=131_072).contains(&delay) {
        return Err(InvalidReservoirFrameDelay(delay));
      }
    }

    if config.switch_frame_interval > 0 && !config.low_latency {
      return Err(InvalidSwitchFrameInterval(config.switch_frame_interval));
    }

    if config.enable_timing_info && config.still_picture {
      return Err(InvalidOptionWithStillPicture("enable_timing_info"));
    }

    // <https://aomediacodec.github.io/av1-spec/#color-config-syntax>
    if let Some(color_description) = config.color_description {
      if config.chroma_sampling != ChromaSampling::Cs400
        && color_description.is_srgb_triple()
      {
        if config.pixel_range != PixelRange::Full {
          return Err(ColorConfigurationMismatch);
        }
        if config.chroma_sampling != ChromaSampling::Cs444 {
          return Err(ColorConfigurationMismatch);
        }
      }
    }

    // TODO: add more validation
    let rc = &self.rate_control;

    if (rc.emit_pass_data || rc.summary.is_some()) && config.bitrate == 0 {
      return Err(TargetBitrateNeeded);
    }

    Ok(())
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020, 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 thiserror::Error;

use std::sync::Arc;

use crate::api::{ChromaSampling, Context, ContextInner, PixelRange};
use crate::cpu_features::CpuFeatureLevel;
use crate::rayon::{ThreadPool, ThreadPoolBuilder};
use crate::tiling::TilingInfo;
use crate::util::Pixel;

mod encoder;
pub use encoder::*;

mod rate;
pub use rate::Error as RateControlError;
pub use rate::{RateControlConfig, RateControlSummary};

mod speedsettings;
pub use speedsettings::*;

/// Enumeration of possible invalid configuration errors.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum InvalidConfig {
  /// The width is invalid.
  #[error("invalid width {0} (expected >= 16, <= 65535)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 65535)")]
  InvalidHeight(usize),
  /// Aspect ratio numerator is invalid.
  #[error("invalid aspect ratio numerator {0} (expected > 0)")]
  InvalidAspectRatioNum(usize),
  /// Aspect ratio denominator is invalid.
  #[error("invalid aspect ratio denominator {0} (expected > 0)")]
  InvalidAspectRatioDen(usize),
  /// The render width (width adjusted based on the aspect ratio) is invalid.
  #[error("invalid render width {0} (expected >= 1, <= 65535")]
  InvalidRenderWidth(usize),
  /// The render height (height adjusted based on the aspect ratio) is invalid.
  #[error("invalid render height {0} (expected >= 1, <= 65535")]
  InvalidRenderHeight(usize),
  /// RDO lookahead frame count is invalid.
  #[error(
    "invalid rdo lookahead frames {actual} (expected <= {max} and >= {min})"
  )]
  InvalidRdoLookaheadFrames {
    /// The actual value.
    actual: usize,
    /// The maximal supported value.
    max: usize,
    /// The minimal supported value.
    min: usize,
  },
  /// Maximal keyframe interval is invalid.
  #[error("invalid max keyframe interval {actual} (expected <= {max})")]
  InvalidMaxKeyFrameInterval {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Tile columns is invalid.
  #[error("invalid tile cols {0} (expected power of 2)")]
  InvalidTileCols(usize),
  /// Tile rows is invalid.
  #[error("invalid tile rows {0} (expected power of 2)")]
  InvalidTileRows(usize),
  /// Framerate numerator is invalid.
  #[error("invalid framerate numerator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateNum {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Framerate denominator is invalid.
  #[error("invalid framerate denominator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateDen {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Reservoir frame delay is invalid.
  #[error("invalid reservoir frame delay {0} (expected >= 12, <= 131072)")]
  InvalidReservoirFrameDelay(i32),
  /// Reservoir frame delay is invalid.
  #[error(
    "invalid switch frame interval {0} (must only be used with low latency mode)"
  )]
  InvalidSwitchFrameInterval(u64),

  /// An option unsupported in still picture mode was enabled along with it.
  #[error("invalid option {0} specified with still picture mode")]
  InvalidOptionWithStillPicture(&'static str),

  /// The rate control needs a target bitrate in order to produce results
  #[error("The rate control requires a target bitrate")]
  TargetBitrateNeeded,

  /// The configuration
  #[error("Mismatch in the rate control configuration")]
  RateControlConfigurationMismatch,

  /// The color configuration mismatches AV1 constraints.
  #[error("Mismatch in the color configuration")]
  ColorConfigurationMismatch,
}

/// Contains the encoder configuration.
#[derive(Clone, Debug, Default)]
pub struct Config {
  /// Settings which impact the produced bitstream.
  pub(crate) enc: EncoderConfig,
  /// Rate control configuration
  pub(crate) rate_control: RateControlConfig,
  /// The number of threads in the threadpool.
  pub(crate) threads: usize,
  /// Shared thread pool
  pub(crate) pool: Option<Arc<ThreadPool>>,
}

impl Config {
  /// Create a default configuration
  ///
  /// same as Default::default()
  pub fn new() -> Self {
    Config::default()
  }

  /// Set the encoder configuration
  ///
  /// EncoderConfig contains the settings impacting the
  /// codec features used in the produced bitstream.
  pub fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
    self.enc = enc;
    self
  }

  /// Set the number of workers in the threadpool
  ///
  /// The threadpool is shared across all the different parallel
  /// components in the encoder.
  ///
  /// If it is left unset `new_context()` will create a new default one
  /// `new_*_channel()` will use the current global threadpool if present.
  pub fn with_threads(mut self, threads: usize) -> Self {
    self.threads = threads;
    self
  }

  /// Set the rate control configuration
  ///
  /// The default configuration is single pass
  pub fn with_rate_control(mut self, rate_control: RateControlConfig) -> Self {
    self.rate_control = rate_control;
    self
  }

  #[cfg(feature = "unstable")]
  /// Use the provided threadpool
  ///
  /// It takes priority over `with_threads()`
  pub fn with_thread_pool(mut self, pool: Arc<ThreadPool>) -> Self {
    self.pool = Some(pool);
    self
  }
}

fn check_tile_log2(n: usize) -> bool {
  let tile_log2 = TilingInfo::tile_log2(1, n);
  if tile_log2.is_none() {
    return false;
  }
  let tile_log2 = tile_log2.unwrap();

  ((1 << tile_log2) - n) == 0 || n == 0
}

impl Config {
  pub(crate) fn new_inner<T: Pixel>(
    &self,
  ) -> Result<ContextInner<T>, InvalidConfig> {
    assert!(
      8 * std::mem::size_of::<T>() >= self.enc.bit_depth,
      "The Pixel u{} does not match the Config bit_depth {}",
      8 * std::mem::size_of::<T>(),
      self.enc.bit_depth
    );

    self.validate()?;

    // Because we don't have a FrameInvariants yet,
    // this is the only way to get the CpuFeatureLevel in use.
    // Since we only call this once, this shouldn't cause
    // performance issues.
    info!("CPU Feature Level: {}", CpuFeatureLevel::default());

    let mut config = self.enc;
    config.set_key_frame_interval(
      config.min_key_frame_interval,
      config.max_key_frame_interval,
    );

    // FIXME: inter unsupported with 4:2:2 and 4:4:4 chroma sampling
    let chroma_sampling = config.chroma_sampling;

    // FIXME: tx partition for intra not supported for chroma 422
    if chroma_sampling == ChromaSampling::Cs422 {
      config.speed_settings.rdo_tx_decision = false;
    }

    let mut inner = ContextInner::new(&config);

    if self.rate_control.emit_pass_data {
      let params = inner.rc_state.get_twopass_out_params(&inner, 0);
      inner.rc_state.init_first_pass(params.pass1_log_base_q);
    }

    if let Some(ref s) = self.rate_control.summary {
      inner.rc_state.init_second_pass();
      inner.rc_state.setup_second_pass(s);
    }

    Ok(inner)
  }
  /// Creates a [`Context`] with this configuration.
  ///
  /// # Examples
  ///
  /// ```
  /// use rav1e::prelude::*;
  ///
  /// # fn main() -> Result<(), InvalidConfig> {
  /// let cfg = Config::default();
  /// let ctx: Context<u8> = cfg.new_context()?;
  /// # Ok(())
  /// # }
  /// ```
  ///
  /// [`Context`]: struct.Context.html
  pub fn new_context<T: Pixel>(&self) -> Result<Context<T>, InvalidConfig> {
    let inner = self.new_inner()?;
    let config = *inner.config;
    let pool = if let Some(ref p) = self.pool {
      Some(p.clone())
    } else if self.threads != 0 {
      let pool =
        ThreadPoolBuilder::new().num_threads(self.threads).build().unwrap();
      Some(Arc::new(pool))
    } else {
      None
    };

    Ok(Context { is_flushing: false, inner, pool, config })
  }

  /// Validates the configuration.
  pub fn validate(&self) -> Result<(), InvalidConfig> {
    use InvalidConfig::*;

    let config = &self.enc;

    if (config.still_picture && config.width < 1)
      || (!config.still_picture && config.width < 16)
      || config.width > u16::max_value() as usize
    {
      return Err(InvalidWidth(config.width));
    }
    if (config.still_picture && config.height < 1)
      || (!config.still_picture && config.height < 16)
      || config.height > u16::max_value() as usize
    {
      return Err(InvalidHeight(config.height));
    }

    if config.sample_aspect_ratio.num == 0 {
      return Err(InvalidAspectRatioNum(
        config.sample_aspect_ratio.num as usize,
      ));
    }
    if config.sample_aspect_ratio.den == 0 {
      return Err(InvalidAspectRatioDen(
        config.sample_aspect_ratio.den as usize,
      ));
    }

    let (render_width, render_height) = config.render_size();
    if render_width == 0 || render_width > u16::max_value() as usize {
      return Err(InvalidRenderWidth(render_width));
    }
    if render_height == 0 || render_height > u16::max_value() as usize {
      return Err(InvalidRenderHeight(render_height));
    }

    if config.rdo_lookahead_frames > MAX_RDO_LOOKAHEAD_FRAMES
      || config.rdo_lookahead_frames < 1
    {
      return Err(InvalidRdoLookaheadFrames {
        actual: config.rdo_lookahead_frames,
        max: MAX_RDO_LOOKAHEAD_FRAMES,
        min: 1,
      });
    }
    if config.max_key_frame_interval > MAX_MAX_KEY_FRAME_INTERVAL {
      return Err(InvalidMaxKeyFrameInterval {
        actual: config.max_key_frame_interval,
        max: MAX_MAX_KEY_FRAME_INTERVAL,
      });
    }

    if !check_tile_log2(config.tile_cols) {
      return Err(InvalidTileCols(config.tile_cols));
    }
    if !check_tile_log2(config.tile_rows) {
      return Err(InvalidTileRows(config.tile_rows));
    }

    if config.time_base.num == 0
      || config.time_base.num > u32::max_value() as u64
    {
      return Err(InvalidFrameRateNum {
        actual: config.time_base.num,
        max: u32::max_value() as u64,
      });
    }
    if config.time_base.den == 0
      || config.time_base.den > u32::max_value() as u64
    {
      return Err(InvalidFrameRateDen {
        actual: config.time_base.den,
        max: u32::max_value() as u64,
      });
    }

    if let Some(delay) = config.reservoir_frame_delay {
      if !(12..=131_072).contains(&delay) {
        return Err(InvalidReservoirFrameDelay(delay));
      }
    }

    if config.switch_frame_interval > 0 && !config.low_latency {
      return Err(InvalidSwitchFrameInterval(config.switch_frame_interval));
    }

    if config.enable_timing_info && config.still_picture {
      return Err(InvalidOptionWithStillPicture("enable_timing_info"));
    }

    // <https://aomediacodec.github.io/av1-spec/#color-config-syntax>
    if let Some(color_description) = config.color_description {
      if config.chroma_sampling != ChromaSampling::Cs400
        && color_description.is_srgb_triple()
      {
        if config.pixel_range != PixelRange::Full {
          return Err(ColorConfigurationMismatch);
        }
        if config.chroma_sampling != ChromaSampling::Cs444 {
          return Err(ColorConfigurationMismatch);
        }
      }
    }

    // TODO: add more validation
    let rc = &self.rate_control;

    if (rc.emit_pass_data || rc.summary.is_some()) && config.bitrate == 0 {
      return Err(TargetBitrateNeeded);
    }

    Ok(())
  }
}
<commit_msg>Minor doc nitpick<commit_after>// Copyright (c) 2020, 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 thiserror::Error;

use std::sync::Arc;

use crate::api::{ChromaSampling, Context, ContextInner, PixelRange};
use crate::cpu_features::CpuFeatureLevel;
use crate::rayon::{ThreadPool, ThreadPoolBuilder};
use crate::tiling::TilingInfo;
use crate::util::Pixel;

mod encoder;
pub use encoder::*;

mod rate;
pub use rate::Error as RateControlError;
pub use rate::{RateControlConfig, RateControlSummary};

mod speedsettings;
pub use speedsettings::*;

/// Enumeration of possible invalid configuration errors.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum InvalidConfig {
  /// The width is invalid.
  #[error("invalid width {0} (expected >= 16, <= 65535)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 65535)")]
  InvalidHeight(usize),
  /// Aspect ratio numerator is invalid.
  #[error("invalid aspect ratio numerator {0} (expected > 0)")]
  InvalidAspectRatioNum(usize),
  /// Aspect ratio denominator is invalid.
  #[error("invalid aspect ratio denominator {0} (expected > 0)")]
  InvalidAspectRatioDen(usize),
  /// The render width (width adjusted based on the aspect ratio) is invalid.
  #[error("invalid render width {0} (expected >= 1, <= 65535")]
  InvalidRenderWidth(usize),
  /// The render height (height adjusted based on the aspect ratio) is invalid.
  #[error("invalid render height {0} (expected >= 1, <= 65535")]
  InvalidRenderHeight(usize),
  /// RDO lookahead frame count is invalid.
  #[error(
    "invalid rdo lookahead frames {actual} (expected <= {max} and >= {min})"
  )]
  InvalidRdoLookaheadFrames {
    /// The actual value.
    actual: usize,
    /// The maximal supported value.
    max: usize,
    /// The minimal supported value.
    min: usize,
  },
  /// Maximal keyframe interval is invalid.
  #[error("invalid max keyframe interval {actual} (expected <= {max})")]
  InvalidMaxKeyFrameInterval {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Tile columns is invalid.
  #[error("invalid tile cols {0} (expected power of 2)")]
  InvalidTileCols(usize),
  /// Tile rows is invalid.
  #[error("invalid tile rows {0} (expected power of 2)")]
  InvalidTileRows(usize),
  /// Framerate numerator is invalid.
  #[error("invalid framerate numerator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateNum {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Framerate denominator is invalid.
  #[error("invalid framerate denominator {actual} (expected > 0, <= {max})")]
  InvalidFrameRateDen {
    /// The actual value.
    actual: u64,
    /// The maximal supported value.
    max: u64,
  },
  /// Reservoir frame delay is invalid.
  #[error("invalid reservoir frame delay {0} (expected >= 12, <= 131072)")]
  InvalidReservoirFrameDelay(i32),
  /// Reservoir frame delay is invalid.
  #[error(
    "invalid switch frame interval {0} (must only be used with low latency mode)"
  )]
  InvalidSwitchFrameInterval(u64),

  /// An option unsupported in still picture mode was enabled along with it.
  #[error("invalid option {0} specified with still picture mode")]
  InvalidOptionWithStillPicture(&'static str),

  /// The rate control needs a target bitrate in order to produce results
  #[error("The rate control requires a target bitrate")]
  TargetBitrateNeeded,

  /// The configuration
  #[error("Mismatch in the rate control configuration")]
  RateControlConfigurationMismatch,

  /// The color configuration mismatches AV1 constraints.
  #[error("Mismatch in the color configuration")]
  ColorConfigurationMismatch,
}

/// Contains the encoder configuration.
#[derive(Clone, Debug, Default)]
pub struct Config {
  /// Settings which impact the produced bitstream.
  pub(crate) enc: EncoderConfig,
  /// Rate control configuration
  pub(crate) rate_control: RateControlConfig,
  /// The number of threads in the threadpool.
  pub(crate) threads: usize,
  /// Shared thread pool
  pub(crate) pool: Option<Arc<ThreadPool>>,
}

impl Config {
  /// Create a default configuration
  ///
  /// same as Default::default()
  pub fn new() -> Self {
    Config::default()
  }

  /// Set the encoder configuration
  ///
  /// EncoderConfig contains the settings impacting the
  /// codec features used in the produced bitstream.
  pub fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
    self.enc = enc;
    self
  }

  /// Set the number of workers in the threadpool
  ///
  /// The threadpool is shared across all the different parallel
  /// components in the encoder.
  ///
  /// If it is left unset `new_context()` will create a new default one
  /// `new_*_channel()` will use the default global threadpool.
  pub fn with_threads(mut self, threads: usize) -> Self {
    self.threads = threads;
    self
  }

  /// Set the rate control configuration
  ///
  /// The default configuration is single pass
  pub fn with_rate_control(mut self, rate_control: RateControlConfig) -> Self {
    self.rate_control = rate_control;
    self
  }

  #[cfg(feature = "unstable")]
  /// Use the provided threadpool
  ///
  /// It takes priority over `with_threads()`
  pub fn with_thread_pool(mut self, pool: Arc<ThreadPool>) -> Self {
    self.pool = Some(pool);
    self
  }
}

fn check_tile_log2(n: usize) -> bool {
  let tile_log2 = TilingInfo::tile_log2(1, n);
  if tile_log2.is_none() {
    return false;
  }
  let tile_log2 = tile_log2.unwrap();

  ((1 << tile_log2) - n) == 0 || n == 0
}

impl Config {
  pub(crate) fn new_inner<T: Pixel>(
    &self,
  ) -> Result<ContextInner<T>, InvalidConfig> {
    assert!(
      8 * std::mem::size_of::<T>() >= self.enc.bit_depth,
      "The Pixel u{} does not match the Config bit_depth {}",
      8 * std::mem::size_of::<T>(),
      self.enc.bit_depth
    );

    self.validate()?;

    // Because we don't have a FrameInvariants yet,
    // this is the only way to get the CpuFeatureLevel in use.
    // Since we only call this once, this shouldn't cause
    // performance issues.
    info!("CPU Feature Level: {}", CpuFeatureLevel::default());

    let mut config = self.enc;
    config.set_key_frame_interval(
      config.min_key_frame_interval,
      config.max_key_frame_interval,
    );

    // FIXME: inter unsupported with 4:2:2 and 4:4:4 chroma sampling
    let chroma_sampling = config.chroma_sampling;

    // FIXME: tx partition for intra not supported for chroma 422
    if chroma_sampling == ChromaSampling::Cs422 {
      config.speed_settings.rdo_tx_decision = false;
    }

    let mut inner = ContextInner::new(&config);

    if self.rate_control.emit_pass_data {
      let params = inner.rc_state.get_twopass_out_params(&inner, 0);
      inner.rc_state.init_first_pass(params.pass1_log_base_q);
    }

    if let Some(ref s) = self.rate_control.summary {
      inner.rc_state.init_second_pass();
      inner.rc_state.setup_second_pass(s);
    }

    Ok(inner)
  }
  /// Creates a [`Context`] with this configuration.
  ///
  /// # Examples
  ///
  /// ```
  /// use rav1e::prelude::*;
  ///
  /// # fn main() -> Result<(), InvalidConfig> {
  /// let cfg = Config::default();
  /// let ctx: Context<u8> = cfg.new_context()?;
  /// # Ok(())
  /// # }
  /// ```
  ///
  /// [`Context`]: struct.Context.html
  pub fn new_context<T: Pixel>(&self) -> Result<Context<T>, InvalidConfig> {
    let inner = self.new_inner()?;
    let config = *inner.config;
    let pool = if let Some(ref p) = self.pool {
      Some(p.clone())
    } else if self.threads != 0 {
      let pool =
        ThreadPoolBuilder::new().num_threads(self.threads).build().unwrap();
      Some(Arc::new(pool))
    } else {
      None
    };

    Ok(Context { is_flushing: false, inner, pool, config })
  }

  /// Validates the configuration.
  pub fn validate(&self) -> Result<(), InvalidConfig> {
    use InvalidConfig::*;

    let config = &self.enc;

    if (config.still_picture && config.width < 1)
      || (!config.still_picture && config.width < 16)
      || config.width > u16::max_value() as usize
    {
      return Err(InvalidWidth(config.width));
    }
    if (config.still_picture && config.height < 1)
      || (!config.still_picture && config.height < 16)
      || config.height > u16::max_value() as usize
    {
      return Err(InvalidHeight(config.height));
    }

    if config.sample_aspect_ratio.num == 0 {
      return Err(InvalidAspectRatioNum(
        config.sample_aspect_ratio.num as usize,
      ));
    }
    if config.sample_aspect_ratio.den == 0 {
      return Err(InvalidAspectRatioDen(
        config.sample_aspect_ratio.den as usize,
      ));
    }

    let (render_width, render_height) = config.render_size();
    if render_width == 0 || render_width > u16::max_value() as usize {
      return Err(InvalidRenderWidth(render_width));
    }
    if render_height == 0 || render_height > u16::max_value() as usize {
      return Err(InvalidRenderHeight(render_height));
    }

    if config.rdo_lookahead_frames > MAX_RDO_LOOKAHEAD_FRAMES
      || config.rdo_lookahead_frames < 1
    {
      return Err(InvalidRdoLookaheadFrames {
        actual: config.rdo_lookahead_frames,
        max: MAX_RDO_LOOKAHEAD_FRAMES,
        min: 1,
      });
    }
    if config.max_key_frame_interval > MAX_MAX_KEY_FRAME_INTERVAL {
      return Err(InvalidMaxKeyFrameInterval {
        actual: config.max_key_frame_interval,
        max: MAX_MAX_KEY_FRAME_INTERVAL,
      });
    }

    if !check_tile_log2(config.tile_cols) {
      return Err(InvalidTileCols(config.tile_cols));
    }
    if !check_tile_log2(config.tile_rows) {
      return Err(InvalidTileRows(config.tile_rows));
    }

    if config.time_base.num == 0
      || config.time_base.num > u32::max_value() as u64
    {
      return Err(InvalidFrameRateNum {
        actual: config.time_base.num,
        max: u32::max_value() as u64,
      });
    }
    if config.time_base.den == 0
      || config.time_base.den > u32::max_value() as u64
    {
      return Err(InvalidFrameRateDen {
        actual: config.time_base.den,
        max: u32::max_value() as u64,
      });
    }

    if let Some(delay) = config.reservoir_frame_delay {
      if !(12..=131_072).contains(&delay) {
        return Err(InvalidReservoirFrameDelay(delay));
      }
    }

    if config.switch_frame_interval > 0 && !config.low_latency {
      return Err(InvalidSwitchFrameInterval(config.switch_frame_interval));
    }

    if config.enable_timing_info && config.still_picture {
      return Err(InvalidOptionWithStillPicture("enable_timing_info"));
    }

    // <https://aomediacodec.github.io/av1-spec/#color-config-syntax>
    if let Some(color_description) = config.color_description {
      if config.chroma_sampling != ChromaSampling::Cs400
        && color_description.is_srgb_triple()
      {
        if config.pixel_range != PixelRange::Full {
          return Err(ColorConfigurationMismatch);
        }
        if config.chroma_sampling != ChromaSampling::Cs444 {
          return Err(ColorConfigurationMismatch);
        }
      }
    }

    // TODO: add more validation
    let rc = &self.rate_control;

    if (rc.emit_pass_data || rc.summary.is_some()) && config.bitrate == 0 {
      return Err(TargetBitrateNeeded);
    }

    Ok(())
  }
}
<|endoftext|>


<commit_before>use std;

type id = libc::intptr_t;
type SEL = libc::intptr_t;

const nil : id = 0 as id;

native mod objc {
    fn objc_getClass(name : *libc::c_char) -> id;
    fn objc_msgSend(theReceiver : id, theSelector : SEL) -> id;
    fn sel_registerName(name : *libc::c_char) -> SEL;
}

#[test]
fn test_nsapp() {
    let klass = str::as_c_str("NSApplication") { |s|
        objc::objc_getClass(s)
    };

    let sel = str::as_c_str("sharedApplication") { |s|
        objc::sel_registerName(s)
    };

    let nsapp = objc::objc_msgSend(klass, sel);

    io::println(#fmt("nsapp: %d", (nsapp as int)));
}

<commit_msg>Add the ability to create classes and implement methods<commit_after>use std;

type id = libc::intptr_t;
type Class = libc::intptr_t;
type IMP = *u8;
type SEL = libc::intptr_t;

const nil : id = 0 as id;

native mod objc {
    fn class_addMethod(cls : Class,
                       name : SEL,
                       imp : IMP,
                       types : *libc::c_char) -> bool;
    fn objc_allocateClassPair(superclass : Class,
                              name : *libc::c_char,
                              extraBytes : libc::size_t) -> Class;
    fn objc_getClass(name : *libc::c_char) -> id;
    fn objc_msgSend(theReceiver : id, theSelector : SEL) -> id;
    fn objc_registerClassPair(cls : Class);
    fn sel_registerName(name : *libc::c_char) -> SEL;
}

#[test]
fn test_nsapp() {
    let klass = str::as_c_str("NSApplication") { |s|
        objc::objc_getClass(s)
    };

    let sel = str::as_c_str("sharedApplication") { |s|
        objc::sel_registerName(s)
    };

    let nsapp = objc::objc_msgSend(klass, sel);

    io::println(#fmt("nsapp: %d", (nsapp as int)));
}

#[test]
fn test_custom_obj() {
    crust fn MyObject_doSomething(this : id, _sel : SEL) -> id {
        io::println("doSomething");
        ret this;
    }

    let NSObject = str::as_c_str("NSObject") { |s|
        objc::objc_getClass(s)
    };
    let MyObject = str::as_c_str("MyObject") { |s|
        objc::objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
    };
    let doSomething = str::as_c_str("doSomething") { |s|
        objc::sel_registerName(s)
    };
    let _ = str::as_c_str("@@:") { |types|
        objc::class_addMethod(MyObject, doSomething, MyObject_doSomething,
                              types)
    };
    objc::objc_registerClassPair(MyObject);

    let alloc = str::as_c_str("alloc") { |s| objc::sel_registerName(s) };
    let init = str::as_c_str("init") { |s| objc::sel_registerName(s) };

    let mut obj = objc::objc_msgSend(MyObject, alloc);
    obj = objc::objc_msgSend(obj, init);
    objc::objc_msgSend(obj, doSomething);
}

<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate clap;
extern crate futures;
extern crate rand;
extern crate rdkafka;
extern crate tokio;

use clap::{App, Arg};
use futures::{Future, lazy, Stream};
use tokio::executor::current_thread;
use tokio::executor::thread_pool;

use rdkafka::Message;
use rdkafka::consumer::Consumer;
use rdkafka::consumer::stream_consumer::StreamConsumer;
use rdkafka::config::ClientConfig;
use rdkafka::message::OwnedMessage;
use rdkafka::producer::{FutureProducer, FutureRecord};

use std::thread;
use std::time::Duration;

mod example_utils;
use crate::example_utils::setup_logger;

// Emulates an expensive, synchronous computation.
fn expensive_computation<'a>(msg: OwnedMessage) -> String {
    info!("Starting expensive computation on message {}", msg.offset());
    thread::sleep(Duration::from_millis(rand::random::<u64>() % 5000));
    info!("Expensive computation completed on message {}", msg.offset());
    match msg.payload_view::<str>() {
        Some(Ok(payload)) => format!("Payload len for {} is {}", payload, payload.len()),
        Some(Err(_)) => "Message payload is not a string".to_owned(),
        None => "No payload".to_owned(),
    }
}

// Creates all the resources and runs the event loop. The event loop will:
//   1) receive a stream of messages from the `StreamConsumer`.
//   2) filter out eventual Kafka errors.
//   3) send the message to a thread pool for processing.
//   4) produce the result to the output topic.
// Moving each message from one stage of the pipeline to next one is handled by the event loop,
// that runs on a single thread. The expensive CPU-bound computation is handled by the `ThreadPool`,
// without blocking the event loop.
fn run_async_processor(brokers: &str, group_id: &str, input_topic: &str, output_topic: &str) {

    // Create the `StreamConsumer`, to receive the messages from the topic in form of a `Stream`.
    let consumer: StreamConsumer = ClientConfig::new()
        .set("group.id", group_id)
        .set("bootstrap.servers", brokers)
        .set("enable.partition.eof", "false")
        .set("session.timeout.ms", "6000")
        .set("enable.auto.commit", "false")
        .create()
        .expect("Consumer creation failed");

    consumer.subscribe(&[input_topic]).expect("Can't subscribe to specified topic");

    // Create the `FutureProducer` to produce asynchronously.
    let producer: FutureProducer = ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("produce.offset.report", "true")
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // Create the thread pool where the expensive computation will be performed.
    let thread_pool = thread_pool::Builder::new()
        .name_prefix("pool-")
        .pool_size(4)
        .build();

    // Use the current thread as IO thread to drive consumer and producer.
    let mut io_thread = current_thread::CurrentThread::new();
    let io_thread_handle = io_thread.handle();

    // Create the outer pipeline on the message stream.
    let stream_processor = consumer.start()
        .filter_map(|result| {  // Filter out errors
            match result {
                Ok(msg) => Some(msg),
                Err(kafka_error) => {
                    warn!("Error while receiving from Kafka: {:?}", kafka_error);
                    None
                }
            }
        }).for_each(move |borrowed_message| {     // Process each message
            info!("Message received: {}", borrowed_message.offset());
            // Borrowed messages can't outlive the consumer they are received from, so they need to
            // be owned in order to be sent to a separate thread.
            let owned_message = borrowed_message.detach();
            let output_topic = output_topic.to_string();
            let producer = producer.clone();
            let io_thread_handle = io_thread_handle.clone();
            let message_future = lazy(move || {
                // The body of this closure will be executed in the thread pool.
                let computation_result = expensive_computation(owned_message);
                let producer_future = producer.send(
                    FutureRecord::to(&output_topic)
                        .key("some key")
                        .payload(&computation_result),
                    0)
                    .then(|result| {
                        match result {
                            Ok(Ok(delivery)) => println!("Sent: {:?}", delivery),
                            Ok(Err((e, _))) => println!("Error: {:?}", e),
                            Err(_) => println!("Future cancelled")
                        }
                        Ok(())
                    });
                let _ = io_thread_handle.spawn(producer_future);
                Ok(())
            });
            thread_pool.spawn(message_future);
            Ok(())
        });

    info!("Starting event loop");
    let _ = io_thread.block_on(stream_processor);
    info!("Stream processing terminated");
}

fn main() {
    let matches = App::new("Async example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("Asynchronous computation example")
        .arg(Arg::with_name("brokers")
             .short("b")
             .long("brokers")
             .help("Broker list in kafka format")
             .takes_value(true)
             .default_value("localhost:9092"))
        .arg(Arg::with_name("group-id")
             .short("g")
             .long("group-id")
             .help("Consumer group id")
             .takes_value(true)
             .default_value("example_consumer_group_id"))
        .arg(Arg::with_name("log-conf")
             .long("log-conf")
             .help("Configure the logging format (example: 'rdkafka=trace')")
             .takes_value(true))
        .arg(Arg::with_name("input-topic")
             .long("input-topic")
             .help("Input topic")
             .takes_value(true)
             .required(true))
        .arg(Arg::with_name("output-topic")
            .long("output-topic")
            .help("Output topic")
            .takes_value(true)
            .required(true))
        .get_matches();

    setup_logger(true, matches.value_of("log-conf"));

    let brokers = matches.value_of("brokers").unwrap();
    let group_id = matches.value_of("group-id").unwrap();
    let input_topic = matches.value_of("input-topic").unwrap();
    let output_topic = matches.value_of("output-topic").unwrap();

    run_async_processor(brokers, group_id, input_topic, output_topic);
}
<commit_msg>examples/asynchronous_processing: use updated Tokio API (#110)<commit_after>#[macro_use] extern crate log;
extern crate clap;
extern crate futures;
extern crate rand;
extern crate rdkafka;
extern crate tokio;

use clap::{App, Arg};
use futures::{Future, lazy, Stream};
use tokio::runtime::current_thread;

use rdkafka::Message;
use rdkafka::consumer::Consumer;
use rdkafka::consumer::stream_consumer::StreamConsumer;
use rdkafka::config::ClientConfig;
use rdkafka::message::OwnedMessage;
use rdkafka::producer::{FutureProducer, FutureRecord};

use std::thread;
use std::time::Duration;

mod example_utils;
use crate::example_utils::setup_logger;

// Emulates an expensive, synchronous computation.
fn expensive_computation<'a>(msg: OwnedMessage) -> String {
    info!("Starting expensive computation on message {}", msg.offset());
    thread::sleep(Duration::from_millis(rand::random::<u64>() % 5000));
    info!("Expensive computation completed on message {}", msg.offset());
    match msg.payload_view::<str>() {
        Some(Ok(payload)) => format!("Payload len for {} is {}", payload, payload.len()),
        Some(Err(_)) => "Message payload is not a string".to_owned(),
        None => "No payload".to_owned(),
    }
}

// Creates all the resources and runs the event loop. The event loop will:
//   1) receive a stream of messages from the `StreamConsumer`.
//   2) filter out eventual Kafka errors.
//   3) send the message to a thread pool for processing.
//   4) produce the result to the output topic.
// Moving each message from one stage of the pipeline to next one is handled by the event loop,
// that runs on a single thread. The expensive CPU-bound computation is handled by the `ThreadPool`,
// without blocking the event loop.
fn run_async_processor(brokers: &str, group_id: &str, input_topic: &str, output_topic: &str) {

    // Create the `StreamConsumer`, to receive the messages from the topic in form of a `Stream`.
    let consumer: StreamConsumer = ClientConfig::new()
        .set("group.id", group_id)
        .set("bootstrap.servers", brokers)
        .set("enable.partition.eof", "false")
        .set("session.timeout.ms", "6000")
        .set("enable.auto.commit", "false")
        .create()
        .expect("Consumer creation failed");

    consumer.subscribe(&[input_topic]).expect("Can't subscribe to specified topic");

    // Create the `FutureProducer` to produce asynchronously.
    let producer: FutureProducer = ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("produce.offset.report", "true")
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // Create the runtime where the expensive computation will be performed.
    let mut thread_pool = tokio::runtime::Builder::new()
        .name_prefix("pool-")
        .core_threads(4)
        .build()
        .unwrap();

    // Use the current thread as IO thread to drive consumer and producer.
    let mut io_thread = current_thread::Runtime::new().unwrap();
    let io_thread_handle = io_thread.handle();

    // Create the outer pipeline on the message stream.
    let stream_processor = consumer.start()
        .filter_map(|result| {  // Filter out errors
            match result {
                Ok(msg) => Some(msg),
                Err(kafka_error) => {
                    warn!("Error while receiving from Kafka: {:?}", kafka_error);
                    None
                }
            }
        }).for_each(move |borrowed_message| {     // Process each message
            info!("Message received: {}", borrowed_message.offset());
            // Borrowed messages can't outlive the consumer they are received from, so they need to
            // be owned in order to be sent to a separate thread.
            let owned_message = borrowed_message.detach();
            let output_topic = output_topic.to_string();
            let producer = producer.clone();
            let io_thread_handle = io_thread_handle.clone();
            let message_future = lazy(move || {
                // The body of this closure will be executed in the thread pool.
                let computation_result = expensive_computation(owned_message);
                let producer_future = producer.send(
                    FutureRecord::to(&output_topic)
                        .key("some key")
                        .payload(&computation_result),
                    0)
                    .then(|result| {
                        match result {
                            Ok(Ok(delivery)) => println!("Sent: {:?}", delivery),
                            Ok(Err((e, _))) => println!("Error: {:?}", e),
                            Err(_) => println!("Future cancelled")
                        }
                        Ok(())
                    });
                let _ = io_thread_handle.spawn(producer_future);
                Ok(())
            });
            thread_pool.spawn(message_future);
            Ok(())
        });

    info!("Starting event loop");
    let _ = io_thread.block_on(stream_processor);
    info!("Stream processing terminated");
}

fn main() {
    let matches = App::new("Async example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("Asynchronous computation example")
        .arg(Arg::with_name("brokers")
             .short("b")
             .long("brokers")
             .help("Broker list in kafka format")
             .takes_value(true)
             .default_value("localhost:9092"))
        .arg(Arg::with_name("group-id")
             .short("g")
             .long("group-id")
             .help("Consumer group id")
             .takes_value(true)
             .default_value("example_consumer_group_id"))
        .arg(Arg::with_name("log-conf")
             .long("log-conf")
             .help("Configure the logging format (example: 'rdkafka=trace')")
             .takes_value(true))
        .arg(Arg::with_name("input-topic")
             .long("input-topic")
             .help("Input topic")
             .takes_value(true)
             .required(true))
        .arg(Arg::with_name("output-topic")
            .long("output-topic")
            .help("Output topic")
            .takes_value(true)
            .required(true))
        .get_matches();

    setup_logger(true, matches.value_of("log-conf"));

    let brokers = matches.value_of("brokers").unwrap();
    let group_id = matches.value_of("group-id").unwrap();
    let input_topic = matches.value_of("input-topic").unwrap();
    let output_topic = matches.value_of("output-topic").unwrap();

    run_async_processor(brokers, group_id, input_topic, output_topic);
}
<|endoftext|>


<commit_before>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use rlua::prelude::LuaInteger;
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

impl Display for DrawinState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawin: {:p}", self)
    }
}

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, "drawin", Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
            // TODO This should be adding properties, e.g like luaA_class_new
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("x".into(),
                                Some(lua.create_function(set_x)),
                                Some(lua.create_function(get_x)),
                                Some(lua.create_function(set_x))))?
        .property(Property::new("y".into(),
                                Some(lua.create_function(set_y)),
                                Some(lua.create_function(get_y)),
                                Some(lua.create_function(set_y))))?
        .property(Property::new("width".into(),
                                Some(lua.create_function(set_width)),
                                Some(lua.create_function(get_width)),
                                Some(lua.create_function(set_width))))?
        .property(Property::new("height".into(),
                                Some(lua.create_function(set_height)),
                                Some(lua.create_function(get_height)),
                                Some(lua.create_function(set_height))))?
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    table.set("struts", lua.create_function(drawin_struts))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Option<Table<'lua>>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    if let Some(geometry) = geometry {
        let w = geometry.get::<_, i32>("width")?;
        let h = geometry.get::<_, i32>("height")?;
        let x = geometry.get::<_, i32>("x")?;
        let y = geometry.get::<_, i32>("y")?;
        if x > 0 && y > 0 {
            let geo = Geometry {
                origin: Point { x, y },
                size: Size { w: w as u32, h: h as u32 }
            };
            drawin.resize(geo)?;
        }
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}

fn get_x<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { x, .. } = drawin.get_geometry()?.origin;
    Ok(x as LuaInteger)
}

fn set_x<'lua>(_: &'lua Lua, (drawin, x): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.x = x as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_y<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { y, .. } = drawin.get_geometry()?.origin;
    Ok(y as LuaInteger)
}

fn set_y<'lua>(_: &'lua Lua, (drawin, y): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.y = y as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_width<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { w, .. } = drawin.get_geometry()?.size;
    Ok(w as LuaInteger)
}

fn set_width<'lua>(_: &'lua Lua, (drawin, width): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if width > 0 {
        geo.size.w = width as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}

fn get_height<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { h, .. } = drawin.get_geometry()?.size;
    Ok(h as LuaInteger)
}

fn set_height<'lua>(_: &'lua Lua, (drawin, height): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if height > 0 {
        geo.size.h = height as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}

fn drawin_struts<'lua>(lua: &'lua Lua, _drawin: Table<'lua>) -> rlua::Result<Table<'lua>> {
    // TODO: Implement this properly. Struts means this drawin reserves some space on the screen
    // that it is visible on, shrinking the workarea in the specified directions.
    let res = lua.create_table();
    res.set("left", 0)?;
    res.set("right", 0)?;
    res.set("top", 0)?;
    res.set("bottom", 0)?;
    Ok(res)
}
<commit_msg>Fix drawin_geometry() to behave like in awesome<commit_after>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use rlua::prelude::LuaInteger;
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

impl Display for DrawinState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawin: {:p}", self)
    }
}

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, "drawin", Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
            // TODO This should be adding properties, e.g like luaA_class_new
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("x".into(),
                                Some(lua.create_function(set_x)),
                                Some(lua.create_function(get_x)),
                                Some(lua.create_function(set_x))))?
        .property(Property::new("y".into(),
                                Some(lua.create_function(set_y)),
                                Some(lua.create_function(get_y)),
                                Some(lua.create_function(set_y))))?
        .property(Property::new("width".into(),
                                Some(lua.create_function(set_width)),
                                Some(lua.create_function(get_width)),
                                Some(lua.create_function(set_width))))?
        .property(Property::new("height".into(),
                                Some(lua.create_function(set_height)),
                                Some(lua.create_function(get_height)),
                                Some(lua.create_function(set_height))))?
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    table.set("struts", lua.create_function(drawin_struts))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Option<Table<'lua>>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    if let Some(geometry) = geometry {
        let w = geometry.get::<_, i32>("width")?;
        let h = geometry.get::<_, i32>("height")?;
        let x = geometry.get::<_, i32>("x")?;
        let y = geometry.get::<_, i32>("y")?;
        if w > 0 && h > 0 {
            let geo = Geometry {
                origin: Point { x, y },
                size: Size { w: w as u32, h: h as u32 }
            };
            drawin.resize(geo)?;
        }
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}

fn get_x<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { x, .. } = drawin.get_geometry()?.origin;
    Ok(x as LuaInteger)
}

fn set_x<'lua>(_: &'lua Lua, (drawin, x): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.x = x as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_y<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Point { y, .. } = drawin.get_geometry()?.origin;
    Ok(y as LuaInteger)
}

fn set_y<'lua>(_: &'lua Lua, (drawin, y): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    geo.origin.y = y as i32;
    drawin.resize(geo)?;
    Ok(())
}

fn get_width<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { w, .. } = drawin.get_geometry()?.size;
    Ok(w as LuaInteger)
}

fn set_width<'lua>(_: &'lua Lua, (drawin, width): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if width > 0 {
        geo.size.w = width as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}

fn get_height<'lua>(_: &'lua Lua, drawin: Table<'lua>) -> rlua::Result<LuaInteger> {
    let drawin = Drawin::cast(drawin.into())?;
    let Size { h, .. } = drawin.get_geometry()?.size;
    Ok(h as LuaInteger)
}

fn set_height<'lua>(_: &'lua Lua, (drawin, height): (Table<'lua>, LuaInteger)) -> rlua::Result<()> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let mut geo = drawin.get_geometry()?;
    if height > 0 {
        geo.size.h = height as u32;
        drawin.resize(geo)?;
    }
    Ok(())
}

fn drawin_struts<'lua>(lua: &'lua Lua, _drawin: Table<'lua>) -> rlua::Result<Table<'lua>> {
    // TODO: Implement this properly. Struts means this drawin reserves some space on the screen
    // that it is visible on, shrinking the workarea in the specified directions.
    let res = lua.create_table();
    res.set("left", 0)?;
    res.set("right", 0)?;
    res.set("top", 0)?;
    res.set("bottom", 0)?;
    Ok(res)
}
<|endoftext|>


<commit_before>use core as _core;

#[doc(hidden)]
pub trait ImplementedByBitFlagsMacro {}

/// A flags enum.
///
/// Manual implementations of this trait are not supported.
/// It should only be automatically implemented through the `bitflags!` macro.
pub trait BitFlags: ImplementedByBitFlagsMacro {
    type Bits;
    /// Returns an empty set of flags.
    fn empty() -> Self;
    /// Returns the set containing all flags.
    fn all() -> Self;
    /// Returns the raw value of the flags currently stored.
    fn bits(&self) -> Self::Bits;
    /// Convert from underlying bit representation, unless that
    /// representation contains bits that do not correspond to a flag.
    fn from_bits(bits: Self::Bits) -> _core::option::Option<Self>
    where Self: Sized;
    /// Convert from underlying bit representation, dropping any bits
    /// that do not correspond to flags.
    fn from_bits_truncate(bits: Self::Bits) -> Self;
    /// Convert from underlying bit representation, preserving all
    /// bits (even those not corresponding to a defined flag).
    ///
    /// # Safety
    ///
    /// The caller of the `bitflags!` macro can chose to allow or
    /// disallow extra bits for their bitflags type.
    ///
    /// The caller of `from_bits_unchecked()` has to ensure that
    /// all bits correspond to a defined flag or that extra bits
    /// are valid for this bitflags type.
    unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self;
    /// Returns `true` if no flags are currently stored.
    fn is_empty(&self) -> bool;
    /// Returns `true` if all flags are currently set.
    fn is_all(&self) -> bool;
    /// Returns `true` if there are flags common to both `self` and `other`.
    fn intersects(&self, other: Self) -> bool;
    /// Returns `true` all of the flags in `other` are contained within `self`.
    fn contains(&self, other: Self) -> bool;
    /// Inserts the specified flags in-place.
    fn insert(&mut self, other: Self);
    /// Removes the specified flags in-place.
    fn remove(&mut self, other: Self);
    /// Toggles the specified flags in-place.
    fn toggle(&mut self, other: Self);
    /// Inserts or removes the specified flags depending on the passed value.
    fn set(&mut self, other: Self, value: bool);
}
<commit_msg>update docs for BitFlags<commit_after>use core as _core;

#[doc(hidden)]
pub trait ImplementedByBitFlagsMacro {}

/// A trait that is automatically implemented for all bitflags.
///
/// It should not be implemented manually.
pub trait BitFlags: ImplementedByBitFlagsMacro {
    type Bits;
    /// Returns an empty set of flags.
    fn empty() -> Self;
    /// Returns the set containing all flags.
    fn all() -> Self;
    /// Returns the raw value of the flags currently stored.
    fn bits(&self) -> Self::Bits;
    /// Convert from underlying bit representation, unless that
    /// representation contains bits that do not correspond to a flag.
    fn from_bits(bits: Self::Bits) -> _core::option::Option<Self>
    where Self: Sized;
    /// Convert from underlying bit representation, dropping any bits
    /// that do not correspond to flags.
    fn from_bits_truncate(bits: Self::Bits) -> Self;
    /// Convert from underlying bit representation, preserving all
    /// bits (even those not corresponding to a defined flag).
    ///
    /// # Safety
    ///
    /// The caller of the `bitflags!` macro can chose to allow or
    /// disallow extra bits for their bitflags type.
    ///
    /// The caller of `from_bits_unchecked()` has to ensure that
    /// all bits correspond to a defined flag or that extra bits
    /// are valid for this bitflags type.
    unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self;
    /// Returns `true` if no flags are currently stored.
    fn is_empty(&self) -> bool;
    /// Returns `true` if all flags are currently set.
    fn is_all(&self) -> bool;
    /// Returns `true` if there are flags common to both `self` and `other`.
    fn intersects(&self, other: Self) -> bool;
    /// Returns `true` all of the flags in `other` are contained within `self`.
    fn contains(&self, other: Self) -> bool;
    /// Inserts the specified flags in-place.
    fn insert(&mut self, other: Self);
    /// Removes the specified flags in-place.
    fn remove(&mut self, other: Self);
    /// Toggles the specified flags in-place.
    fn toggle(&mut self, other: Self);
    /// Inserts or removes the specified flags depending on the passed value.
    fn set(&mut self, other: Self, value: bool);
}
<|endoftext|>


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

//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain existential
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
//! contain revealed `impl Trait` values).

use borrow_check::nll::renumber;
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferOk;
use rustc::ty::Ty;
use rustc::ty::subst::Subst;
use rustc::mir::*;
use rustc::mir::visit::TyContext;
use rustc::traits::PredicateObligations;

use rustc_data_structures::indexed_vec::Idx;

use super::{AtLocation, TypeChecker};

impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        mir: &Mir<'tcx>,
        mir_def_id: DefId,
        universal_regions: &UniversalRegions<'tcx>,
    ) {
        let tcx = self.infcx.tcx;

        let &UniversalRegions {
            unnormalized_output_ty,
            unnormalized_input_tys,
            ..
        } = universal_regions;
        let infcx = self.infcx;

        let start_position = Location {
            block: START_BLOCK,
            statement_index: 0,
        };

        // Equate expected input tys with those in the MIR.
        let argument_locals = (1..).map(Local::new);
        for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) {
            let input_ty = self.normalize(&unnormalized_input_ty, start_position);
            let mir_input_ty = mir.local_decls[local].ty;
            self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
        }

        // Return types are a bit more complex. They may contain existential `impl Trait`
        // types.
        debug!(
            "equate_inputs_and_outputs: unnormalized_output_ty={:?}",
            unnormalized_output_ty
        );
        let output_ty = self.normalize(&unnormalized_output_ty, start_position);
        debug!(
            "equate_inputs_and_outputs: normalized output_ty={:?}",
            output_ty
        );
        let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
        let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
            let mut obligations = ObligationAccumulator::default();

            let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
                mir_def_id,
                cx.body_id,
                cx.param_env,
                &output_ty,
            ));
            debug!(
                "equate_inputs_and_outputs: instantiated output_ty={:?}",
                output_ty
            );
            debug!(
                "equate_inputs_and_outputs: anon_type_map={:#?}",
                anon_type_map
            );

            debug!(
                "equate_inputs_and_outputs: mir_output_ty={:?}",
                mir_output_ty
            );
            obligations.add(infcx
                .at(&cx.misc(cx.last_span), cx.param_env)
                .eq(output_ty, mir_output_ty)?);

            for (&anon_def_id, anon_decl) in &anon_type_map {
                let anon_defn_ty = tcx.type_of(anon_def_id);
                let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
                let anon_defn_ty = renumber::renumber_regions(
                    cx.infcx,
                    TyContext::Location(start_position),
                    &anon_defn_ty,
                );
                debug!(
                    "equate_inputs_and_outputs: concrete_ty={:?}",
                    anon_decl.concrete_ty
                );
                debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
                obligations.add(infcx
                    .at(&cx.misc(cx.last_span), cx.param_env)
                    .eq(anon_decl.concrete_ty, anon_defn_ty)?);
            }

            debug!("equate_inputs_and_outputs: equated");

            Ok(InferOk {
                value: Some(anon_type_map),
                obligations: obligations.into_vec(),
            })
        }).unwrap_or_else(|terr| {
                span_mirbug!(
                    self,
                    start_position,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    output_ty,
                    mir_output_ty,
                    terr
                );
                None
            });

        // Finally
        if let Some(anon_type_map) = anon_type_map {
            self.fully_perform_op(start_position.at_self(), |_cx| {
                infcx.constrain_anon_types(&anon_type_map, universal_regions);
                Ok(InferOk {
                    value: (),
                    obligations: vec![],
                })
            }).unwrap();
        }
    }

    fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) = self.eq_types(a, b, location.at_self()) {
            span_mirbug!(
                self,
                location,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}

#[derive(Debug, Default)]
struct ObligationAccumulator<'tcx> {
    obligations: PredicateObligations<'tcx>,
}

impl<'tcx> ObligationAccumulator<'tcx> {
    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
        let InferOk { value, obligations } = value;
        self.obligations.extend(obligations);
        value
    }

    fn into_vec(self) -> PredicateObligations<'tcx> {
        self.obligations
    }
}
<commit_msg>fix truncated comment<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain existential
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
//! contain revealed `impl Trait` values).

use borrow_check::nll::renumber;
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferOk;
use rustc::ty::Ty;
use rustc::ty::subst::Subst;
use rustc::mir::*;
use rustc::mir::visit::TyContext;
use rustc::traits::PredicateObligations;

use rustc_data_structures::indexed_vec::Idx;

use super::{AtLocation, TypeChecker};

impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        mir: &Mir<'tcx>,
        mir_def_id: DefId,
        universal_regions: &UniversalRegions<'tcx>,
    ) {
        let tcx = self.infcx.tcx;

        let &UniversalRegions {
            unnormalized_output_ty,
            unnormalized_input_tys,
            ..
        } = universal_regions;
        let infcx = self.infcx;

        let start_position = Location {
            block: START_BLOCK,
            statement_index: 0,
        };

        // Equate expected input tys with those in the MIR.
        let argument_locals = (1..).map(Local::new);
        for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) {
            let input_ty = self.normalize(&unnormalized_input_ty, start_position);
            let mir_input_ty = mir.local_decls[local].ty;
            self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
        }

        // Return types are a bit more complex. They may contain existential `impl Trait`
        // types.
        debug!(
            "equate_inputs_and_outputs: unnormalized_output_ty={:?}",
            unnormalized_output_ty
        );
        let output_ty = self.normalize(&unnormalized_output_ty, start_position);
        debug!(
            "equate_inputs_and_outputs: normalized output_ty={:?}",
            output_ty
        );
        let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
        let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
            let mut obligations = ObligationAccumulator::default();

            let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
                mir_def_id,
                cx.body_id,
                cx.param_env,
                &output_ty,
            ));
            debug!(
                "equate_inputs_and_outputs: instantiated output_ty={:?}",
                output_ty
            );
            debug!(
                "equate_inputs_and_outputs: anon_type_map={:#?}",
                anon_type_map
            );

            debug!(
                "equate_inputs_and_outputs: mir_output_ty={:?}",
                mir_output_ty
            );
            obligations.add(infcx
                .at(&cx.misc(cx.last_span), cx.param_env)
                .eq(output_ty, mir_output_ty)?);

            for (&anon_def_id, anon_decl) in &anon_type_map {
                let anon_defn_ty = tcx.type_of(anon_def_id);
                let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
                let anon_defn_ty = renumber::renumber_regions(
                    cx.infcx,
                    TyContext::Location(start_position),
                    &anon_defn_ty,
                );
                debug!(
                    "equate_inputs_and_outputs: concrete_ty={:?}",
                    anon_decl.concrete_ty
                );
                debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
                obligations.add(infcx
                    .at(&cx.misc(cx.last_span), cx.param_env)
                    .eq(anon_decl.concrete_ty, anon_defn_ty)?);
            }

            debug!("equate_inputs_and_outputs: equated");

            Ok(InferOk {
                value: Some(anon_type_map),
                obligations: obligations.into_vec(),
            })
        }).unwrap_or_else(|terr| {
                span_mirbug!(
                    self,
                    start_position,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    output_ty,
                    mir_output_ty,
                    terr
                );
                None
            });

        // Finally, if we instantiated the anon types successfully, we
        // have to solve any bounds (e.g., `-> impl Iterator` needs to
        // prove that `T: Iterator` where `T` is the type we
        // instantiated it with).
        if let Some(anon_type_map) = anon_type_map {
            self.fully_perform_op(start_position.at_self(), |_cx| {
                infcx.constrain_anon_types(&anon_type_map, universal_regions);
                Ok(InferOk {
                    value: (),
                    obligations: vec![],
                })
            }).unwrap();
        }
    }

    fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) = self.eq_types(a, b, location.at_self()) {
            span_mirbug!(
                self,
                location,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}

#[derive(Debug, Default)]
struct ObligationAccumulator<'tcx> {
    obligations: PredicateObligations<'tcx>,
}

impl<'tcx> ObligationAccumulator<'tcx> {
    fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
        let InferOk { value, obligations } = value;
        self.obligations.extend(obligations);
        value
    }

    fn into_vec(self) -> PredicateObligations<'tcx> {
        self.obligations
    }
}
<|endoftext|>