<commit_before>use crate::model::id::MessageId;
use crate::utils::VecMap;

/// Builds a request for a request to the API to retrieve messages.
///
/// This can have 2 different sets of parameters. The first set is around where
/// to get the messages:
///
/// - `after`
/// - `around`
/// - `before`
/// - `most_recent`
///
/// These can not be mixed, and the first in the list alphabetically will be
/// used. If one is not specified, `most_recent` will be used.
///
/// The fourth parameter is to specify the number of messages to retrieve. This
/// does not _need_ to be called and defaults to a value of 50.
///
/// This should be used only for retrieving messages; see
/// [`GuildChannel::messages`] for examples.
///
/// # Examples
///
/// Creating a `GetMessages` builder to retrieve the first 25 messages after the
/// message with an Id of `158339864557912064`:
///
/// ```rust,no_run
/// # use serenity::http::Http;
/// # use std::{error::Error, sync::Arc};
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// # let http = Arc::new(Http::default());
/// use serenity::model::id::{ChannelId, MessageId};
///
/// // you can then pass it into a function which retrieves messages:
/// let channel_id = ChannelId(81384788765712384);
///
/// let _messages = channel_id.messages(&http, |retriever| {
///     retriever.after(MessageId(158339864557912064)).limit(25)
/// })?;
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
/// ```
///
/// [`GuildChannel::messages`]: ../model/channel/struct.GuildChannel.html#method.messages
#[derive(Clone, Debug, Default)]
pub struct GetMessages(pub VecMap<&'static str, u64>);

impl GetMessages {
    /// Indicates to retrieve the messages after a specific message, given by
    /// its Id.
    #[inline]
    pub fn after<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._after(message_id.into());
        self
    }

    fn _after(&mut self, message_id: MessageId) {
        self.0.insert("after", message_id.0);
    }

    /// Indicates to retrieve the messages _around_ a specific message in either
    /// direction (before+after) the given message.
    #[inline]
    pub fn around<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._around(message_id.into());
        self
    }

    fn _around(&mut self, message_id: MessageId) {
        self.0.insert("around", message_id.0);
    }

    /// Indicates to retrieve the messages before a specific message, given by
    /// its Id.
    #[inline]
    pub fn before<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._before(message_id.into());
        self
    }

    fn _before(&mut self, message_id: MessageId) {
        self.0.insert("before", message_id.0);
    }

    /// The maximum number of messages to retrieve for the query.
    ///
    /// If this is not specified, a default value of 50 is used.
    ///
    /// **Note**: This field is capped to 100 messages due to a Discord
    /// limitation. If an amount larger than 100 is supplied, it will be
    /// reduced.
    pub fn limit(&mut self, limit: u64) -> &mut Self {
        self.0.insert("limit", if limit > 100 { 100 } else { limit });
        self
    }

    /// This is a function that is here for completeness. You do not need to
    /// call this - except to clear previous calls to `after`, `around`, and
    /// `before` - as it is the default value.
    pub fn most_recent(&self) { }
}
<commit_msg>Remove useless method<commit_after>use crate::model::id::MessageId;
use crate::utils::VecMap;

/// Builds a request for a request to the API to retrieve messages.
///
/// This can have 2 different sets of parameters. The first set is around where
/// to get the messages:
///
/// - `after`
/// - `around`
/// - `before`
///
/// These can not be mixed, and the first in the list alphabetically will be
/// used. If one is not specified, `most_recent` will be used.
///
/// The fourth parameter is to specify the number of messages to retrieve. This
/// does not _need_ to be called and defaults to a value of 50.
///
/// This should be used only for retrieving messages; see
/// [`GuildChannel::messages`] for examples.
///
/// # Examples
///
/// Creating a `GetMessages` builder to retrieve the first 25 messages after the
/// message with an Id of `158339864557912064`:
///
/// ```rust,no_run
/// # use serenity::http::Http;
/// # use std::{error::Error, sync::Arc};
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// # let http = Arc::new(Http::default());
/// use serenity::model::id::{ChannelId, MessageId};
///
/// // you can then pass it into a function which retrieves messages:
/// let channel_id = ChannelId(81384788765712384);
///
/// let _messages = channel_id.messages(&http, |retriever| {
///     retriever.after(MessageId(158339864557912064)).limit(25)
/// })?;
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
/// ```
///
/// [`GuildChannel::messages`]: ../model/channel/struct.GuildChannel.html#method.messages
#[derive(Clone, Debug, Default)]
pub struct GetMessages(pub VecMap<&'static str, u64>);

impl GetMessages {
    /// Indicates to retrieve the messages after a specific message, given by
    /// its Id.
    #[inline]
    pub fn after<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._after(message_id.into());
        self
    }

    fn _after(&mut self, message_id: MessageId) {
        self.0.insert("after", message_id.0);
    }

    /// Indicates to retrieve the messages _around_ a specific message in either
    /// direction (before+after) the given message.
    #[inline]
    pub fn around<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._around(message_id.into());
        self
    }

    fn _around(&mut self, message_id: MessageId) {
        self.0.insert("around", message_id.0);
    }

    /// Indicates to retrieve the messages before a specific message, given by
    /// its Id.
    #[inline]
    pub fn before<M: Into<MessageId>>(&mut self, message_id: M) -> &mut Self {
        self._before(message_id.into());
        self
    }

    fn _before(&mut self, message_id: MessageId) {
        self.0.insert("before", message_id.0);
    }

    /// The maximum number of messages to retrieve for the query.
    ///
    /// If this is not specified, a default value of 50 is used.
    ///
    /// **Note**: This field is capped to 100 messages due to a Discord
    /// limitation. If an amount larger than 100 is supplied, it will be
    /// reduced.
    pub fn limit(&mut self, limit: u64) -> &mut Self {
        self.0.insert("limit", if limit > 100 { 100 } else { limit });
        self
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsString;

use crate::core::compiler::{Compilation, Doctest};
use crate::core::shell::Verbosity;
use crate::core::Workspace;
use crate::ops;
use crate::util::errors::CargoResult;
use crate::util::{CargoTestError, Config, ProcessError, Test};

pub struct TestOptions {
    pub compile_opts: ops::CompileOptions,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

pub fn run_tests(
    ws: &Workspace<'_>,
    options: &TestOptions,
    test_args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }
    let (test, mut errors) = run_unit_tests(ws.config(), options, test_args, &compilation)?;

    // If we have an error and want to fail fast, then return.
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(test, errors)));
    }

    let (doctest, docerrors) = run_doc_tests(ws.config(), options, test_args, &compilation)?;
    let test = if docerrors.is_empty() { test } else { doctest };
    errors.extend(docerrors);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(test, errors)))
    }
}

pub fn run_benches(
    ws: &Workspace<'_>,
    options: &TestOptions,
    args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }

    let mut args = args.to_vec();
    args.push("--bench");

    let (test, errors) = run_unit_tests(ws.config(), options, &args, &compilation)?;

    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(test, errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation
        .tests
        .sort_by(|a, b| (a.0.package_id(), &a.1, &a.2).cmp(&(b.0.package_id(), &b.1, &b.2)));
    Ok(compilation)
}

/// Runs the unit and integration tests of a package.
fn run_unit_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let cwd = config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, ref target, ref exe) in &compilation.tests {
        let kind = target.kind();
        let test = target.name().to_string();
        let exe_display = exe.strip_prefix(cwd).unwrap_or(exe).display();
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        if target.harness() && config.shell().verbosity() == Verbosity::Quiet {
            cmd.arg("--quiet");
        }
        config
            .shell()
            .concise(|shell| shell.status("Running", &exe_display))?;
        config
            .shell()
            .verbose(|shell| shell.status("Running", &cmd))?;

        let result = cmd.exec();

        match result {
            Err(e) => {
                let e = e.downcast::<ProcessError>()?;
                errors.push((kind.clone(), test.clone(), pkg.name().to_string(), e));
                if !options.no_fail_fast {
                    break;
                }
            }
            Ok(()) => {}
        }
    }

    if errors.len() == 1 {
        let (kind, name, pkg_name, e) = errors.pop().unwrap();
        Ok((
            Test::UnitTest {
                kind,
                name,
                pkg_name,
            },
            vec![e],
        ))
    } else {
        Ok((
            Test::Multiple,
            errors.into_iter().map(|(_, _, _, e)| e).collect(),
        ))
    }
}

