<commit_before>use std::cmp;
use std::iter;

use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_self_ty;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in iter::zip(decl.inputs, fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id(), &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _) => {
                if header.abi != Abi::Rust {
                    return;
                }
                let attrs = cx.tcx.hir().attrs(hir_id);
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<commit_msg>Auto merge of #7065 - rail-rain:warn_copy_pass_by_ref, r=Manishearth<commit_after>use std::cmp;
use std::iter;

use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_self_ty;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// Also, it does not take account of other similar cases where getting memory addresses
    /// matters; namely, returning the pointer to the argument in question,
    /// and passing the argument, as both references and pointers,
    /// to a function that needs the memory address. For further details, refer to
    /// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
    /// that explains a real case in which this false positive
    /// led to an **undefined behaviour** introduced with unsafe code.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in iter::zip(decl.inputs, fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id(), &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _) => {
                if header.abi != Abi::Rust {
                    return;
                }
                let attrs = cx.tcx.hir().attrs(hir_id);
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<|endoftext|>


<commit_before>use short_fibonacci::*;

#[test]
fn test_empty() {
    assert_eq!(create_empty(), Vec::new());
}
#[test]
#[ignore]
fn test_buffer() {
    for n in 0..10 {
        let zeroized = create_buffer(n);
        assert_eq!(zeroized.len(), n);
        assert!(zeroized.iter().all(|&v| v == 0));
    }
}
#[test]
#[ignore]
fn test_fibonacci() {
    let fibb = fibonacci();
    assert_eq!(fibb.len(), 5);
    for window in fibb.windows(3) {
        assert_eq!(window[0] + window[1], window[2]);
    }
}
<commit_msg>Update short-fibonacci.rs (#1315)<commit_after>use short_fibonacci::*;

#[test]
fn test_empty() {
    assert_eq!(create_empty(), Vec::new());
}
#[test]
#[ignore]
fn test_buffer() {
    for n in 0..10 {
        let zeroized = create_buffer(n);
        assert_eq!(zeroized.len(), n);
        assert!(zeroized.iter().all(|&v| v == 0));
    }
}
#[test]
#[ignore]
fn test_fibonacci() {
    let fibb = fibonacci();
    assert_eq!(fibb.len(), 5);
    assert_eq!(fibb[0], 1);
    assert_eq!(fibb[1], 1);
    for window in fibb.windows(3) {
        assert_eq!(window[0] + window[1], window[2]);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Robert Clipsham <robert@octarineparrot.com>
// Copyright (c) 2021 Pierre Chifflier <chifflier@wzdftpd.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The pnet_macros crate provides the `#[packet]` macro and compiler plugin, which is used to
//! specify the format of on-the-wire packets, and automatically generate zero-copy accessors and
//! mutators for the fields. It is used as follows:
//!
//! ```ignore
//!
//! extern crate pnet_macros_support;
//!
//! /// This module contains a list of type aliases which may be used
//! use pnet_macros_support::types::{u4, u12be};
//!
//! /// Packets are specified in the same way as normal Rust structs, but with a `#[packet]`
//! /// attribute.
//! #[packet]
//! pub struct Example {
//!     // This is a simple field which contains a 4-bit, unsigned integer.
//!     // Note that `u4` is simply an alias for `u8` - the name is a hint
//!     // to the compiler plugin, it is NOT a usable 4 bit type!
//!     simple_field1: u4,
//!
//!     // This specifies that `simple_field2` should be a 12-bit field,
//!     // with bits stored in big endian
//!     simple_field2: u12be,
//!
//!     // All packets must specify a `#[payload]`, which should be a
//!     // `Vec<u8>`. This represents the packet's payload, for example in
//!     // an IPv4 packet, the payload could be a UDP packet, or in a UDP
//!     // packet the payload could be the application data. All the
//!     // remaining space in the packet is considered to be the payload
//!     // (this doesn't have to be the case, see the documentation for
//!     // `#[payload]` below.
//!     #[payload]
//!     payload: Vec<u8>
//! }
//!
//! # fn main(){}
//! ```
//! A number of things will then be generated. You can see this in action in the documentation and
//! source of each of the packet types in the `pnet::packet` module. Things generated include
//! (assuming the `Example` struct from above):
//!
//!  * An `ExamplePacket<'p>` structure, which is used for receiving packets on the network.
//!    This structure contains:
//!      - A method, `pub fn new<'p>(packet: &'p [u8]) -> ExamplePacket<'p>`, used for the
//!        construction of an `ExamplePacket`, given a buffer to store it. The buffer should be
//!        long enough to contain all the fields in the packet.
//!      - A method, `pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>`, which is simply an
//!        identity function. It exists for consistency with `MutableExamplePacket`.
//!      - A number of accessor methods, of the form `pub get_{field_name}(&self) -> {field_type}`,
//!        which will retrieve the host representation of the on-the-wire value.
//!  * A `MutableExamplePacket<'p>` structure, which is used when sending packets on the network.
//!    This structure contains:
//!      - A method, `pub fn new<'p>(packet: &'p mut [u8]) -> MutableExamplePacket<'p>`, used for
//!        the construction of a `MutableExamplePacket`, given a buffer to store it. The buffer
//!        should be long enough to contain all the fields in the packet.
//!      - A method, `pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>`, which converts from
//!        a `MutableExamplePacket` to an `ExamplePacket`
//!      - A method, `pub fn populate(&mut self, packet: Example)`, which, given an `Example`
//!        struct, will populate the `MutableExamplePacket` with the values from the `Example`
//!        struct.
//!      - A number of accessor methods, of the form `pub get_{field_name}(&self) -> {field_type}`,
//!        which will retrieve the host representation of the on-the-wire value.
//!      - A number of mutator methods, of the form `pub set_{field_name}(&mut self,
//!        val: {field_type})`, which will take a host value, convert it to the required
//!        on-the-wire format, and store it in the buffer which backs the `MutableExamplePacket`.
//!  * A number of trait implementations for each of the `MutableExamplePacket` and `ExamplePacket`
//!    structures. These include:
//!      - `pnet::packet::Packet` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::MutablePacket` (`MutableExamplePacket` only)
//!      - `std::fmt::Debug` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::FromPacket` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::PacketSize` (`ExamplePacket` and `MutableExamplePacket`)
//!  * An `ExampleIterator` structure, which implements `std::iter::Iterator`, to allow iterating
//!    over vectors of `ExamplePacket` contained within another packet. Used internally.
//!
//! ## Attributes
//!
//! There are a number of attributes which fields may have, these include:
//!
//!  * \#[length_fn = "function_name"]
//!
//!    This attribute is used to enable variable length fields. To specify a variable length field,
//!    it should have the type `Vec<T>`. It must have the `#[length_fn]` (or #[length]) attribute,
//!    which specifies a function name to calculate the length of the field. The signature for the
//!    length function should be
//!    `fn {function_name}<'a>(example_packet: &ExamplePacket<'a>) -> usize`, substituting
//!    `&ExamplePacket<'a>` for the appropriately named packet type for your structure. You may
//!    access whichever fields are required to calculate the length of the field. The returned
//!    value should be a number of bytes that the field uses.
//!
//!    The type contained in the vector may either be one of the primitive types specified in
//!    `pnet_macros::types`, or another structure marked with #[packet], for example
//!    `Vec<Example>`.
//!
//!  * \#[length = "arithmetic expression"]
//!
//!    This attribute is used to enable variable length fields. To specify a variable length field,
//!    it should have the type `Vec<T>`. It must have the `#[length]` (or #[length_fn]) attribute,
//!    which specifies an arithmetic expression to calculate the length of the field. Only field
//!    names, constants, integers, basic arithmetic expressions (+ - * / %) and parentheses are
//!    in the expression. An example would be `#[length = "field_name + CONSTANT - 4]`.
//!
//!    The type contained in the vector may either be one of the primitive types specified in
//!    `pnet_macros::types`, or another structure marked with #[packet], for example
//!    `Vec<Example>`.
//!
//!  * \#[payload]
//!
//!    This attribute specifies the payload associated with the packet. This should specify the
//!    data associated with the packet. It may be used in two places:
//!      - The last field in the packet, in which case it is assumed to use the remaining length of
//!        the buffer containing the packet
//!      - Another location in the packet, in which case the `#[length_fn]` attribute must also be
//!        specified to give the length of the payload.
//!    If the packet has no payload, you must still specify this attribute, but you can provide a
//!    `#[length_fn]` attribute returning zero.
//!
//!  * \#[construct_with(<primitive type>, ...)]
//!
//!    Unfortunately, compiler plugins do not currently have access to type information during the
//!    decoration stage (where all of the above is generated), so this attribute is required. This
//!    must be used for all fields which are neither primitive types, nor vectors of primitive
//!    types. Three things are required when using `#[construct_with]`:
//!      - The field type must have a method `new`, which takes one or more parameters of primitive
//!        types.
//!      - The field must be annotated with the `#[construct_with(...)]` attribute, specifying a
//!        list of types identical to those taken by the `new` method.
//!      - The `pnet::packet::ToPrimitiveValues` trait must be implemented for the field type,
//!        which must return a tuple of the primitive types specified in the parameters to the
//!        `#[construct_with(...)]` attribute, and in the `new` method.

#![deny(missing_docs)]
// #![cfg_attr(feature = "clippy", feature(plugin))]
// #![cfg_attr(feature = "clippy", plugin(clippy))]
// #![cfg_attr(feature = "clippy", allow(let_and_return))]

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Visibility};

mod decorator;
mod util;

/// The entry point for the `derive(Packet)` custom derive
#[proc_macro_derive(Packet, attributes(construct_with, length, length_fn, payload))]
pub fn derive_packet(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    // ensure struct is public
    match ast.vis {
        Visibility::Public(_) => (),
        _ => {
            let ts = syn::Error::new(ast.ident.span(), "#[packet] structs must be public")
                .to_compile_error();
            return ts.into();
        }
    }
    let name = &ast.ident;
    let s = match &ast.data {
        syn::Data::Struct(ref s) => decorator::generate_packet(s, name.to_string()),
        _ => panic!("Only structs are supported"),
    };
    s.into()
}

/// The entry point for the `packet` proc_macro_attribute
#[proc_macro_attribute]
pub fn packet(_attrs: TokenStream, code: TokenStream) -> TokenStream {
    // let _attrs = parse_macro_input!(attrs as AttributeArgs);
    let input = parse_macro_input!(code as DeriveInput);
    // enhancement: if input already has Clone and/or Debug, do not add them
    let s = quote! {
        #[derive(::pnet_macros::Packet, Clone, Debug)]
        #[allow(unused_attributes)]
        #input
    };
    s.into()
}
<commit_msg>pnet_macros: doctest can now compile and run<commit_after>// Copyright (c) 2015 Robert Clipsham <robert@octarineparrot.com>
// Copyright (c) 2021 Pierre Chifflier <chifflier@wzdftpd.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The pnet_macros crate provides the `#[packet]` macro and compiler plugin, which is used to
//! specify the format of on-the-wire packets, and automatically generate zero-copy accessors and
//! mutators for the fields. It is used as follows:
//!
//! ```
//! /// Import the #[packet] custom attribute
//! use pnet_macros::packet;
//! /// This module contains a list of type aliases which may be used
//! use pnet_macros_support::types::{u4, u12be};
//!
//! /// Packets are specified in the same way as normal Rust structs, but with a `#[packet]`
//! /// attribute.
//! #[packet]
//! pub struct Example {
//!     // This is a simple field which contains a 4-bit, unsigned integer.
//!     // Note that `u4` is simply an alias for `u8` - the name is a hint
//!     // to the compiler plugin, it is NOT a usable 4 bit type!
//!     simple_field1: u4,
//!
//!     // This specifies that `simple_field2` should be a 12-bit field,
//!     // with bits stored in big endian
//!     simple_field2: u12be,
//!
//!     // All packets must specify a `#[payload]`, which should be a
//!     // `Vec<u8>`. This represents the packet's payload, for example in
//!     // an IPv4 packet, the payload could be a UDP packet, or in a UDP
//!     // packet the payload could be the application data. All the
//!     // remaining space in the packet is considered to be the payload
//!     // (this doesn't have to be the case, see the documentation for
//!     // `#[payload]` below.
//!     #[payload]
//!     payload: Vec<u8>
//! }
//! ```
//! A number of things will then be generated. You can see this in action in the documentation and
//! source of each of the packet types in the `pnet::packet` module. Things generated include
//! (assuming the `Example` struct from above):
//!
//!  * An `ExamplePacket<'p>` structure, which is used for receiving packets on the network.
//!    This structure contains:
//!      - A method, `pub fn new<'p>(packet: &'p [u8]) -> ExamplePacket<'p>`, used for the
//!        construction of an `ExamplePacket`, given a buffer to store it. The buffer should be
//!        long enough to contain all the fields in the packet.
//!      - A method, `pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>`, which is simply an
//!        identity function. It exists for consistency with `MutableExamplePacket`.
//!      - A number of accessor methods, of the form `pub get_{field_name}(&self) -> {field_type}`,
//!        which will retrieve the host representation of the on-the-wire value.
//!  * A `MutableExamplePacket<'p>` structure, which is used when sending packets on the network.
//!    This structure contains:
//!      - A method, `pub fn new<'p>(packet: &'p mut [u8]) -> MutableExamplePacket<'p>`, used for
//!        the construction of a `MutableExamplePacket`, given a buffer to store it. The buffer
//!        should be long enough to contain all the fields in the packet.
//!      - A method, `pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>`, which converts from
//!        a `MutableExamplePacket` to an `ExamplePacket`
//!      - A method, `pub fn populate(&mut self, packet: Example)`, which, given an `Example`
//!        struct, will populate the `MutableExamplePacket` with the values from the `Example`
//!        struct.
//!      - A number of accessor methods, of the form `pub get_{field_name}(&self) -> {field_type}`,
//!        which will retrieve the host representation of the on-the-wire value.
//!      - A number of mutator methods, of the form `pub set_{field_name}(&mut self,
//!        val: {field_type})`, which will take a host value, convert it to the required
//!        on-the-wire format, and store it in the buffer which backs the `MutableExamplePacket`.
//!  * A number of trait implementations for each of the `MutableExamplePacket` and `ExamplePacket`
//!    structures. These include:
//!      - `pnet::packet::Packet` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::MutablePacket` (`MutableExamplePacket` only)
//!      - `std::fmt::Debug` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::FromPacket` (`ExamplePacket` and `MutableExamplePacket`)
//!      - `pnet::packet::PacketSize` (`ExamplePacket` and `MutableExamplePacket`)
//!  * An `ExampleIterator` structure, which implements `std::iter::Iterator`, to allow iterating
//!    over vectors of `ExamplePacket` contained within another packet. Used internally.
//!
//! ## Attributes
//!
//! There are a number of attributes which fields may have, these include:
//!
//!  * \#[length_fn = "function_name"]
//!
//!    This attribute is used to enable variable length fields. To specify a variable length field,
//!    it should have the type `Vec<T>`. It must have the `#[length_fn]` (or #[length]) attribute,
//!    which specifies a function name to calculate the length of the field. The signature for the
//!    length function should be
//!    `fn {function_name}<'a>(example_packet: &ExamplePacket<'a>) -> usize`, substituting
//!    `&ExamplePacket<'a>` for the appropriately named packet type for your structure. You may
//!    access whichever fields are required to calculate the length of the field. The returned
//!    value should be a number of bytes that the field uses.
//!
//!    The type contained in the vector may either be one of the primitive types specified in
//!    `pnet_macros::types`, or another structure marked with #[packet], for example
//!    `Vec<Example>`.
//!
//!  * \#[length = "arithmetic expression"]
//!
//!    This attribute is used to enable variable length fields. To specify a variable length field,
//!    it should have the type `Vec<T>`. It must have the `#[length]` (or #[length_fn]) attribute,
//!    which specifies an arithmetic expression to calculate the length of the field. Only field
//!    names, constants, integers, basic arithmetic expressions (+ - * / %) and parentheses are
//!    in the expression. An example would be `#[length = "field_name + CONSTANT - 4]`.
//!
//!    The type contained in the vector may either be one of the primitive types specified in
//!    `pnet_macros::types`, or another structure marked with #[packet], for example
//!    `Vec<Example>`.
//!
//!  * \#[payload]
//!
//!    This attribute specifies the payload associated with the packet. This should specify the
//!    data associated with the packet. It may be used in two places:
//!      - The last field in the packet, in which case it is assumed to use the remaining length of
//!        the buffer containing the packet
//!      - Another location in the packet, in which case the `#[length_fn]` attribute must also be
//!        specified to give the length of the payload.
//!    If the packet has no payload, you must still specify this attribute, but you can provide a
//!    `#[length_fn]` attribute returning zero.
//!
//!  * \#[construct_with(<primitive type>, ...)]
//!
//!    Unfortunately, compiler plugins do not currently have access to type information during the
//!    decoration stage (where all of the above is generated), so this attribute is required. This
//!    must be used for all fields which are neither primitive types, nor vectors of primitive
//!    types. Three things are required when using `#[construct_with]`:
//!      - The field type must have a method `new`, which takes one or more parameters of primitive
//!        types.
//!      - The field must be annotated with the `#[construct_with(...)]` attribute, specifying a
//!        list of types identical to those taken by the `new` method.
//!      - The `pnet::packet::ToPrimitiveValues` trait must be implemented for the field type,
//!        which must return a tuple of the primitive types specified in the parameters to the
//!        `#[construct_with(...)]` attribute, and in the `new` method.

#![deny(missing_docs)]
// #![cfg_attr(feature = "clippy", feature(plugin))]
// #![cfg_attr(feature = "clippy", plugin(clippy))]
// #![cfg_attr(feature = "clippy", allow(let_and_return))]

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Visibility};

mod decorator;
mod util;

/// The entry point for the `derive(Packet)` custom derive
#[proc_macro_derive(Packet, attributes(construct_with, length, length_fn, payload))]
pub fn derive_packet(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    // ensure struct is public
    match ast.vis {
        Visibility::Public(_) => (),
        _ => {
            let ts = syn::Error::new(ast.ident.span(), "#[packet] structs must be public")
                .to_compile_error();
            return ts.into();
        }
    }
    let name = &ast.ident;
    let s = match &ast.data {
        syn::Data::Struct(ref s) => decorator::generate_packet(s, name.to_string()),
        _ => panic!("Only structs are supported"),
    };
    s.into()
}

/// The entry point for the `packet` proc_macro_attribute
#[proc_macro_attribute]
pub fn packet(_attrs: TokenStream, code: TokenStream) -> TokenStream {
    // let _attrs = parse_macro_input!(attrs as AttributeArgs);
    let input = parse_macro_input!(code as DeriveInput);
    // enhancement: if input already has Clone and/or Debug, do not add them
    let s = quote! {
        #[derive(::pnet_macros::Packet, Clone, Debug)]
        #[allow(unused_attributes)]
        #input
    };
    s.into()
}
<|endoftext|>


<commit_before>extern crate "pkg-config" as pkg_config;

fn main() {
    let opts = pkg_config::default_options("portaudio-2.0");
    match pkg_config::find_library_opts("portaudio-2.0", &opts)
    {
        Ok(..) => {},
        Err(e) => panic!("{}", e),
    }
}

<commit_msg>Update for latest pkg-config<commit_after>extern crate "pkg-config" as pkg_config;

fn main() {
    match pkg_config::find_library("portaudio-2.0")
    {
        Ok(..) => {},
        Err(e) => panic!("{}", e),
    }
}

<|endoftext|>


<commit_before>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! An audio unit can be constructed with the builder pattern.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    audio_unit: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> AudioUnitBuilder {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            use std::ptr::null_mut;
            // Find the default audio unit for the description.
            let component_result = match au::AudioComponentFindNext(null_mut(), &desc as *const _) {
                component if component.is_null() => Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => Ok(component),
            };

            // Get an instance of the default audio unit using the component.
            let mut audio_unit: au::AudioUnit = mem::uninitialized();

            let audio_unit_result = match component_result {
                Ok(component) => {
                    au::AudioComponentInstanceNew(component, &mut audio_unit as *mut au::AudioUnit);
                    Ok((audio_unit, None))
                },
                Err(err) => Err(err),
            };
            AudioUnitBuilder { audio_unit_result: audio_unit_result }
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.audio_unit,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

    /// Close the audio unit.
    pub fn close(self) {}

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = error::Error::from_os_status(au::AudioOutputUnitStop(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.audio_unit)) {
                panic!("{:?}", err.description());
            }
            if let Some(callback) = self.callback {
                // Here, we transfer ownership of the callback back to the current scope so that it
                // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
                let _: Box<RenderCallback> = mem::transmute(callback);
            }
        }
    }
}

