<commit_before>// Copyright (c) 2017-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.

//! rav1e is an [AV1] video encoder. It is designed to eventually cover all use
//! cases, though in its current form it is most suitable for cases where
//! libaom (the reference encoder) is too slow.
//!
//! ## Features
//!
//! * Intra and inter frames
//! * 64x64 superblocks
//! * 4x4 to 64x64 RDO-selected square and 2:1/1:2 rectangular blocks
//! * DC, H, V, Paeth, smooth, and a subset of directional prediction modes
//! * DCT, (FLIP-)ADST and identity transforms (up to 64x64, 16x16 and 32x32
//!   respectively)
//! * 8-, 10- and 12-bit depth color
//! * 4:2:0 (full support), 4:2:2 and 4:4:4 (limited) chroma sampling
//! * Variable speed settings
//! * Near real-time encoding at high speed levels
//!
//! ## Usage
//!
//! Encoding is done through the [`Context`] struct. Examples on
//! [`Context::receive_packet`] show how to create a [`Context`], send frames
//! into it and receive packets of encoded data.
//!
//! [AV1]: https://aomediacodec.github.io/av1-spec/av1-spec.pdf
//! [`Context`]: struct.Context.html
//! [`Context::receive_packet`]: struct.Context.html#method.receive_packet

#![deny(bare_trait_objects)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::cast_ptr_alignment)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::verbose_bit_mask)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::many_single_char_names)]
#![allow(clippy::wrong_self_convention)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::comparison_chain)]
#![warn(clippy::expl_impl_clone_on_copy)]
#![warn(clippy::linkedlist)]
#![warn(clippy::map_flatten)]
#![warn(clippy::mem_forget)]
#![warn(clippy::mut_mut)]
#![warn(clippy::mutex_integer)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::needless_continue)]
#![warn(clippy::path_buf_push_overwrite)]
#![warn(clippy::range_plus_one)]

// Override assert! and assert_eq! in tests
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;

#[macro_use]
extern crate log;

mod serialize {
  cfg_if::cfg_if! {
    if #[cfg(feature="serialize")] {
      pub use serde::*;
    } else {
      pub use noop_proc_macro::{Deserialize, Serialize};
    }
  }
}

mod wasm_bindgen {
  cfg_if::cfg_if! {
    if #[cfg(feature="wasm")] {
      pub use wasm_bindgen::prelude::*;
    } else {
      pub use noop_proc_macro::wasm_bindgen;
    }
  }
}

mod rayon {
  cfg_if::cfg_if! {
    if #[cfg(target_arch="wasm32")] {
      pub struct ThreadPoolBuilder ();
      impl ThreadPoolBuilder {
        pub fn new() -> ThreadPoolBuilder {
          ThreadPoolBuilder()
        }
        pub fn build(self) -> Result<ThreadPool, ()> {
          Ok(ThreadPool())
        }
        pub fn num_threads(self, _num_threads: usize) -> ThreadPoolBuilder {
          ThreadPoolBuilder()
        }
      }
      #[derive(Debug)]
      pub struct ThreadPool ();
      impl ThreadPool {
        pub fn install<OP, R>(&self, op: OP) -> R where
              OP: FnOnce() -> R + Send,
                  R: Send, {
          op()
        }
      }

      pub mod iter {
        pub trait IntoParallelIterator {
            type Iter: Iterator<Item = Self::Item>;
            type Item: Send;

            fn into_par_iter(self) -> Self::Iter;
        }

        impl<I: IntoIterator> IntoParallelIterator for I where
          I::Item : Send {
          type Item = I::Item;
          type Iter = I::IntoIter;

          fn into_par_iter(self) -> I::IntoIter {
            self.into_iter()
          }
        }

        pub trait IntoParallelRefMutIterator<'data> {
            type Iter: IntoParallelIterator<Item = Self::Item>;
            type Item: Send + 'data;

            fn par_iter_mut(&'data mut self) -> Self::Iter;
        }

        impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I
        where
            &'data mut I: IntoParallelIterator,
        {
            type Iter = <&'data mut I as IntoParallelIterator>::Iter;
            type Item = <&'data mut I as IntoParallelIterator>::Item;

            fn par_iter_mut(&'data mut self) -> Self::Iter {
                self.into_par_iter()
            }
        }

        pub trait ParallelIterator: Iterator {
          fn flat_map_iter<U, F>(self, f: F) -> std::iter::FlatMap<Self, U, F>
          where
            Self: Sized,
            U: IntoIterator,
            F: FnMut(<Self as Iterator>::Item) -> U,
          {
            self.flat_map(f)
          }
        }

        impl<I: Iterator> ParallelIterator for I {}
      }

      pub mod slice {
        pub trait ParallelSlice<T: Sync> {
          fn par_chunks_exact(
            &self, chunk_size: usize,
          ) -> std::slice::ChunksExact<'_, T>;
        }

        impl<T: Sync> ParallelSlice<T> for [T] {
          #[inline]
          fn par_chunks_exact(
            &self, chunk_size: usize,
          ) -> std::slice::ChunksExact<'_, T> {
            self.chunks_exact(chunk_size)
          }
        }
      }

      pub mod prelude {
        pub use super::iter::*;
        pub use super::slice::*;
      }

      pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
      where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send {
        (oper_a(), oper_b())
      }
    } else {
      pub use rayon::*;
    }
  }
}

#[cfg(any(cargo_c, feature = "capi"))]
pub mod capi;

#[macro_use]
mod transform;
#[macro_use]
mod cpu_features;

mod activity;
pub(crate) mod asm;
mod dist;
mod ec;
mod partition;
mod predict;
mod quantize;
mod rdo;
mod rdo_tables;
#[macro_use]
mod util;
mod cdef;
mod context;
mod deblock;
mod encoder;
mod entropymode;
mod lrf;
mod mc;
mod me;
mod rate;
mod recon_intra;
mod scan_order;
#[cfg(feature = "scenechange")]
pub mod scenechange;
#[cfg(not(feature = "scenechange"))]
mod scenechange;
mod segmentation;
mod stats;
mod tiling;
mod token_cdfs;

mod api;
mod frame;
mod header;

use crate::encoder::*;

pub use crate::api::{
  Config, Context, EncoderConfig, EncoderStatus, InvalidConfig, Packet,
};
pub use crate::frame::Frame;
pub use crate::util::{CastFromPrimitive, Pixel, PixelType};

/// Commonly used types and traits.
pub mod prelude {
  pub use crate::api::*;
  pub use crate::encoder::{Sequence, Tune};
  pub use crate::frame::{
    Frame, FrameParameters, FrameTypeOverride, Plane, PlaneConfig,
  };
  pub use crate::partition::BlockSize;
  pub use crate::predict::PredictionMode;
  pub use crate::transform::TxType;
  pub use crate::util::{CastFromPrimitive, Pixel, PixelType};
}

/// Basic data structures
pub mod data {
  pub use crate::api::{
    ChromaticityPoint, EncoderStatus, FrameType, Packet, Rational,
  };
  pub use crate::frame::{Frame, FrameParameters};
  pub use crate::stats::EncoderStats;
  pub use crate::util::{CastFromPrimitive, Pixel, PixelType};
}

pub use crate::api::color;

/// Encoder configuration and settings
pub mod config {
  pub use crate::api::{
    Config, EncoderConfig, InvalidConfig, PredictionModesSetting,
    RateControlConfig, RateControlError, RateControlSummary, SpeedSettings,
  };
  pub use crate::cpu_features::CpuFeatureLevel;
}