fn run_doc_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let mut errors = Vec::new();

    // The unstable doctest-xcompile feature enables both per-target-ignores and
    // cross-compiling doctests. As a side effect, this feature also gates running
    // doctests with runtools when target == host.
    let doctest_xcompile = config.cli_unstable().doctest_xcompile;
    let mut runtool: &Option<(std::path::PathBuf, Vec<String>)> = &None;
    if doctest_xcompile {
        runtool = compilation.target_runner();
    } else if compilation.host != compilation.target {
        return Ok((Test::Doc, errors));
    }

    for doctest_info in &compilation.to_doc_test {
        let Doctest {
            package,
            target,
            args,
            unstable_opts,
        } = doctest_info;
        config.shell().status("Doc-tests", target.name())?;
        let mut p = compilation.rustdoc_process(package, target)?;
        p.arg("--test")
            .arg(target.src_path().path().unwrap())
            .arg("--crate-name")
            .arg(&target.crate_name());

        if doctest_xcompile {
            p.arg("--target").arg(&compilation.target);
            p.arg("-Zunstable-options");
            p.arg("--enable-per-target-ignores");
        }

        if let Some((runtool, runtool_args)) = runtool {
            p.arg("--runtool").arg(runtool);
            for arg in runtool_args {
                p.arg("--runtool-arg").arg(arg);
            }
        }

        for &rust_dep in &[&compilation.deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(rust_dep);
            p.arg("-L").arg(arg);
        }

        for native_dep in compilation.native_dirs.iter() {
            p.arg("-L").arg(native_dep);
        }

        for &host_rust_dep in &[&compilation.host_deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(host_rust_dep);
            p.arg("-L").arg(arg);
        }

        for arg in test_args {
            p.arg("--test-args").arg(arg);
        }

        if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
            for cfg in cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }
        }

        for arg in args {
            p.arg(arg);
        }

        if *unstable_opts {
            p.arg("-Zunstable-options");
        }

        if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) {
            p.args(flags);
        }
        config
            .shell()
            .verbose(|shell| shell.status("Running", p.to_string()))?;
        if let Err(e) = p.exec() {
            let e = e.downcast::<ProcessError>()?;
            errors.push(e);
            if !options.no_fail_fast {
                return Ok((Test::Doc, errors));
            }
        }
    }
    Ok((Test::Doc, errors))
}
<commit_msg>fix target<commit_after>use std::ffi::OsString;

use crate::core::compiler::{Compilation, CompileKind, Doctest};
use crate::core::shell::Verbosity;
use crate::core::Workspace;
use crate::ops;
use crate::util::errors::CargoResult;
use crate::util::{CargoTestError, Config, ProcessError, Test};

pub struct TestOptions {
    pub compile_opts: ops::CompileOptions,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

pub fn run_tests(
    ws: &Workspace<'_>,
    options: &TestOptions,
    test_args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }
    let (test, mut errors) = run_unit_tests(ws.config(), options, test_args, &compilation)?;

    // If we have an error and want to fail fast, then return.
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(test, errors)));
    }

    let (doctest, docerrors) = run_doc_tests(ws.config(), options, test_args, &compilation)?;
    let test = if docerrors.is_empty() { test } else { doctest };
    errors.extend(docerrors);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(test, errors)))
    }
}

pub fn run_benches(
    ws: &Workspace<'_>,
    options: &TestOptions,
    args: &[&str],
) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None);
    }

    let mut args = args.to_vec();
    args.push("--bench");

    let (test, errors) = run_unit_tests(ws.config(), options, &args, &compilation)?;

    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(test, errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation
        .tests
        .sort_by(|a, b| (a.0.package_id(), &a.1, &a.2).cmp(&(b.0.package_id(), &b.1, &b.2)));
    Ok(compilation)
}

/// Runs the unit and integration tests of a package.
fn run_unit_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let cwd = config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, ref target, ref exe) in &compilation.tests {
        let kind = target.kind();
        let test = target.name().to_string();
        let exe_display = exe.strip_prefix(cwd).unwrap_or(exe).display();
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        if target.harness() && config.shell().verbosity() == Verbosity::Quiet {
            cmd.arg("--quiet");
        }
        config
            .shell()
            .concise(|shell| shell.status("Running", &exe_display))?;
        config
            .shell()
            .verbose(|shell| shell.status("Running", &cmd))?;

        let result = cmd.exec();

        match result {
            Err(e) => {
                let e = e.downcast::<ProcessError>()?;
                errors.push((kind.clone(), test.clone(), pkg.name().to_string(), e));
                if !options.no_fail_fast {
                    break;
                }
            }
            Ok(()) => {}
        }
    }

    if errors.len() == 1 {
        let (kind, name, pkg_name, e) = errors.pop().unwrap();
        Ok((
            Test::UnitTest {
                kind,
                name,
                pkg_name,
            },
            vec![e],
        ))
    } else {
        Ok((
            Test::Multiple,
            errors.into_iter().map(|(_, _, _, e)| e).collect(),
        ))
    }
}

fn run_doc_tests(
    config: &Config,
    options: &TestOptions,
    test_args: &[&str],
    compilation: &Compilation<'_>,
) -> CargoResult<(Test, Vec<ProcessError>)> {
    let mut errors = Vec::new();

    // The unstable doctest-xcompile feature enables both per-target-ignores and
    // cross-compiling doctests. As a side effect, this feature also gates running
    // doctests with runtools when target == host.
    let doctest_xcompile = config.cli_unstable().doctest_xcompile;
    let mut runtool: &Option<(std::path::PathBuf, Vec<String>)> = &None;
    if doctest_xcompile {
        runtool = compilation.target_runner();
    } else if compilation.host != compilation.target {
        return Ok((Test::Doc, errors));
    }

    for doctest_info in &compilation.to_doc_test {
        let Doctest {
            package,
            target,
            args,
            unstable_opts,
        } = doctest_info;
        config.shell().status("Doc-tests", target.name())?;
        let mut p = compilation.rustdoc_process(package, target)?;
        p.arg("--test")
            .arg(target.src_path().path().unwrap())
            .arg("--crate-name")
            .arg(&target.crate_name());

        if doctest_xcompile {
            if let CompileKind::Target(target) = options.compile_opts.build_config.requested_kind {
                p.arg("--target").arg(target.rustc_target());
            }
            p.arg("-Zunstable-options");
            p.arg("--enable-per-target-ignores");
        }

        if let Some((runtool, runtool_args)) = runtool {
            p.arg("--runtool").arg(runtool);
            for arg in runtool_args {
                p.arg("--runtool-arg").arg(arg);
            }
        }

        for &rust_dep in &[&compilation.deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(rust_dep);
            p.arg("-L").arg(arg);
        }

        for native_dep in compilation.native_dirs.iter() {
            p.arg("-L").arg(native_dep);
        }

        for &host_rust_dep in &[&compilation.host_deps_output] {
            let mut arg = OsString::from("dependency=");
            arg.push(host_rust_dep);
            p.arg("-L").arg(arg);
        }

        for arg in test_args {
            p.arg("--test-args").arg(arg);
        }

        if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
            for cfg in cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }
        }

        for arg in args {
            p.arg(arg);
        }

        if *unstable_opts {
            p.arg("-Zunstable-options");
        }

        if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) {
            p.args(flags);
        }
        config
            .shell()
            .verbose(|shell| shell.status("Running", p.to_string()))?;
        if let Err(e) = p.exec() {
            let e = e.downcast::<ProcessError>()?;
            errors.push(e);
            if !options.no_fail_fast {
                return Ok((Test::Doc, errors));
            }
        }
    }
    Ok((Test::Doc, errors))
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use forktable::ForkTable;
use position::Positional;
use ast::{ Form
         , DefForm
         , Ident };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Positional<String>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

// because we are in the Raw Pointer Sadness Zone (read: unsafe),
// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    pub fn get_fn_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect(&format!(
                      "Could not create C string for function name: {:?}"
                    , name
                  ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self { Primitive::IntSize    => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Uint(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }.expect(
                        &format!("Could not get {:?} type from LLVM", *self)
                        )
    }
}
<commit_msg>Some tweaks to Compile<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use forktable::ForkTable;
use position::Positional;
use ast::{ Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    pub fn get_fn_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect(&format!(
                      "Could not create C string for function name: {:?}"
                    , name
                  ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        unimplemented!()
    }
}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self { Primitive::IntSize    => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Uint(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }.expect(
                        &format!("Could not get {:?} type from LLVM", *self)
                        )
    }
}
<|endoftext|>


<commit_before>use nom::{
  Consumer, ConsumerState,
  ErrorKind,
  HexDisplay,
  Producer, FileProducer,
  Input, IResult,
  Move, Needed,
};

