<commit_before>use syntax::ast::{Expr, Lit, TokenTree, TtToken};
use syntax::ext::base::ExtCtxt;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(Show)]
pub enum Markup {
    Element(Vec<(String, Value)>, Vec<Markup>),
    Value(Value),
}

#[deriving(Show)]
pub struct Value {
    pub value: Value_,
    pub escape: Escape,
}

impl Value {
    pub fn escape(value: Value_) -> Value {
        Value {
            value: value,
            escape: Escape::Escape,
        }
    }

    pub fn no_escape(value: Value_) -> Value {
        Value {
            value: value,
            escape: Escape::NoEscape,
        }
    }
}

#[deriving(Show)]
pub enum Value_ {
    Literal(String),
    Splice(P<Expr>),
}

#[deriving(Copy, PartialEq, Show)]
pub enum Escape {
    NoEscape,
    Escape,
}

pub fn parse(cx: &mut ExtCtxt, mut args: &[TokenTree]) -> Option<Vec<Markup>> {
    macro_rules! minus {
        () => (TtToken(_, token::BinOp(token::Minus)))
    }
    macro_rules! literal {
        () => (TtToken(_, token::Literal(..)))
    }

    let mut result = vec![];
    loop {
        match match args {
            [minus!(), ref tt @ literal!(), ..] => {
                args.shift(2);
                parse_literal(cx, tt, true)
            },
            [ref tt @ literal!(), ..] => {
                args.shift(1);
                parse_literal(cx, tt, false)
            },
            _ => None,
        } {
            Some(x) => result.push(x),
            None => break,
        }
    }
    match args {
        [] => Some(result),
        [ref tt, ..] => {
            cx.span_err(tt.get_span(), "invalid syntax");
            None
        }
    }
}

fn parse_literal(cx: &mut ExtCtxt, tt: &TokenTree, minus: bool) -> Option<Markup> {
    let mut parser = parse::tts_to_parser(cx.parse_sess, vec![tt.clone()], cx.cfg.clone());
    let lit = parser.parse_lit();
    lit_to_string(cx, lit, minus)
        .map(|s| Markup::Value(Value::escape(Value_::Literal(s))))
}

fn lit_to_string(cx: &mut ExtCtxt, lit: Lit, minus: bool) -> Option<String> {
    use syntax::ast::Lit_::*;
    let mut result = String::new();
    if minus {
        result.push('-');
    }
    match lit.node {
        LitStr(s, _) => result.push_str(s.get()),
        LitBinary(..) | LitByte(..) => {
            cx.span_err(lit.span, "cannot splice binary data");
            return None;
        },
        LitChar(c) => result.push(c),
        LitInt(x, _) => result.push_str(&*x.to_string()),
        LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(s.get()),
        LitBool(b) => result.push_str(if b { "true" } else { "false" }),
    };
    Some(result)
}

trait Shift {
    fn shift(&mut self, n: uint);
}

impl<'a, T> Shift for &'a [T] {
    fn shift(&mut self, n: uint) {
        *self = self.slice_from(n);
    }
}
<commit_msg>Parse semicolons<commit_after>use syntax::ast::{Expr, Lit, TokenTree, TtToken};
use syntax::ext::base::ExtCtxt;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(Show)]
pub enum Markup {
    Element(Vec<(String, Value)>, Vec<Markup>),
    Value(Value),
}

#[deriving(Show)]
pub struct Value {
    pub value: Value_,
    pub escape: Escape,
}

impl Value {
    pub fn escape(value: Value_) -> Value {
        Value {
            value: value,
            escape: Escape::Escape,
        }
    }

    pub fn no_escape(value: Value_) -> Value {
        Value {
            value: value,
            escape: Escape::NoEscape,
        }
    }
}

#[deriving(Show)]
pub enum Value_ {
    Literal(String),
    Splice(P<Expr>),
}

#[deriving(Copy, PartialEq, Show)]
pub enum Escape {
    NoEscape,
    Escape,
}

pub fn parse(cx: &mut ExtCtxt, mut args: &[TokenTree]) -> Option<Vec<Markup>> {
    macro_rules! semi {
        () => (TtToken(_, token::Semi))
    }
    macro_rules! minus {
        () => (TtToken(_, token::BinOp(token::Minus)))
    }
    macro_rules! literal {
        () => (TtToken(_, token::Literal(..)))
    }

    let mut result = vec![];
    loop {
        match match args {
            [semi!(), ..] => {
                args.shift(1);
                continue
            },
            [minus!(), ref tt @ literal!(), ..] => {
                args.shift(2);
                parse_literal(cx, tt, true)
            },
            [ref tt @ literal!(), ..] => {
                args.shift(1);
                parse_literal(cx, tt, false)
            },
            _ => None,
        } {
            Some(x) => result.push(x),
            None => break,
        }
    }
    match args {
        [] => Some(result),
        [ref tt, ..] => {
            cx.span_err(tt.get_span(), "invalid syntax");
            None
        }
    }
}

fn parse_literal(cx: &mut ExtCtxt, tt: &TokenTree, minus: bool) -> Option<Markup> {
    let mut parser = parse::tts_to_parser(cx.parse_sess, vec![tt.clone()], cx.cfg.clone());
    let lit = parser.parse_lit();
    lit_to_string(cx, lit, minus)
        .map(|s| Markup::Value(Value::escape(Value_::Literal(s))))
}

fn lit_to_string(cx: &mut ExtCtxt, lit: Lit, minus: bool) -> Option<String> {
    use syntax::ast::Lit_::*;
    let mut result = String::new();
    if minus {
        result.push('-');
    }
    match lit.node {
        LitStr(s, _) => result.push_str(s.get()),
        LitBinary(..) | LitByte(..) => {
            cx.span_err(lit.span, "cannot splice binary data");
            return None;
        },
        LitChar(c) => result.push(c),
        LitInt(x, _) => result.push_str(&*x.to_string()),
        LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(s.get()),
        LitBool(b) => result.push_str(if b { "true" } else { "false" }),
    };
    Some(result)
}