/// Version information
///
/// The information is recovered from `Cargo.toml` and `git describe`, when available.
///
/// ```
/// use rav1e::version;
/// use semver::Version;
///
/// let major = version::major();
/// let minor = version::minor();
/// let patch = version::patch();
///
/// let short = version::short();
///
/// let v1 = Version::new(major, minor, patch);
/// let v2 = Version::parse(&short).unwrap();
///
/// assert_eq!(v1.major, v2.major);
/// ```
pub mod version {
  /// Major version component
  ///
  /// It is increased every time a release presents a incompatible API change.
  pub fn major() -> u64 {
    env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap()
  }
  /// Minor version component
  ///
  /// It is increased every time a release presents new functionalities are added
  /// in a backwards-compatible manner.
  pub fn minor() -> u64 {
    env!("CARGO_PKG_VERSION_MINOR").parse().unwrap()
  }
  /// Patch version component
  ///
  /// It is increased every time a release provides only backwards-compatible bugfixes.
  pub fn patch() -> u64 {
    env!("CARGO_PKG_VERSION_PATCH").parse().unwrap()
  }

  /// Version information as presented in `[package]` `version`.
  ///
  /// e.g. `0.1.0``
  ///
  /// Can be parsed by [semver](https://crates.io/crates/semver).
  pub fn short() -> String {
    env!("CARGO_PKG_VERSION").to_string()
  }

  /// Version information as presented in `[package] version` followed by the
  /// short commit hash if present.
  ///
  /// e.g. `0.1.0 - g743d464`
  ///
  pub fn long() -> String {
    let s = short();
    let hash = hash();

    if hash.is_empty() {
      s
    } else {
      format!("{} - {}", s, hash)
    }
  }

  /// Commit hash (short)
  ///
  /// Short hash of the git commit used by this build
  ///
  /// e.g. `g743d464`
  ///
  pub fn hash() -> String {
    env!("VERGEN_SHA_SHORT").to_string()
  }

  /// Version information with the information
  /// provided by `git describe --tags`.
  ///
  /// e.g. `0.1.0 (v0.1.0-1-g743d464)`
  ///
  pub fn full() -> String {
    let semver = env!("VERGEN_SEMVER_LIGHTWEIGHT");
    format!("{} ({})", short(), semver)
  }
}
#[cfg(all(
  any(test, fuzzing),
  any(feature = "decode_test", feature = "decode_test_dav1d")
))]
mod test_encode_decode;

#[cfg(feature = "bench")]
pub mod bench {
  pub mod api {
    pub use crate::api::*;
  }
  pub mod cdef {
    pub use crate::cdef::*;
  }
  pub mod context {
    pub use crate::context::*;
  }
  pub mod dist {
    pub use crate::dist::*;
  }
  pub mod ec {
    pub use crate::ec::*;
  }
  pub mod encoder {
    pub use crate::encoder::*;
  }
  pub mod mc {
    pub use crate::mc::*;
  }
  pub mod partition {
    pub use crate::partition::*;
  }
  pub mod frame {
    pub use crate::frame::*;
  }
  pub mod predict {
    pub use crate::predict::*;
  }
  pub mod rdo {
    pub use crate::rdo::*;
  }
  pub mod tiling {
    pub use crate::tiling::*;
  }
  pub mod transform {
    pub use crate::transform::*;
  }
  pub mod util {
    pub use crate::util::*;
  }
  pub mod cpu_features {
    pub use crate::cpu_features::*;
  }
}

#[cfg(fuzzing)]
pub mod fuzzing;
<commit_msg>Allow Rayon if Wasm is built with atomics support<commit_after>// Copyright (c) 2017-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.

//! rav1e is an [AV1] video encoder. It is designed to eventually cover all use
//! cases, though in its current form it is most suitable for cases where
//! libaom (the reference encoder) is too slow.
//!
//! ## Features
//!
//! * Intra and inter frames
//! * 64x64 superblocks
//! * 4x4 to 64x64 RDO-selected square and 2:1/1:2 rectangular blocks
//! * DC, H, V, Paeth, smooth, and a subset of directional prediction modes
//! * DCT, (FLIP-)ADST and identity transforms (up to 64x64, 16x16 and 32x32
//!   respectively)
//! * 8-, 10- and 12-bit depth color
//! * 4:2:0 (full support), 4:2:2 and 4:4:4 (limited) chroma sampling
//! * Variable speed settings
//! * Near real-time encoding at high speed levels
//!
//! ## Usage
//!
//! Encoding is done through the [`Context`] struct. Examples on
//! [`Context::receive_packet`] show how to create a [`Context`], send frames
//! into it and receive packets of encoded data.
//!
//! [AV1]: https://aomediacodec.github.io/av1-spec/av1-spec.pdf
//! [`Context`]: struct.Context.html
//! [`Context::receive_packet`]: struct.Context.html#method.receive_packet

#![deny(bare_trait_objects)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::cast_ptr_alignment)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::verbose_bit_mask)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::many_single_char_names)]
#![allow(clippy::wrong_self_convention)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::comparison_chain)]
#![warn(clippy::expl_impl_clone_on_copy)]
#![warn(clippy::linkedlist)]
#![warn(clippy::map_flatten)]
#![warn(clippy::mem_forget)]
#![warn(clippy::mut_mut)]
#![warn(clippy::mutex_integer)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::needless_continue)]
#![warn(clippy::path_buf_push_overwrite)]
#![warn(clippy::range_plus_one)]

// Override assert! and assert_eq! in tests
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;

#[macro_use]
extern crate log;

mod serialize {
  cfg_if::cfg_if! {
    if #[cfg(feature="serialize")] {
      pub use serde::*;
    } else {
      pub use noop_proc_macro::{Deserialize, Serialize};
    }
  }
}

mod wasm_bindgen {
  cfg_if::cfg_if! {
    if #[cfg(feature="wasm")] {
      pub use wasm_bindgen::prelude::*;
    } else {
      pub use noop_proc_macro::wasm_bindgen;
    }
  }
}

mod rayon {
  cfg_if::cfg_if! {
    if #[cfg(all(target_arch="wasm32", not(target_feature = "atomics")))] {
      pub struct ThreadPoolBuilder ();
      impl ThreadPoolBuilder {
        pub fn new() -> ThreadPoolBuilder {
          ThreadPoolBuilder()
        }
        pub fn build(self) -> Result<ThreadPool, ()> {
          Ok(ThreadPool())
        }
        pub fn num_threads(self, _num_threads: usize) -> ThreadPoolBuilder {
          ThreadPoolBuilder()
        }
      }
      #[derive(Debug)]
      pub struct ThreadPool ();
      impl ThreadPool {
        pub fn install<OP, R>(&self, op: OP) -> R where
              OP: FnOnce() -> R + Send,
                  R: Send, {
          op()
        }
      }

      pub mod iter {
        pub trait IntoParallelIterator {
            type Iter: Iterator<Item = Self::Item>;
            type Item: Send;

            fn into_par_iter(self) -> Self::Iter;
        }

        impl<I: IntoIterator> IntoParallelIterator for I where
          I::Item : Send {
          type Item = I::Item;
          type Iter = I::IntoIter;

          fn into_par_iter(self) -> I::IntoIter {
            self.into_iter()
          }
        }

        pub trait IntoParallelRefMutIterator<'data> {
            type Iter: IntoParallelIterator<Item = Self::Item>;
            type Item: Send + 'data;

            fn par_iter_mut(&'data mut self) -> Self::Iter;
        }

        impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I
        where
            &'data mut I: IntoParallelIterator,
        {
            type Iter = <&'data mut I as IntoParallelIterator>::Iter;
            type Item = <&'data mut I as IntoParallelIterator>::Item;

            fn par_iter_mut(&'data mut self) -> Self::Iter {
                self.into_par_iter()
            }
        }

        pub trait ParallelIterator: Iterator {
          fn flat_map_iter<U, F>(self, f: F) -> std::iter::FlatMap<Self, U, F>
          where
            Self: Sized,
            U: IntoIterator,
            F: FnMut(<Self as Iterator>::Item) -> U,
          {
            self.flat_map(f)
          }
        }

        impl<I: Iterator> ParallelIterator for I {}
      }

      pub mod slice {
        pub trait ParallelSlice<T: Sync> {
          fn par_chunks_exact(
            &self, chunk_size: usize,
          ) -> std::slice::ChunksExact<'_, T>;
        }

        impl<T: Sync> ParallelSlice<T> for [T] {
          #[inline]
          fn par_chunks_exact(
            &self, chunk_size: usize,
          ) -> std::slice::ChunksExact<'_, T> {
            self.chunks_exact(chunk_size)
          }
        }
      }