use metadata;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::resize_producer;

use std::io;
use std::io::{Error, Result};

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  consumer_state: ConsumerState<(), ErrorKind, Move>,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      let consumed = Move::Consume(0);

      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    let consumed = Move::Consume(0);

    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      consumer_state: ConsumerState::Continue(consumed),
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> Result<Stream> {
    FileProducer::new(filename, 1024).and_then(|mut producer| {
      let consumed        = Move::Consume(0);
      let mut buffer_size = 1024;
      let mut is_error    = false;
      let mut stream      = Stream {
        info: StreamInfo::new(),
        metadata: Vec::new(),
        frames: Vec::new(),
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      };

      loop {
        match *producer.apply(&mut stream) {
          ConsumerState::Done(_, _)      => break,
          ConsumerState::Continue(await) => {
            let result = resize_producer(&mut producer, &await, buffer_size);

            if let Some(size) = result {
              buffer_size = size;
            }

            continue;
          }
          ConsumerState::Error(_)        => {
            is_error = true;

            break;
          }
        }
      }

      if !is_error {
        Ok(stream)
      } else {
        let error_str = format!("parser: couldn't parse the given file {}",
                                filename);

        Err(Error::new(io::ErrorKind::InvalidData, error_str))
      }
    })
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }
}

impl<'a> Consumer<&'a [u8], (), ErrorKind, Move> for Stream {
  fn state(&self) -> &ConsumerState<(), ErrorKind, Move> {
    &self.consumer_state
  }

  fn handle(&mut self, input: Input<&'a [u8]>)
            -> &ConsumerState<(), ErrorKind, Move> {
    match input {
      Input::Element(i) | Input::Eof(Some(i)) => {
        match self.state {
          ParserState::Marker   => self.handle_marker(i),
          ParserState::Metadata => self.handle_metadata(i),
          ParserState::Frame    => self.handle_frame(i),
        }
      }
      Input::Empty | Input::Eof(None)         => {
        self.consumer_state = match self.state {
          ParserState::Marker   => ConsumerState::Error(ErrorKind::Custom(0)),
          ParserState::Metadata => ConsumerState::Error(ErrorKind::Custom(1)),
          ParserState::Frame    => ConsumerState::Done(Move::Consume(0), ()),
        };
      }
    }

    &self.consumer_state
  }
}
<commit_msg>Remove `Consumer` trait from `Stream`<commit_after>use nom::{
  Consumer, ConsumerState,
  ErrorKind,
  HexDisplay,
  Producer, FileProducer,
  Input, IResult,
  Move, Needed,
};

use metadata;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::resize_producer;

use std::io;
use std::io::{Error, Result};

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  consumer_state: ConsumerState<(), ErrorKind, Move>,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      let consumed = Move::Consume(0);

      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    let consumed = Move::Consume(0);

    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      consumer_state: ConsumerState::Continue(consumed),
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> Result<Stream> {
    FileProducer::new(filename, 1024).and_then(|mut producer| {
      let consumed        = Move::Consume(0);
      let mut buffer_size = 1024;
      let mut is_error    = false;
      let mut stream      = Stream {
        info: StreamInfo::new(),
        metadata: Vec::new(),
        frames: Vec::new(),
        state: ParserState::Marker,
        consumer_state: ConsumerState::Continue(consumed),
      };

      loop {
        match *producer.apply(&mut stream) {
          ConsumerState::Done(_, _)      => break,
          ConsumerState::Continue(await) => {
            let result = resize_producer(&mut producer, &await, buffer_size);

            if let Some(size) = result {
              buffer_size = size;
            }

            continue;
          }
          ConsumerState::Error(_)        => {
            is_error = true;

            break;
          }
        }
      }

      if !is_error {
        Ok(stream)
      } else {
        let error_str = format!("parser: couldn't parse the given file {}",
                                filename);

        Err(Error::new(io::ErrorKind::InvalidData, error_str))
      }
    })
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }
}
<|endoftext|>


<commit_before>use std::os::raw::{c_int, c_double, c_void};

use ffi;
use base::*;

extern "C" fn write_callback_wrapper<W>(raw_out: *mut ffi::SoundIoOutStream,
                                        min: c_int,
                                        max: c_int)
    where W: Fn(OutStream, i32, i32)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    match callbacks.write {
        Some(ref f) => f(out, min as i32, max as i32),
        None => println!("No registered callback found!"),
    }
}

extern "C" fn underflow_callback_wrapper<U>(raw_out: *mut ffi::SoundIoOutStream)
    where U: Fn(OutStream)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    println!("match");
    match callbacks.underflow {
        Some(ref f) => f(out),
        None => println!("No registered callback found!"),
    }
}

extern "C" fn error_callback_wrapper<E>(raw_out: *mut ffi::SoundIoOutStream, error: ffi::SioError)
    where E: Fn(OutStream, ffi::SioError)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    println!("match");
    match callbacks.error {
        Some(ref f) => f(out, error),
        None => println!("No registered callback found!"),
    }
}

struct OutStreamCallbacks<'a> {
    write: Option<Box<Fn(OutStream, i32, i32) + 'a>>,
    underflow: Option<Box<Fn(OutStream) + 'a>>,
    error: Option<Box<Fn(OutStream, ffi::SioError) + 'a>>,
}
impl<'a> Default for OutStreamCallbacks<'a> {
    fn default() -> Self {
        OutStreamCallbacks {
            write: None,
            underflow: None,
            error: None,
        }
    }
}
impl<'a> Drop for OutStreamCallbacks<'a> {
    fn drop(&mut self) {}
}

pub struct OutStream<'a> {
    // TODO: make this private again
    pub stream: *mut ffi::SoundIoOutStream,
    callbacks: Box<OutStreamCallbacks<'a>>,
}
impl<'a> OutStream<'a> {
    pub fn new(raw_stream: *mut ffi::SoundIoOutStream) -> Self {
        let callbacks = Box::new(OutStreamCallbacks::default());
        OutStream {
            stream: raw_stream,
            callbacks: callbacks,
        }
    }