/// A context on which to build the audio unit.
pub struct AudioUnitBuilder {
    audio_unit_result: Result<(au::AudioUnit, Option<*mut libc::c_void>), Error>,
}

impl AudioUnitBuilder {

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    /// This will be called every time the AudioUnit requests audio.
    /// f is a boxed FnMut whose arg is [frames[channels]].
    #[inline]
    pub fn render_callback(self, f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>)
        -> AudioUnitBuilder
    {
        let audio_unit_result = match self.audio_unit_result {
            Err(err) => Err(err),
            Ok((audio_unit, previous_callback)) => {
                unsafe {
                    if let Some(previous_callback_ptr) = previous_callback {
                        // Here, we transfer ownership of the previous callback back to the current
                        // scope so that it is dropped and cleaned up. Without this line, we would
                        // leak the Boxed callback.
                        let _: Box<RenderCallback> = mem::transmute(previous_callback_ptr);
                    }

                    let size_of_render_callback_struct =
                        mem::size_of::<au::AURenderCallbackStruct>() as u32;

                    // Setup render callback. Notice that we relinquish ownership of the Callback
                    // here so that it can be used as the C render callback via a void pointer.
                    // We do however store the *mut so that we can transmute back to a
                    // Box<RenderCallback> within our AudioUnit's Drop implementation (otherwise it
                    // would leak).
                    let boxed_render_callback = Box::new(RenderCallback { f: f });
                    let callback: *mut libc::c_void = mem::transmute(boxed_render_callback);
                    let render_callback = au::AURenderCallbackStruct {
                        inputProc: Some(input_proc),
                        inputProcRefCon: callback,
                    };

                    match Error::from_os_status(au::AudioUnitSetProperty(
                                                audio_unit,
                                                au::kAudioUnitProperty_SetRenderCallback,
                                                Scope::Input as libc::c_uint,
                                                Element::Output as libc::c_uint,
                                                &render_callback as *const _ as *const libc::c_void,
                                                size_of_render_callback_struct)) {
                        Ok(()) => Ok((audio_unit, Some(callback))),
                        Err(err) => Err(err),
                    }
                }
            },
        };
        AudioUnitBuilder { audio_unit_result: audio_unit_result }
    }