      pub mod prelude {
        pub use super::iter::*;
        pub use super::slice::*;
      }

      pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
      where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send {
        (oper_a(), oper_b())
      }
    } else {
      pub use rayon::*;
    }
  }
}

#[cfg(any(cargo_c, feature = "capi"))]
pub mod capi;

#[macro_use]
mod transform;
#[macro_use]
mod cpu_features;

mod activity;
pub(crate) mod asm;
mod dist;
mod ec;
mod partition;
mod predict;
mod quantize;
mod rdo;
mod rdo_tables;
#[macro_use]
mod util;
mod cdef;
mod context;
mod deblock;
mod encoder;
mod entropymode;
mod lrf;
mod mc;
mod me;
mod rate;
mod recon_intra;
mod scan_order;
#[cfg(feature = "scenechange")]
pub mod scenechange;
#[cfg(not(feature = "scenechange"))]
mod scenechange;
mod segmentation;
mod stats;
mod tiling;
mod token_cdfs;

mod api;
mod frame;
mod header;

use crate::encoder::*;

pub use crate::api::{
  Config, Context, EncoderConfig, EncoderStatus, InvalidConfig, Packet,
};
pub use crate::frame::Frame;
pub use crate::util::{CastFromPrimitive, Pixel, PixelType};

/// Commonly used types and traits.
pub mod prelude {
  pub use crate::api::*;
  pub use crate::encoder::{Sequence, Tune};
  pub use crate::frame::{
    Frame, FrameParameters, FrameTypeOverride, Plane, PlaneConfig,
  };
  pub use crate::partition::BlockSize;
  pub use crate::predict::PredictionMode;
  pub use crate::transform::TxType;
  pub use crate::util::{CastFromPrimitive, Pixel, PixelType};
}

/// Basic data structures
pub mod data {
  pub use crate::api::{
    ChromaticityPoint, EncoderStatus, FrameType, Packet, Rational,
  };
  pub use crate::frame::{Frame, FrameParameters};
  pub use crate::stats::EncoderStats;
  pub use crate::util::{CastFromPrimitive, Pixel, PixelType};
}

pub use crate::api::color;

/// Encoder configuration and settings
pub mod config {
  pub use crate::api::{
    Config, EncoderConfig, InvalidConfig, PredictionModesSetting,
    RateControlConfig, RateControlError, RateControlSummary, SpeedSettings,
  };
  pub use crate::cpu_features::CpuFeatureLevel;
}

/// Version information
///
/// The information is recovered from `Cargo.toml` and `git describe`, when available.
///
/// ```
/// use rav1e::version;
/// use semver::Version;
///
/// let major = version::major();
/// let minor = version::minor();
/// let patch = version::patch();
///
/// let short = version::short();
///
/// let v1 = Version::new(major, minor, patch);
/// let v2 = Version::parse(&short).unwrap();
///
/// assert_eq!(v1.major, v2.major);
/// ```
pub mod version {
  /// Major version component
  ///
  /// It is increased every time a release presents a incompatible API change.
  pub fn major() -> u64 {
    env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap()
  }
  /// Minor version component
  ///
  /// It is increased every time a release presents new functionalities are added
  /// in a backwards-compatible manner.
  pub fn minor() -> u64 {
    env!("CARGO_PKG_VERSION_MINOR").parse().unwrap()
  }
  /// Patch version component
  ///
  /// It is increased every time a release provides only backwards-compatible bugfixes.
  pub fn patch() -> u64 {
    env!("CARGO_PKG_VERSION_PATCH").parse().unwrap()
  }

  /// Version information as presented in `[package]` `version`.
  ///
  /// e.g. `0.1.0``
  ///
  /// Can be parsed by [semver](https://crates.io/crates/semver).
  pub fn short() -> String {
    env!("CARGO_PKG_VERSION").to_string()
  }

  /// Version information as presented in `[package] version` followed by the
  /// short commit hash if present.
  ///
  /// e.g. `0.1.0 - g743d464`
  ///
  pub fn long() -> String {
    let s = short();
    let hash = hash();

    if hash.is_empty() {
      s
    } else {
      format!("{} - {}", s, hash)
    }
  }

  /// Commit hash (short)
  ///
  /// Short hash of the git commit used by this build
  ///
  /// e.g. `g743d464`
  ///
  pub fn hash() -> String {
    env!("VERGEN_SHA_SHORT").to_string()
  }

  /// Version information with the information
  /// provided by `git describe --tags`.
  ///
  /// e.g. `0.1.0 (v0.1.0-1-g743d464)`
  ///
  pub fn full() -> String {
    let semver = env!("VERGEN_SEMVER_LIGHTWEIGHT");
    format!("{} ({})", short(), semver)
  }
}
#[cfg(all(
  any(test, fuzzing),
  any(feature = "decode_test", feature = "decode_test_dav1d")
))]
mod test_encode_decode;

#[cfg(feature = "bench")]
pub mod bench {
  pub mod api {
    pub use crate::api::*;
  }
  pub mod cdef {
    pub use crate::cdef::*;
  }
  pub mod context {
    pub use crate::context::*;
  }
  pub mod dist {
    pub use crate::dist::*;
  }
  pub mod ec {
    pub use crate::ec::*;
  }
  pub mod encoder {
    pub use crate::encoder::*;
  }
  pub mod mc {
    pub use crate::mc::*;
  }
  pub mod partition {
    pub use crate::partition::*;
  }
  pub mod frame {
    pub use crate::frame::*;
  }
  pub mod predict {
    pub use crate::predict::*;
  }
  pub mod rdo {
    pub use crate::rdo::*;
  }
  pub mod tiling {
    pub use crate::tiling::*;
  }
  pub mod transform {
    pub use crate::transform::*;
  }
  pub mod util {
    pub use crate::util::*;
  }
  pub mod cpu_features {
    pub use crate::cpu_features::*;
  }
}

#[cfg(fuzzing)]
pub mod fuzzing;
<|endoftext|>


