<commit_before>use std::{cmp::Ordering, convert::TryFrom};

use wayland_protocols::wlr::unstable::layer_shell::v1::server::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};

/// Available layers for surfaces
///
/// These values indicate which layers a surface can be rendered in.
/// They are ordered by z depth, bottom-most first.
/// Traditional shell surfaces will typically be rendered between the bottom and top layers.
/// Fullscreen shell surfaces are typically rendered at the top layer.
/// Multiple surfaces can share a single layer, and ordering within a single layer is undefined.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Layer {
    /// The lowest layer, used usualy for wallpapers
    Background,
    /// The layer bellow the windows and above the wallpaper
    Bottom,
    /// The layer above the windows and bellow overlay
    Top,
    /// The top layer above all other layers
    Overlay,
}

impl TryFrom<zwlr_layer_shell_v1::Layer> for Layer {
    type Error = (zwlr_layer_shell_v1::Error, String);

    fn try_from(layer: zwlr_layer_shell_v1::Layer) -> Result<Self, Self::Error> {
        match layer {
            zwlr_layer_shell_v1::Layer::Background => Ok(Self::Background),
            zwlr_layer_shell_v1::Layer::Bottom => Ok(Self::Bottom),
            zwlr_layer_shell_v1::Layer::Top => Ok(Self::Top),
            zwlr_layer_shell_v1::Layer::Overlay => Ok(Self::Overlay),
            _ => Err((
                zwlr_layer_shell_v1::Error::InvalidLayer,
                format!("invalid layer: {:?}", layer),
            )),
        }
    }
}

impl Default for Layer {
    fn default() -> Self {
        Self::Background
    }
}

/// Types of keyboard interaction possible for a layer shell surface
///
/// The rationale for this is twofold:
/// - some applications are not interested in keyboard events
///   and not allowing them to be focused can improve the desktop experience
/// - some applications will want to take exclusive keyboard focus.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyboardInteractivity {
    /// This value indicates that this surface is not interested in keyboard events
    /// and the compositor should never assign it the keyboard focus.
    ///
    /// This is the default value, set for newly created layer shell surfaces.
    ///
    /// This is useful for e.g. desktop widgets that display information
    /// or only have interaction with non-keyboard input devices.
    None,
    /// Request exclusive keyboard focus if this surface is above the shell surface layer.
    ///
    /// For the top and overlay layers, the seat will always give exclusive keyboard focus
    /// to the top-most layer which has keyboard interactivity set to exclusive.
    /// If this layer contains multiple surfaces with keyboard interactivity set to exclusive,
    /// the compositor determines the one receiving keyboard events in an implementation- defined manner.
    /// In this case, no guarantee is made when this surface will receive keyboard focus (if ever).
    ///
    /// For the bottom and background layers, the compositor is allowed to use normal focus semantics.
    ///
    /// This setting is mainly intended for applications that need to
    /// ensure they receive all keyboard events, such as a lock screen or a password prompt.
    Exclusive,
    /// This requests the compositor to allow this surface
    /// to be focused and unfocused by the user in an implementation-defined manner.
    /// The user should be able to unfocus this surface even regardless of the layer it is on.
    ///
    /// Typically, the compositor will want to use its normal mechanism
    /// to manage keyboard focus between layer shell surfaces
    /// with this setting and regular toplevels on the desktop layer (e.g. click to focus).
    /// Nevertheless, it is possible for a compositor to require a special interaction
    /// to focus or unfocus layer shell surfaces
    ///
    /// This setting is mainly intended for desktop shell components that allow keyboard interaction.
    /// Using this option can allow implementing a desktop shell that can be fully usable without the mouse.
    OnDemand,
}

impl Default for KeyboardInteractivity {
    fn default() -> Self {
        Self::None
    }
}

impl TryFrom<zwlr_layer_surface_v1::KeyboardInteractivity> for KeyboardInteractivity {
    type Error = (zwlr_layer_surface_v1::Error, String);

    fn try_from(ki: zwlr_layer_surface_v1::KeyboardInteractivity) -> Result<Self, Self::Error> {
        match ki {
            zwlr_layer_surface_v1::KeyboardInteractivity::None => Ok(Self::None),
            zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive => Ok(Self::Exclusive),
            zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand => Ok(Self::OnDemand),
            _ => Err((
                zwlr_layer_surface_v1::Error::InvalidKeyboardInteractivity,
                format!("wrong keyboard interactivity value: {:?}", ki),
            )),
        }
    }
}

bitflags::bitflags! {
    /// Anchor bitflags, describing how the layers surface should be positioned and sized
    pub struct Anchor: u32 {
        /// The top edge of the anchor rectangle
        const TOP = 1;
        /// The bottom edge of the anchor rectangle
        const BOTTOM = 2;
        /// The left edge of the anchor rectangle
        const LEFT = 4;
        /// The right edge of the anchor rectangle
        const RIGHT = 8;
    }
}

impl Anchor {
    /// Check if anchored horizontally
    ///
    /// If it is anchored to `left` and `right` anchor at the same time
    /// it returns `true`
    pub fn anchored_horizontally(&self) -> bool {
        self.contains(Self::LEFT) && self.contains(Self::RIGHT)
    }
    /// Check if anchored vertically
    ///
    /// If it is anchored to `top` and `bottom` anchor at the same time
    /// it returns `true`
    pub fn anchored_vertically(&self) -> bool {
        self.contains(Self::TOP) && self.contains(Self::BOTTOM)
    }
}

impl Default for Anchor {
    fn default() -> Self {
        Self::empty()
    }
}

impl TryFrom<zwlr_layer_surface_v1::Anchor> for Anchor {
    type Error = (zwlr_layer_surface_v1::Error, String);

    fn try_from(anchor: zwlr_layer_surface_v1::Anchor) -> Result<Self, Self::Error> {
        match Anchor::from_bits(anchor.bits()) {
            Some(a) => Ok(a),
            _ => Err((
                zwlr_layer_surface_v1::Error::InvalidAnchor,
                format!("invalid anchor {:?}", anchor),
            )),
        }
    }
}

/// Exclusive zone descriptor
#[derive(Debug, Clone, Copy)]
pub enum ExclusiveZone {
    /// Requests that the compositor avoids occluding an area with other surfaces.
    ///
    /// A exclusive zone value is the distance from the edge in surface-local coordinates to consider exclusive.
    ///
    /// A exclusive value is only meaningful if the surface is
    /// anchored to one edge or an edge and both perpendicular edges.
    ///
    /// If the surface is:
    /// - not anchored
    /// - anchored to only two perpendicular edges (a corner),
    /// - anchored to only two parallel edges or anchored to all edges,
    ///
    /// The exclusive value should be treated the same as [`ExclusiveZone::Neutral`].
    Exclusive(u32),
    /// If set to Neutral,
    /// the surface indicates that it would like to be moved to avoid occluding surfaces with a exclusive zone.
    Neutral,
    /// If set to DontCare,
    /// the surface indicates that it would not like to be moved to accommodate for other surfaces,
    /// and the compositor should extend it all the way to the edges it is anchored to.
    DontCare,
}

impl Default for ExclusiveZone {
    fn default() -> Self {
        Self::Neutral
    }
}