    /// Finish building the audio unit, initialise it and start it.
    pub fn start(self) -> Result<AudioUnit, Error> {
        let (audio_unit, callback) = try!(self.audio_unit_result);
        unsafe {
            // Initialise the audio unit!
            try!(Error::from_os_status(au::AudioUnitInitialize(audio_unit)));
            try!(Error::from_os_status(au::AudioOutputUnitStart(audio_unit)));
        }
        Ok(AudioUnit { audio_unit: audio_unit, callback: callback })
    }

}

pub type NumFrames = usize;

/// A struct in which we will pass the callback to the AudioUnit's render callback.
pub struct RenderCallback {
    f: Box<FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>>,
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus
{
    let callback: *mut RenderCallback = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*(*callback).f)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<commit_msg>Lots of stuff (see below)<commit_after>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component_result = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => Ok(component),
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            match component_result {
                Ok(component) => {
                    au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit); // TODO: Check error code
                    // Initialise the audio unit!
                    au::AudioUnitInitialize(instance); // TODO: Check error code
                    Ok(AudioUnit {
                        instance: instance,
                        callback: None
                    })
                },
                Err(err) => Err(err),
            }
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { mem::transmute(callback) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, callback: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        // TODO: Double-check naming etc in here; could probably be better.
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can transmute back to a
            // Box<RenderCallback> within our AudioUnit's Drop implementation (otherwise it
            // would leak).
            let callback_ptr: *mut libc::c_void = match callback {
                Some(x) => mem::transmute(Box::new(x)),
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            match Error::from_os_status(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32)) {
                Ok(()) => {
                    self.free_render_callback();
                    self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
                    Ok(())
                },
                Err(err) => Err(err),
            }
        }
    }

    /// Start the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already started.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStart(self.instance))); }
        Ok(())
    }

    /// Stop the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already stopped.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStop(self.instance))); }
        Ok(())
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.instance,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<|endoftext|>