    pub fn open(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_open(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn start(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_start(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn register_write_callback<W>(&mut self, callback: Box<W>)
        where W: Fn(OutStream, i32, i32) + 'a
    {
        // stored box reference to callback closure
        self.callbacks.write = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).write_callback = Some(write_callback_wrapper::<W>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn register_underflow_callback<U>(&mut self, callback: Box<U>)
        where U: Fn(OutStream) + 'a
    {
        self.callbacks.underflow = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).underflow_callback = Some(underflow_callback_wrapper::<U>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn register_error_callback<E>(&mut self, callback: Box<E>)
        where E: Fn(OutStream, ffi::SioError) + 'a
    {
        self.callbacks.error = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).error_callback = Some(error_callback_wrapper::<E>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn begin_write(&self,
                       areas: *mut *mut ffi::SoundIoChannelArea,
                       frame_count: *mut c_int)
                       -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_begin_write(self.stream, areas, frame_count) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn end_write(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_end_write(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn clear_buffer(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_clear_buffer(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn pause(&self, pause: bool) -> Option<ffi::SioError> {
        let pause_c_bool = match pause {
            true => 1u8,
            false => 0u8,
        };
        match unsafe { ffi::soundio_outstream_pause(self.stream, pause_c_bool) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn get_latency(&self) -> Result<f64, ffi::SioError> {
        let mut latency = 0.0f64;
        match unsafe {
            ffi::soundio_outstream_get_latency(self.stream, &mut latency as *mut c_double)
        } {
            ffi::SioError::None => Ok(latency),
            err @ _ => Err(err),
        }

    }

    pub fn current_format(&self) -> Result<ffi::SioFormat, ffi::SioError> {
        match unsafe { (*self.stream).format } {
            ffi::SioFormat::Invalid => Err(ffi::SioError::Invalid),
            fmt @ _ => Ok(fmt),
        }
    }

    pub fn get_layout(&self) -> ChannelLayout {
        ChannelLayout::new(unsafe { &(*self.stream).layout })
    }

    pub fn get_sample_rate(&self) -> i32 {
        unsafe { (*self.stream).sample_rate as i32 }
    }

    pub fn get_device(&self) -> Device {
        let dev = Device::new(unsafe { (*self.stream).device });
        dev.inc_ref();
        dev
    }

    pub fn destroy(&self) {
        unsafe { ffi::soundio_outstream_destroy(self.stream) }
    }
}
impl<'a> Drop for OutStream<'a> {
    fn drop(&mut self) {
        // TODO: call destroy manually.
        // OutStream will get dropped each time a new
        // struct is created from the same *mut pointer.
    }
}
<commit_msg>Make raw stream private<commit_after>use std::os::raw::{c_int, c_double, c_void};

use ffi;
use base::*;

extern "C" fn write_callback_wrapper<W>(raw_out: *mut ffi::SoundIoOutStream,
                                        min: c_int,
                                        max: c_int)
    where W: Fn(OutStream, i32, i32)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    match callbacks.write {
        Some(ref f) => f(out, min as i32, max as i32),
        None => println!("No registered callback found!"),
    }
}

extern "C" fn underflow_callback_wrapper<U>(raw_out: *mut ffi::SoundIoOutStream)
    where U: Fn(OutStream)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    println!("match");
    match callbacks.underflow {
        Some(ref f) => f(out),
        None => println!("No registered callback found!"),
    }
}

extern "C" fn error_callback_wrapper<E>(raw_out: *mut ffi::SoundIoOutStream, error: ffi::SioError)
    where E: Fn(OutStream, ffi::SioError)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    println!("match");
    match callbacks.error {
        Some(ref f) => f(out, error),
        None => println!("No registered callback found!"),
    }
}

struct OutStreamCallbacks<'a> {
    write: Option<Box<Fn(OutStream, i32, i32) + 'a>>,
    underflow: Option<Box<Fn(OutStream) + 'a>>,
    error: Option<Box<Fn(OutStream, ffi::SioError) + 'a>>,
}
impl<'a> Default for OutStreamCallbacks<'a> {
    fn default() -> Self {
        OutStreamCallbacks {
            write: None,
            underflow: None,
            error: None,
        }
    }
}
impl<'a> Drop for OutStreamCallbacks<'a> {
    fn drop(&mut self) {}
}

pub struct OutStream<'a> {
    stream: *mut ffi::SoundIoOutStream,
    callbacks: Box<OutStreamCallbacks<'a>>,
}
impl<'a> OutStream<'a> {
    pub fn new(raw_stream: *mut ffi::SoundIoOutStream) -> Self {
        let callbacks = Box::new(OutStreamCallbacks::default());
        OutStream {
            stream: raw_stream,
            callbacks: callbacks,
        }
    }

    pub fn open(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_open(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn start(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_start(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn register_write_callback<W>(&mut self, callback: Box<W>)
        where W: Fn(OutStream, i32, i32) + 'a
    {
        // stored box reference to callback closure
        self.callbacks.write = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).write_callback = Some(write_callback_wrapper::<W>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn register_underflow_callback<U>(&mut self, callback: Box<U>)
        where U: Fn(OutStream) + 'a
    {
        self.callbacks.underflow = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).underflow_callback = Some(underflow_callback_wrapper::<U>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn register_error_callback<E>(&mut self, callback: Box<E>)
        where E: Fn(OutStream, ffi::SioError) + 'a
    {
        self.callbacks.error = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).error_callback = Some(error_callback_wrapper::<E>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    pub fn begin_write(&self,
                       areas: *mut *mut ffi::SoundIoChannelArea,
                       frame_count: *mut c_int)
                       -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_begin_write(self.stream, areas, frame_count) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn end_write(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_end_write(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn clear_buffer(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_clear_buffer(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn pause(&self, pause: bool) -> Option<ffi::SioError> {
        let pause_c_bool = match pause {
            true => 1u8,
            false => 0u8,
        };
        match unsafe { ffi::soundio_outstream_pause(self.stream, pause_c_bool) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn get_latency(&self) -> Result<f64, ffi::SioError> {
        let mut latency = 0.0f64;
        match unsafe {
            ffi::soundio_outstream_get_latency(self.stream, &mut latency as *mut c_double)
        } {
            ffi::SioError::None => Ok(latency),
            err @ _ => Err(err),
        }

    }

    pub fn current_format(&self) -> Result<ffi::SioFormat, ffi::SioError> {
        match unsafe { (*self.stream).format } {
            ffi::SioFormat::Invalid => Err(ffi::SioError::Invalid),
            fmt @ _ => Ok(fmt),
        }
    }

    pub fn get_layout(&self) -> ChannelLayout {
        ChannelLayout::new(unsafe { &(*self.stream).layout })
    }

    pub fn get_sample_rate(&self) -> i32 {
        unsafe { (*self.stream).sample_rate as i32 }
    }

    pub fn get_device(&self) -> Device {
        let dev = Device::new(unsafe { (*self.stream).device });
        dev.inc_ref();
        dev
    }

    pub fn destroy(&self) {
        unsafe { ffi::soundio_outstream_destroy(self.stream) }
    }
}
impl<'a> Drop for OutStream<'a> {
    fn drop(&mut self) {
        // TODO: call destroy manually.
        // OutStream will get dropped each time a new
        // struct is created from the same *mut pointer.
    }
}
<|endoftext|>


<commit_before>extern crate ndarray;
extern crate fnv;

use self::fnv::FnvHashMap;
use ndarray_ext::NdArray;
use ops;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use topology;

/// Symbolic multi-dimensional array which supports
/// efficient gradient computation.
pub struct Tensor(pub Rc<RefCell<RawTensor>>);

pub struct RawTensor {
    // Operation of this node
    pub op: Box<ops::Op>,

    // Shared variable of this node; this is `Some` if created by:
    // - variable()
    // - constant()
    // - scalar()
    pub param: Option<NdArray>,

    // References to immediate predecessors.
    pub inputs: Vec<Tensor>,

    // rank number for topological ordering
    pub rank: usize,
}

impl Tensor {
    #[inline]
    pub fn is_source(&self) -> bool
    {
        self.borrow().inputs.is_empty()
    }

    /// Returns a value of this node
    #[inline]
    pub fn eval(&self) -> ndarray::Array<f32, ndarray::IxDyn>
    {
        self.eval_with_input(Input::new())
    }

    #[inline]
    /// Returns a value of this node
    pub fn eval_with_input(&self, feed_dict: Input) -> ndarray::Array<f32, ndarray::IxDyn>
    {
        // pre process.
        // pack `feed_dict` in `memo` and collect shared variables
        let mut memo = feed_dict.hash_map;
        let mut variable_set = HashSet::new();
        self.visit_once(&mut |arg: &Tensor| {
            let mut cur_node = arg.borrow_mut();
            if let Some(v) = mem::replace(&mut cur_node.param, None) {
                variable_set.insert(arg.clone());
                memo.insert(arg.clone(), v);
            }
        });

        // run graph
        topology::perform_eval(self, &mut memo, false);

        //  make return value
        // TODO
        let result = if let Some(res) = memo.remove(self) {
            res
        } else {
            panic!("Some placeholders could'nt get initial value")
        };

        // post process.
        // return variable arrays to the original place
        for v in variable_set.into_iter() {
            mem::swap(&mut v.borrow_mut().param, &mut memo.remove(&v));
        }

        // return evaluated array
        result
    }

    #[inline]
    pub fn visit_once<F>(&self, f: &mut F)
    where
        F: FnMut(&Tensor) -> (),
    {
        self.run_visit_once(f, &mut HashSet::new())
    }

    #[inline]
    fn run_visit_once<F>(&self, f: &mut F, visited: &mut HashSet<Tensor>)
    where
        F: FnMut(&Tensor) -> (),
    {
        if visited.contains(self) {
            return; // exit early
        } else {
            visited.insert(self.clone()); // first visit
        }

        f(self);

        for child in &(*self).borrow().inputs {
            child.run_visit_once(f, visited)
        }
    }

    #[inline]
    pub fn visit<F>(&self, f: &mut F)
    where
        F: FnMut(&Tensor) -> (),
    {
        f(self);

        for child in &(*self).borrow().inputs {
            child.visit(f)
        }
    }
}

impl Ord for Tensor {
    fn cmp(&self, other: &Self) -> Ordering
    {
        self.borrow().rank.cmp(&other.borrow().rank)
    }
}

impl PartialOrd for Tensor {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering>
    {
        Some(self.cmp(other))
    }
}

// empty implementation
impl Eq for Tensor {}

impl PartialEq for Tensor {
    fn eq(&self, other: &Tensor) -> bool
    {
        // compare addresses on the heap
        Rc::ptr_eq(&self.0, &other.0)
    }
}

// empty implementation
impl Hash for Tensor {
    fn hash<H: Hasher>(&self, _: &mut H)
    {
    }
}

// data is not cloned; only reference count is incremented.
impl Clone for Tensor {
    fn clone(&self) -> Tensor
    {
        Tensor(self.0.clone())
    }
}

impl Deref for Tensor {
    type Target = Rc<RefCell<RawTensor>>;
    fn deref(&self) -> &Self::Target
    {
        &self.0
    }
}

impl DerefMut for Tensor {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Rc<RefCell<RawTensor>>
    {
        &mut self.0
    }
}

impl fmt::Display for Tensor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        let ref_obj = &self.0.borrow();
        let input_names = ref_obj
            .inputs
            .iter()
            .map(|a| a.borrow().op.name().to_string())
            .collect::<Vec<String>>();
        write!(
            f,
            "op: {}\ninputs: {:?}\n",
            ref_obj.op.name(),
            input_names.as_slice()
        )
    }
}

#[derive(Clone)]
pub struct Input {
    pub hash_map: FnvHashMap<Tensor, NdArray>,
}

impl Input {
    #[inline]
    pub fn new() -> Input
    {
        Input { hash_map: FnvHashMap::default() }
    }

    #[inline]
    pub fn add<T>(mut self, symbolic_tensor: &Tensor, array: ndarray::Array<f32, T>) -> Self
    where
        T: ndarray::Dimension,
    {
        self.hash_map.insert(
            symbolic_tensor.clone(),
            array.into_dyn(),
        );
        // move self
        self
    }
}
<commit_msg>feed_array to placeholder<commit_after>extern crate ndarray;
extern crate fnv;

use self::fnv::FnvHashMap;
use ndarray_ext::NdArray;
use ops;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_set::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use topology;

/// Symbolic multi-dimensional array which supports
/// efficient gradient computation.
pub struct Tensor(pub Rc<RefCell<RawTensor>>);

pub struct RawTensor {
    // Operation of this node
    pub op: Box<ops::Op>,

    // Shared variable of this node; this is `Some` if created by:
    // - variable()
    // - constant()
    // - scalar()
    pub param: Option<NdArray>,

    // References to immediate predecessors.
    pub inputs: Vec<Tensor>,

    // rank number for topological ordering
    pub rank: usize,
}

impl Tensor {
    #[inline]
    pub fn is_source(&self) -> bool
    {
        self.borrow().inputs.is_empty()
    }

    /// Returns a value of this node
    #[inline]
    pub fn eval(&self) -> ndarray::Array<f32, ndarray::IxDyn>
    {
        self.eval_with_input(Input::new())
    }

    #[inline]
    /// Returns a value of this node
    pub fn eval_with_input(&self, feed_dict: Input) -> ndarray::Array<f32, ndarray::IxDyn>
    {
        // pre process.
        // pack `feed_dict` in `memo` and collect shared variables
        let mut memo = feed_dict.hash_map;
        let mut variable_set = HashSet::new();
        self.visit_once(&mut |arg: &Tensor| {
            let mut cur_node = arg.borrow_mut();
            if let Some(v) = mem::replace(&mut cur_node.param, None) {
                variable_set.insert(arg.clone());
                memo.insert(arg.clone(), v);
            }
        });

        // run graph
        topology::perform_eval(self, &mut memo, false);

        //  make return value
        // TODO
        let result = if let Some(res) = memo.remove(self) {
            res
        } else {
            panic!("Some placeholders could'nt get initial value")
        };

        // post process.
        // return variable arrays to the original place
        for v in variable_set.into_iter() {
            mem::swap(&mut v.borrow_mut().param, &mut memo.remove(&v));
        }

        // return evaluated array
        result
    }

    #[inline]
    pub fn visit_once<F>(&self, f: &mut F)
    where
        F: FnMut(&Tensor) -> (),
    {
        self.run_visit_once(f, &mut HashSet::new())
    }

    #[inline]
    fn run_visit_once<F>(&self, f: &mut F, visited: &mut HashSet<Tensor>)
    where
        F: FnMut(&Tensor) -> (),
    {
        if visited.contains(self) {
            return; // exit early
        } else {
            visited.insert(self.clone()); // first visit
        }

        f(self);

        for child in &(*self).borrow().inputs {
            child.run_visit_once(f, visited)
        }
    }

    #[inline]
    pub fn visit<F>(&self, f: &mut F)
    where
        F: FnMut(&Tensor) -> (),
    {
        f(self);

        for child in &(*self).borrow().inputs {
            child.visit(f)
        }
    }

    pub fn feed_array<T: ndarray::Dimension>(&self, arr: ndarray::Array<f32, T>)
    {
        if self.borrow().op.name() != "Placeholder" {
            panic!("Can't feed array to non-placeholder");
        }
        self.borrow_mut().param = Some(arr.into_dyn());
    }
}

impl Ord for Tensor {
    fn cmp(&self, other: &Self) -> Ordering
    {
        self.borrow().rank.cmp(&other.borrow().rank)
    }
}

impl PartialOrd for Tensor {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering>
    {
        Some(self.cmp(other))
    }
}

// empty implementation
impl Eq for Tensor {}

impl PartialEq for Tensor {
    fn eq(&self, other: &Tensor) -> bool
    {
        // compare addresses on the heap
        Rc::ptr_eq(&self.0, &other.0)
    }
}

// empty implementation
impl Hash for Tensor {
    fn hash<H: Hasher>(&self, _: &mut H)
    {
    }
}

// data is not cloned; only reference count is incremented.
impl Clone for Tensor {
    fn clone(&self) -> Tensor
    {
        Tensor(self.0.clone())
    }
}

impl Deref for Tensor {
    type Target = Rc<RefCell<RawTensor>>;
    fn deref(&self) -> &Self::Target
    {
        &self.0
    }
}

impl DerefMut for Tensor {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Rc<RefCell<RawTensor>>
    {
        &mut self.0
    }
}

impl fmt::Display for Tensor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        let ref_obj = &self.0.borrow();
        let input_names = ref_obj
            .inputs
            .iter()
            .map(|a| a.borrow().op.name().to_string())
            .collect::<Vec<String>>();
        write!(
            f,
            "op: {}\ninputs: {:?}\n",
            ref_obj.op.name(),
            input_names.as_slice()
        )
    }
}

#[derive(Clone)]
pub struct Input {
    pub hash_map: FnvHashMap<Tensor, NdArray>,
}

impl Input {
    #[inline]
    pub fn new() -> Input
    {
        Input { hash_map: FnvHashMap::default() }
    }

    #[inline]
    pub fn add<T>(mut self, symbolic_tensor: &Tensor, array: ndarray::Array<f32, T>) -> Self
    where
        T: ndarray::Dimension,
    {
        self.hash_map.insert(
            symbolic_tensor.clone(),
            array.into_dyn(),
        );
        // move self
        self
    }
}
<|endoftext|>


<commit_before>//! Interpretation of DICOM data sets as streams of tokens.
use dicom_core::header::{DataElementHeader, Length};
use dicom_core::value::{DicomValueType, PrimitiveValue};
use dicom_core::Tag;
use std::fmt;

pub mod read;
pub mod write;

pub use self::read::DataSetReader;
pub use self::write::DataSetWriter;

/// A token of a DICOM data set stream. This is part of the interpretation of a
/// data set as a stream of symbols, which may either represent data headers or
/// actual value data.
#[derive(Debug, Clone)]
pub enum DataToken {
    /// A data header of a primitive value.
    ElementHeader(DataElementHeader),
    /// The beginning of a sequence element.
    SequenceStart { tag: Tag, len: Length },
    /// The ending delimiter of a sequence.
    SequenceEnd,
    /// The beginning of a new item in the sequence.
    ItemStart { len: Length },
    /// The ending delimiter of an item.
    ItemEnd,
    /// A primitive data element value.
    PrimitiveValue(PrimitiveValue),
}

impl fmt::Display for DataToken {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DataToken::PrimitiveValue(ref v) => write!(f, "PrimitiveValue({:?})", v.value_type()),
            other => write!(f, "{:?}", other),
        }
    }
}

/// This implementation treats undefined lengths as equal.
impl PartialEq<Self> for DataToken {
    fn eq(&self, other: &Self) -> bool {
        use DataToken::*;
        match (self, other) {
            (
                ElementHeader(DataElementHeader {
                    tag: tag1,
                    vr: vr1,
                    len: len1,
                }),
                ElementHeader(DataElementHeader {
                    tag: tag2,
                    vr: vr2,
                    len: len2,
                }),
            ) => tag1 == tag2 && vr1 == vr2 && len1.inner_eq(*len2),
            (
                SequenceStart {
                    tag: tag1,
                    len: len1,
                },
                SequenceStart {
                    tag: tag2,
                    len: len2,
                },
            ) => tag1 == tag2 && len1.inner_eq(*len2),
            (ItemStart { len: len1 }, ItemStart { len: len2 }) => len1.inner_eq(*len2),
            (PrimitiveValue(v1), PrimitiveValue(v2)) => v1 == v2,
            (ItemEnd, ItemEnd) | (SequenceEnd, SequenceEnd) => true,
            _ => false,
        }
    }
}

/// The type of delimiter: sequence or item.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SeqTokenType {
    Sequence,
    Item,
}
<commit_msg>[parser] extend dataset module<commit_after>//! Interpretation of DICOM data sets as streams of tokens.
use dicom_core::header::{DataElementHeader, Length, VR};
use dicom_core::value::{DicomValueType, PrimitiveValue};
use dicom_core::{value::Value, DataElement, Tag};
use std::fmt;

pub mod read;
pub mod write;

pub use self::read::DataSetReader;
pub use self::write::DataSetWriter;

/// A token of a DICOM data set stream. This is part of the interpretation of a
/// data set as a stream of symbols, which may either represent data headers or
/// actual value data.
#[derive(Debug, Clone)]
pub enum DataToken {
    /// A data header of a primitive value.
    ElementHeader(DataElementHeader),
    /// The beginning of a sequence element.
    SequenceStart { tag: Tag, len: Length },
    /// The ending delimiter of a sequence.
    SequenceEnd,
    /// The beginning of a new item in the sequence.
    ItemStart { len: Length },
    /// The ending delimiter of an item.
    ItemEnd,
    /// A primitive data element value.
    PrimitiveValue(PrimitiveValue),
}

impl fmt::Display for DataToken {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DataToken::PrimitiveValue(ref v) => write!(f, "PrimitiveValue({:?})", v.value_type()),
            other => write!(f, "{:?}", other),
        }
    }
}

/// This implementation treats undefined lengths as equal.
impl PartialEq<Self> for DataToken {
    fn eq(&self, other: &Self) -> bool {
        use DataToken::*;
        match (self, other) {
            (
                ElementHeader(DataElementHeader {
                    tag: tag1,
                    vr: vr1,
                    len: len1,
                }),
                ElementHeader(DataElementHeader {
                    tag: tag2,
                    vr: vr2,
                    len: len2,
                }),
            ) => tag1 == tag2 && vr1 == vr2 && len1.inner_eq(*len2),
            (
                SequenceStart {
                    tag: tag1,
                    len: len1,
                },
                SequenceStart {
                    tag: tag2,
                    len: len2,
                },
            ) => tag1 == tag2 && len1.inner_eq(*len2),
            (ItemStart { len: len1 }, ItemStart { len: len2 }) => len1.inner_eq(*len2),
            (PrimitiveValue(v1), PrimitiveValue(v2)) => v1 == v2,
            (ItemEnd, ItemEnd) | (SequenceEnd, SequenceEnd) => true,
            _ => false,
        }
    }
}

impl From<DataElementHeader> for DataToken {
    fn from(header: DataElementHeader) -> Self {
        match header.vr() {
            VR::SQ => DataToken::SequenceStart {
                tag: header.tag,
                len: header.len,
            },
            _ => DataToken::ElementHeader(header),
        }
    }
}

impl DataToken {
    pub fn is_sequence_start(&self) -> bool {
        match self {
            DataToken::SequenceStart { .. } => true,
            _ => false,
        }
    }
}

/// The type of delimiter: sequence or item.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SeqTokenType {
    Sequence,
    Item,
}

/// A trait for converting structured DICOM data into a stream of data tokens.
pub trait IntoTokens {
    /// The iterator type through which tokens are obtained.
    type Iter: Iterator<Item = DataToken>;

    /// Convert the value into tokens.
    fn into_tokens(self) -> Self::Iter;
}

/// Token generator from a DICOM data element.
pub enum DataElementTokens<I>
where
    I: IntoTokens,
{
    /// initial state, at the beginning of the element
    Start(
        // Option is used for easy taking from a &mut,
        // should always be Some in practice
        Option<DataElement<I>>,
    ),
    /// header was read
    Header(
        // Option is used for easy taking from a &mut,
        // should always be Some in practice
        Option<DataElement<I>>,
    ),
    /// reading tokens from items
    Items(
        FlattenTokens<
            <dicom_core::value::C<AsItem<I>> as IntoIterator>::IntoIter,
            ItemTokens<I::Iter>,
        >,
    ),
    /// no more elements
    End,
}

impl<I> Iterator for DataElementTokens<I>
where
    I: IntoTokens,
{
    type Item = DataToken;

    fn next(&mut self) -> Option<Self::Item> {
        use DataElementTokens::*;
        let (out, next_state) = match self {
            Start(elem) => {
                let elem = elem.take().unwrap();
                // data element header token

                let token = DataToken::from(*elem.header());
                if token.is_sequence_start() {
                    // retrieve sequence value, begin item sequence
                    match elem.into_value() {
                        Value::Primitive(_) => unreachable!(),
                        Value::Sequence { items, size: _ } => {
                            let items: dicom_core::value::C<_> = items
                                .into_iter()
                                .map(|o| AsItem(Length::UNDEFINED, o))
                                .collect();
                            (Some(token), DataElementTokens::Items(items.into_tokens()))
                        }
                    }
                } else {
                    (
                        Some(DataToken::ElementHeader(*elem.header())),
                        Header(Some(elem)),
                    )
                }
            }
            Header(elem) => {
                let elem = elem.take().unwrap();
                match elem.into_value() {
                    Value::Sequence { .. } => unreachable!(),
                    Value::Primitive(value) => {
                        // return primitive value, done
                        let token = DataToken::PrimitiveValue(value);
                        (Some(token), End)
                    }
                }
            }
            Items(tokens) => {
                if let Some(token) = tokens.next() {
                    // bypass manual state transition
                    return Some(token);
                } else {
                    // sequence end token, end
                    (Some(DataToken::SequenceEnd), End)
                }
            }
            End => (None, End),
        };
        *self = next_state;

        out
    }
}

impl<I> IntoTokens for DataElement<I>
where
    I: IntoTokens,
{
    type Iter = DataElementTokens<I>;

    fn into_tokens(self) -> Self::Iter {
        DataElementTokens::Start(Some(self))
    }
}

/// Flatten a sequence of elements into their respective
/// token sequence in order.
#[derive(Debug, PartialEq)]
pub struct FlattenTokens<O, K> {
    seq: O,
    tokens: Option<K>,
}

impl<O, K> Iterator for FlattenTokens<O, K>
where
    O: Iterator,
    O::Item: IntoTokens<Iter = K>,
    K: Iterator<Item = DataToken>,
{
    type Item = DataToken;

    fn next(&mut self) -> Option<Self::Item> {
        // ensure a token sequence
        if self.tokens.is_none() {
            match self.seq.next() {
                Some(entries) => {
                    self.tokens = Some(entries.into_tokens());
                }
                None => return None,
            }
        }

        // retrieve the next token
        match self.tokens.as_mut().map(|s| s.next()) {
            Some(Some(token)) => Some(token),
            Some(None) => {
                self.tokens = None;
                self.next()
            }
            None => unreachable!(),
        }
    }
}

impl<T> IntoTokens for Vec<T>
where
    T: IntoTokens,
{
    type Iter = FlattenTokens<<Vec<T> as IntoIterator>::IntoIter, <T as IntoTokens>::Iter>;

    fn into_tokens(self) -> Self::Iter {
        FlattenTokens {
            seq: self.into_iter(),
            tokens: None,
        }
    }
}

impl<T> IntoTokens for dicom_core::value::C<T>
where
    T: IntoTokens,
{
    type Iter =
        FlattenTokens<<dicom_core::value::C<T> as IntoIterator>::IntoIter, <T as IntoTokens>::Iter>;

    fn into_tokens(self) -> Self::Iter {
        FlattenTokens {
            seq: self.into_iter(),
            tokens: None,
        }
    }
}

// A stream of tokens from a DICOM item.
#[derive(Debug)]
pub enum ItemTokens<T> {
    /// Just started, an item header token will come next
    Start {
        len: Length,
        object_tokens: Option<T>,
    },
    /// Will return tokens from the inner object, then an end of item token
    /// when it ends
    Object { object_tokens: T },
    /// Just ended, no more tokens
    End,
}

impl<T> ItemTokens<T>
where
    T: Iterator<Item = DataToken>,
{
    pub fn new<O>(len: Length, object: O) -> Self
    where
        O: IntoTokens<Iter = T>,
    {
        ItemTokens::Start {
            len,
            object_tokens: Some(object.into_tokens()),
        }
    }
}

impl<T> Iterator for ItemTokens<T>
where
    T: Iterator<Item = DataToken>,
{
    type Item = DataToken;

    fn next(&mut self) -> Option<Self::Item> {
        let (next_state, out) = match self {
            ItemTokens::Start { len, object_tokens } => (
                ItemTokens::Object {
                    object_tokens: object_tokens.take().unwrap(),
                },
                Some(DataToken::ItemStart { len: *len }),
            ),
            ItemTokens::Object { object_tokens } => {
                if let Some(token) = object_tokens.next() {
                    return Some(token);
                } else {
                    (ItemTokens::End, Some(DataToken::ItemEnd))
                }
            }
            ItemTokens::End => {
                return None;
            }
        };

        *self = next_state;
        out
    }
}

/// A newtype for interpreting the given data as an item.
/// When converting a value of this type into tokens, the inner value's tokens
/// will be surrounded by an item start and an item delimiter.
#[derive(Debug, Clone, PartialEq)]
pub struct AsItem<I>(Length, I);

impl<I> IntoTokens for AsItem<I>
where
    I: IntoTokens,
{
    type Iter = ItemTokens<I::Iter>;

    fn into_tokens(self) -> Self::Iter {
        ItemTokens::new(self.0, self.1)
    }
}
<|endoftext|>


<commit_before>use crate::transform::MirPass;
use crate::util::patch::MirPatch;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_target::spec::PanicStrategy;

/// A pass that removes noop landing pads and replaces jumps to them with
/// `None`. This is important because otherwise LLVM generates terrible
/// code for these.
pub struct RemoveNoopLandingPads;

pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
        return;
    }
    debug!("remove_noop_landing_pads({:?})", body);

    RemoveNoopLandingPads.remove_nop_landing_pads(body)
}

impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        remove_noop_landing_pads(tcx, body);
    }
}

impl RemoveNoopLandingPads {
    fn is_nop_landing_pad(
        &self,
        bb: BasicBlock,
        body: &Body<'_>,
        nop_landing_pads: &BitSet<BasicBlock>,
    ) -> bool {
        for stmt in &body[bb].statements {
            match &stmt.kind {
                StatementKind::FakeRead(..)
                | StatementKind::StorageLive(_)
                | StatementKind::StorageDead(_)
                | StatementKind::AscribeUserType(..)
                | StatementKind::Coverage(..)
                | StatementKind::Nop => {
                    // These are all nops in a landing pad
                }

                StatementKind::Assign(box (place, Rvalue::Use(_))) => {
                    if place.as_local().is_some() {
                        // Writing to a local (e.g., a drop flag) does not
                        // turn a landing pad to a non-nop
                    } else {
                        return false;
                    }
                }

                StatementKind::Assign { .. }
                | StatementKind::SetDiscriminant { .. }
                | StatementKind::LlvmInlineAsm { .. }
                | StatementKind::Retag { .. } => {
                    return false;
                }
            }
        }

        let terminator = body[bb].terminator();
        match terminator.kind {
            TerminatorKind::Goto { .. }
            | TerminatorKind::Resume
            | TerminatorKind::SwitchInt { .. }
            | TerminatorKind::FalseEdge { .. }
            | TerminatorKind::FalseUnwind { .. } => {
                terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
            }
            TerminatorKind::GeneratorDrop
            | TerminatorKind::Yield { .. }
            | TerminatorKind::Return
            | TerminatorKind::Abort
            | TerminatorKind::Unreachable
            | TerminatorKind::Call { .. }
            | TerminatorKind::Assert { .. }
            | TerminatorKind::DropAndReplace { .. }
            | TerminatorKind::Drop { .. }
            | TerminatorKind::InlineAsm { .. } => false,
        }
    }

    fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
        // make sure there's a single resume block
        let resume_block = {
            let patch = MirPatch::new(body);
            let resume_block = patch.resume_block();
            patch.apply(body);
            resume_block
        };
        debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);

        let mut jumps_folded = 0;
        let mut landing_pads_removed = 0;
        let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len());

        // This is a post-order traversal, so that if A post-dominates B
        // then A will be visited before B.
        let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
        for bb in postorder {
            debug!("  processing {:?}", bb);
            if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
                if let Some(unwind_bb) = *unwind {
                    if nop_landing_pads.contains(unwind_bb) {
                        debug!("    removing noop landing pad");
                        landing_pads_removed += 1;
                        *unwind = None;
                    }
                }
            }

            for target in body[bb].terminator_mut().successors_mut() {
                if *target != resume_block && nop_landing_pads.contains(*target) {
                    debug!("    folding noop jump to {:?} to resume block", target);
                    *target = resume_block;
                    jumps_folded += 1;
                }
            }

            let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
            if is_nop_landing_pad {
                nop_landing_pads.insert(bb);
            }
            debug!("    is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
        }

        debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
    }
}
<commit_msg>Auto merge of #77793 - tmiasko:no-op-discriminant, r=ecstatic-morse<commit_after>use crate::transform::MirPass;
use crate::util::patch::MirPatch;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_target::spec::PanicStrategy;

/// A pass that removes noop landing pads and replaces jumps to them with
/// `None`. This is important because otherwise LLVM generates terrible
/// code for these.
pub struct RemoveNoopLandingPads;

pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
        return;
    }
    debug!("remove_noop_landing_pads({:?})", body);

    RemoveNoopLandingPads.remove_nop_landing_pads(body)
}

impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        remove_noop_landing_pads(tcx, body);
    }
}