impl From<i32> for ExclusiveZone {
    fn from(v: i32) -> Self {
        match v.cmp(&0) {
            Ordering::Greater => Self::Exclusive(v as u32),
            Ordering::Equal => Self::Neutral,
            Ordering::Less => Self::DontCare,
        }
    }
}

impl From<ExclusiveZone> for i32 {
    fn from(z: ExclusiveZone) -> i32 {
        match z {
            ExclusiveZone::Exclusive(v) => v as i32,
            ExclusiveZone::Neutral => 0,
            ExclusiveZone::DontCare => -1,
        }
    }
}

/// Describes distance from the anchor point of the output, in surface-local coordinates.
///
/// If surface did not anchor curtain edge, margin for that edge should be ignored.
///
/// The exclusive zone should includes the margins.
#[derive(Debug, Default, Clone, Copy)]
pub struct Margins {
    /// Distance from [`Anchor::TOP`]
    pub top: i32,
    /// Distance from [`Anchor::TOP`]
    pub right: i32,
    /// Distance from [`Anchor::BOTTOM`]
    pub bottom: i32,
    /// Distance from [`Anchor::LEFT`]
    pub left: i32,
}
<commit_msg>Add PartialEq/Eq implementation for ExclusiveZone<commit_after>use std::{cmp::Ordering, convert::TryFrom};

use wayland_protocols::wlr::unstable::layer_shell::v1::server::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};

/// Available layers for surfaces
///
/// These values indicate which layers a surface can be rendered in.
/// They are ordered by z depth, bottom-most first.
/// Traditional shell surfaces will typically be rendered between the bottom and top layers.
/// Fullscreen shell surfaces are typically rendered at the top layer.
/// Multiple surfaces can share a single layer, and ordering within a single layer is undefined.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Layer {
    /// The lowest layer, used usualy for wallpapers
    Background,
    /// The layer bellow the windows and above the wallpaper
    Bottom,
    /// The layer above the windows and bellow overlay
    Top,
    /// The top layer above all other layers
    Overlay,
}

impl TryFrom<zwlr_layer_shell_v1::Layer> for Layer {
    type Error = (zwlr_layer_shell_v1::Error, String);

    fn try_from(layer: zwlr_layer_shell_v1::Layer) -> Result<Self, Self::Error> {
        match layer {
            zwlr_layer_shell_v1::Layer::Background => Ok(Self::Background),
            zwlr_layer_shell_v1::Layer::Bottom => Ok(Self::Bottom),
            zwlr_layer_shell_v1::Layer::Top => Ok(Self::Top),
            zwlr_layer_shell_v1::Layer::Overlay => Ok(Self::Overlay),
            _ => Err((
                zwlr_layer_shell_v1::Error::InvalidLayer,
                format!("invalid layer: {:?}", layer),
            )),
        }
    }
}

impl Default for Layer {
    fn default() -> Self {
        Self::Background
    }
}

/// Types of keyboard interaction possible for a layer shell surface
///
/// The rationale for this is twofold:
/// - some applications are not interested in keyboard events
///   and not allowing them to be focused can improve the desktop experience
/// - some applications will want to take exclusive keyboard focus.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyboardInteractivity {
    /// This value indicates that this surface is not interested in keyboard events
    /// and the compositor should never assign it the keyboard focus.
    ///
    /// This is the default value, set for newly created layer shell surfaces.
    ///
    /// This is useful for e.g. desktop widgets that display information
    /// or only have interaction with non-keyboard input devices.
    None,
    /// Request exclusive keyboard focus if this surface is above the shell surface layer.
    ///
    /// For the top and overlay layers, the seat will always give exclusive keyboard focus
    /// to the top-most layer which has keyboard interactivity set to exclusive.
    /// If this layer contains multiple surfaces with keyboard interactivity set to exclusive,
    /// the compositor determines the one receiving keyboard events in an implementation- defined manner.
    /// In this case, no guarantee is made when this surface will receive keyboard focus (if ever).
    ///
    /// For the bottom and background layers, the compositor is allowed to use normal focus semantics.
    ///
    /// This setting is mainly intended for applications that need to
    /// ensure they receive all keyboard events, such as a lock screen or a password prompt.
    Exclusive,
    /// This requests the compositor to allow this surface
    /// to be focused and unfocused by the user in an implementation-defined manner.
    /// The user should be able to unfocus this surface even regardless of the layer it is on.
    ///
    /// Typically, the compositor will want to use its normal mechanism
    /// to manage keyboard focus between layer shell surfaces
    /// with this setting and regular toplevels on the desktop layer (e.g. click to focus).
    /// Nevertheless, it is possible for a compositor to require a special interaction
    /// to focus or unfocus layer shell surfaces
    ///
    /// This setting is mainly intended for desktop shell components that allow keyboard interaction.
    /// Using this option can allow implementing a desktop shell that can be fully usable without the mouse.
    OnDemand,
}

impl Default for KeyboardInteractivity {
    fn default() -> Self {
        Self::None
    }
}

impl TryFrom<zwlr_layer_surface_v1::KeyboardInteractivity> for KeyboardInteractivity {
    type Error = (zwlr_layer_surface_v1::Error, String);

    fn try_from(ki: zwlr_layer_surface_v1::KeyboardInteractivity) -> Result<Self, Self::Error> {
        match ki {
            zwlr_layer_surface_v1::KeyboardInteractivity::None => Ok(Self::None),
            zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive => Ok(Self::Exclusive),
            zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand => Ok(Self::OnDemand),
            _ => Err((
                zwlr_layer_surface_v1::Error::InvalidKeyboardInteractivity,
                format!("wrong keyboard interactivity value: {:?}", ki),
            )),
        }
    }
}

bitflags::bitflags! {
    /// Anchor bitflags, describing how the layers surface should be positioned and sized
    pub struct Anchor: u32 {
        /// The top edge of the anchor rectangle
        const TOP = 1;
        /// The bottom edge of the anchor rectangle
        const BOTTOM = 2;
        /// The left edge of the anchor rectangle
        const LEFT = 4;
        /// The right edge of the anchor rectangle
        const RIGHT = 8;
    }
}

impl Anchor {
    /// Check if anchored horizontally
    ///
    /// If it is anchored to `left` and `right` anchor at the same time
    /// it returns `true`
    pub fn anchored_horizontally(&self) -> bool {
        self.contains(Self::LEFT) && self.contains(Self::RIGHT)
    }
    /// Check if anchored vertically
    ///
    /// If it is anchored to `top` and `bottom` anchor at the same time
    /// it returns `true`
    pub fn anchored_vertically(&self) -> bool {
        self.contains(Self::TOP) && self.contains(Self::BOTTOM)
    }
}

impl Default for Anchor {
    fn default() -> Self {
        Self::empty()
    }
}

impl TryFrom<zwlr_layer_surface_v1::Anchor> for Anchor {
    type Error = (zwlr_layer_surface_v1::Error, String);

    fn try_from(anchor: zwlr_layer_surface_v1::Anchor) -> Result<Self, Self::Error> {
        match Anchor::from_bits(anchor.bits()) {
            Some(a) => Ok(a),
            _ => Err((
                zwlr_layer_surface_v1::Error::InvalidAnchor,
                format!("invalid anchor {:?}", anchor),
            )),
        }
    }
}