<commit_before>//! TODO Fill in

use rustwlc::{Geometry, Point, Size, WlcOutput};
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::property::Property;
use super::class::{self, Class, ClassBuilder};

pub const SCREENS_HANDLE: &'static str = "__screens";

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Output {
    pub name: String,
    pub mm_width: u32,
    pub mm_height: u32,
    // TODO The XID array?
}

impl From<WlcOutput> for Output {
    fn from(output: WlcOutput) -> Output {
        let resolution = output.get_resolution().unwrap();
        Output {
            name: output.get_name(),
            mm_width: resolution.w,
            mm_height: resolution.h
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScreenState {
    // Is this screen still valid and may be used
    pub valid: bool,
    // Screen geometry
    pub geometry: Geometry,
    // Screen workarea
    pub workarea: Geometry,
    // The screen outputs information
    pub outputs: Vec<Output>,
    // Some XID indetifying this screen
    pub xid: u32
}

pub struct Screen<'lua>(Table<'lua>);

impl_objectable!(Screen, ScreenState);

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

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

impl UserData for ScreenState {}

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            valid: true,
            geometry: Geometry::zero(),
            workarea: Geometry::zero(),
            outputs: vec![],
            xid: 0
        }
    }
}

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

    fn init_screens(&mut self, outputs: Vec<Output>) -> rlua::Result<()> {
        let mut state = self.state()?;
        state.outputs = outputs;
        self.set_state(state)
    }

    fn get_workarea(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.workarea.origin;
        let Size { w, h } = state.workarea.size;
        // TODO I do this a lot, put it somewhere
        let table = lua.create_table();
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    let res = property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Screen::new)), None, None)?)?)?
        .save_class("screen")?
        .build()?;
    let mut screens: Vec<Screen> = vec![];
    for output in WlcOutput::list() {
        let mut screen = Screen::cast(Screen::new(lua)?)?;
        screen.init_screens(vec![output.into()])?;
        // TODO Move to Screen impl like the others
        screens.push(screen);
    }
    // TODO Uncomment
    // This breaks rc.lua because of layoutbox stuff.
    // Please fix that when you uncomment this.
    lua.globals().set(SCREENS_HANDLE, lua.create_table()/*screens.to_lua(lua)?*/)?;
    Ok(res)
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("__index".into(), lua.create_function(index))?
           .method("__call".into(), lua.create_function(iterate_over_screens))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("workarea".into(),
                                None,
                                Some(lua.create_function(get_workarea)),
                                None))
}