trait Shift {
    fn shift(&mut self, n: uint);
}

impl<'a, T> Shift for &'a [T] {
    fn shift(&mut self, n: uint) {
        *self = self.slice_from(n);
    }
}
<|endoftext|>


<commit_before>//! Utilities for encoding symbols as a C4FM signal.

use bits;
use consts;

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulses<T> {
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T: Iterator<Item = bits::Dibit>> C4FMImpulses<T> {
    /// Construct a new `C4FMImpulses<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4FMImpulses<T> {
        C4FMImpulses {
            src: src,
            sample: 0,
        }
    }
}

impl<T: Iterator<Item = bits::Dibit>> Iterator for C4FMImpulses<T> {
    type Item = f32;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % consts::SYMBOL_PERIOD != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit.bits() {
                0b01 => Some(0.18),
                0b00 => Some(0.06),
                0b10 => Some(-0.06),
                0b11 => Some(-0.18),
                _ => unreachable!(),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit::new(0b01)
        } else {
            bits::Dibit::new(0b11)
        })
    }
}

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

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulses::new(d);

        assert!(imp.next().unwrap() == 0.06);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.18);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -0.06);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -0.18);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
    }
}
<commit_msg>s/C4FMImpulses/C4fmImpulses/<commit_after>//! Utilities for encoding symbols as a C4FM signal.

use bits;
use consts;

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4fmImpulses<T> {
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T: Iterator<Item = bits::Dibit>> C4fmImpulses<T> {
    /// Construct a new `C4fmImpulses<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4fmImpulses<T> {
        C4fmImpulses {
            src: src,
            sample: 0,
        }
    }
}

impl<T: Iterator<Item = bits::Dibit>> Iterator for C4fmImpulses<T> {
    type Item = f32;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % consts::SYMBOL_PERIOD != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit.bits() {
                0b01 => Some(0.18),
                0b00 => Some(0.06),
                0b10 => Some(-0.06),
                0b11 => Some(-0.18),
                _ => unreachable!(),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit::new(0b01)
        } else {
            bits::Dibit::new(0b11)
        })
    }
}

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

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4fmImpulses::new(d);

        assert!(imp.next().unwrap() == 0.06);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.18);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -0.06);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -0.18);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
    }
}
<|endoftext|>


<commit_before>//! Implementation of compiling the compiler and standard library, in "check"-based modes.

use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
use crate::config::TargetSelection;
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
use crate::{Compiler, Mode, Subcommand};
use std::path::{Path, PathBuf};

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
    pub target: TargetSelection,
}

/// Returns args for the subcommand itself (not for cargo)
fn args(builder: &Builder<'_>) -> Vec<String> {
    fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
        arr.iter().copied().map(String::from)
    }

    if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
        // disable the most spammy clippy lints
        let ignored_lints = vec![
            "many_single_char_names", // there are a lot in stdarch
            "collapsible_if",
            "type_complexity",
            "missing_safety_doc", // almost 3K warnings
            "too_many_arguments",
            "needless_lifetimes", // people want to keep the lifetimes
            "wrong_self_convention",
        ];
        let mut args = vec![];
        if fix {
            #[rustfmt::skip]
            args.extend(strings(&[
                "--fix", "-Zunstable-options",
                // FIXME: currently, `--fix` gives an error while checking tests for libtest,
                // possibly because libtest is not yet built in the sysroot.
                // As a workaround, avoid checking tests and benches when passed --fix.
                "--lib", "--bins", "--examples",
            ]));
        }
        args.extend(strings(&["--", "--cap-lints", "warn"]));
        args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
        args
    } else {
        vec![]
    }
}

fn cargo_subcommand(kind: Kind) -> &'static str {
    match kind {
        Kind::Check => "check",
        Kind::Clippy => "clippy",
        Kind::Fix => "fix",
        _ => unreachable!(),
    }
}

impl Step for Std {
    type Output = ();
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("test")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Std { target: run.target });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.update_submodule(&Path::new("library").join("stdarch"));

        let target = self.target;
        let compiler = builder.compiler(builder.top_stage, builder.config.build);

        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        std_cargo(builder, target, compiler.stage, &mut cargo);

        builder.info(&format!(
            "Checking stage{} std artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_stamp(builder, compiler, target),
            vec![],
            true,
        );

        // We skip populating the sysroot in non-zero stage because that'll lead
        // to rlib/rmeta conflicts if std gets built during this session.
        if compiler.stage == 0 {
            let libdir = builder.sysroot_libdir(compiler, target);
            let hostdir = builder.sysroot_libdir(compiler, compiler.host);
            add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
        }

        // Then run cargo again, once we've put the rmeta files for the library
        // crates into the sysroot. This is needed because e.g., core's tests
        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
        // since we initialize with an empty sysroot.
        //
        // Currently only the "libtest" tree of crates does this.
        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        cargo.arg("--all-targets");
        std_cargo(builder, target, compiler.stage, &mut cargo);

        // Explicitly pass -p for all dependencies krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("test", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} std test/bench/example targets ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_test_stamp(builder, compiler, target),
            vec![],
            true,
        );
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
    pub target: TargetSelection,
}

impl Step for Rustc {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("rustc-main")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Rustc { target: run.target });
    }

    /// Builds the compiler.
    ///
    /// This will build the compiler for a particular stage of the build using
    /// the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;

        if compiler.stage != 0 {
            // If we're not in stage 0, then we won't have a std from the beta
            // compiler around. That means we need to make sure there's one in
            // the sysroot for the compiler to find. Otherwise, we're going to
            // fail when building crates that need to generate code (e.g., build
            // scripts and their dependencies).
            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
            builder.ensure(crate::compile::Std { target, compiler });
        } else {
            builder.ensure(Std { target });
        }

        let mut cargo = builder.cargo(
            compiler,
            Mode::Rustc,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        rustc_cargo(builder, &mut cargo, target);
        cargo.arg("--all-targets");

        // Explicitly pass -p for all compiler krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("rustc-main", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} compiler artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &librustc_stamp(builder, compiler, target),
            vec![],
            true,
        );

        let libdir = builder.sysroot_libdir(compiler, target);
        let hostdir = builder.sysroot_libdir(compiler, compiler.host);
        add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
    pub target: TargetSelection,
    pub backend: Interned<String>,
}