/// Exclusive zone descriptor
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExclusiveZone {
    /// Requests that the compositor avoids occluding an area with other surfaces.
    ///
    /// A exclusive zone value is the distance from the edge in surface-local coordinates to consider exclusive.
    ///
    /// A exclusive value is only meaningful if the surface is
    /// anchored to one edge or an edge and both perpendicular edges.
    ///
    /// If the surface is:
    /// - not anchored
    /// - anchored to only two perpendicular edges (a corner),
    /// - anchored to only two parallel edges or anchored to all edges,
    ///
    /// The exclusive value should be treated the same as [`ExclusiveZone::Neutral`].
    Exclusive(u32),
    /// If set to Neutral,
    /// the surface indicates that it would like to be moved to avoid occluding surfaces with a exclusive zone.
    Neutral,
    /// If set to DontCare,
    /// the surface indicates that it would not like to be moved to accommodate for other surfaces,
    /// and the compositor should extend it all the way to the edges it is anchored to.
    DontCare,
}

impl Default for ExclusiveZone {
    fn default() -> Self {
        Self::Neutral
    }
}

impl From<i32> for ExclusiveZone {
    fn from(v: i32) -> Self {
        match v.cmp(&0) {
            Ordering::Greater => Self::Exclusive(v as u32),
            Ordering::Equal => Self::Neutral,
            Ordering::Less => Self::DontCare,
        }
    }
}

impl From<ExclusiveZone> for i32 {
    fn from(z: ExclusiveZone) -> i32 {
        match z {
            ExclusiveZone::Exclusive(v) => v as i32,
            ExclusiveZone::Neutral => 0,
            ExclusiveZone::DontCare => -1,
        }
    }
}

/// Describes distance from the anchor point of the output, in surface-local coordinates.
///
/// If surface did not anchor curtain edge, margin for that edge should be ignored.
///
/// The exclusive zone should includes the margins.
#[derive(Debug, Default, Clone, Copy)]
pub struct Margins {
    /// Distance from [`Anchor::TOP`]
    pub top: i32,
    /// Distance from [`Anchor::TOP`]
    pub right: i32,
    /// Distance from [`Anchor::BOTTOM`]
    pub bottom: i32,
    /// Distance from [`Anchor::LEFT`]
    pub left: i32,
}
<|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};
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, <= 32767)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 32767)")]
  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),
  /// 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),

  /// 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.width < 16 || config.width > u16::max_value() as usize {
      return Err(InvalidWidth(config.width));
    }
    if 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,
      ));
    }

    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 delay < 12 || delay > 131_072 {
        return Err(InvalidReservoirFrameDelay(delay));
      }
    }

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

    // 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>Detect invalid use of enable_timing_info with still_picture<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};
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, <= 32767)")]
  InvalidWidth(usize),
  /// The height is invalid.
  #[error("invalid height {0} (expected >= 16, <= 32767)")]
  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),
  /// 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.width < 16 || config.width > u16::max_value() as usize {
      return Err(InvalidWidth(config.width));
    }
    if 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,
      ));
    }

    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 delay < 12 || delay > 131_072 {
        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(())
  }
}
<|endoftext|>


<commit_before>extern crate bitcoin;
extern crate secp256k1;
extern crate rand;
extern crate regex;
#[macro_use] extern crate clap;

use secp256k1::{Secp256k1, ContextFlag};
use secp256k1::key::{PublicKey, SecretKey};
use bitcoin::util::address::{Address, Privkey};
use bitcoin::network::constants::Network;
use bitcoin::util::base58::ToBase58;
use rand::{thread_rng};
use regex::Regex;

fn main() {
    // command line arguments and help
    let matches = clap_app!(genaddress =>
            (version: "1.0")
            (author: "Ilya E. <erik.lite@gmail.com>, Sergei K. <sergant_chern@mail.ru")
            (about: "Generates random Bitcoin address (base58 encoded) and corresponding private key (also base58).")
            (@arg attempts: -a +takes_value "Sets the maximum number of keypairs to be generated during search")
            (@arg pattern: -p +takes_value "Specifies regular expression to be matched agains address string")
            (@arg verbose: -v --verbose "Outputs generated addresses during search")
        ).get_matches();

    // extract arguments
    let attempts: i64 = matches.value_of("attempts").unwrap_or("0").parse().unwrap_or(0);
    let pattern = matches.value_of("pattern").unwrap_or(r"*");
    let is_verbose = matches.is_present("verbose");
    let re = Regex::new(pattern).unwrap();
    let network = Network::Bitcoin;
    let compressed = false;

    // let's generate private\public keypairs until we find a match
    println!("Searching for address that matches the following pattern: {}", pattern);
    let secp = Secp256k1::with_caps(ContextFlag::SignOnly);

    // infinite loop
    let mut i : i64 = 0; // number of attempts made so far
    loop {
        // generate keypair from secp256k1 elliptic curve
        let sk = SecretKey::new(&secp, &mut thread_rng());
        let pk = PublicKey::from_secret_key(&secp, &sk).expect("Failed to create public key");

        // convert public key to Bitcoin address and private key to base58
        let address = Address::from_key(network, &pk, compressed);
        let privkey = Privkey::from_key(network, sk, compressed);
        let address_base58str = address.to_base58check();

        //Output number of attempts and addresses generated in verbose mode
        if is_verbose { println!("{} : {:?}", i, base58str) };

        // Search for desired pattern
        if re.is_match(&address_base58str) {
            println!("Match was found for address {} and private key {}",
             address_base58str,
             privkey.to_base58check());
            break;
        }

        // Maximum number of attempts check
        i = i + 1;
        if i == attempts {
            // Unsuccessfull search
            println!("Match was not found! Try again later.");
            break ;
        };
    }
}
<commit_msg>Implemented -truncate option<commit_after>extern crate bitcoin;
extern crate secp256k1;
extern crate rand;
extern crate regex;
#[macro_use] extern crate clap;

use secp256k1::{Secp256k1, ContextFlag};
use secp256k1::key::{PublicKey, SecretKey};
use bitcoin::util::address::{Address, Privkey};
use bitcoin::network::constants::Network;
use bitcoin::util::base58::ToBase58;
use rand::{thread_rng};
use regex::Regex;