fn get_workarea<'lua>(lua: &'lua Lua, table: Table<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(table.into())?;
    screen.get_workarea(lua)
}

/// Ok this requires some explanation...
/// Lua gives us the previous value in the loop, with the first one being nil
/// since there was nothing there before.
///
/// To ensure we loop over everything, we take the index of that value in our list,
/// increment it by 1 (starting at 0 if it's the start) and then once it falls outside
/// the bounds it will stop by returning nil.
fn iterate_over_screens<'lua>(lua: &'lua Lua,
                              (_, _, prev): (Value<'lua>, Value<'lua>, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<Table>>(SCREENS_HANDLE)?
        .into_iter().map(|t| Screen::cast(t.into()).unwrap())
        .collect();
    let index = match prev {
        Value::Nil => 0,
        Value::Table(ref table) => {
            if let Ok(screen) = Screen::cast(table.clone().into()) {
                screens.iter().position(|t| t.state().unwrap() == screen.state().unwrap())
                    .unwrap_or(screens.len()) + 1
            } else {
                panic!("Unexpected non-screen table in loop");
            }
        }
        _ => panic!("Unexpected non-screen or nil value in screens loop")
    };
    if index < screens.len() {
        screens[index].get_table().to_lua(lua)
    } else {
        Ok(Value::Nil)
    }

}