impl Step for CodegenBackend {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
    }

    fn make_run(run: RunConfig<'_>) {
        for &backend in &[INTERNER.intern_str("cranelift")] {
            run.builder.ensure(CodegenBackend { target: run.target, backend });
        }
    }

    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;
        let backend = self.backend;

        builder.ensure(Rustc { target });

        let mut cargo = builder.cargo(
            compiler,
            Mode::Codegen,
            SourceType::Submodule,
            target,
            cargo_subcommand(builder.kind),
        );
        cargo
            .arg("--manifest-path")
            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
        rustc_cargo_env(builder, &mut cargo, target);

        builder.info(&format!(
            "Checking stage{} {} artifacts ({} -> {})",
            builder.top_stage, backend, &compiler.host.triple, target.triple
        ));

        run_cargo(
            builder,
            cargo,
            args(builder),
            &codegen_backend_stamp(builder, compiler, target, backend),
            vec![],
            true,
        );
    }
}

macro_rules! tool_check_step {
    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub target: TargetSelection,
        }

        impl Step for $name {
            type Output = ();
            const ONLY_HOSTS: bool = true;
            // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
            const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                run.paths(&[ $path, $($alias),* ])
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name { target: run.target });
            }

            fn run(self, builder: &Builder<'_>) {
                let compiler = builder.compiler(builder.top_stage, builder.config.build);
                let target = self.target;

                builder.ensure(Rustc { target });

                let mut cargo = prepare_tool_cargo(
                    builder,
                    compiler,
                    Mode::ToolRustc,
                    target,
                    cargo_subcommand(builder.kind),
                    $path,
                    $source_type,
                    &[],
                );
                cargo.arg("--all-targets");

                // Enable internal lints for clippy and rustdoc
                // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                cargo.rustflag("-Zunstable-options");

                builder.info(&format!(
                    "Checking stage{} {} artifacts ({} -> {})",
                    builder.top_stage,
                    stringify!($name).to_lowercase(),
                    &compiler.host.triple,
                    target.triple
                ));
                run_cargo(
                    builder,
                    cargo,
                    args(builder),
                    &stamp(builder, compiler, target),
                    vec![],
                    true,
                );

                /// Cargo's output path in a given stage, compiled by a particular
                /// compiler for the specified target.
                fn stamp(
                    builder: &Builder<'_>,
                    compiler: Compiler,
                    target: TargetSelection,
                ) -> PathBuf {
                    builder
                        .cargo_out(compiler, Mode::ToolRustc, target)
                        .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
                }
            }
        }
    };
}

tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
// Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule);
tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);

tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_test_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}

/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}

/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
    backend: Interned<String>,
) -> PathBuf {
    builder
        .cargo_out(compiler, Mode::Codegen, target)
        .join(format!(".librustc_codegen_{}-check.stamp", backend))
}
<commit_msg>Rollup merge of #88511 - matthiaskrgr:xpyclippydefaulttarget, r=jyn514<commit_after>//! Implementation of compiling the compiler and standard library, in "check"-based modes.

use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
use crate::config::TargetSelection;
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
use crate::{Compiler, Mode, Subcommand};
use std::path::{Path, PathBuf};

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
    pub target: TargetSelection,
}

/// Returns args for the subcommand itself (not for cargo)
fn args(builder: &Builder<'_>) -> Vec<String> {
    fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
        arr.iter().copied().map(String::from)
    }

    if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
        // disable the most spammy clippy lints
        let ignored_lints = vec![
            "many_single_char_names", // there are a lot in stdarch
            "collapsible_if",
            "type_complexity",
            "missing_safety_doc", // almost 3K warnings
            "too_many_arguments",
            "needless_lifetimes", // people want to keep the lifetimes
            "wrong_self_convention",
        ];
        let mut args = vec![];
        if fix {
            #[rustfmt::skip]
            args.extend(strings(&[
                "--fix", "-Zunstable-options",
                // FIXME: currently, `--fix` gives an error while checking tests for libtest,
                // possibly because libtest is not yet built in the sysroot.
                // As a workaround, avoid checking tests and benches when passed --fix.
                "--lib", "--bins", "--examples",
            ]));
        }
        args.extend(strings(&["--", "--cap-lints", "warn"]));
        args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
        args
    } else {
        vec![]
    }
}

fn cargo_subcommand(kind: Kind) -> &'static str {
    match kind {
        Kind::Check => "check",
        Kind::Clippy => "clippy",
        Kind::Fix => "fix",
        _ => unreachable!(),
    }
}

impl Step for Std {
    type Output = ();
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("test")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Std { target: run.target });
    }

    fn run(self, builder: &Builder<'_>) {
        builder.update_submodule(&Path::new("library").join("stdarch"));

        let target = self.target;
        let compiler = builder.compiler(builder.top_stage, builder.config.build);

        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        std_cargo(builder, target, compiler.stage, &mut cargo);

        builder.info(&format!(
            "Checking stage{} std artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_stamp(builder, compiler, target),
            vec![],
            true,
        );

        // We skip populating the sysroot in non-zero stage because that'll lead
        // to rlib/rmeta conflicts if std gets built during this session.
        if compiler.stage == 0 {
            let libdir = builder.sysroot_libdir(compiler, target);
            let hostdir = builder.sysroot_libdir(compiler, compiler.host);
            add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
        }

        // don't run on std twice with x.py clippy
        if builder.kind == Kind::Clippy {
            return;
        }

        // Then run cargo again, once we've put the rmeta files for the library
        // crates into the sysroot. This is needed because e.g., core's tests
        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
        // since we initialize with an empty sysroot.
        //
        // Currently only the "libtest" tree of crates does this.
        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );

        cargo.arg("--all-targets");
        std_cargo(builder, target, compiler.stage, &mut cargo);

        // Explicitly pass -p for all dependencies krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("test", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} std test/bench/example targets ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_test_stamp(builder, compiler, target),
            vec![],
            true,
        );
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
    pub target: TargetSelection,
}