impl RemoveNoopLandingPads {
    fn is_nop_landing_pad(
        &self,
        bb: BasicBlock,
        body: &Body<'_>,
        nop_landing_pads: &BitSet<BasicBlock>,
    ) -> bool {
        for stmt in &body[bb].statements {
            match &stmt.kind {
                StatementKind::FakeRead(..)
                | StatementKind::StorageLive(_)
                | StatementKind::StorageDead(_)
                | StatementKind::AscribeUserType(..)
                | StatementKind::Coverage(..)
                | StatementKind::Nop => {
                    // These are all nops in a landing pad
                }

                StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => {
                    if place.as_local().is_some() {
                        // Writing to a local (e.g., a drop flag) does not
                        // turn a landing pad to a non-nop
                    } else {
                        return false;
                    }
                }

                StatementKind::Assign { .. }
                | StatementKind::SetDiscriminant { .. }
                | StatementKind::LlvmInlineAsm { .. }
                | StatementKind::Retag { .. } => {
                    return false;
                }
            }
        }

        let terminator = body[bb].terminator();
        match terminator.kind {
            TerminatorKind::Goto { .. }
            | TerminatorKind::Resume
            | TerminatorKind::SwitchInt { .. }
            | TerminatorKind::FalseEdge { .. }
            | TerminatorKind::FalseUnwind { .. } => {
                terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
            }
            TerminatorKind::GeneratorDrop
            | TerminatorKind::Yield { .. }
            | TerminatorKind::Return
            | TerminatorKind::Abort
            | TerminatorKind::Unreachable
            | TerminatorKind::Call { .. }
            | TerminatorKind::Assert { .. }
            | TerminatorKind::DropAndReplace { .. }
            | TerminatorKind::Drop { .. }
            | TerminatorKind::InlineAsm { .. } => false,
        }
    }

    fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
        // make sure there's a single resume block
        let resume_block = {
            let patch = MirPatch::new(body);
            let resume_block = patch.resume_block();
            patch.apply(body);
            resume_block
        };
        debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);

        let mut jumps_folded = 0;
        let mut landing_pads_removed = 0;
        let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len());

        // This is a post-order traversal, so that if A post-dominates B
        // then A will be visited before B.
        let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
        for bb in postorder {
            debug!("  processing {:?}", bb);
            if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
                if let Some(unwind_bb) = *unwind {
                    if nop_landing_pads.contains(unwind_bb) {
                        debug!("    removing noop landing pad");
                        landing_pads_removed += 1;
                        *unwind = None;
                    }
                }
            }

            for target in body[bb].terminator_mut().successors_mut() {
                if *target != resume_block && nop_landing_pads.contains(*target) {
                    debug!("    folding noop jump to {:?} to resume block", target);
                    *target = resume_block;
                    jumps_folded += 1;
                }
            }

            let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
            if is_nop_landing_pad {
                nop_landing_pads.insert(bb);
            }
            debug!("    is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
        }

        debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
    }
}
<|endoftext|>


<commit_before>use itertools::{EitherOrBoth, Itertools};
use std::fmt::Debug;
use std::ops::BitXor;
use quickcheck::quickcheck;