fn main() {
    // command line arguments and help
    let matches = clap_app!(genaddress =>
            (version: "1.0")
            (author: "Ilya E. <erik.lite@gmail.com>, Sergei K. <sergant_chern@mail.ru")
            (about: "Generates random Bitcoin address (base58 encoded) and corresponding private key (base58 encoded)")
            (@arg attempts: -a +takes_value "Sets the maximum number of keypairs to be generated during search")
            (@arg pattern: -p +takes_value "Specifies regular expression to be matched against address string")
            (@arg truncate: -t +takes_value "Truncate address string to given lenght and match only first symbols")
            (@arg verbose: -v --verbose "Outputs generated addresses during search")
        ).get_matches();

    // extract arguments
    let attempts: i64 = matches.value_of("attempts").unwrap_or("0").parse().unwrap_or(0);
    let truncate: usize = matches.value_of("truncate").unwrap_or("0").parse().unwrap_or(0);
    let pattern = matches.value_of("pattern").unwrap_or(r"*");
    let is_verbose = matches.is_present("verbose");
    let re = Regex::new(pattern).unwrap();
    let network = Network::Bitcoin;
    let compressed = false;

    // let's generate private\public keypairs until we find a match
    println!("Searching for address that matches the following pattern: {}", pattern);
    let secp = Secp256k1::with_caps(ContextFlag::SignOnly);

    // infinite loop
    let mut i : i64 = 0; // number of attempts made so far
    loop {
        // generate keypair from secp256k1 elliptic curve
        let sk = SecretKey::new(&secp, &mut thread_rng());
        let pk = PublicKey::from_secret_key(&secp, &sk).expect("Failed to create public key");

        // convert public key to Bitcoin address and private key to base58
        let address = Address::from_key(network, &pk, compressed);
        let privkey = Privkey::from_key(network, sk, compressed);
        let mut address_base58str = address.to_base58check();

        //Output number of attempts and addresses generated in verbose mode
        if is_verbose { println!("{} : {:?}", i, address_base58str) };

        // Search for desired pattern and truncate if necessary
        if (truncate != 0) { address_base58str.truncate(truncate) };
        if re.is_match(&address_base58str) {
            println!("Match was found for address {} and private key {}",
             address.to_base58check(),
             privkey.to_base58check());
            break;
        }

        // Maximum number of attempts check
        i = i + 1;
        if i == attempts {
            // Unsuccessfull search
            println!("Match was not found! Try again later.");
            break ;
        };
    }
}
<|endoftext|>


<commit_before>use crate::types::ShortString;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ChannelStatus {
    inner: Arc<RwLock<Inner>>,
}

impl ChannelStatus {
    pub fn is_initializing(&self) -> bool {
        self.inner.read().state == ChannelState::Initial
    }

    pub fn is_closing(&self) -> bool {
        self.inner.read().state == ChannelState::Closing
    }

    pub fn is_connected(&self) -> bool {
        !&[
            ChannelState::Initial,
            ChannelState::Closing,
            ChannelState::Closed,
            ChannelState::Error,
        ]
        .contains(&self.inner.read().state)
    }

    pub fn confirm(&self) -> bool {
        self.inner.read().confirm
    }

    pub(crate) fn set_confirm(&self) {
        self.inner.write().confirm = true
        trace!("Publisher confirms activated");
    }

    pub fn state(&self) -> ChannelState {
        self.inner.read().state.clone()
    }

    pub(crate) fn set_state(&self, state: ChannelState) {
        self.inner.write().state = state
    }

    pub(crate) fn set_send_flow(&self, flow: bool) {
        self.inner.write().send_flow = flow;
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner.read().send_flow
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelState {
    Initial,
    Connected,
    Closing,
    Closed,
    Error,
    SendingContent(usize),
    WillReceiveContent(Option<ShortString>, Option<ShortString>),
    ReceivingContent(Option<ShortString>, Option<ShortString>, usize),
}

impl Default for ChannelState {
    fn default() -> Self {
        ChannelState::Initial
    }
}

#[derive(Debug)]
struct Inner {
    confirm: bool,
    send_flow: bool,
    state: ChannelState,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            confirm: false,
            send_flow: true,
            state: ChannelState::default(),
        }
    }
}
<commit_msg>fix build<commit_after>use crate::types::ShortString;
use log::trace;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ChannelStatus {
    inner: Arc<RwLock<Inner>>,
}

impl ChannelStatus {
    pub fn is_initializing(&self) -> bool {
        self.inner.read().state == ChannelState::Initial
    }

    pub fn is_closing(&self) -> bool {
        self.inner.read().state == ChannelState::Closing
    }

    pub fn is_connected(&self) -> bool {
        !&[
            ChannelState::Initial,
            ChannelState::Closing,
            ChannelState::Closed,
            ChannelState::Error,
        ]
        .contains(&self.inner.read().state)
    }

    pub fn confirm(&self) -> bool {
        self.inner.read().confirm
    }

    pub(crate) fn set_confirm(&self) {
        self.inner.write().confirm = true;
        trace!("Publisher confirms activated");
    }

    pub fn state(&self) -> ChannelState {
        self.inner.read().state.clone()
    }

    pub(crate) fn set_state(&self, state: ChannelState) {
        self.inner.write().state = state
    }

    pub(crate) fn set_send_flow(&self, flow: bool) {
        self.inner.write().send_flow = flow;
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner.read().send_flow
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelState {
    Initial,
    Connected,
    Closing,
    Closed,
    Error,
    SendingContent(usize),
    WillReceiveContent(Option<ShortString>, Option<ShortString>),
    ReceivingContent(Option<ShortString>, Option<ShortString>, usize),
}

impl Default for ChannelState {
    fn default() -> Self {
        ChannelState::Initial
    }
}

#[derive(Debug)]
struct Inner {
    confirm: bool,
    send_flow: bool,
    state: ChannelState,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            confirm: false,
            send_flow: true,
            state: ChannelState::default(),
        }
    }
}
<|endoftext|>


<commit_before>use super::{
    child_properties, function, general,
    general::{cfg_deprecated_string, version_condition_no_doc, version_condition_string},
    properties, signal, trait_impls,
};
use crate::{
    analysis::{self, ref_mode::RefMode, rust_type::RustType, special_functions::Type},
    case::CaseExt,
    env::Env,
    library::{self, Nullable},
    nameutil,
    traits::IntoString,
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    general::start_comments(w, &env.config)?;
    general::uses(w, env, &analysis.imports, analysis.version)?;

    general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        analysis.c_class_type.as_deref(),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    )?;

    if need_generate_inherent(analysis) {
        writeln!(w)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in &analysis.constructors() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !analysis.builder_properties.is_empty() {
            // generate builder method that returns the corresponding builder
            let builder_name = format!("{}Builder", analysis.name);
            writeln!(
                w,
                "
            // rustdoc-stripper-ignore-next
            /// Creates a new builder-pattern struct instance to construct [`{name}`] objects.
            ///
            /// This method returns an instance of [`{builder_name}`] which can be used to create [`{name}`] objects.
            pub fn builder() -> {builder_name} {{
                {builder_name}::default()
            }}
        ",
                name = analysis.name,
                builder_name = builder_name
            )?;
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                function::generate(
                    w,
                    env,
                    func_analysis,
                    Some(&analysis.specials),
                    analysis.version,
                    false,
                    false,
                    1,
                )?;
            }

            for property in &analysis.properties {
                properties::generate(w, env, property, false, false, 1)?;
            }

            for child_property in &analysis.child_properties {
                child_properties::generate(w, env, child_property, false, false, 1)?;
            }
        }

        for func_analysis in &analysis.functions() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                signal::generate(w, env, signal_analysis, false, false, 1)?;
            }
        }

        writeln!(w, "}}")?;

        general::declare_default_from_new(w, env, &analysis.name, &analysis.functions)?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
        analysis.version,
        &None, // There is no need for #[cfg()] since it's applied on the whole file.
    )?;

    if !analysis.builder_properties.is_empty() {
        writeln!(w)?;
        generate_builder(w, env, analysis)?;
    }

    if analysis.concurrency != library::Concurrency::None {
        writeln!(w)?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            writeln!(w, "unsafe impl Send for {} {{}}", analysis.name)?;
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name)?;
            } else {
                writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name)?;
            }

            writeln!(w, "    fn is_unique(&self) -> bool {{")?;
            writeln!(w, "        self.ref_count() == 1")?;
            writeln!(w, "    }}")?;

            writeln!(w, "}}")?;
        }
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name)?;
    }

    if !analysis.final_type {
        writeln!(w)?;
        writeln!(
            w,
            "pub const NONE_{}: Option<&{}> = None;",
            analysis.name.to_snake().to_uppercase(),
            analysis.name
        )?;
    }

    if need_generate_trait(analysis) {
        writeln!(w)?;
        generate_trait(w, env, analysis)?;
    }

    if generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        writeln!(w, "\nimpl fmt::Display for {} {{", analysis.name,)?;
        // Generate Display trait implementation.
        writeln!(
            w,
            "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\tf.write_str(\"{}\")\n\
             \t}}\n\
             }}",
            analysis.name
        )?;
    }

    Ok(())
}