impl Step for Rustc {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("rustc-main")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Rustc { target: run.target });
    }

    /// Builds the compiler.
    ///
    /// This will build the compiler for a particular stage of the build using
    /// the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;

        if compiler.stage != 0 {
            // If we're not in stage 0, then we won't have a std from the beta
            // compiler around. That means we need to make sure there's one in
            // the sysroot for the compiler to find. Otherwise, we're going to
            // fail when building crates that need to generate code (e.g., build
            // scripts and their dependencies).
            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
            builder.ensure(crate::compile::Std { target, compiler });
        } else {
            builder.ensure(Std { target });
        }

        let mut cargo = builder.cargo(
            compiler,
            Mode::Rustc,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        rustc_cargo(builder, &mut cargo, target);

        // For ./x.py clippy, don't run with --all-targets because
        // linting tests and benchmarks can produce very noisy results
        if builder.kind != Kind::Clippy {
            cargo.arg("--all-targets");
        }

        // Explicitly pass -p for all compiler krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("rustc-main", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} compiler artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &librustc_stamp(builder, compiler, target),
            vec![],
            true,
        );

        let libdir = builder.sysroot_libdir(compiler, target);
        let hostdir = builder.sysroot_libdir(compiler, compiler.host);
        add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
    pub target: TargetSelection,
    pub backend: Interned<String>,
}

impl Step for CodegenBackend {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
    }

    fn make_run(run: RunConfig<'_>) {
        for &backend in &[INTERNER.intern_str("cranelift")] {
            run.builder.ensure(CodegenBackend { target: run.target, backend });
        }
    }

    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;
        let backend = self.backend;

        builder.ensure(Rustc { target });

        let mut cargo = builder.cargo(
            compiler,
            Mode::Codegen,
            SourceType::Submodule,
            target,
            cargo_subcommand(builder.kind),
        );
        cargo
            .arg("--manifest-path")
            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
        rustc_cargo_env(builder, &mut cargo, target);

        builder.info(&format!(
            "Checking stage{} {} artifacts ({} -> {})",
            builder.top_stage, backend, &compiler.host.triple, target.triple
        ));

        run_cargo(
            builder,
            cargo,
            args(builder),
            &codegen_backend_stamp(builder, compiler, target, backend),
            vec![],
            true,
        );
    }
}

macro_rules! tool_check_step {
    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub target: TargetSelection,
        }

        impl Step for $name {
            type Output = ();
            const ONLY_HOSTS: bool = true;
            // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
            const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                run.paths(&[ $path, $($alias),* ])
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name { target: run.target });
            }

            fn run(self, builder: &Builder<'_>) {
                let compiler = builder.compiler(builder.top_stage, builder.config.build);
                let target = self.target;

                builder.ensure(Rustc { target });

                let mut cargo = prepare_tool_cargo(
                    builder,
                    compiler,
                    Mode::ToolRustc,
                    target,
                    cargo_subcommand(builder.kind),
                    $path,
                    $source_type,
                    &[],
                );

                // For ./x.py clippy, don't run with --all-targets because
                // linting tests and benchmarks can produce very noisy results
                if builder.kind != Kind::Clippy {
                    cargo.arg("--all-targets");
                }

                // Enable internal lints for clippy and rustdoc
                // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                cargo.rustflag("-Zunstable-options");

                builder.info(&format!(
                    "Checking stage{} {} artifacts ({} -> {})",
                    builder.top_stage,
                    stringify!($name).to_lowercase(),
                    &compiler.host.triple,
                    target.triple
                ));
                run_cargo(
                    builder,
                    cargo,
                    args(builder),
                    &stamp(builder, compiler, target),
                    vec![],
                    true,
                );

                /// Cargo's output path in a given stage, compiled by a particular
                /// compiler for the specified target.
                fn stamp(
                    builder: &Builder<'_>,
                    compiler: Compiler,
                    target: TargetSelection,
                ) -> PathBuf {
                    builder
                        .cargo_out(compiler, Mode::ToolRustc, target)
                        .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
                }
            }
        }
    };
}

tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
// Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule);
tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);

tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_test_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}

/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}