fn index<'lua>(lua: &'lua Lua,
               (obj_table, index): (Table<'lua>, Value<'lua>))
               -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<Table>>(SCREENS_HANDLE)?
        .into_iter().map(|t| Screen::cast(t.into()).unwrap())
        .collect();
    match index {
        Value::String(ref string) => {
            let string = string.to_str()?;
            if string == "primary" {
                // TODO Emit primary changed signal
                if screens.len() > 0 {
                    return screens[0].get_table().clone().to_lua(lua)
                }
            }
            for screen in screens.iter() {
                let screen_state = screen.state()?;
                for output in &screen_state.outputs {
                    if output.name.as_str() == string {
                        return screen.get_table().clone().to_lua(lua)
                    }
                }
            }
        },
        // TODO Might need to do Number instead
        Value::Integer(screen_index) => {
            if screen_index < 1 || screen_index as usize > screens.len() {
                return Err(rlua::Error::RuntimeError(
                    format!("invalid screen number: {} (of {} existing)",
                            screen_index, screens.len())))
            }
            return screens[screen_index as usize].get_table().clone().to_lua(lua).clone()
        },
        Value::Table(ref table) => {
            // If this is a screen, just return it
            if let Ok(screen) = Screen::cast(table.clone().into()) {
                return screen.to_lua(lua)
            }
        },
        // TODO This checke user data like in luaA_toudata in awesome
        _ => {}
    }
    // TODO checkudata
    let meta = obj_table.get_metatable().unwrap();
    meta.get(index.clone()).or_else(|_| super::object::default_index(lua, (obj_table, index)))
}
<commit_msg>screen: Implement .geometry<commit_after>//! TODO Fill in

use rustwlc::{Geometry, Point, Size, WlcOutput};
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::property::Property;
use super::class::{self, Class, ClassBuilder};

pub const SCREENS_HANDLE: &'static str = "__screens";

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Output {
    pub name: String,
    pub mm_width: u32,
    pub mm_height: u32,
    // TODO The XID array?
}