// TODO: instead create a Vec<> inside the Builder instead of Options.
fn generate_builder(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    let mut methods = vec![];
    let mut properties = vec![];
    writeln!(w, "#[derive(Clone, Default)]")?;
    writeln!(
        w,
        "// rustdoc-stripper-ignore-next
        /// A [builder-pattern] type to construct [`{}`] objects.
        /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html",
        analysis.name,
    )?;
    writeln!(w, "pub struct {}Builder {{", analysis.name)?;
    for property in &analysis.builder_properties {
        match RustType::try_new(env, property.typ) {
            Ok(type_string) => {
                let type_string = match type_string.as_str() {
                    s if nameutil::is_gstring(s) => "String",
                    "Vec<GString>" | "Vec<glib::GString>" | "Vec<crate::GString>" => "Vec<String>",
                    typ => typ,
                };
                let direction = if property.is_get {
                    library::ParameterDirection::In
                } else {
                    library::ParameterDirection::Out
                };
                let mut param_type = RustType::builder(env, property.typ)
                    .direction(direction)
                    .ref_mode(property.set_in_ref_mode)
                    .try_build()
                    .into_string();
                let (param_type_override, bounds, conversion) = match &param_type[..] {
                    "&str" => (None, String::new(), ".to_string()"),
                    "&[&str]" => (Some("Vec<String>".to_string()), String::new(), ""),
                    _ if !property.bounds.is_empty() => {
                        let (bounds, _) = function::bounds(&property.bounds, &[], false, false);
                        let alias =
                            property
                                .bounds
                                .get_parameter_bound(&property.name)
                                .map(|bound| {
                                    bound.full_type_parameter_reference(
                                        RefMode::ByRef,
                                        Nullable(false),
                                    )
                                });
                        (alias, bounds, ".clone().upcast()")
                    }
                    typ if typ.starts_with('&') => (None, String::new(), ".clone()"),
                    _ => (None, String::new(), ""),
                };
                if let Some(param_type_override) = param_type_override {
                    param_type = param_type_override.to_string();
                }
                let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                let version_condition_string =
                    version_condition_string(env, property.version, false, 1);
                let deprecated_string =
                    cfg_deprecated_string(env, property.deprecated_version, false, 1);
                if let Some(ref version_condition_string) = version_condition_string {
                    writeln!(w, "{}", version_condition_string)?;
                }
                if let Some(ref deprecated_string) = deprecated_string {
                    writeln!(w, "{}", deprecated_string)?;
                }
                writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                let version_prefix = version_condition_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                let deprecation_prefix = deprecated_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                methods.push(format!(
                    "\n{version_prefix}{deprecation_prefix}    pub fn {name}{bounds}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}",
                    version_prefix = version_prefix,
                    deprecation_prefix = deprecation_prefix,
                    param_type = param_type,
                    name = name,
                    conversion = conversion,
                    bounds = bounds
                ));
                properties.push(property);
            }
            Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
        }
    }
    writeln!(
        w,
        "}}

impl {name}Builder {{
    // rustdoc-stripper-ignore-next
    /// Create a new [`{name}Builder`].
    pub fn new() -> Self {{
        Self::default()
    }}
",
        name = analysis.name
    )?;

    writeln!(
        w,
        "
    // rustdoc-stripper-ignore-next
    /// Build the [`{name}`].
    pub fn build(self) -> {name} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];",
        name = analysis.name
    )?;
    for property in &properties {
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        version_condition_no_doc(w, env, property.version, false, 2)?;
        writeln!(
            w,
            "\
            if let Some(ref {field}) = self.{field} {{
                properties.push((\"{name}\", {field}));
            }}",
            name = property.name,
            field = name
        )?;
    }
    let glib_crate_name = if env.namespaces.is_glib_crate {
        "crate"
    } else {
        "glib"
    };

    // The split allows us to not have clippy::let_and_return lint disabled
    if let Some(code) = analysis.builder_postprocess.as_ref() {
        writeln!(
            w,
            r#"        let ret = {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}");"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "        {{\n            {}\n        }}", code)?;
        writeln!(w, "    ret\n    }}")?;
    } else {
        writeln!(
            w,
            r#"        {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}")"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "\n    }}")?;
    }

    for method in methods {
        writeln!(w, "{}", method)?;
    }
    writeln!(w, "}}")
}

fn generate_trait(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    write!(w, "pub trait {}: 'static {{", analysis.trait_name)?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            true,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, true, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, true, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, true, 1)?;
    }
    writeln!(w, "}}")?;

    writeln!(w)?;
    write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name, analysis.trait_name,
    )?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            false,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, false, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, false, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, false, 1)?;
    }
    writeln!(w, "}}")?;

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors
        || analysis.has_functions
        || !need_generate_trait(analysis)
        || !analysis.builder_properties.is_empty()
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::cfg_deprecated_string(env, analysis.deprecated_version, false, 0) {
        cfgs.push(cfg);
    }

    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    contents.push(format!(
        "pub use self::{}::{{{}{}}};",
        module_name, analysis.name, none_type
    ));
    if need_generate_trait(analysis) {
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!(
            "\tpub use super::{}::{};",
            module_name, analysis.trait_name
        ));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{}Builder;",
            module_name, analysis.name
        ));
    }
}
<commit_msg>Fix link to builder pattern explanation<commit_after>use super::{
    child_properties, function, general,
    general::{cfg_deprecated_string, version_condition_no_doc, version_condition_string},
    properties, signal, trait_impls,
};
use crate::{
    analysis::{self, ref_mode::RefMode, rust_type::RustType, special_functions::Type},
    case::CaseExt,
    env::Env,
    library::{self, Nullable},
    nameutil,
    traits::IntoString,
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    general::start_comments(w, &env.config)?;
    general::uses(w, env, &analysis.imports, analysis.version)?;

    general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        analysis.c_class_type.as_deref(),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    )?;

    if need_generate_inherent(analysis) {
        writeln!(w)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in &analysis.constructors() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !analysis.builder_properties.is_empty() {
            // generate builder method that returns the corresponding builder
            let builder_name = format!("{}Builder", analysis.name);
            writeln!(
                w,
                "
            // rustdoc-stripper-ignore-next
            /// Creates a new builder-pattern struct instance to construct [`{name}`] objects.
            ///
            /// This method returns an instance of [`{builder_name}`] which can be used to create [`{name}`] objects.
            pub fn builder() -> {builder_name} {{
                {builder_name}::default()
            }}
        ",
                name = analysis.name,
                builder_name = builder_name
            )?;
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                function::generate(
                    w,
                    env,
                    func_analysis,
                    Some(&analysis.specials),
                    analysis.version,
                    false,
                    false,
                    1,
                )?;
            }

            for property in &analysis.properties {
                properties::generate(w, env, property, false, false, 1)?;
            }

            for child_property in &analysis.child_properties {
                child_properties::generate(w, env, child_property, false, false, 1)?;
            }
        }

        for func_analysis in &analysis.functions() {
            function::generate(
                w,
                env,
                func_analysis,
                Some(&analysis.specials),
                analysis.version,
                false,
                false,
                1,
            )?;
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                signal::generate(w, env, signal_analysis, false, false, 1)?;
            }
        }

        writeln!(w, "}}")?;

        general::declare_default_from_new(w, env, &analysis.name, &analysis.functions)?;
    }

    trait_impls::generate(
        w,
        env,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
        analysis.version,
        &None, // There is no need for #[cfg()] since it's applied on the whole file.
    )?;

    if !analysis.builder_properties.is_empty() {
        writeln!(w)?;
        generate_builder(w, env, analysis)?;
    }

    if analysis.concurrency != library::Concurrency::None {
        writeln!(w)?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            writeln!(w, "unsafe impl Send for {} {{}}", analysis.name)?;
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name)?;
            } else {
                writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name)?;
            }

            writeln!(w, "    fn is_unique(&self) -> bool {{")?;
            writeln!(w, "        self.ref_count() == 1")?;
            writeln!(w, "    }}")?;

            writeln!(w, "}}")?;
        }
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name)?;
    }

    if !analysis.final_type {
        writeln!(w)?;
        writeln!(
            w,
            "pub const NONE_{}: Option<&{}> = None;",
            analysis.name.to_snake().to_uppercase(),
            analysis.name
        )?;
    }

    if need_generate_trait(analysis) {
        writeln!(w)?;
        generate_trait(w, env, analysis)?;
    }

    if generate_display_trait && !analysis.specials.has_trait(Type::Display) {
        writeln!(w, "\nimpl fmt::Display for {} {{", analysis.name,)?;
        // Generate Display trait implementation.
        writeln!(
            w,
            "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\tf.write_str(\"{}\")\n\
             \t}}\n\
             }}",
            analysis.name
        )?;
    }

    Ok(())
}