<commit_before>//! [![github]](https://github.com/dtolnay/erased-serde) [![crates-io]](https://crates.io/crates/erased-serde) [![docs-rs]](https://docs.rs/erased-serde)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! This crate provides type-erased versions of Serde's `Serialize`, `Serializer`
//! and `Deserializer` traits that can be used as [trait objects].
//!
//! [trait objects]: https://doc.rust-lang.org/book/trait-objects.html
//!
//! The usual Serde `Serialize`, `Serializer` and `Deserializer` traits cannot
//! be used as trait objects like `&dyn Serialize` or boxed trait objects like
//! `Box<dyn Serialize>` because of Rust's ["object safety" rules]. In
//! particular, all three traits contain generic methods which cannot be made
//! into a trait object.
//!
//! ["object safety" rules]: http://huonw.github.io/blog/2015/01/object-safety/
//!
//! This library should be considered a low-level building block for interacting
//! with Serde APIs in an object-safe way. Most use cases will require higher
//! level functionality such as provided by [`typetag`] which uses this crate
//! internally.
//!
//! [`typetag`]: https://github.com/dtolnay/typetag
//!
//! **The traits in this crate work seamlessly with any existing Serde
//! `Serialize` and `Deserialize` type and any existing Serde `Serializer` and
//! `Deserializer` format.**
//!
//! ## Serialization
//!
//! ```rust
//! use erased_serde::{Serialize, Serializer};
//! use std::collections::BTreeMap as Map;
//! use std::io;
//!
//! fn main() {
//!     // Construct some serializers.
//!     let json = &mut serde_json::Serializer::new(io::stdout());
//!     let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));
//!
//!     // The values in this map are boxed trait objects. Ordinarily this would not
//!     // be possible with serde::Serializer because of object safety, but type
//!     // erasure makes it possible with erased_serde::Serializer.
//!     let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
//!     formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
//!     formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));
//!
//!     // These are boxed trait objects as well. Same thing here - type erasure
//!     // makes this possible.
//!     let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
//!     values.insert("vec", Box::new(vec!["a", "b"]));
//!     values.insert("int", Box::new(65536));
//!
//!     // Pick a Serializer out of the formats map.
//!     let format = formats.get_mut("json").unwrap();
//!
//!     // Pick a Serialize out of the values map.
//!     let value = values.get("vec").unwrap();
//!
//!     // This line prints `["a","b"]` to stdout.
//!     value.erased_serialize(format).unwrap();
//! }
//! ```
//!
//! ## Deserialization
//!
//! ```rust
//! use erased_serde::Deserializer;
//! use std::collections::BTreeMap as Map;
//!
//! fn main() {
//!     static JSON: &'static [u8] = br#"{"A": 65, "B": 66}"#;
//!     static CBOR: &'static [u8] = &[162, 97, 65, 24, 65, 97, 66, 24, 66];
//!
//!     // Construct some deserializers.
//!     let json = &mut serde_json::Deserializer::from_slice(JSON);
//!     let cbor = &mut serde_cbor::Deserializer::from_slice(CBOR);
//!
//!     // The values in this map are boxed trait objects, which is not possible
//!     // with the normal serde::Deserializer because of object safety.
//!     let mut formats: Map<&str, Box<dyn Deserializer>> = Map::new();
//!     formats.insert("json", Box::new(<dyn Deserializer>::erase(json)));
//!     formats.insert("cbor", Box::new(<dyn Deserializer>::erase(cbor)));
//!
//!     // Pick a Deserializer out of the formats map.
//!     let format = formats.get_mut("json").unwrap();
//!
//!     let data: Map<String, usize> = erased_serde::deserialize(format).unwrap();
//!
//!     println!("{}", data["A"] + data["B"]);
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/erased-serde/0.3.20")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))]
#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
#![allow(
    clippy::items_after_statements,
    clippy::manual_map, // https://github.com/rust-lang/rust-clippy/issues/7820
    clippy::missing_errors_doc,
    clippy::needless_doctest_main,
    clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7324
    clippy::unused_self,
    clippy::wildcard_imports
)]

mod alloc {
    #[cfg(not(feature = "std"))]
    extern crate alloc;

    #[cfg(feature = "std")]
    use std as alloc;

    pub use self::alloc::borrow::ToOwned;
    pub use self::alloc::boxed::Box;
    pub use self::alloc::string::{String, ToString};
    pub use self::alloc::{vec, vec::Vec};
}

#[macro_use]
mod macros;

mod any;
mod de;
mod error;
mod features_check;
mod map;
mod ser;

pub use crate::de::{deserialize, Deserializer};
pub use crate::error::{Error, Result};
pub use crate::ser::{serialize, Serialize, Serializer};

// Not public API.
#[doc(hidden)]
pub mod private;
<commit_msg>Ignore derive_partial_eq_without_eq clippy lint<commit_after>//! [![github]](https://github.com/dtolnay/erased-serde) [![crates-io]](https://crates.io/crates/erased-serde) [![docs-rs]](https://docs.rs/erased-serde)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! This crate provides type-erased versions of Serde's `Serialize`, `Serializer`
//! and `Deserializer` traits that can be used as [trait objects].
//!
//! [trait objects]: https://doc.rust-lang.org/book/trait-objects.html
//!
//! The usual Serde `Serialize`, `Serializer` and `Deserializer` traits cannot
//! be used as trait objects like `&dyn Serialize` or boxed trait objects like
//! `Box<dyn Serialize>` because of Rust's ["object safety" rules]. In
//! particular, all three traits contain generic methods which cannot be made
//! into a trait object.
//!
//! ["object safety" rules]: http://huonw.github.io/blog/2015/01/object-safety/
//!
//! This library should be considered a low-level building block for interacting
//! with Serde APIs in an object-safe way. Most use cases will require higher
//! level functionality such as provided by [`typetag`] which uses this crate
//! internally.
//!
//! [`typetag`]: https://github.com/dtolnay/typetag
//!
//! **The traits in this crate work seamlessly with any existing Serde
//! `Serialize` and `Deserialize` type and any existing Serde `Serializer` and
//! `Deserializer` format.**
//!
//! ## Serialization
//!
//! ```rust
//! use erased_serde::{Serialize, Serializer};
//! use std::collections::BTreeMap as Map;
//! use std::io;
//!
//! fn main() {
//!     // Construct some serializers.
//!     let json = &mut serde_json::Serializer::new(io::stdout());
//!     let cbor = &mut serde_cbor::Serializer::new(serde_cbor::ser::IoWrite::new(io::stdout()));
//!
//!     // The values in this map are boxed trait objects. Ordinarily this would not
//!     // be possible with serde::Serializer because of object safety, but type
//!     // erasure makes it possible with erased_serde::Serializer.
//!     let mut formats: Map<&str, Box<dyn Serializer>> = Map::new();
//!     formats.insert("json", Box::new(<dyn Serializer>::erase(json)));
//!     formats.insert("cbor", Box::new(<dyn Serializer>::erase(cbor)));
//!
//!     // These are boxed trait objects as well. Same thing here - type erasure
//!     // makes this possible.
//!     let mut values: Map<&str, Box<dyn Serialize>> = Map::new();
//!     values.insert("vec", Box::new(vec!["a", "b"]));
//!     values.insert("int", Box::new(65536));
//!
//!     // Pick a Serializer out of the formats map.
//!     let format = formats.get_mut("json").unwrap();
//!
//!     // Pick a Serialize out of the values map.
//!     let value = values.get("vec").unwrap();
//!
//!     // This line prints `["a","b"]` to stdout.
//!     value.erased_serialize(format).unwrap();
//! }
//! ```
//!
//! ## Deserialization
//!
//! ```rust
//! use erased_serde::Deserializer;
//! use std::collections::BTreeMap as Map;
//!
//! fn main() {
//!     static JSON: &'static [u8] = br#"{"A": 65, "B": 66}"#;
//!     static CBOR: &'static [u8] = &[162, 97, 65, 24, 65, 97, 66, 24, 66];
//!
//!     // Construct some deserializers.
//!     let json = &mut serde_json::Deserializer::from_slice(JSON);
//!     let cbor = &mut serde_cbor::Deserializer::from_slice(CBOR);
//!
//!     // The values in this map are boxed trait objects, which is not possible
//!     // with the normal serde::Deserializer because of object safety.
//!     let mut formats: Map<&str, Box<dyn Deserializer>> = Map::new();
//!     formats.insert("json", Box::new(<dyn Deserializer>::erase(json)));
//!     formats.insert("cbor", Box::new(<dyn Deserializer>::erase(cbor)));
//!
//!     // Pick a Deserializer out of the formats map.
//!     let format = formats.get_mut("json").unwrap();
//!
//!     let data: Map<String, usize> = erased_serde::deserialize(format).unwrap();
//!
//!     println!("{}", data["A"] + data["B"]);
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/erased-serde/0.3.20")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))]
#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
#![allow(
    clippy::derive_partial_eq_without_eq,
    clippy::items_after_statements,
    clippy::manual_map, // https://github.com/rust-lang/rust-clippy/issues/7820
    clippy::missing_errors_doc,
    clippy::needless_doctest_main,
    clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7324
    clippy::unused_self,
    clippy::wildcard_imports
)]