/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
    backend: Interned<String>,
) -> PathBuf {
    builder
        .cargo_out(compiler, Mode::Codegen, target)
        .join(format!(".librustc_codegen_{}-check.stamp", backend))
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.
use gstrsaudiofx;

use glib;

extern crate gstreamer as gst;
extern crate gstreamer_app as gst_app;
extern crate gstreamer_audio as gst_audio;
extern crate gstreamer_check as gst_check;

use glib::prelude::*;
use gst::prelude::*;

use byte_slice_cast::*;

use std::sync::{Arc, Mutex};

fn init() {
    use std::sync::Once;
    static INIT: Once = Once::new();

    INIT.call_once(|| {
        gst::init().unwrap();
        gstrsaudiofx::plugin_register_static().expect("Failed to register rsaudiofx plugin");
    });
}

fn run_test(wave: &str, num_buffers: u32, samples_per_buffer: u32, channels: u32) {
    init();

    let pipeline = gst::parse_launch(&format!(
        "audiotestsrc wave={} num-buffers={} samplesperbuffer={} ! rsaudioloudnorm ! appsink name=sink",
        wave, num_buffers, samples_per_buffer
    ))
    .unwrap()
    .downcast::<gst::Pipeline>()
    .unwrap();
    let sink = pipeline
        .get_by_name("sink")
        .unwrap()
        .downcast::<gst_app::AppSink>()
        .unwrap();

    sink.set_property("sync", &false).unwrap();
    let caps = gst_audio::AudioInfo::new(gst_audio::AUDIO_FORMAT_F64, 192_000, channels)
        .build()
        .unwrap()
        .to_caps()
        .unwrap();
    sink.set_caps(Some(&caps));

    let samples = Arc::new(Mutex::new(Vec::new()));

    let samples_clone = samples.clone();
    sink.set_callbacks(
        gst_app::AppSinkCallbacks::new()
            .new_sample(move |sink| {
                let sample = sink.pull_sample().unwrap();

                let mut samples = samples_clone.lock().unwrap();
                samples.push(sample);
                Ok(gst::FlowSuccess::Ok)
            })
            .build(),
    );

    pipeline.set_state(gst::State::Playing).unwrap();

    let mut eos = false;
    let bus = pipeline.get_bus().unwrap();
    while let Some(msg) = bus.timed_pop(gst::CLOCK_TIME_NONE) {
        use gst::MessageView;
        match msg.view() {
            MessageView::Eos(..) => {
                eos = true;
                break;
            }
            MessageView::Error(..) => unreachable!(),
            _ => (),
        }
    }

    pipeline.set_state(gst::State::Null).unwrap();

    assert!(eos);
    let samples = samples.lock().unwrap();

    let mut r128 = ebur128::EbuR128::new(
        channels,
        192_000,
        ebur128::Mode::I | ebur128::Mode::SAMPLE_PEAK,
    )
    .unwrap();

    let mut num_samples = 0;
    let mut expected_ts = gst::ClockTime::from(0);
    for sample in samples.iter() {
        let buf = sample.get_buffer().unwrap();

        let ts = buf.get_pts();
        if ts > expected_ts {
            assert!(
                ts - expected_ts <= gst::ClockTime::from(1),
                "TS is {} instead of {}",
                ts,
                expected_ts
            );
        } else if ts < expected_ts {
            assert!(
                expected_ts - ts <= gst::ClockTime::from(1),
                "TS is {} instead of {}",
                ts,
                expected_ts
            );
        }

        let map = buf.map_readable().unwrap();
        let data = map.as_slice_of::<f64>().unwrap();

        num_samples += data.len() / channels as usize;
        r128.add_frames_f64(data).unwrap();

        expected_ts +=
            gst::ClockTime::from((data.len() as u64 / channels as u64) * gst::SECOND_VAL / 192_000);
    }

    assert_eq!(
        num_samples,
        num_buffers as usize * samples_per_buffer as usize
    );

    let loudness = r128.loudness_global().unwrap();
    assert!(
        f64::abs(loudness + 24.0) < 1.0,
        "Loudness is {} instead of -24.0",
        loudness
    );

    for c in 0..channels {
        let peak = 20.0 * f64::log10(r128.sample_peak(c).unwrap());
        assert!(peak < -2.0, "Peak {} for channel {} is above -2.0", c, peak,);
    }
}

#[test]
fn basic() {
    run_test("sine", 1000, 1920, 1);
}

#[test]
fn basic_white_noise() {
    run_test("white-noise", 1000, 1920, 1);
}

#[test]
fn remaining_at_eos() {
    run_test("sine", 1000, 1024, 1);
}

#[test]
fn short_input() {
    run_test("sine", 100, 1024, 1);
}

#[test]
fn basic_two_channels() {
    run_test("sine", 1000, 1920, 2);
}
<commit_msg>audioloudnorm: Add some more tests<commit_after>// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.
use gstrsaudiofx;

use glib;

extern crate gstreamer as gst;
extern crate gstreamer_app as gst_app;
extern crate gstreamer_audio as gst_audio;
extern crate gstreamer_check as gst_check;

use glib::prelude::*;
use gst::prelude::*;

use byte_slice_cast::*;

use std::sync::{Arc, Mutex};

fn init() {
    use std::sync::Once;
    static INIT: Once = Once::new();

    INIT.call_once(|| {
        gst::init().unwrap();
        gstrsaudiofx::plugin_register_static().expect("Failed to register rsaudiofx plugin");
    });
}

fn run_test(
    first_input: &str,
    second_input: Option<&str>,
    num_buffers: u32,
    samples_per_buffer: u32,
    channels: u32,
    expected_loudness: f64,
) {
    init();

    let format = if cfg!(target_endian = "little") {
        format!("audio/x-raw,format=F64LE,rate=192000,channels={}", channels)
    } else {
        format!("audio/x-raw,format=F64BE,rate=192000,channels={}", channels)
    };

    let pipeline = if let Some(second_input) = second_input {
        gst::parse_launch(&format!(
        "audiotestsrc {first_input} num-buffers={num_buffers} samplesperbuffer={samples_per_buffer} ! {format} ! audiomixer name=mixer output-buffer-duration={output_buffer_duration} ! {format} ! rsaudioloudnorm ! appsink name=sink  audiotestsrc {second_input} num-buffers={num_buffers} samplesperbuffer={samples_per_buffer} ! {format} ! mixer.",
        first_input = first_input,
        second_input = second_input,
        num_buffers = num_buffers,
        samples_per_buffer = samples_per_buffer,
        output_buffer_duration = samples_per_buffer as u64 * gst::SECOND_VAL / 192_000,
        format = format,
        ))
    } else {
        gst::parse_launch(&format!(
        "audiotestsrc {first_input} num-buffers={num_buffers} samplesperbuffer={samples_per_buffer} ! {format} ! rsaudioloudnorm ! appsink name=sink",
        first_input = first_input,
        num_buffers = num_buffers,
        samples_per_buffer = samples_per_buffer,
        format = format,
        ))
    }
    .unwrap()
    .downcast::<gst::Pipeline>()
    .unwrap();
    let sink = pipeline
        .get_by_name("sink")
        .unwrap()
        .downcast::<gst_app::AppSink>()
        .unwrap();

    sink.set_property("sync", &false).unwrap();
    let caps = gst_audio::AudioInfo::new(gst_audio::AUDIO_FORMAT_F64, 192_000, channels)
        .build()
        .unwrap()
        .to_caps()
        .unwrap();
    sink.set_caps(Some(&caps));

    let samples = Arc::new(Mutex::new(Vec::new()));

    let samples_clone = samples.clone();
    sink.set_callbacks(
        gst_app::AppSinkCallbacks::new()
            .new_sample(move |sink| {
                let sample = sink.pull_sample().unwrap();

                let mut samples = samples_clone.lock().unwrap();
                samples.push(sample);
                Ok(gst::FlowSuccess::Ok)
            })
            .build(),
    );

    pipeline.set_state(gst::State::Playing).unwrap();

    let mut eos = false;
    let bus = pipeline.get_bus().unwrap();
    while let Some(msg) = bus.timed_pop(gst::CLOCK_TIME_NONE) {
        use gst::MessageView;
        match msg.view() {
            MessageView::Eos(..) => {
                eos = true;
                break;
            }
            MessageView::Error(..) => unreachable!(),
            _ => (),
        }
    }

    pipeline.set_state(gst::State::Null).unwrap();

    assert!(eos);
    let samples = samples.lock().unwrap();

    let mut r128 = ebur128::EbuR128::new(
        channels,
        192_000,
        ebur128::Mode::I | ebur128::Mode::SAMPLE_PEAK,
    )
    .unwrap();

    let mut num_samples = 0;
    let mut expected_ts = gst::ClockTime::from(0);
    for sample in samples.iter() {
        let buf = sample.get_buffer().unwrap();

        let ts = buf.get_pts();
        if ts > expected_ts {
            assert!(
                ts - expected_ts <= gst::ClockTime::from(1),
                "TS is {} instead of {}",
                ts,
                expected_ts
            );
        } else if ts < expected_ts {
            assert!(
                expected_ts - ts <= gst::ClockTime::from(1),
                "TS is {} instead of {}",
                ts,
                expected_ts
            );
        }

        let map = buf.map_readable().unwrap();
        let data = map.as_slice_of::<f64>().unwrap();

        num_samples += data.len() / channels as usize;
        r128.add_frames_f64(data).unwrap();

        expected_ts +=
            gst::ClockTime::from((data.len() as u64 / channels as u64) * gst::SECOND_VAL / 192_000);
    }

    assert_eq!(
        num_samples,
        num_buffers as usize * samples_per_buffer as usize
    );

    let loudness = r128.loudness_global().unwrap();

    if expected_loudness.classify() == std::num::FpCategory::Infinite && expected_loudness < 0.0 {
        assert!(
            loudness.classify() == std::num::FpCategory::Infinite && loudness < 0.0,
            "Loudness is {} instead of {}",
            loudness,
            expected_loudness,
        );
    } else {
        assert!(
            f64::abs(loudness - expected_loudness) < 1.0,
            "Loudness is {} instead of {}",
            loudness,
            expected_loudness,
        );
    }

    for c in 0..channels {
        let peak = 20.0 * f64::log10(r128.sample_peak(c).unwrap());
        assert!(
            peak <= -2.0,
            "Peak {} for channel {} is above -2.0",
            c,
            peak,
        );
    }
}

#[test]
fn basic() {
    run_test("wave=sine", None, 1000, 1920, 1, -24.0);
}

#[test]
fn basic_white_noise() {
    run_test("wave=white-noise", None, 1000, 1920, 1, -24.0);
}

#[test]
fn remaining_at_eos() {
    run_test("wave=sine", None, 1000, 1024, 1, -24.0);
}

#[test]
fn short_input() {
    run_test("wave=sine", None, 100, 1024, 1, -24.0);
}

#[test]
fn basic_two_channels() {
    run_test("wave=sine", None, 1000, 1920, 2, -24.0);
}

#[test]
fn silence() {
    run_test("wave=silence", None, 1000, 1024, 1, std::f64::NEG_INFINITY);
}

#[test]
fn quiet() {
    // -6dB
    run_test("wave=sine volume=0.5", None, 1000, 1024, 1, -24.0);
}

#[test]
fn very_quiet() {
    // -20dB
    run_test("wave=sine volume=0.1", None, 1000, 1024, 1, -24.0);
}

#[test]
fn very_very_quiet() {
    // -40dB
    run_test("wave=sine volume=0.01", None, 1000, 1024, 1, -24.0);
}

#[test]
fn below_threshold() {
    // -70dB
    run_test(
        "wave=sine volume=0.00045",
        None,
        1000,
        1024,
        1,
        std::f64::NEG_INFINITY,
    );
}

#[test]
fn limiter() {
    run_test(
        "wave=sine volume=0.05",
        Some("wave=ticks sine-periods-per-tick=1 tick-interval=4000000000"),
        1000,
        1024,
        1,
        -24.0,
    );
}

#[test]
fn limiter_on_first_frame() {
    run_test(
        "wave=sine volume=0.05",
        Some("wave=ticks sine-periods-per-tick=10 tick-interval=4000000000"),
        1000,
        1024,
        1,
        -24.0,
    );
}
<|endoftext|>


<commit_before>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use parser::LookaheadBuffer;
use parser::skip_whitespace;
use parser::EOF;

enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, String(~str), Eof }