struct Unspecialized<I>(I);
impl<I> Iterator for Unspecialized<I>
where
    I: Iterator,
{
    type Item = I::Item;

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }

    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

fn check_specialized<'a, V, IterItem, Iter, F>(iterator: &Iter, mapper: F)
where
    V: Eq + Debug,
    IterItem: 'a,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
    F: Fn(Box<dyn Iterator<Item = IterItem> + 'a>) -> V,
{
    assert_eq!(
        mapper(Box::new(Unspecialized(iterator.clone()))),
        mapper(Box::new(iterator.clone()))
    )
}

fn check_specialized_count_last_nth_sizeh<'a, IterItem, Iter>(
    it: &Iter,
    known_expected_size: Option<usize>,
) where
    IterItem: 'a + Eq + Debug,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
{
    let size = it.clone().count();
    if let Some(expected_size) = known_expected_size {
        assert_eq!(size, expected_size);
    }
    check_specialized(it, |i| i.count());
    check_specialized(it, |i| i.last());
    for n in 0..size + 2 {
        check_specialized(it, |mut i| i.nth(n));
    }
    let mut it_sh = it.clone();
    for n in 0..size + 2 {
        let len = it_sh.clone().count();
        let (min, max) = it_sh.size_hint();
        assert_eq!((size - n.min(size)), len);
        assert!(min <= len);
        if let Some(max) = max {
            assert!(len <= max);
        }
        it_sh.next();
    }
}