mod alloc {
    #[cfg(not(feature = "std"))]
    extern crate alloc;

    #[cfg(feature = "std")]
    use std as alloc;

    pub use self::alloc::borrow::ToOwned;
    pub use self::alloc::boxed::Box;
    pub use self::alloc::string::{String, ToString};
    pub use self::alloc::{vec, vec::Vec};
}

#[macro_use]
mod macros;

mod any;
mod de;
mod error;
mod features_check;
mod map;
mod ser;

pub use crate::de::{deserialize, Deserializer};
pub use crate::error::{Error, Result};
pub use crate::ser::{serialize, Serialize, Serializer};

// Not public API.
#[doc(hidden)]
pub mod private;
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]

extern crate byteorder;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, Read, Seek, SeekFrom, BufRead, BufReader};
use std::fs::File;
use std::cell::RefCell;

pub mod errors;
use errors::ReadError;

pub struct BigArchive<T: Read + Seek> {
    pub format: Format,
    pub size: u32,

    _buf_reader: RefCell<BufReader<T>>,
    _junk_len: u32,
    _entries: HashMap<String, BigEntry>,
}

// impl BigArchive {
//     pub fn create_from_file(file_path: &str) -> Result<Self, CreateError> {
//         let path = PathBuf::from(file_path);
//         let bytes = File::open(&file_path)?.bytes().collect::<Vec<_>>();
//         let file_len = bytes.len();
//         let cursor = Cursor::new(bytes);
//         let br = BufReader::new(cursor);
//
//         let entries = {
//             let m = HashMap::new();
//
//             let entry = BigEntry {
//                 offset: 0,
//                 size: file_len,
//                 name: "foo.txt".to_owned(),
//             }
//
//             m.insert("foo.txt", )
//             m
//         };
//
//         Some(BigArchive {
//             format: Format::Big4,
//             size: len,
//             _buf_reader: RefCell::new(br),
//             _entries: entries,
//         })
//     }
// }

impl BigArchive<File> {
    pub fn new_from_path(path: &str) -> Result<Self, ReadError> {
        let f = try!(File::open(&path));
        let br = BufReader::new(f);
        Ok(try!(BigArchive::new(br)))
    }
}

impl<T: Read + Seek> BigArchive<T> {
    pub fn new(mut data: BufReader<T>) -> Result<Self, ReadError> {
        let format = try!(read_format(&mut data));

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownArchiveFormat(bytes));
        }

        let archive_len = try!(data.read_u32::<LittleEndian>());
        let num_entries = try!(data.read_u32::<BigEndian>());
        let first_offset = try!(data.read_u32::<BigEndian>());
        let mut pos = 16;

        let mut entries = HashMap::new();

        for _ in 0..num_entries {
            let offset = try!(data.read_u32::<BigEndian>());
            let data_len = try!(data.read_u32::<BigEndian>());

            let mut buf = Vec::new();
            let name_len = try!(data.read_until(b'\0', &mut buf));

            let entry = BigEntry {
                offset: offset,
                data_len: data_len,
                name: String::from_utf8_lossy(&buf[..name_len - 1]).to_string(),
            };

            entries.insert(entry.name.clone(), entry);

            let entry_metadata_len = 4 + 4 + name_len as u32;
            pos += entry_metadata_len;
        }

        let junk_len = first_offset - pos
        // Patching an off-by-one. Need to revisit and fix this properly.
        + 1;

        Ok(BigArchive {
            format: format,
            size: archive_len,
            _buf_reader: RefCell::new(data),
            _junk_len: junk_len,
            _entries: entries,
        })
    }

    pub fn junk_len(&self) -> u32 {
        self._junk_len
    }

    pub fn entry_count(&self) -> usize {
        self._entries.len()
    }

    /// TODO: Don't return owned data, instead give the caller back a slice
    pub fn read_entry(&self, entry_name: &str) -> Option<Vec<u8>> {
        if let Some(entry) = self._entries.get(entry_name) {
            let br = &mut self._buf_reader.borrow_mut();

            if br.seek(SeekFrom::Start((*entry).offset as u64)).is_err() {
                return None;
            }

            let mut buf = vec![0; entry.data_len as usize];
            if br.read_exact(&mut buf).is_err() {
                return None;
            }

            Some(buf)
        } else {
            None
        }
    }

    pub fn contains(&self, entry_name: &str) -> bool {
        self._entries.contains_key(entry_name)
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub data_len: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGF" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

#[cfg(test)]
mod tests_bytes {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");
    use std::io::{BufReader, Cursor};
    use super::{Format, BigArchive};

    #[test]
    fn is_big4() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}

#[cfg(test)]
mod tests_file {
    use super::{Format, BigArchive};
    const ARCHIVE_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/test.big");

    #[test]
    fn is_big4() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}
<commit_msg>Remove rotted code in sagebig<commit_after>#![cfg_attr(test, feature(test))]

extern crate byteorder;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, Read, Seek, SeekFrom, BufRead, BufReader};
use std::fs::File;
use std::cell::RefCell;

pub mod errors;
use errors::ReadError;

pub struct BigArchive<T: Read + Seek> {
    pub format: Format,
    pub size: u32,

    _buf_reader: RefCell<BufReader<T>>,
    _junk_len: u32,
    _entries: HashMap<String, BigEntry>,
}

impl BigArchive<File> {
    pub fn new_from_path(path: &str) -> Result<Self, ReadError> {
        let f = try!(File::open(&path));
        let br = BufReader::new(f);
        Ok(try!(BigArchive::new(br)))
    }
}