// TODO: instead create a Vec<> inside the Builder instead of Options.
fn generate_builder(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    let mut methods = vec![];
    let mut properties = vec![];
    writeln!(w, "#[derive(Clone, Default)]")?;
    writeln!(
        w,
        "// rustdoc-stripper-ignore-next
        /// A [builder-pattern] type to construct [`{}`] objects.
        ///
        /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html",
        analysis.name,
    )?;
    writeln!(w, "pub struct {}Builder {{", analysis.name)?;
    for property in &analysis.builder_properties {
        match RustType::try_new(env, property.typ) {
            Ok(type_string) => {
                let type_string = match type_string.as_str() {
                    s if nameutil::is_gstring(s) => "String",
                    "Vec<GString>" | "Vec<glib::GString>" | "Vec<crate::GString>" => "Vec<String>",
                    typ => typ,
                };
                let direction = if property.is_get {
                    library::ParameterDirection::In
                } else {
                    library::ParameterDirection::Out
                };
                let mut param_type = RustType::builder(env, property.typ)
                    .direction(direction)
                    .ref_mode(property.set_in_ref_mode)
                    .try_build()
                    .into_string();
                let (param_type_override, bounds, conversion) = match &param_type[..] {
                    "&str" => (None, String::new(), ".to_string()"),
                    "&[&str]" => (Some("Vec<String>".to_string()), String::new(), ""),
                    _ if !property.bounds.is_empty() => {
                        let (bounds, _) = function::bounds(&property.bounds, &[], false, false);
                        let alias =
                            property
                                .bounds
                                .get_parameter_bound(&property.name)
                                .map(|bound| {
                                    bound.full_type_parameter_reference(
                                        RefMode::ByRef,
                                        Nullable(false),
                                    )
                                });
                        (alias, bounds, ".clone().upcast()")
                    }
                    typ if typ.starts_with('&') => (None, String::new(), ".clone()"),
                    _ => (None, String::new(), ""),
                };
                if let Some(param_type_override) = param_type_override {
                    param_type = param_type_override.to_string();
                }
                let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                let version_condition_string =
                    version_condition_string(env, property.version, false, 1);
                let deprecated_string =
                    cfg_deprecated_string(env, property.deprecated_version, false, 1);
                if let Some(ref version_condition_string) = version_condition_string {
                    writeln!(w, "{}", version_condition_string)?;
                }
                if let Some(ref deprecated_string) = deprecated_string {
                    writeln!(w, "{}", deprecated_string)?;
                }
                writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                let version_prefix = version_condition_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                let deprecation_prefix = deprecated_string
                    .map(|version| format!("{}\n", version))
                    .unwrap_or_default();

                methods.push(format!(
                    "\n{version_prefix}{deprecation_prefix}    pub fn {name}{bounds}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}",
                    version_prefix = version_prefix,
                    deprecation_prefix = deprecation_prefix,
                    param_type = param_type,
                    name = name,
                    conversion = conversion,
                    bounds = bounds
                ));
                properties.push(property);
            }
            Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
        }
    }
    writeln!(
        w,
        "}}

impl {name}Builder {{
    // rustdoc-stripper-ignore-next
    /// Create a new [`{name}Builder`].
    pub fn new() -> Self {{
        Self::default()
    }}
",
        name = analysis.name
    )?;

    writeln!(
        w,
        "
    // rustdoc-stripper-ignore-next
    /// Build the [`{name}`].
    pub fn build(self) -> {name} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];",
        name = analysis.name
    )?;
    for property in &properties {
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        version_condition_no_doc(w, env, property.version, false, 2)?;
        writeln!(
            w,
            "\
            if let Some(ref {field}) = self.{field} {{
                properties.push((\"{name}\", {field}));
            }}",
            name = property.name,
            field = name
        )?;
    }
    let glib_crate_name = if env.namespaces.is_glib_crate {
        "crate"
    } else {
        "glib"
    };

    // The split allows us to not have clippy::let_and_return lint disabled
    if let Some(code) = analysis.builder_postprocess.as_ref() {
        writeln!(
            w,
            r#"        let ret = {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}");"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "        {{\n            {}\n        }}", code)?;
        writeln!(w, "    ret\n    }}")?;
    } else {
        writeln!(
            w,
            r#"        {}::Object::new::<{}>(&properties)
                .expect("Failed to create an instance of {}")"#,
            glib_crate_name, analysis.name, analysis.name,
        )?;
        writeln!(w, "\n    }}")?;
    }

    for method in methods {
        writeln!(w, "{}", method)?;
    }
    writeln!(w, "}}")
}

fn generate_trait(w: &mut dyn Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    write!(w, "pub trait {}: 'static {{", analysis.trait_name)?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            true,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, true, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, true, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, true, 1)?;
    }
    writeln!(w, "}}")?;

    writeln!(w)?;
    write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name, analysis.trait_name,
    )?;

    for func_analysis in &analysis.methods() {
        function::generate(
            w,
            env,
            func_analysis,
            Some(&analysis.specials),
            analysis.version,
            true,
            false,
            1,
        )?;
    }
    for property in &analysis.properties {
        properties::generate(w, env, property, true, false, 1)?;
    }
    for child_property in &analysis.child_properties {
        child_properties::generate(w, env, child_property, true, false, 1)?;
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        signal::generate(w, env, signal_analysis, true, false, 1)?;
    }
    writeln!(w, "}}")?;

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors
        || analysis.has_functions
        || !need_generate_trait(analysis)
        || !analysis.builder_properties.is_empty()
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::cfg_deprecated_string(env, analysis.deprecated_version, false, 0) {
        cfgs.push(cfg);
    }

    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    contents.push(format!(
        "pub use self::{}::{{{}{}}};",
        module_name, analysis.name, none_type
    ));
    if need_generate_trait(analysis) {
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!(
            "\tpub use super::{}::{};",
            module_name, analysis.trait_name
        ));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{}Builder;",
            module_name, analysis.name
        ));
    }
}
<|endoftext|>