enum Ast { Symb(~str), Union(~Ast, ~Ast),
           Conc(~Ast, ~Ast), Star(~Ast), Epsilon }

fn parse_string(buffer: &mut LookaheadBuffer, delim: char) -> ~str {
    let mut res : ~str = ~"";
    let mut c = buffer.next_char();
    while c != delim {
        if (c == EOF) {
            fail!(fmt!("Unexpected end of file. Expected closing %c", delim));
        }
        res.push_char(c);
        c = buffer.next_char();
    }
    res
}

#[test]
fn test_parse_string() {
    let mut b1 = std::io::with_str_reader("abc'* ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b1, '\''), &~"abc"));

    let mut b2 = std::io::with_str_reader("abc'def\"  ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b2, '"'), &~"abc'def"));
}

#[test]
#[should_fail]
fn unclosed_string() {
    let mut b1 = std::io::with_str_reader("abc'def  ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b1, '"'), &~"abc'def"));
}

#[inline]
fn is_id_char(c: char) -> bool {
    std::char::is_alphanumeric(c) || c == '_'
}

fn parse_id(buffer: &mut LookaheadBuffer, first: char) -> ~str {
    let mut res : ~str = ~"";
    res.push_char(first);
    let mut c = buffer.next_char();
    while is_id_char(c) {
        res.push_char(c);
        c = buffer.next_char();
    }
    res
}

#[test]
fn test_parse_id() {
    let mut b1 = std::io::with_str_reader("abc'* ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b1, 'x'), &~"xabc"));

    let mut b2 = std::io::with_str_reader("bc_def   ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b2, 'a'), &~"abc_def"));

    let mut b3 = std::io::with_str_reader("_times|'xy')*   ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b3, 'n'), &~"n_times"));
}

fn get_next_token(buffer: &mut LookaheadBuffer) -> ~Token {
    skip_whitespace(buffer);
    match buffer.next_char() {
        '[' => ~LBrack,
        ']' => ~RBrack,
        '(' => ~LParen,
        ')' => ~RParen,
        '*' => ~Asterisk,
        '+' => ~Plus,
        '|' => ~Bar,
        '\'' => ~String(parse_string(buffer, '\'')),
        '"' => ~String(parse_string(buffer, '"')),
        c if std::char::is_alphabetic(c) => ~Id(parse_id(buffer, c)),
        EOF => ~Eof,
        _ => ~Eof // TODO: signal error?
    }
}

fn parse_regexp(buffer: &mut LookaheadBuffer) {
    skip_whitespace(buffer);
    let c = buffer.next_char();
}

<commit_msg>Added tests.<commit_after>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use parser::LookaheadBuffer;
use parser::skip_whitespace;
use parser::EOF;

enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, String(~str), Eof }

enum Ast { Symb(~str), Union(~Ast, ~Ast),
           Conc(~Ast, ~Ast), Star(~Ast), Epsilon }

fn parse_string(buffer: &mut LookaheadBuffer, delim: char) -> ~str {
    let mut res : ~str = ~"";
    let mut c = buffer.next_char();
    while c != delim {
        if (c == EOF) {
            fail!(fmt!("Unexpected end of file. Expected closing %c", delim));
        }
        res.push_char(c);
        c = buffer.next_char();
    }
    res
}

#[test]
fn test_parse_string() {
    let mut b1 = std::io::with_str_reader("abc'* ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b1, '\''), &~"abc"));
    assert!(b1.next_char() == '*');

    let mut b2 = std::io::with_str_reader("abc'def\"  ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b2, '"'), &~"abc'def"));
    assert!(b2.next_char() == ' ');
}

#[test]
#[should_fail]
fn unclosed_string() {
    let mut b1 = std::io::with_str_reader("abc'def  ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_string(&mut b1, '"'), &~"abc'def"));
}

#[inline]
fn is_id_char(c: char) -> bool {
    std::char::is_alphanumeric(c) || c == '_'
}

fn parse_id(buffer: &mut LookaheadBuffer, first: char) -> ~str {
    let mut res : ~str = ~"";
    res.push_char(first);
    let mut c = buffer.next_char();
    while is_id_char(c) {
        res.push_char(c);
        c = buffer.next_char();
    }
    buffer.return_char(c);
    res
}

#[test]
fn test_parse_id() {
    let mut b1 = std::io::with_str_reader("abc'* ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b1, 'x'), &~"xabc"));
    assert!(b1.next_char() == '\'');

    let mut b2 = std::io::with_str_reader("bc_def   ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b2, 'a'), &~"abc_def"));

    let mut b3 = std::io::with_str_reader("_times|'xy')*   ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b3, 'n'), &~"n_times"));
    assert!(b3.next_char() == '|');

    let mut b4 = std::io::with_str_reader(" +xy)*   ", LookaheadBuffer::new);
    assert!(std::str::eq(&parse_id(&mut b4, 'n'), &~"n"));
    assert!(b4.next_char() == ' ');
    assert!(b4.next_char() == '+');
    assert!(b4.next_char() == 'x');
    assert!(std::str::eq(&parse_id(&mut b4, 'x'), &~"xy"));
}

fn get_next_token(buffer: &mut LookaheadBuffer) -> ~Token {
    skip_whitespace(buffer);
    match buffer.next_char() {
        '[' => ~LBrack,
        ']' => ~RBrack,
        '(' => ~LParen,
        ')' => ~RParen,
        '*' => ~Asterisk,
        '+' => ~Plus,
        '|' => ~Bar,
        '\'' => ~String(parse_string(buffer, '\'')),
        '"' => ~String(parse_string(buffer, '"')),
        c if std::char::is_alphabetic(c) => ~Id(parse_id(buffer, c)),
        EOF => ~Eof,
        _ => ~Eof // TODO: signal error?
    }
}

fn parse_regexp(buffer: &mut LookaheadBuffer) {
    skip_whitespace(buffer);
    let c = buffer.next_char();
}

<|endoftext|>


<commit_before>#[feature(macro_rules)];

use std::os;
use std::io::buffered::BufferedWriter;
use std::io::{File, Writer};
use std::io;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::init(args[2].clone());
            // TODO: maybe not 0777?
            mkdir_recursive(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<commit_msg>Fixed path initialization in codegen<commit_after>#[feature(macro_rules)];

use std::os;
use std::io::buffered::BufferedWriter;
use std::io::{File, Writer};
use std::io;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args[2].clone());
            // TODO: maybe not 0777?
            mkdir_recursive(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{TypeStruct, write_file_name, write_item_doc};
use traits::*;

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> TypeStruct;
    fn doc(&self) -> Option<&str>;
    fn doc_deprecated(&self) -> Option<&str>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<&str> {
                self.doc.as_ref().map(|s| &s[..])
            }

            fn doc_deprecated(&self) -> Option<&str> {
                self.doc_deprecated.as_ref().map(|s| &s[..])
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("docs.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if obj.status.ignored() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            if info.type_id.ns_id == MAIN {
                try!(create_object_doc(w, env, &info));
            }
        }

        if let Some(info) = analysis::record::new(env, obj) {
            if info.type_id.ns_id == MAIN {
                println!("documenting struct {}", info.name);
                let record = env.library.type_(info.type_id).to_ref_as::<Record>();
                let symbols = env.symbols.borrow();
                try!(create_record_doc(w, record, &symbols));
            }
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let impl_self = if has_trait { Some(info.type_id) } else { None };
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = impl_self.iter()
                .chain(cl.parents.iter())
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = impl_self.iter()
                .chain(iface.prereq_parents.iter())
                .map(|&tid| tid)
                .collect();
        }
        _ => unreachable!(),
    }

    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = class.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }

            try!(writeln!(w, "\n# Implements\n"));
            let implements = implements.iter()
                .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
                .map(|&tid| format!("[`{name}Ext`](trait.{name}Ext.html)",
                                    name = env.library.type_(tid).get_name()))
                .collect::<Vec<_>>();
            try!(writeln!(w, "{}", &implements.join(", ")));

            if let Some(doc) = class.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }
            Ok(())
        }));
    }

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            writeln!(w, "Trait containing all `{}` methods.", ty.name)
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_record_doc(w: &mut Write, record: &Record, symbols: &symbols::Info) -> Result<()> {
    let ty = record.convert();

    if record.doc().is_some() || record.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = record.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }

            if let Some(doc) = record.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };
    for function in &record.functions {
        try!(create_fn_doc(w, &function, Some(Box::new(ty.clone())), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(doc) = enum_.doc() {
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        if let Some(doc) = enum_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        Ok(())
    }));

    for member in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member.convert();

        if member.doc().is_some() || member.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(doc) = member.doc() {
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                if let Some(doc) = member.doc_deprecated() {
                    try!(writeln!(w, "\n# Deprecated\n"));
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                Ok(())
            }));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &sub_ty, |w| {
        if let Some(doc) = fn_.doc() {
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };
        if let Some(doc) = fn_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };

        if fn_.parameters.iter().any(|x| {
               x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
           }) {
            try!(writeln!(w, "\n# Parameters\n"));
        }
        for parameter in fn_.parameters.iter() {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue
            }
            if let Some(doc) = parameter.doc() {
                try!(writeln!(w, "## `{}`", nameutil::mangle_keywords(&parameter.name[..])));
                try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
            }
        }

        if let Some(doc) = fn_.ret.doc() {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        }
        Ok(())
    })
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(write_item_doc(w, &sub_ty, |w| {
            if let Some(doc) = ty.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            if let Some(doc) = ty.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }
    Ok(())
}
<commit_msg>Remove the 'Parameters' subheading in function docs, it's redundant<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{TypeStruct, write_file_name, write_item_doc};
use traits::*;

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> TypeStruct;
    fn doc(&self) -> Option<&str>;
    fn doc_deprecated(&self) -> Option<&str>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<&str> {
                self.doc.as_ref().map(|s| &s[..])
            }

            fn doc_deprecated(&self) -> Option<&str> {
                self.doc_deprecated.as_ref().map(|s| &s[..])
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("docs.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if obj.status.ignored() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            if info.type_id.ns_id == MAIN {
                try!(create_object_doc(w, env, &info));
            }
        }

        if let Some(info) = analysis::record::new(env, obj) {
            if info.type_id.ns_id == MAIN {
                println!("documenting struct {}", info.name);
                let record = env.library.type_(info.type_id).to_ref_as::<Record>();
                let symbols = env.symbols.borrow();
                try!(create_record_doc(w, record, &symbols));
            }
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let impl_self = if has_trait { Some(info.type_id) } else { None };
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = impl_self.iter()
                .chain(cl.parents.iter())
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = impl_self.iter()
                .chain(iface.prereq_parents.iter())
                .map(|&tid| tid)
                .collect();
        }
        _ => unreachable!(),
    }

    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = class.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }

            try!(writeln!(w, "\n# Implements\n"));
            let implements = implements.iter()
                .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
                .map(|&tid| format!("[`{name}Ext`](trait.{name}Ext.html)",
                                    name = env.library.type_(tid).get_name()))
                .collect::<Vec<_>>();
            try!(writeln!(w, "{}", &implements.join(", ")));

            if let Some(doc) = class.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }
            Ok(())
        }));
    }

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            writeln!(w, "Trait containing all `{}` methods.", ty.name)
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_record_doc(w: &mut Write, record: &Record, symbols: &symbols::Info) -> Result<()> {
    let ty = record.convert();

    if record.doc().is_some() || record.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = record.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }

            if let Some(doc) = record.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };
    for function in &record.functions {
        try!(create_fn_doc(w, &function, Some(Box::new(ty.clone())), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(doc) = enum_.doc() {
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        if let Some(doc) = enum_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        Ok(())
    }));

    for member in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member.convert();

        if member.doc().is_some() || member.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(doc) = member.doc() {
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                if let Some(doc) = member.doc_deprecated() {
                    try!(writeln!(w, "\n# Deprecated\n"));
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                Ok(())
            }));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &sub_ty, |w| {
        if let Some(doc) = fn_.doc() {
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };
        if let Some(doc) = fn_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };

        for parameter in fn_.parameters.iter() {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue
            }
            if let Some(doc) = parameter.doc() {
                try!(writeln!(w, "## `{}`", nameutil::mangle_keywords(&parameter.name[..])));
                try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
            }
        }

        if let Some(doc) = fn_.ret.doc() {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        }
        Ok(())
    })
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(write_item_doc(w, &sub_ty, |w| {
            if let Some(doc) = ty.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            if let Some(doc) = ty.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }
    Ok(())
}
<|endoftext|>