impl<T: Read + Seek> BigArchive<T> {
    pub fn new(mut data: BufReader<T>) -> Result<Self, ReadError> {
        let format = try!(read_format(&mut data));

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownArchiveFormat(bytes));
        }

        let archive_len = try!(data.read_u32::<LittleEndian>());
        let num_entries = try!(data.read_u32::<BigEndian>());
        let first_offset = try!(data.read_u32::<BigEndian>());
        let mut pos = 16;

        let mut entries = HashMap::new();

        for _ in 0..num_entries {
            let offset = try!(data.read_u32::<BigEndian>());
            let data_len = try!(data.read_u32::<BigEndian>());

            let mut buf = Vec::new();
            let name_len = try!(data.read_until(b'\0', &mut buf));

            let entry = BigEntry {
                offset: offset,
                data_len: data_len,
                name: String::from_utf8_lossy(&buf[..name_len - 1]).to_string(),
            };

            entries.insert(entry.name.clone(), entry);

            let entry_metadata_len = 4 + 4 + name_len as u32;
            pos += entry_metadata_len;
        }

        let junk_len = first_offset - pos
        // Patching an off-by-one. Need to revisit and fix this properly.
        + 1;

        Ok(BigArchive {
            format: format,
            size: archive_len,
            _buf_reader: RefCell::new(data),
            _junk_len: junk_len,
            _entries: entries,
        })
    }

    pub fn junk_len(&self) -> u32 {
        self._junk_len
    }

    pub fn entry_count(&self) -> usize {
        self._entries.len()
    }

    /// TODO: Don't return owned data, instead give the caller back a slice
    pub fn read_entry(&self, entry_name: &str) -> Option<Vec<u8>> {
        if let Some(entry) = self._entries.get(entry_name) {
            let br = &mut self._buf_reader.borrow_mut();

            if br.seek(SeekFrom::Start((*entry).offset as u64)).is_err() {
                return None;
            }

            let mut buf = vec![0; entry.data_len as usize];
            if br.read_exact(&mut buf).is_err() {
                return None;
            }

            Some(buf)
        } else {
            None
        }
    }

    pub fn contains(&self, entry_name: &str) -> bool {
        self._entries.contains_key(entry_name)
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub data_len: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGF" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

#[cfg(test)]
mod tests_bytes {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");
    use std::io::{BufReader, Cursor};
    use super::{Format, BigArchive};

    #[test]
    fn is_big4() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}

#[cfg(test)]
mod tests_file {
    use super::{Format, BigArchive};
    const ARCHIVE_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/test.big");

    #[test]
    fn is_big4() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}
<|endoftext|>


<commit_before>/// EventFD binding
///
/// This crate implements a simple binding for Linux eventfd(). See
/// eventfd(2) for specific details of behaviour.

extern crate libc;

use libc::{c_int, c_uint, c_void};
use std::io::{IoResult, IoError};

pub struct EventFD {
    fd: uint,
    flags: uint,
}

/// Construct a semaphore-style EventFD.
pub const EFD_SEMAPHORE: uint = 0x00001; // 00000001

/// In non-blocking mode, reads and writes will return IoError
/// containing EAGAIN rather than blocking.
pub const EFD_NONBLOCK: uint  = 0x00800; // 00004000

/// Set the close-on-exec flag on the eventfd.
pub const EFD_CLOEXEC: uint   = 0x80000; // 02000000

impl EventFD {
    /// Create a new EventFD. Flags is the bitwise OR of EFD_* constants, or 0 for no flags.
    /// The underlying file descriptor is closed when the EventFD instance's lifetime ends.
    ///
    /// TODO: work out how to integrate this FD into the wider world
    /// of fds. There's currently no way to poll/select on the fd.
    pub fn new(initval: uint, flags: uint) -> IoResult<EventFD> {
        let r = unsafe { eventfd(initval as u32, flags as u32) };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(EventFD { fd: r as uint, flags: flags })
        }
    }

    /// Read the current value of the eventfd. This will block until
    /// the value is non-zero. In semaphore mode this will only ever
    /// decrement the count by 1 and return 1; otherwise it atomically
    /// returns the current value and sets it to zero.
    pub fn read(&self) -> IoResult<u64> {
        let mut ret : u64 = 0;
        let r = unsafe {
            let ptr : *mut u64 = &mut ret;
            ::libc::read(self.fd as c_int, ptr as *mut c_void, std::mem::size_of_val(&ret) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(ret)
        }
    }

    /// Add to the current value. Blocks if the value would wrap u64.
    pub fn write(&self, val: u64) -> IoResult<()> {
        let r = unsafe {
            let ptr : *const u64 = &val;
            ::libc::write(self.fd as c_int, ptr as *const c_void, std::mem::size_of_val(&val) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(())
        }
    }

    /// Return a stream of events. The channel has a synchronous
    /// sender because there's no point in building up a queue of
    /// events; if this task blocks on send, the event state will
    /// still update.
    ///
    /// This will be an infinite loop if the EventFD is created
    /// non-blocking.
    ///
    /// XXX FIXME This has no way of terminating except if the other
    /// end closes the connection, and only then if we're not blocked
    /// in the read()...
    pub fn events(&self) -> std::comm::Receiver<u64> {
        let (tx, rx) = std::comm::sync_channel(1);
        let c = self.clone();

        spawn(proc() {
            loop {
                match c.read() {
                    Ok(v) => tx.send(v),
                    Err(e) => panic!("read failed: {}", e),
                }
            }
        });

        rx
    }
}

impl Sync for EventFD {}
impl Send for EventFD {}

impl Drop for EventFD {
    fn drop(&mut self) {
        let r = unsafe { ::libc::close(self.fd as c_int) };
        if r < 0 {
            panic!("eventfd close {} failed", self.fd)
        }
    }
}

/// Construct a linked clone of an existing EventFD. Once created, the
/// new instance interacts with the original in a way that's
/// indistinguishable from the original.
impl Clone for EventFD {
    fn clone(&self) -> EventFD {
        let r = unsafe { ::libc::dup(self.fd as c_int) };
        if r < 0 {
            panic!("EventFD clone dup failed: {}", IoError::last_error())
        }

        EventFD { fd: r as uint, flags: self.flags }
    }
}

#[link(name = "c")]
extern "C" {
    fn eventfd(initval: c_uint, flags: c_uint) -> c_int;
}

#[test]
fn test_basic() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let cefd = efd.clone();

    assert!(efd.read() == Ok(10));

    spawn(proc() {
        assert!(cefd.read() == Ok(7));
        assert!(cefd.write(1) == Ok(()));
        assert!(cefd.write(2) == Ok(()));
        tx.send(());
    });

    assert!(efd.write(7) == Ok(()));
    rx.recv();
    assert!(efd.read() == Ok(3));
}

#[test]
fn test_sema() {
    let efd = match EventFD::new(0, EFD_SEMAPHORE | EFD_NONBLOCK) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }

    assert!(efd.write(5) == Ok(()));

    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }
}

#[test]
fn test_stream() {
    let efd = match EventFD::new(10, EFD_SEMAPHORE) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let mut count = 0;

    for v in efd.events().iter() {
        assert!(v == 1);
        count += v;
        if count == 10 {
            break;
        }
    }
}

#[test]
fn test_chan() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    assert!(efd.write(1) == Ok(()));
    tx.send(efd);

    let t = std::task::try(proc() {
        let efd = rx.recv();
        assert!(efd.read() == Ok(11))
    });

    match t {
        Ok(_) => println!("ok"),
        Err(_) => panic!("failed"),
    }
}
<commit_msg>Clean up streamning shutdown, don't let stream test hang tests<commit_after>/// EventFD binding
///
/// This crate implements a simple binding for Linux eventfd(). See
/// eventfd(2) for specific details of behaviour.

extern crate libc;

use libc::{c_int, c_uint, c_void};
use std::io::{IoResult, IoError};

pub struct EventFD {
    fd: uint,
    flags: uint,
}

/// Construct a semaphore-style EventFD.
pub const EFD_SEMAPHORE: uint = 0x00001; // 00000001

/// In non-blocking mode, reads and writes will return IoError
/// containing EAGAIN rather than blocking.
pub const EFD_NONBLOCK: uint  = 0x00800; // 00004000

/// Set the close-on-exec flag on the eventfd.
pub const EFD_CLOEXEC: uint   = 0x80000; // 02000000