<commit_before>import driver::session;
import lib::llvm::llvm;
import middle::trans;
import std::str;
import std::fs;

import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::mk_pass_manager;
import lib::llvm::mk_target_data;
import lib::llvm::mk_type_names;
import lib::llvm::False;
import lib::llvm::True;

tag output_type {
    output_type_none;
    output_type_bitcode;
    output_type_assembly;
    output_type_object;
    output_type_exe;
}

fn llvm_err(session::session sess, str msg) {
    auto buf = llvm::LLVMRustGetLastError();
    if ((buf as uint) == 0u) {
        sess.err(msg);
    } else {
        sess.err(msg + ": " + str::str_from_cstr(buf));
    }
    fail;
}

fn link_intrinsics(session::session sess, ModuleRef llmod) {
    auto path = fs::connect(sess.get_opts().sysroot, "intrinsics.bc");
    auto membuf =
        llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(str::buf(path));
    if ((membuf as uint) == 0u) {
        llvm_err(sess, "installation problem: couldn't open intrinstics.bc");
        fail;
    }

    auto llintrinsicsmod = llvm::LLVMRustParseBitcode(membuf);
    llvm::LLVMDisposeMemoryBuffer(membuf);

    if ((llintrinsicsmod as uint) == 0u) {
        llvm_err(sess, "installation problem: couldn't parse intrinstics.bc");
        fail;
    }

    auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod);
    llvm::LLVMDisposeModule(llintrinsicsmod);

    if (linkres == False) {
        llvm_err(sess, "couldn't link the module with the intrinsics");
        fail;
    }
}

mod write {
    fn is_object_or_assembly_or_exe(output_type ot) -> bool {
        if ( (ot == output_type_assembly) ||
             (ot == output_type_object) ||
             (ot == output_type_exe) ) {
            ret true;
        }
        ret false;
    }

    // Decides what to call an intermediate file, given the name of the output
    // and the extension to use.
    fn mk_intermediate_name(str output_path, str extension) -> str {
        auto dot_pos = str::index(output_path, '.' as u8);
        auto stem;
        if (dot_pos < 0) {
            stem = output_path;
        } else {
            stem = str::substr(output_path, 0u, dot_pos as uint);
        }
        ret stem + "." + extension;
    }

    fn run_passes(session::session sess, ModuleRef llmod, str output) {

        auto opts = sess.get_opts();

        if (opts.time_llvm_passes) {
          llvm::LLVMRustEnableTimePasses();
        }

        link_intrinsics(sess, llmod);

        auto pm = mk_pass_manager();
        auto td = mk_target_data(x86::get_data_layout());
        llvm::LLVMAddTargetData(td.lltd, pm.llpm);

        // TODO: run the linter here also, once there are llvm-c bindings for
        // it.

        // Generate a pre-optimization intermediate file if -save-temps was
        // specified.
        if (opts.save_temps) {
            alt (opts.output_type) {
                case (output_type_bitcode) {
                    if (opts.optimize != 0u) {
                        auto filename = mk_intermediate_name(output,
                                                             "no-opt.bc");
                        llvm::LLVMWriteBitcodeToFile(llmod,
                                                    str::buf(filename));
                    }
                }
                case (_) {
                    auto filename = mk_intermediate_name(output, "bc");
                    llvm::LLVMWriteBitcodeToFile(llmod, str::buf(filename));
                }
            }
        }

        if (opts.verify) {
            llvm::LLVMAddVerifierPass(pm.llpm);
        }

        // FIXME: This is mostly a copy of the bits of opt's -O2 that are
        // available in the C api.
        // FIXME2: We might want to add optimization levels like -O1, -O2,
        // -Os, etc
        // FIXME3: Should we expose and use the pass lists used by the opt
        // tool?
        if (opts.optimize != 0u) {
            auto fpm = mk_pass_manager();
            llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
            llvm::LLVMAddStandardFunctionPasses(fpm.llpm, 2u);
            llvm::LLVMRunPassManager(fpm.llpm, llmod);

            let uint threshold = 225u;
            if (opts.optimize == 3u) {
                threshold = 275u;
            }

            llvm::LLVMAddStandardModulePasses(pm.llpm,
                                              // optimization level
                                              opts.optimize,
                                              False, // optimize for size
                                              True,  // unit-at-a-time
                                              True,  // unroll loops
                                              True,  // simplify lib calls
                                              True,  // have exceptions
                                              threshold); // inline threshold
        }

        if (opts.verify) {
            llvm::LLVMAddVerifierPass(pm.llpm);
        }

        if (is_object_or_assembly_or_exe(opts.output_type)) {
            let int LLVMAssemblyFile = 0;
            let int LLVMObjectFile = 1;
            let int LLVMNullFile = 2;
            auto FileType;
            if ((opts.output_type == output_type_object) ||
                (opts.output_type == output_type_exe)) {
                FileType = LLVMObjectFile;
            } else {
                FileType = LLVMAssemblyFile;
            }

            // Write optimized bitcode if --save-temps was on.
            if (opts.save_temps) {

                // Always output the bitcode file with --save-temps
                auto filename = mk_intermediate_name(output, "opt.bc");
                llvm::LLVMRunPassManager(pm.llpm, llmod);
                llvm::LLVMWriteBitcodeToFile(llmod, str::buf(filename));
                pm = mk_pass_manager();

                // Save the assembly file if -S is used
                if (opts.output_type == output_type_assembly) {
                        llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                               str::buf(x86::get_target_triple()),
                               str::buf(output), LLVMAssemblyFile);
                }

                // Save the object file for -c or --save-temps alone
                // This .o is needed when an exe is built
                if ((opts.output_type == output_type_object) ||
                    (opts.output_type == output_type_exe)) {
                        llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                               str::buf(x86::get_target_triple()),
                               str::buf(output), LLVMObjectFile);
               }
            } else {

                // If we aren't saving temps then just output the file
                // type corresponding to the '-c' or '-S' flag used
                llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                                     str::buf(x86::get_target_triple()),
                                     str::buf(output),
                                     FileType);
            }

            // Clean up and return
            llvm::LLVMDisposeModule(llmod);
            if (opts.time_llvm_passes) {
              llvm::LLVMRustPrintPassTimings();
            }
            ret;
        }

        // If only a bitcode file is asked for by using the '--emit-llvm'
        // flag, then output it here
        llvm::LLVMRunPassManager(pm.llpm, llmod);

        llvm::LLVMWriteBitcodeToFile(llmod, str::buf(output));
        llvm::LLVMDisposeModule(llmod);

        if (opts.time_llvm_passes) {
          llvm::LLVMRustPrintPassTimings();
        }
    }
}