impl From<WlcOutput> for Output {
    fn from(output: WlcOutput) -> Output {
        let resolution = output.get_resolution().unwrap();
        Output {
            name: output.get_name(),
            mm_width: resolution.w,
            mm_height: resolution.h
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScreenState {
    // Is this screen still valid and may be used
    pub valid: bool,
    // Screen geometry
    pub geometry: Geometry,
    // Screen workarea
    pub workarea: Geometry,
    // The screen outputs information
    pub outputs: Vec<Output>,
    // Some XID indetifying this screen
    pub xid: u32
}

pub struct Screen<'lua>(Table<'lua>);

impl_objectable!(Screen, ScreenState);

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

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

impl UserData for ScreenState {}

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            valid: true,
            geometry: Geometry::zero(),
            workarea: Geometry::zero(),
            outputs: vec![],
            xid: 0
        }
    }
}

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

    fn init_screens(&mut self, outputs: Vec<Output>) -> rlua::Result<()> {
        let mut state = self.state()?;
        state.outputs = outputs;
        self.set_state(state)
    }

    fn get_geometry(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.geometry.origin;
        let Size { w, h } = state.geometry.size;
        // TODO I do this a lot, put it somewhere
        let table = lua.create_table();
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }

    fn get_workarea(&self, lua: &'lua Lua) -> rlua::Result<Table<'lua>> {
        let state = self.state()?;
        let Point { x, y } = state.workarea.origin;
        let Size { w, h } = state.workarea.size;
        // TODO I do this a lot, put it somewhere
        let table = lua.create_table();
        table.set("x", x)?;
        table.set("y", y)?;
        table.set("width", w)?;
        table.set("height", h)?;
        Ok(table)
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    let res = property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Screen::new)), None, None)?)?)?
        .save_class("screen")?
        .build()?;
    let mut screens: Vec<Screen> = vec![];
    for output in WlcOutput::list() {
        let mut screen = Screen::cast(Screen::new(lua)?)?;
        screen.init_screens(vec![output.into()])?;
        // TODO Move to Screen impl like the others
        screens.push(screen);
    }
    // TODO Uncomment
    // This breaks rc.lua because of layoutbox stuff.
    // Please fix that when you uncomment this.
    lua.globals().set(SCREENS_HANDLE, lua.create_table()/*screens.to_lua(lua)?*/)?;
    Ok(res)
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("__index".into(), lua.create_function(index))?
           .method("__call".into(), lua.create_function(iterate_over_screens))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("geometry".into(),
                                None,
                                Some(lua.create_function(get_geometry)),
                                None))?
        .property(Property::new("workarea".into(),
                                None,
                                Some(lua.create_function(get_workarea)),
                                None))
}

fn get_geometry<'lua>(lua: &'lua Lua, table: Table<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(table.into())?;
    screen.get_geometry(lua)
}

fn get_workarea<'lua>(lua: &'lua Lua, table: Table<'lua>) -> rlua::Result<Table<'lua>> {
    let screen = Screen::cast(table.into())?;
    screen.get_workarea(lua)
}

/// Ok this requires some explanation...
/// Lua gives us the previous value in the loop, with the first one being nil
/// since there was nothing there before.
///
/// To ensure we loop over everything, we take the index of that value in our list,
/// increment it by 1 (starting at 0 if it's the start) and then once it falls outside
/// the bounds it will stop by returning nil.
fn iterate_over_screens<'lua>(lua: &'lua Lua,
                              (_, _, prev): (Value<'lua>, Value<'lua>, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<Table>>(SCREENS_HANDLE)?
        .into_iter().map(|t| Screen::cast(t.into()).unwrap())
        .collect();
    let index = match prev {
        Value::Nil => 0,
        Value::Table(ref table) => {
            if let Ok(screen) = Screen::cast(table.clone().into()) {
                screens.iter().position(|t| t.state().unwrap() == screen.state().unwrap())
                    .unwrap_or(screens.len()) + 1
            } else {
                panic!("Unexpected non-screen table in loop");
            }
        }
        _ => panic!("Unexpected non-screen or nil value in screens loop")
    };
    if index < screens.len() {
        screens[index].get_table().to_lua(lua)
    } else {
        Ok(Value::Nil)
    }

}