impl EventFD {
    /// Create a new EventFD. Flags is the bitwise OR of EFD_* constants, or 0 for no flags.
    /// The underlying file descriptor is closed when the EventFD instance's lifetime ends.
    ///
    /// TODO: work out how to integrate this FD into the wider world
    /// of fds. There's currently no way to poll/select on the fd.
    pub fn new(initval: uint, flags: uint) -> IoResult<EventFD> {
        let r = unsafe { eventfd(initval as u32, flags as u32) };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(EventFD { fd: r as uint, flags: flags })
        }
    }

    /// Read the current value of the eventfd. This will block until
    /// the value is non-zero. In semaphore mode this will only ever
    /// decrement the count by 1 and return 1; otherwise it atomically
    /// returns the current value and sets it to zero.
    pub fn read(&self) -> IoResult<u64> {
        let mut ret : u64 = 0;
        let r = unsafe {
            let ptr : *mut u64 = &mut ret;
            ::libc::read(self.fd as c_int, ptr as *mut c_void, std::mem::size_of_val(&ret) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(ret)
        }
    }

    /// Add to the current value. Blocks if the value would wrap u64.
    pub fn write(&self, val: u64) -> IoResult<()> {
        let r = unsafe {
            let ptr : *const u64 = &val;
            ::libc::write(self.fd as c_int, ptr as *const c_void, std::mem::size_of_val(&val) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(())
        }
    }

    /// Return a stream of events. The channel has a synchronous
    /// sender because there's no point in building up a queue of
    /// events; if this task blocks on send, the event state will
    /// still update.
    ///
    /// The task will exit if the receiver end is shut down.
    ///
    /// This will be a CPU-spin loop if the EventFD is created
    /// non-blocking.
    ///
    /// XXX FIXME This has no way of terminating except if the other
    /// end closes the connection, and only then if we're not blocked
    /// in the read()...
    pub fn events(&self) -> std::comm::Receiver<u64> {
        let (tx, rx) = std::comm::sync_channel(1);
        let c = self.clone();

        spawn(proc() {
            loop {
                match c.read() {
                    Ok(v) => match tx.send_opt(v) {
                        Ok(_) => (),
                        Err(_) => break,
                    },
                    Err(e) => panic!("read failed: {}", e),
                }
            }
        });

        rx
    }
}

impl Sync for EventFD {}
impl Send for EventFD {}

impl Drop for EventFD {
    fn drop(&mut self) {
        let r = unsafe { ::libc::close(self.fd as c_int) };
        if r < 0 {
            panic!("eventfd close {} failed", self.fd)
        }
    }
}

/// Construct a linked clone of an existing EventFD. Once created, the
/// new instance interacts with the original in a way that's
/// indistinguishable from the original.
impl Clone for EventFD {
    fn clone(&self) -> EventFD {
        let r = unsafe { ::libc::dup(self.fd as c_int) };
        if r < 0 {
            panic!("EventFD clone dup failed: {}", IoError::last_error())
        }

        EventFD { fd: r as uint, flags: self.flags }
    }
}

#[link(name = "c")]
extern "C" {
    fn eventfd(initval: c_uint, flags: c_uint) -> c_int;
}

#[test]
fn test_basic() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let cefd = efd.clone();

    assert!(efd.read() == Ok(10));

    spawn(proc() {
        assert!(cefd.read() == Ok(7));
        assert!(cefd.write(1) == Ok(()));
        assert!(cefd.write(2) == Ok(()));
        tx.send(());
    });

    assert!(efd.write(7) == Ok(()));
    rx.recv();
    assert!(efd.read() == Ok(3));
}

#[test]
fn test_sema() {
    let efd = match EventFD::new(0, EFD_SEMAPHORE | EFD_NONBLOCK) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }

    assert!(efd.write(5) == Ok(()));

    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }
}

#[test]
fn test_stream() {
    let efd = match EventFD::new(11, EFD_SEMAPHORE) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let mut count = 0;

    // only take 10 of 11 so the stream task doesn't block in read and hang the test
    for v in efd.events().iter().take(10) {
        assert!(v == 1);
        count += v;
    }

    assert!(count == 10)
}

#[test]
fn test_chan() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    assert!(efd.write(1) == Ok(()));
    tx.send(efd);

    let t = std::task::try(proc() {
        let efd = rx.recv();
        assert!(efd.read() == Ok(11))
    });

    match t {
        Ok(_) => println!("ok"),
        Err(_) => panic!("failed"),
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext};
}
<commit_msg>Add `FramebufferContext` to the prelude<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use framebuffer::FramebufferContext;
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext};
}
<|endoftext|>


<commit_before>// TODO: for a good time, comment this line and let rust point out all the extra stuff
#![allow(dead_code)]

#![feature(proc_macro)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]

// Clippy specific settings
#![feature(plugin)]
#![plugin(clippy)]
#![allow(len_without_is_empty)]
#![allow(mutex_atomic)] // TODO: comment out and address AtomicBools

// Serde specific settings
extern crate serde;
#[macro_use] extern crate serde_derive;

//#[macro_use] extern crate log;
#[macro_use] extern crate bitflags;

extern crate byteorder;

// mod only exposed
pub mod cdr;
pub mod common_types;
pub mod sync;

// flattened expose
pub mod entity;
pub mod message;
pub mod submessage;

// glob expose
//pub use cdr::*;
pub use message::*;
pub use submessage::*;
pub use entity::*;<commit_msg>so fun<commit_after>// TODO: for a good time, comment this line and let rust point out all the extra stuff
#![allow(dead_code)]

#![feature(proc_macro)]
#![feature(type_ascription)]
#![feature(rustc_attrs)]

// TODO: big deal to not have for stable!
#![feature(integer_atomics)]

// Clippy specific settings
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![allow(len_without_is_empty)]
#![allow(mutex_atomic)] // TODO: comment out and address AtomicBools

// Serde specific settings
extern crate serde;
#[macro_use] extern crate serde_derive;

//#[macro_use] extern crate log;
#[macro_use] extern crate bitflags;

extern crate byteorder;

// mod only exposed
pub mod cdr;
pub mod common_types;
pub mod sync;

// flattened expose
pub mod entity;
pub mod message;
pub mod submessage;

// glob expose
//pub use cdr::*;
pub use message::*;
pub use submessage::*;
pub use entity::*;<|endoftext|>


<commit_before>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

/*!
Alternatives and extensions to the unstable `char.encode_utf8()` and `char.encode_utf16()`.

[crates.io page](https://crates.io/crates/encode_unicode)
[github repository](https://github.com/tormol/encode_unicode)

# Optional features:
* **no_std**: Use `#[no_std]`; There are some differences:
  * `AsciiExt` doesn't exist, but `is_ascii()` is made available as an inherent impl.
  * `Error` doesn't exist, but `description()` is made available as an inherent impl.
  * There is no `io`, so `Utf8Iterator` doesn't implement `Read`.
  * The iterators doesn't implement `Debug`.
* **ascii**: Convert `Utf8Char` and `Utf16Char` to and from [ascii](https://tomprogrammer.github.io/rust-ascii/ascii/index.html)::[`AsciiChar`](https://tomprogrammer.github.io/rust-ascii/ascii/enum.AsciiChar.html).
* **ascii_no_std**: You need to use this feature instead of both ascii and no_std.
  This is because the ascii crate needs to know about `#[no_std]`, but the features are otherwize independent.
*/

#![cfg_attr(feature="std", warn(missing_docs))] // Don't bother documenting std standins.

#![cfg_attr(not(feature="std"), no_std)]
// either `cargo clippy` doesn't see theese, or I get a warning when I build.
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", allow(len_without_is_empty))]// UtfxChar is never empty
#![cfg_attr(feature="clippy", allow(match_same_arms))]
#![cfg_attr(feature="clippy", allow(derive_hash_xor_eq))]// tested
// precedence: I prefer spaces to parentheses, but it's nice to recheck.

mod errors;
mod traits;
mod utf8_char;
mod utf8_iterator;
mod utf16_char;
mod utf16_iterator;

pub use traits::CharExt;
pub use utf8_char::Utf8Char;
pub use utf16_char::Utf16Char;
pub use utf8_iterator::Utf8Iterator;
pub use utf16_iterator::Utf16Iterator;
pub use traits::U8UtfExt;
pub use traits::U16UtfExt;

pub mod error {// keeping the public interface in one file
    //! Errors returned by various conversion methods in this crate.
    pub use utf8_char::FromStrError;
    pub use errors::{InvalidCodepoint};
    pub use errors::{InvalidUtf8};
    pub use errors::{InvalidUtf8FirstByte,InvalidUtf16FirstUnit};
    pub use errors::{InvalidUtf8Slice,InvalidUtf16Slice};
    pub use errors::{InvalidUtf8Array,InvalidUtf16Tuple};
}
<commit_msg>Ignore a few more Clippy lints<commit_after>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