<commit_msg>Fix typo in error message<commit_after>import driver::session;
import lib::llvm::llvm;
import middle::trans;
import std::str;
import std::fs;

import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::mk_pass_manager;
import lib::llvm::mk_target_data;
import lib::llvm::mk_type_names;
import lib::llvm::False;
import lib::llvm::True;

tag output_type {
    output_type_none;
    output_type_bitcode;
    output_type_assembly;
    output_type_object;
    output_type_exe;
}

fn llvm_err(session::session sess, str msg) {
    auto buf = llvm::LLVMRustGetLastError();
    if ((buf as uint) == 0u) {
        sess.err(msg);
    } else {
        sess.err(msg + ": " + str::str_from_cstr(buf));
    }
    fail;
}

fn link_intrinsics(session::session sess, ModuleRef llmod) {
    auto path = fs::connect(sess.get_opts().sysroot, "intrinsics.bc");
    auto membuf =
        llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(str::buf(path));
    if ((membuf as uint) == 0u) {
        llvm_err(sess, "installation problem: couldn't open " + path);
        fail;
    }

    auto llintrinsicsmod = llvm::LLVMRustParseBitcode(membuf);
    llvm::LLVMDisposeMemoryBuffer(membuf);

    if ((llintrinsicsmod as uint) == 0u) {
        llvm_err(sess, "installation problem: couldn't parse intrinsics.bc");
        fail;
    }

    auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod);
    llvm::LLVMDisposeModule(llintrinsicsmod);

    if (linkres == False) {
        llvm_err(sess, "couldn't link the module with the intrinsics");
        fail;
    }
}

mod write {
    fn is_object_or_assembly_or_exe(output_type ot) -> bool {
        if ( (ot == output_type_assembly) ||
             (ot == output_type_object) ||
             (ot == output_type_exe) ) {
            ret true;
        }
        ret false;
    }

    // Decides what to call an intermediate file, given the name of the output
    // and the extension to use.
    fn mk_intermediate_name(str output_path, str extension) -> str {
        auto dot_pos = str::index(output_path, '.' as u8);
        auto stem;
        if (dot_pos < 0) {
            stem = output_path;
        } else {
            stem = str::substr(output_path, 0u, dot_pos as uint);
        }
        ret stem + "." + extension;
    }

    fn run_passes(session::session sess, ModuleRef llmod, str output) {

        auto opts = sess.get_opts();

        if (opts.time_llvm_passes) {
          llvm::LLVMRustEnableTimePasses();
        }

        link_intrinsics(sess, llmod);

        auto pm = mk_pass_manager();
        auto td = mk_target_data(x86::get_data_layout());
        llvm::LLVMAddTargetData(td.lltd, pm.llpm);

        // TODO: run the linter here also, once there are llvm-c bindings for
        // it.

        // Generate a pre-optimization intermediate file if -save-temps was
        // specified.
        if (opts.save_temps) {
            alt (opts.output_type) {
                case (output_type_bitcode) {
                    if (opts.optimize != 0u) {
                        auto filename = mk_intermediate_name(output,
                                                             "no-opt.bc");
                        llvm::LLVMWriteBitcodeToFile(llmod,
                                                    str::buf(filename));
                    }
                }
                case (_) {
                    auto filename = mk_intermediate_name(output, "bc");
                    llvm::LLVMWriteBitcodeToFile(llmod, str::buf(filename));
                }
            }
        }

        if (opts.verify) {
            llvm::LLVMAddVerifierPass(pm.llpm);
        }

        // FIXME: This is mostly a copy of the bits of opt's -O2 that are
        // available in the C api.
        // FIXME2: We might want to add optimization levels like -O1, -O2,
        // -Os, etc
        // FIXME3: Should we expose and use the pass lists used by the opt
        // tool?
        if (opts.optimize != 0u) {
            auto fpm = mk_pass_manager();
            llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
            llvm::LLVMAddStandardFunctionPasses(fpm.llpm, 2u);
            llvm::LLVMRunPassManager(fpm.llpm, llmod);

            let uint threshold = 225u;
            if (opts.optimize == 3u) {
                threshold = 275u;
            }

            llvm::LLVMAddStandardModulePasses(pm.llpm,
                                              // optimization level
                                              opts.optimize,
                                              False, // optimize for size
                                              True,  // unit-at-a-time
                                              True,  // unroll loops
                                              True,  // simplify lib calls
                                              True,  // have exceptions
                                              threshold); // inline threshold
        }

        if (opts.verify) {
            llvm::LLVMAddVerifierPass(pm.llpm);
        }

        if (is_object_or_assembly_or_exe(opts.output_type)) {
            let int LLVMAssemblyFile = 0;
            let int LLVMObjectFile = 1;
            let int LLVMNullFile = 2;
            auto FileType;
            if ((opts.output_type == output_type_object) ||
                (opts.output_type == output_type_exe)) {
                FileType = LLVMObjectFile;
            } else {
                FileType = LLVMAssemblyFile;
            }

            // Write optimized bitcode if --save-temps was on.
            if (opts.save_temps) {

                // Always output the bitcode file with --save-temps
                auto filename = mk_intermediate_name(output, "opt.bc");
                llvm::LLVMRunPassManager(pm.llpm, llmod);
                llvm::LLVMWriteBitcodeToFile(llmod, str::buf(filename));
                pm = mk_pass_manager();

                // Save the assembly file if -S is used
                if (opts.output_type == output_type_assembly) {
                        llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                               str::buf(x86::get_target_triple()),
                               str::buf(output), LLVMAssemblyFile);
                }

                // Save the object file for -c or --save-temps alone
                // This .o is needed when an exe is built
                if ((opts.output_type == output_type_object) ||
                    (opts.output_type == output_type_exe)) {
                        llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                               str::buf(x86::get_target_triple()),
                               str::buf(output), LLVMObjectFile);
               }
            } else {

                // If we aren't saving temps then just output the file
                // type corresponding to the '-c' or '-S' flag used
                llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
                                     str::buf(x86::get_target_triple()),
                                     str::buf(output),
                                     FileType);
            }

            // Clean up and return
            llvm::LLVMDisposeModule(llmod);
            if (opts.time_llvm_passes) {
              llvm::LLVMRustPrintPassTimings();
            }
            ret;
        }

        // If only a bitcode file is asked for by using the '--emit-llvm'
        // flag, then output it here
        llvm::LLVMRunPassManager(pm.llpm, llmod);

        llvm::LLVMWriteBitcodeToFile(llmod, str::buf(output));
        llvm::LLVMDisposeModule(llmod);

        if (opts.time_llvm_passes) {
          llvm::LLVMRustPrintPassTimings();
        }
    }
}

<|endoftext|>