fn index<'lua>(lua: &'lua Lua,
               (obj_table, index): (Table<'lua>, Value<'lua>))
               -> rlua::Result<Value<'lua>> {
    let screens: Vec<Screen> = lua.globals().get::<_, Vec<Table>>(SCREENS_HANDLE)?
        .into_iter().map(|t| Screen::cast(t.into()).unwrap())
        .collect();
    match index {
        Value::String(ref string) => {
            let string = string.to_str()?;
            if string == "primary" {
                // TODO Emit primary changed signal
                if screens.len() > 0 {
                    return screens[0].get_table().clone().to_lua(lua)
                }
            }
            for screen in screens.iter() {
                let screen_state = screen.state()?;
                for output in &screen_state.outputs {
                    if output.name.as_str() == string {
                        return screen.get_table().clone().to_lua(lua)
                    }
                }
            }
        },
        // TODO Might need to do Number instead
        Value::Integer(screen_index) => {
            if screen_index < 1 || screen_index as usize > screens.len() {
                return Err(rlua::Error::RuntimeError(
                    format!("invalid screen number: {} (of {} existing)",
                            screen_index, screens.len())))
            }
            return screens[screen_index as usize].get_table().clone().to_lua(lua).clone()
        },
        Value::Table(ref table) => {
            // If this is a screen, just return it
            if let Ok(screen) = Screen::cast(table.clone().into()) {
                return screen.to_lua(lua)
            }
        },
        // TODO This checke user data like in luaA_toudata in awesome
        _ => {}
    }
    // TODO checkudata
    let meta = obj_table.get_metatable().unwrap();
    meta.get(index.clone()).or_else(|_| super::object::default_index(lua, (obj_table, index)))
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<commit_msg>auto merge of #75 : samebchase/cargo/add-help-for-test, r=alexcrichton<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate toml = "github.com/mneumann/rust-toml#toml";
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use serialize::Encodable;
use cargo::{NoFlags,execute_main_without_stdin,handle_error};
use cargo::core::errors::{CLIError,CLIResult,ToResult};
use cargo::util::important_paths::find_project;
use cargo::util::config;

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, _) = match process(os::args()) {
        Ok((cmd, args)) => (cmd, args),
        Err(err) => return handle_error(err)
    };

    if cmd == "config-for-key".to_str() {
        log!(4, "cmd == config-for-key");
        execute_main_without_stdin(config_for_key)
    }
    else if cmd == "config-list".to_str() {
        log!(4, "cmd == config-list");
        execute_main_without_stdin(config_list)
    }
    else if cmd == "locate-project".to_str() {
        log!(4, "cmd == locate-project");
        execute_main_without_stdin(locate_project)
    }
    else {
        // TODO: Handle automatic dispatching to cargo-*
        debug!("unknown command");
        println!("Automatic execing of cargo-* commands has not yet been implemented. Call cargo-* commands directly for now");
    }
}

fn process(args: Vec<String>) -> CLIResult<(String, Vec<String>)> {
    let args: Vec<String> = Vec::from_slice(args.tail());
    let head = try!(args.iter().nth(0).to_result(|_| CLIError::new("No subcommand found", None::<&str>, 1))).to_str();
    let tail = Vec::from_slice(args.tail());

    Ok((head, tail))
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>, config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags) -> CLIResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(), args.key.as_slice()).to_result(|err|
        CLIError::new("Couldn't load configuration", Some(err), 1)));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>, config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags) -> CLIResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).to_result(|err|
        CLIError::new("Couldn't load conifguration", Some(err), 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags) -> CLIResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").to_result(|err|
        CLIError::new(err.to_str(), None::<&str>, 1)));

    let string = try!(root.as_str().to_result(|_|
        CLIError::new(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), None::<&str>, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<commit_msg>Make `cargo foo` work<commit_after>#![feature(phase)]

extern crate cargo;
extern crate toml = "github.com/mneumann/rust-toml#toml";
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{NoFlags,execute_main_without_stdin,handle_error};
use cargo::core::errors::{CLIError,CLIResult,ToResult};
use cargo::util::important_paths::find_project;
use cargo::util::{ToCLI,Wrap,config,io_error,simple_human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = match process(os::args()) {
        Ok((cmd, args)) => (cmd, args),
        Err(err) => return handle_error(err)
    };

    if cmd == "config-for-key".to_str() {
        log!(4, "cmd == config-for-key");
        execute_main_without_stdin(config_for_key)
    }
    else if cmd == "config-list".to_str() {
        log!(4, "cmd == config-list");
        execute_main_without_stdin(config_list)
    }
    else if cmd == "locate-project".to_str() {
        log!(4, "cmd == locate-project");
        execute_main_without_stdin(locate_project)
    }
    else {
        let command = Command::new(format!("cargo-{}", cmd))
            .args(args.as_slice())
            .stdin(InheritFd(0))
            .stdout(InheritFd(1))
            .stderr(InheritFd(2))
            .status();

        match command.map_err(|_| simple_human("No such subcommand")) {
            Ok(ExitStatus(0)) => (),
            Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(simple_human("").to_cli(i as uint)),
            Err(err) => handle_error(err.to_cli(127))
        }
    }
}

fn process(args: Vec<String>) -> CLIResult<(String, Vec<String>)> {
    let args: Vec<String> = Vec::from_slice(args.tail());
    let head = try!(args.iter().nth(0).to_result(|_| CLIError::new("No subcommand found", None::<&str>, 1))).to_str();
    let tail = Vec::from_slice(args.tail());

    Ok((head, tail))
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>, config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags) -> CLIResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(), args.key.as_slice()).to_result(|err|
        CLIError::new("Couldn't load configuration", Some(err), 1)));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>, config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags) -> CLIResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).to_result(|err|
        CLIError::new("Couldn't load conifguration", Some(err), 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags) -> CLIResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").to_result(|err|
        CLIError::new(err.to_str(), None::<&str>, 1)));

    let string = try!(root.as_str().to_result(|_|
        CLIError::new(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), None::<&str>, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<|endoftext|>