/*!
Alternatives and extensions to the unstable `char.encode_utf8()` and `char.encode_utf16()`.

[crates.io page](https://crates.io/crates/encode_unicode)
[github repository](https://github.com/tormol/encode_unicode)

# Optional features:
* **no_std**: Use `#[no_std]`; There are some differences:
  * `AsciiExt` doesn't exist, but `is_ascii()` is made available as an inherent impl.
  * `Error` doesn't exist, but `description()` is made available as an inherent impl.
  * There is no `io`, so `Utf8Iterator` doesn't implement `Read`.
  * The iterators doesn't implement `Debug`.
* **ascii**: Convert `Utf8Char` and `Utf16Char` to and from [ascii](https://tomprogrammer.github.io/rust-ascii/ascii/index.html)::[`AsciiChar`](https://tomprogrammer.github.io/rust-ascii/ascii/enum.AsciiChar.html).
* **ascii_no_std**: You need to use this feature instead of both ascii and no_std.
  This is because the ascii crate needs to know about `#[no_std]`, but the features are otherwize independent.
*/

#![cfg_attr(feature="std", warn(missing_docs))] // Don't bother documenting std standins.

#![cfg_attr(not(feature="std"), no_std)]
// either `cargo clippy` doesn't see theese, or I get a warning when I build.
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", allow(derive_hash_xor_eq))]// tested
#![cfg_attr(feature="clippy", allow(len_without_is_empty))]// UtfxChar is never empty
#![cfg_attr(feature="clippy", allow(match_same_arms))]// looks better IMO
#![cfg_attr(feature="clippy", allow(needless_return))]// `foo.bar(); foo` looks unfinished
#![cfg_attr(feature="clippy", allow(redundant_closure))]// keep it explicit
// precedence: I prefer spaces to parentheses, but it's nice to recheck.

mod errors;
mod traits;
mod utf8_char;
mod utf8_iterator;
mod utf16_char;
mod utf16_iterator;

pub use traits::CharExt;
pub use utf8_char::Utf8Char;
pub use utf16_char::Utf16Char;
pub use utf8_iterator::Utf8Iterator;
pub use utf16_iterator::Utf16Iterator;
pub use traits::U8UtfExt;
pub use traits::U16UtfExt;

pub mod error {// keeping the public interface in one file
    //! Errors returned by various conversion methods in this crate.
    pub use utf8_char::FromStrError;
    pub use errors::{InvalidCodepoint};
    pub use errors::{InvalidUtf8};
    pub use errors::{InvalidUtf8FirstByte,InvalidUtf16FirstUnit};
    pub use errors::{InvalidUtf8Slice,InvalidUtf16Slice};
    pub use errors::{InvalidUtf8Array,InvalidUtf16Tuple};
}
<|endoftext|>


<commit_before>#![feature(rustc_private, never_type, decl_macro)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate rustc;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_fs_util;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::any::Any;
use std::sync::mpsc;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift::codegen::settings;

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod driver;
mod intrinsics;
mod linkage;
mod llvm_intrinsics;
mod main_shim;
mod metadata;
mod pretty_clif;
mod target_features_whitelist;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};
    pub use std::convert::{TryFrom, TryInto};

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::{Pos, Span, DUMMY_SP};

    pub use rustc::bug;
    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::collector;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::cast::*;
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::trap::*;
    pub use crate::unimpl::{unimpl, with_unimpl_span};
    pub use crate::value_and_place::{CValue, CPlace};
    pub use crate::{Caches, CodegenCx};

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
}

impl Default for Caches<'_> {
    fn default() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    ccx: ConstantCx,
    caches: Caches<'tcx>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            ccx: ConstantCx::default(),
            caches: Caches::default(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.ccx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, _sess: &Session) {}

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_ssa::back::symbol_export::provide(providers);

        providers.target_features_whitelist = |tcx, cnum| {
            assert_eq!(cnum, LOCAL_CRATE);
            if tcx.sess.opts.actually_rustdoc {
                // rustdoc needs to be able to document functions that use all the features, so
                // whitelist them all
                 tcx.arena.alloc(target_features_whitelist::all_known_features()
                    .map(|(a, b)| (a.to_string(), b))
                    .collect())
            } else {
                tcx.arena.alloc(target_features_whitelist::target_feature_whitelist(tcx.sess)
                    .iter()
                    .map(|&(a, b)| (a.to_string(), b))
                    .collect())
            }
        };
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
        _rx: mpsc::Receiver<Box<dyn Any + Send>>,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_incremental::assert_module_sources::assert_module_sources(tcx);

        res
    }

    fn join_codegen_and_link(
        &self,
        res: Box<dyn Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let target_cpu = ::target_lexicon::HOST.to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    let mut target = &*sess.target.target.llvm_target;

    // FIXME add support for x86_64-apple-macosx10.7.0 to target-lexicon
    if target.starts_with("x86_64-apple-macosx") {
        target = "x86_64-apple-darwin";
    }

    target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("probestack_enabled", "false").unwrap(); // __cranelift_probestack is not provided
        flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
        "true"
    } else {
        "false"
    }).unwrap();

    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
    //flags_builder.set("opt_level", "best").unwrap();

    // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let target_triple = target_triple(sess);
    let flags = settings::Flags::new(flags_builder);
    cranelift::codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<commit_msg>Print error for #[rustc_def_path] like expected<commit_after>#![feature(rustc_private, never_type, decl_macro)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate rustc;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_fs_util;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
extern crate syntax;

use std::any::Any;
use std::sync::mpsc;

use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift::codegen::settings;

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod driver;
mod intrinsics;
mod linkage;
mod llvm_intrinsics;
mod main_shim;
mod metadata;
mod pretty_clif;
mod target_features_whitelist;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};
    pub use std::convert::{TryFrom, TryInto};

    pub use syntax::ast::{FloatTy, IntTy, UintTy};
    pub use syntax::source_map::{Pos, Span, DUMMY_SP};

    pub use rustc::bug;
    pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use rustc_mir::monomorphize::collector;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
    };
    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::cast::*;
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::trap::*;
    pub use crate::unimpl::{unimpl, with_unimpl_span};
    pub use crate::value_and_place::{CValue, CPlace};
    pub use crate::{Caches, CodegenCx};

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
}

impl Default for Caches<'_> {
    fn default() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    ccx: ConstantCx,
    caches: Caches<'tcx>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            ccx: ConstantCx::default(),
            caches: Caches::default(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.ccx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, _sess: &Session) {}

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_ssa::back::symbol_export::provide(providers);

        providers.target_features_whitelist = |tcx, cnum| {
            assert_eq!(cnum, LOCAL_CRATE);
            if tcx.sess.opts.actually_rustdoc {
                // rustdoc needs to be able to document functions that use all the features, so
                // whitelist them all
                 tcx.arena.alloc(target_features_whitelist::all_known_features()
                    .map(|(a, b)| (a.to_string(), b))
                    .collect())
            } else {
                tcx.arena.alloc(target_features_whitelist::target_feature_whitelist(tcx.sess)
                    .iter()
                    .map(|&(a, b)| (a.to_string(), b))
                    .collect())
            }
        };
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
        _rx: mpsc::Receiver<Box<dyn Any + Send>>,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_incremental::assert_module_sources::assert_module_sources(tcx);
        rustc_codegen_utils::symbol_names_test::report_symbol_names(tcx);

        res
    }

    fn join_codegen_and_link(
        &self,
        res: Box<dyn Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let target_cpu = ::target_lexicon::HOST.to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    let mut target = &*sess.target.target.llvm_target;

    // FIXME add support for x86_64-apple-macosx10.7.0 to target-lexicon
    if target.starts_with("x86_64-apple-macosx") {
        target = "x86_64-apple-darwin";
    }

    target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("probestack_enabled", "false").unwrap(); // __cranelift_probestack is not provided
        flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
        "true"
    } else {
        "false"
    }).unwrap();

    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
    //flags_builder.set("opt_level", "best").unwrap();

    // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let target_triple = target_triple(sess);
    let flags = settings::Flags::new(flags_builder);
    cranelift::codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<|endoftext|>