fn check_specialized_fold_xor<'a, IterItem, Iter>(it: &Iter)
where
    IterItem: 'a
        + BitXor
        + Eq
        + Debug
        + BitXor<<IterItem as BitXor>::Output, Output = <IterItem as BitXor>::Output>
        + Clone,
    <IterItem as BitXor>::Output:
        BitXor<Output = <IterItem as BitXor>::Output> + Eq + Debug + Clone,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
{
    check_specialized(it, |mut i| {
        let first = i.next().map(|f| f.clone() ^ (f.clone() ^ f));
        i.fold(first, |acc, v: IterItem| acc.map(move |a| v ^ a))
    });
}

fn put_back_test(test_vec: Vec<i32>, known_expected_size: Option<usize>) {
    {
        // Lexical lifetimes support
        let pb = itertools::put_back(test_vec.iter());
        check_specialized_count_last_nth_sizeh(&pb, known_expected_size);
        check_specialized_fold_xor(&pb);
    }

    let mut pb = itertools::put_back(test_vec.into_iter());
    pb.put_back(1);
    check_specialized_count_last_nth_sizeh(&pb, known_expected_size.map(|x| x + 1));
    check_specialized_fold_xor(&pb)
}

#[test]
fn put_back() {
    put_back_test(vec![7, 4, 1], Some(3));
}

quickcheck! {
    fn put_back_qc(test_vec: Vec<i32>) -> () {
        put_back_test(test_vec, None)
    }
}

fn merge_join_by_test(i1: Vec<usize>, i2: Vec<usize>, known_expected_size: Option<usize>) {
    let i1 = i1.into_iter();
    let i2 = i2.into_iter();
    let mjb = i1.clone().merge_join_by(i2.clone(), std::cmp::Ord::cmp);
    check_specialized_count_last_nth_sizeh(&mjb, known_expected_size);
    // Rust 1.24 compatibility:
    fn eob_left_z(eob: EitherOrBoth<usize, usize>) -> usize {
        eob.left().unwrap_or(0)
    }
    fn eob_right_z(eob: EitherOrBoth<usize, usize>) -> usize {
        eob.right().unwrap_or(0)
    }
    fn eob_both_z(eob: EitherOrBoth<usize, usize>) -> usize {
        let (a, b) = eob.both().unwrap_or((0, 0));
        assert_eq!(a, b);
        a
    }
    check_specialized_fold_xor(&mjb.clone().map(eob_left_z));
    check_specialized_fold_xor(&mjb.clone().map(eob_right_z));
    check_specialized_fold_xor(&mjb.clone().map(eob_both_z));

    // And the other way around
    let mjb = i2.merge_join_by(i1, std::cmp::Ord::cmp);
    check_specialized_count_last_nth_sizeh(&mjb, known_expected_size);
    check_specialized_fold_xor(&mjb.clone().map(eob_left_z));
    check_specialized_fold_xor(&mjb.clone().map(eob_right_z));
    check_specialized_fold_xor(&mjb.clone().map(eob_both_z));
}

#[test]
fn merge_join_by() {
    let i1 = vec![1, 3, 5, 7, 8, 9];
    let i2 = vec![0, 3, 4, 5];
    merge_join_by_test(i1, i2, Some(8));
}

quickcheck! {
    fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
        merge_join_by_test(i1, i2, None)
    }
}
<commit_msg>Simpler checks for specialized fold<commit_after>use itertools::Itertools;
use std::fmt::Debug;
use quickcheck::quickcheck;

struct Unspecialized<I>(I);
impl<I> Iterator for Unspecialized<I>
where
    I: Iterator,
{
    type Item = I::Item;

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }

    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

fn check_specialized<'a, V, IterItem, Iter, F>(iterator: &Iter, mapper: F)
where
    V: Eq + Debug,
    IterItem: 'a,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
    F: Fn(Box<dyn Iterator<Item = IterItem> + 'a>) -> V,
{
    assert_eq!(
        mapper(Box::new(Unspecialized(iterator.clone()))),
        mapper(Box::new(iterator.clone()))
    )
}

fn check_specialized_count_last_nth_sizeh<'a, IterItem, Iter>(
    it: &Iter,
    known_expected_size: Option<usize>,
) where
    IterItem: 'a + Eq + Debug,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
{
    let size = it.clone().count();
    if let Some(expected_size) = known_expected_size {
        assert_eq!(size, expected_size);
    }
    check_specialized(it, |i| i.count());
    check_specialized(it, |i| i.last());
    for n in 0..size + 2 {
        check_specialized(it, |mut i| i.nth(n));
    }
    let mut it_sh = it.clone();
    for n in 0..size + 2 {
        let len = it_sh.clone().count();
        let (min, max) = it_sh.size_hint();
        assert_eq!((size - n.min(size)), len);
        assert!(min <= len);
        if let Some(max) = max {
            assert!(len <= max);
        }
        it_sh.next();
    }
}

fn check_specialized_fold<IterItem, Iter>(it: &Iter)
where
    IterItem: Eq + Debug + Clone,
    Iter: Iterator<Item = IterItem> + Clone,
{
    check_specialized(it, |i| {
        let mut parameters_from_fold = vec![];
        let fold_result = i.fold(vec![], |mut acc, v: IterItem| {
            parameters_from_fold.push((acc.clone(), v.clone()));
            acc.push(v);
            acc
        });
        (parameters_from_fold, fold_result)
    });
}

fn put_back_test(test_vec: Vec<i32>, known_expected_size: Option<usize>) {
    {
        // Lexical lifetimes support
        let pb = itertools::put_back(test_vec.iter());
        check_specialized_count_last_nth_sizeh(&pb, known_expected_size);
        check_specialized_fold(&pb);
    }

    let mut pb = itertools::put_back(test_vec.into_iter());
    pb.put_back(1);
    check_specialized_count_last_nth_sizeh(&pb, known_expected_size.map(|x| x + 1));
    check_specialized_fold(&pb)
}

#[test]
fn put_back() {
    put_back_test(vec![7, 4, 1], Some(3));
}

quickcheck! {
    fn put_back_qc(test_vec: Vec<i32>) -> () {
        put_back_test(test_vec, None)
    }
}

fn merge_join_by_test(i1: Vec<usize>, i2: Vec<usize>, known_expected_size: Option<usize>) {
    let i1 = i1.into_iter();
    let i2 = i2.into_iter();
    let mjb = i1.clone().merge_join_by(i2.clone(), std::cmp::Ord::cmp);
    check_specialized_count_last_nth_sizeh(&mjb, known_expected_size);
    check_specialized_fold(&mjb);

    // And the other way around
    let mjb = i2.merge_join_by(i1, std::cmp::Ord::cmp);
    check_specialized_count_last_nth_sizeh(&mjb, known_expected_size);
    check_specialized_fold(&mjb);
}

#[test]
fn merge_join_by() {
    let i1 = vec![1, 3, 5, 7, 8, 9];
    let i2 = vec![0, 3, 4, 5];
    merge_join_by_test(i1, i2, Some(8));
}

quickcheck! {
    fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
        merge_join_by_test(i1, i2, None)
    }
}
<|endoftext|>