<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Unsafe casting functions

use mem;
use intrinsics;
use ptr::copy_nonoverlapping_memory;

/// Casts the value at `src` to U. The two types must have the same length.
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
    let mut dest: U = mem::uninit();
    let dest_ptr: *mut u8 = transmute(&mut dest);
    let src_ptr: *u8 = transmute(src);
    copy_nonoverlapping_memory(dest_ptr, src_ptr, mem::size_of::<U>());
    dest
}

/**
 * Move a thing into the void
 *
 * The forget function will take ownership of the provided value but neglect
 * to run any required cleanup or memory-management operations on it. This
 * can be used for various acts of magick.
 */
#[inline]
pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); }

/**
 * Force-increment the reference count on a shared box. If used
 * carelessly, this can leak the box.
 */
#[inline]
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }

/**
 * Transform a value of one type into a value of another type.
 * Both types must have the same size and alignment.
 *
 * # Example
 *
 * ```rust
 * use std::cast;
 *
 * let v: &[u8] = unsafe { cast::transmute("L") };
 * assert!(v == [76u8]);
 * ```
 */
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
    intrinsics::transmute(thing)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

/// Coerce a reference to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut_unsafe<T>(ptr: *T) -> *mut T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_immut_unsafe<T>(ptr: *mut T) -> *T {
    transmute(ptr)
}

/// Coerce a mutable reference to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
    transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T {
    transmute_mut_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/****************************************************************************
 * Tests
 ****************************************************************************/

#[cfg(test)]
mod tests {
    use cast::{bump_box_refcount, transmute};
    use raw;

    #[test]
    fn test_transmute_copy() {
        assert_eq!(1u, unsafe { ::cast::transmute_copy(&1) });
    }

    #[test]
    fn test_bump_managed_refcount() {
        unsafe {
            let managed = @~"box box box";      // refcount 1
            bump_box_refcount(managed);     // refcount 2
            let ptr: *int = transmute(managed); // refcount 2
            let _box1: @~str = ::cast::transmute_copy(&ptr);
            let _box2: @~str = ::cast::transmute_copy(&ptr);
            assert!(*_box1 == ~"box box box");
            assert!(*_box2 == ~"box box box");
            // Will destroy _box1 and _box2. Without the bump, this would
            // use-after-free. With too many bumps, it would leak.
        }
    }

    #[test]
    fn test_transmute() {
        unsafe {
            let x = @100u8;
            let x: *raw::Box<u8> = transmute(x);
            assert!((*x).data == 100);
            let _x: @int = transmute(x);
        }
    }

    #[test]
    fn test_transmute2() {
        unsafe {
            assert_eq!(~[76u8], transmute(~"L"));
        }
    }
}
<commit_msg>auto merge of #13015 : tbu-/rust/pr_remove_immut, r=alexcrichton<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Unsafe casting functions

use mem;
use intrinsics;
use ptr::copy_nonoverlapping_memory;

/// Casts the value at `src` to U. The two types must have the same length.
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
    let mut dest: U = mem::uninit();
    let dest_ptr: *mut u8 = transmute(&mut dest);
    let src_ptr: *u8 = transmute(src);
    copy_nonoverlapping_memory(dest_ptr, src_ptr, mem::size_of::<U>());
    dest
}

/**
 * Move a thing into the void
 *
 * The forget function will take ownership of the provided value but neglect
 * to run any required cleanup or memory-management operations on it. This
 * can be used for various acts of magick.
 */
#[inline]
pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); }

/**
 * Force-increment the reference count on a shared box. If used
 * carelessly, this can leak the box.
 */
#[inline]
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }

/**
 * Transform a value of one type into a value of another type.
 * Both types must have the same size and alignment.
 *
 * # Example
 *
 * ```rust
 * use std::cast;
 *
 * let v: &[u8] = unsafe { cast::transmute("L") };
 * assert!(v == [76u8]);
 * ```
 */
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
    intrinsics::transmute(thing)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

/// Coerce a reference to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut_unsafe<T>(ptr: *T) -> *mut T {
    transmute(ptr)
}

/// Coerce a mutable reference to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
    transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T {
    transmute_mut_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/****************************************************************************
 * Tests
 ****************************************************************************/

#[cfg(test)]
mod tests {
    use cast::{bump_box_refcount, transmute};
    use raw;

    #[test]
    fn test_transmute_copy() {
        assert_eq!(1u, unsafe { ::cast::transmute_copy(&1) });
    }

    #[test]
    fn test_bump_managed_refcount() {
        unsafe {
            let managed = @~"box box box";      // refcount 1
            bump_box_refcount(managed);     // refcount 2
            let ptr: *int = transmute(managed); // refcount 2
            let _box1: @~str = ::cast::transmute_copy(&ptr);
            let _box2: @~str = ::cast::transmute_copy(&ptr);
            assert!(*_box1 == ~"box box box");
            assert!(*_box2 == ~"box box box");
            // Will destroy _box1 and _box2. Without the bump, this would
            // use-after-free. With too many bumps, it would leak.
        }
    }

    #[test]
    fn test_transmute() {
        unsafe {
            let x = @100u8;
            let x: *raw::Box<u8> = transmute(x);
            assert!((*x).data == 100);
            let _x: @int = transmute(x);
        }
    }

    #[test]
    fn test_transmute2() {
        unsafe {
            assert_eq!(~[76u8], transmute(~"L"));
        }
    }
}
<|endoftext|>


<commit_before>use super::*;

/// Represents a macro invocation. The Path indicates which macro
/// is being invoked, and the vector of token-trees contains the source
/// of the macro invocation.
///
/// NB: the additional ident for a `macro_rules`-style macro is actually
/// stored in the enclosing item. Oog.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Mac {
    pub path: Path,
    pub tts: Vec<TokenTree>,
}

/// When the main rust parser encounters a syntax-extension invocation, it
/// parses the arguments to the invocation as a token-tree. This is a very
/// loose structure, such that all sorts of different AST-fragments can
/// be passed to syntax extensions using a uniform type.
///
/// If the syntax extension is an MBE macro, it will attempt to match its
/// LHS token tree against the provided token tree, and if it finds a
/// match, will transcribe the RHS token tree, splicing in any captured
/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
///
/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenTree {
    /// A single token
    Token(Token),
    /// A delimited sequence of token trees
    Delimited(Delimited),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Delimited {
    /// The type of delimiter
    pub delim: DelimToken,
    /// The delimited sequence of token trees
    pub tts: Vec<TokenTree>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Token {
    /* Expression-operator symbols. */
    Eq,
    Lt,
    Le,
    EqEq,
    Ne,
    Ge,
    Gt,
    AndAnd,
    OrOr,
    Not,
    Tilde,
    BinOp(BinOpToken),
    BinOpEq(BinOpToken),

    /* Structural symbols */
    At,
    Dot,
    DotDot,
    DotDotDot,
    Comma,
    Semi,
    Colon,
    ModSep,
    RArrow,
    LArrow,
    FatArrow,
    Pound,
    Dollar,
    Question,

    /* Literals */
    Literal(Lit),

    /* Name components */
    Ident(Ident),
    Underscore,
    Lifetime(Ident),

    DocComment(String),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinOpToken {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    Caret,
    And,
    Or,
    Shl,
    Shr,
}

/// A delimiter token
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DelimToken {
    /// A round parenthesis: `(` or `)`
    Paren,
    /// A square bracket: `[` or `]`
    Bracket,
    /// A curly brace: `{` or `}`
    Brace,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use Lifetime;
    use generics::parsing::lifetime;
    use ident::parsing::ident;
    use lit::parsing::lit;
    use space::{block_comment, whitespace};

    named!(pub mac -> Mac, do_parse!(
        name: ident >>
        punct!("!") >>
        body: delimited >>
        (Mac {
            path: name.into(),
            tts: vec![TokenTree::Delimited(body)],
        })
    ));

    named!(pub delimited -> Delimited, alt!(
        delimited!(
            punct!("("),
            many0!(token_tree),
            punct!(")")
        ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
        |
        delimited!(
            punct!("["),
            many0!(token_tree),
            punct!("]")
        ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
        |
        delimited!(
            punct!("{"),
            many0!(token_tree),
            punct!("}")
        ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
    ));

    named!(token_tree -> TokenTree, alt!(
        map!(token, TokenTree::Token)
        |
        map!(delimited, TokenTree::Delimited)
    ));

    named!(token -> Token, alt!(
        map!(bin_op_eq, Token::BinOpEq)
        |
        map!(bin_op, Token::BinOp)
        |
        punct!("=") => { |_| Token::Eq }
        |
        punct!("<") => { |_| Token::Lt }
        |
        punct!("<=") => { |_| Token::Le }
        |
        punct!("==") => { |_| Token::EqEq }
        |
        punct!("!=") => { |_| Token::Ne }
        |
        punct!(">=") => { |_| Token::Ge }
        |
        punct!(">") => { |_| Token::Gt }
        |
        punct!("&&") => { |_| Token::AndAnd }
        |
        punct!("||") => { |_| Token::OrOr }
        |
        punct!("!") => { |_| Token::Not }
        |
        punct!("~") => { |_| Token::Tilde }
        |
        punct!("@") => { |_| Token::At }
        |
        punct!(".") => { |_| Token::Dot }
        |
        punct!("..") => { |_| Token::DotDot }
        |
        punct!("...") => { |_| Token::DotDotDot }
        |
        punct!(",") => { |_| Token::Comma }
        |
        punct!(";") => { |_| Token::Semi }
        |
        punct!(":") => { |_| Token::Colon }
        |
        punct!("::") => { |_| Token::ModSep }
        |
        punct!("->") => { |_| Token::RArrow }
        |
        punct!("<-") => { |_| Token::LArrow }
        |
        punct!("=>") => { |_| Token::FatArrow }
        |
        punct!("#") => { |_| Token::Pound }
        |
        punct!("$") => { |_| Token::Dollar }
        |
        punct!("?") => { |_| Token::Question }
        |
        punct!("_") => { |_| Token::Underscore }
        |
        map!(lit, Token::Literal)
        |
        map!(ident, Token::Ident)
        |
        map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
        |
        map!(doc_comment, Token::DocComment)
    ));

    named!(bin_op -> BinOpToken, alt!(
        punct!("+") => { |_| BinOpToken::Plus }
        |
        punct!("-") => { |_| BinOpToken::Minus }
        |
        punct!("*") => { |_| BinOpToken::Star }
        |
        punct!("/") => { |_| BinOpToken::Slash }
        |
        punct!("%") => { |_| BinOpToken::Percent }
        |
        punct!("^") => { |_| BinOpToken::Caret }
        |
        punct!("&") => { |_| BinOpToken::And }
        |
        punct!("|") => { |_| BinOpToken::Or }
        |
        punct!("<<") => { |_| BinOpToken::Shl }
        |
        punct!(">>") => { |_| BinOpToken::Shr }
    ));

    named!(bin_op_eq -> BinOpToken, alt!(
        punct!("+=") => { |_| BinOpToken::Plus }
        |
        punct!("-=") => { |_| BinOpToken::Minus }
        |
        punct!("*=") => { |_| BinOpToken::Star }
        |
        punct!("/=") => { |_| BinOpToken::Slash }
        |
        punct!("%=") => { |_| BinOpToken::Percent }
        |
        punct!("^=") => { |_| BinOpToken::Caret }
        |
        punct!("&=") => { |_| BinOpToken::And }
        |
        punct!("|=") => { |_| BinOpToken::Or }
        |
        punct!("<<=") => { |_| BinOpToken::Shl }
        |
        punct!(">>=") => { |_| BinOpToken::Shr }
    ));

    named!(doc_comment -> String, alt!(
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (format!("//!{}", content))
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (com.to_owned())
        )
        |
        do_parse!(
            punct!("///") >>
            not!(peek!(tag!("/"))) >>
            content: take_until!("\n") >>
            (format!("///{}", content))
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (com.to_owned())
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Mac {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.path.to_tokens(tokens);
            tokens.append("!");
            for tt in &self.tts {
                tt.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TokenTree {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TokenTree::Token(ref token) => token.to_tokens(tokens),
                TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
            }
        }
    }

    impl DelimToken {
        fn open(&self) -> &'static str {
            match *self {
                DelimToken::Paren => "(",
                DelimToken::Bracket => "[",
                DelimToken::Brace => "{",
            }
        }

        fn close(&self) -> &'static str {
            match *self {
                DelimToken::Paren => ")",
                DelimToken::Bracket => "]",
                DelimToken::Brace => "}",
            }
        }
    }

    impl ToTokens for Delimited {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.delim.open());
            for tt in &self.tts {
                tt.to_tokens(tokens);
            }
            tokens.append(self.delim.close());
        }
    }

    impl ToTokens for Token {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Token::Eq => tokens.append("="),
                Token::Lt => tokens.append("<"),
                Token::Le => tokens.append("<="),
                Token::EqEq => tokens.append("=="),
                Token::Ne => tokens.append("!="),
                Token::Ge => tokens.append(">="),
                Token::Gt => tokens.append(">"),
                Token::AndAnd => tokens.append("&&"),
                Token::OrOr => tokens.append("||"),
                Token::Not => tokens.append("!"),
                Token::Tilde => tokens.append("~"),
                Token::BinOp(binop) => tokens.append(binop.op()),
                Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
                Token::At => tokens.append("@"),
                Token::Dot => tokens.append("."),
                Token::DotDot => tokens.append(".."),
                Token::DotDotDot => tokens.append("..."),
                Token::Comma => tokens.append(","),
                Token::Semi => tokens.append(";"),
                Token::Colon => tokens.append(":"),
                Token::ModSep => tokens.append("::"),
                Token::RArrow => tokens.append("->"),
                Token::LArrow => tokens.append("<-"),
                Token::FatArrow => tokens.append("=>"),
                Token::Pound => tokens.append("#"),
                Token::Dollar => tokens.append("$"),
                Token::Question => tokens.append("?"),
                Token::Literal(ref lit) => lit.to_tokens(tokens),
                Token::Ident(ref ident) => ident.to_tokens(tokens),
                Token::Underscore => tokens.append("_"),
                Token::Lifetime(ref ident) => ident.to_tokens(tokens),
                Token::DocComment(ref com) => {
                    tokens.append(&format!("{}\n", com));
                }
            }
        }
    }

    impl BinOpToken {
        fn op(&self) -> &'static str {
            match *self {
                BinOpToken::Plus => "+",
                BinOpToken::Minus => "-",
                BinOpToken::Star => "*",
                BinOpToken::Slash => "/",
                BinOpToken::Percent => "%",
                BinOpToken::Caret => "^",
                BinOpToken::And => "&",
                BinOpToken::Or => "|",
                BinOpToken::Shl => "<<",
                BinOpToken::Shr => ">>",
            }
        }

        fn assign_op(&self) -> &'static str {
            match *self {
                BinOpToken::Plus => "+=",
                BinOpToken::Minus => "-=",
                BinOpToken::Star => "*=",
                BinOpToken::Slash => "/=",
                BinOpToken::Percent => "%=",
                BinOpToken::Caret => "^=",
                BinOpToken::And => "&=",
                BinOpToken::Or => "|=",
                BinOpToken::Shl => "<<=",
                BinOpToken::Shr => ">>=",
            }
        }
    }

    impl ToTokens for BinOpToken {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.op());
        }
    }
}
<commit_msg>Sort macro parsing by length<commit_after>use super::*;

/// Represents a macro invocation. The Path indicates which macro
/// is being invoked, and the vector of token-trees contains the source
/// of the macro invocation.
///
/// NB: the additional ident for a `macro_rules`-style macro is actually
/// stored in the enclosing item. Oog.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Mac {
    pub path: Path,
    pub tts: Vec<TokenTree>,
}

/// When the main rust parser encounters a syntax-extension invocation, it
/// parses the arguments to the invocation as a token-tree. This is a very
/// loose structure, such that all sorts of different AST-fragments can
/// be passed to syntax extensions using a uniform type.
///
/// If the syntax extension is an MBE macro, it will attempt to match its
/// LHS token tree against the provided token tree, and if it finds a
/// match, will transcribe the RHS token tree, splicing in any captured
/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
///
/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenTree {
    /// A single token
    Token(Token),
    /// A delimited sequence of token trees
    Delimited(Delimited),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Delimited {
    /// The type of delimiter
    pub delim: DelimToken,
    /// The delimited sequence of token trees
    pub tts: Vec<TokenTree>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Token {
    /* Expression-operator symbols. */
    Eq,
    Lt,
    Le,
    EqEq,
    Ne,
    Ge,
    Gt,
    AndAnd,
    OrOr,
    Not,
    Tilde,
    BinOp(BinOpToken),
    BinOpEq(BinOpToken),

    /* Structural symbols */
    At,
    Dot,
    DotDot,
    DotDotDot,
    Comma,
    Semi,
    Colon,
    ModSep,
    RArrow,
    LArrow,
    FatArrow,
    Pound,
    Dollar,
    Question,

    /* Literals */
    Literal(Lit),

    /* Name components */
    Ident(Ident),
    Underscore,
    Lifetime(Ident),

    DocComment(String),
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinOpToken {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    Caret,
    And,
    Or,
    Shl,
    Shr,
}

/// A delimiter token
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DelimToken {
    /// A round parenthesis: `(` or `)`
    Paren,
    /// A square bracket: `[` or `]`
    Bracket,
    /// A curly brace: `{` or `}`
    Brace,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use Lifetime;
    use generics::parsing::lifetime;
    use ident::parsing::ident;
    use lit::parsing::lit;
    use space::{block_comment, whitespace};

    named!(pub mac -> Mac, do_parse!(
        name: ident >>
        punct!("!") >>
        body: delimited >>
        (Mac {
            path: name.into(),
            tts: vec![TokenTree::Delimited(body)],
        })
    ));

    named!(pub delimited -> Delimited, alt!(
        delimited!(
            punct!("("),
            many0!(token_tree),
            punct!(")")
        ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
        |
        delimited!(
            punct!("["),
            many0!(token_tree),
            punct!("]")
        ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
        |
        delimited!(
            punct!("{"),
            many0!(token_tree),
            punct!("}")
        ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
    ));

    named!(token_tree -> TokenTree, alt!(
        map!(token, TokenTree::Token)
        |
        map!(delimited, TokenTree::Delimited)
    ));

    named!(token -> Token, alt!(
        punct!("_") => { |_| Token::Underscore }
        |
        map!(bin_op_eq, Token::BinOpEq)
        |
        map!(bin_op, Token::BinOp)
        |
        map!(lit, Token::Literal)
        |
        map!(ident, Token::Ident)
        |
        map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
        |
        map!(doc_comment, Token::DocComment)
        |
        punct!("<=") => { |_| Token::Le }
        |
        punct!("==") => { |_| Token::EqEq }
        |
        punct!("!=") => { |_| Token::Ne }
        |
        punct!(">=") => { |_| Token::Ge }
        |
        punct!("&&") => { |_| Token::AndAnd }
        |
        punct!("||") => { |_| Token::OrOr }
        |
        punct!("::") => { |_| Token::ModSep }
        |
        punct!("->") => { |_| Token::RArrow }
        |
        punct!("<-") => { |_| Token::LArrow }
        |
        punct!("=>") => { |_| Token::FatArrow }
        |
        punct!("...") => { |_| Token::DotDotDot }
        |
        punct!("..") => { |_| Token::DotDot }
        |
        punct!(".") => { |_| Token::Dot }
        |
        punct!("=") => { |_| Token::Eq }
        |
        punct!("<") => { |_| Token::Lt }
        |
        punct!(">") => { |_| Token::Gt }
        |
        punct!("!") => { |_| Token::Not }
        |
        punct!("~") => { |_| Token::Tilde }
        |
        punct!("@") => { |_| Token::At }
        |
        punct!(",") => { |_| Token::Comma }
        |
        punct!(";") => { |_| Token::Semi }
        |
        punct!(":") => { |_| Token::Colon }
        |
        punct!("#") => { |_| Token::Pound }
        |
        punct!("$") => { |_| Token::Dollar }
        |
        punct!("?") => { |_| Token::Question }
    ));

    named!(bin_op -> BinOpToken, alt!(
        punct!("+") => { |_| BinOpToken::Plus }
        |
        punct!("-") => { |_| BinOpToken::Minus }
        |
        punct!("*") => { |_| BinOpToken::Star }
        |
        punct!("/") => { |_| BinOpToken::Slash }
        |
        punct!("%") => { |_| BinOpToken::Percent }
        |
        punct!("^") => { |_| BinOpToken::Caret }
        |
        punct!("&") => { |_| BinOpToken::And }
        |
        punct!("|") => { |_| BinOpToken::Or }
        |
        punct!("<<") => { |_| BinOpToken::Shl }
        |
        punct!(">>") => { |_| BinOpToken::Shr }
    ));

    named!(bin_op_eq -> BinOpToken, alt!(
        punct!("+=") => { |_| BinOpToken::Plus }
        |
        punct!("-=") => { |_| BinOpToken::Minus }
        |
        punct!("*=") => { |_| BinOpToken::Star }
        |
        punct!("/=") => { |_| BinOpToken::Slash }
        |
        punct!("%=") => { |_| BinOpToken::Percent }
        |
        punct!("^=") => { |_| BinOpToken::Caret }
        |
        punct!("&=") => { |_| BinOpToken::And }
        |
        punct!("|=") => { |_| BinOpToken::Or }
        |
        punct!("<<=") => { |_| BinOpToken::Shl }
        |
        punct!(">>=") => { |_| BinOpToken::Shr }
    ));

    named!(doc_comment -> String, alt!(
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (format!("//!{}", content))
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (com.to_owned())
        )
        |
        do_parse!(
            punct!("///") >>
            not!(peek!(tag!("/"))) >>
            content: take_until!("\n") >>
            (format!("///{}", content))
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (com.to_owned())
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Mac {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.path.to_tokens(tokens);
            tokens.append("!");
            for tt in &self.tts {
                tt.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TokenTree {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TokenTree::Token(ref token) => token.to_tokens(tokens),
                TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
            }
        }
    }

    impl DelimToken {
        fn open(&self) -> &'static str {
            match *self {
                DelimToken::Paren => "(",
                DelimToken::Bracket => "[",
                DelimToken::Brace => "{",
            }
        }

        fn close(&self) -> &'static str {
            match *self {
                DelimToken::Paren => ")",
                DelimToken::Bracket => "]",
                DelimToken::Brace => "}",
            }
        }
    }

    impl ToTokens for Delimited {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.delim.open());
            for tt in &self.tts {
                tt.to_tokens(tokens);
            }
            tokens.append(self.delim.close());
        }
    }

    impl ToTokens for Token {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Token::Eq => tokens.append("="),
                Token::Lt => tokens.append("<"),
                Token::Le => tokens.append("<="),
                Token::EqEq => tokens.append("=="),
                Token::Ne => tokens.append("!="),
                Token::Ge => tokens.append(">="),
                Token::Gt => tokens.append(">"),
                Token::AndAnd => tokens.append("&&"),
                Token::OrOr => tokens.append("||"),
                Token::Not => tokens.append("!"),
                Token::Tilde => tokens.append("~"),
                Token::BinOp(binop) => tokens.append(binop.op()),
                Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
                Token::At => tokens.append("@"),
                Token::Dot => tokens.append("."),
                Token::DotDot => tokens.append(".."),
                Token::DotDotDot => tokens.append("..."),
                Token::Comma => tokens.append(","),
                Token::Semi => tokens.append(";"),
                Token::Colon => tokens.append(":"),
                Token::ModSep => tokens.append("::"),
                Token::RArrow => tokens.append("->"),
                Token::LArrow => tokens.append("<-"),
                Token::FatArrow => tokens.append("=>"),
                Token::Pound => tokens.append("#"),
                Token::Dollar => tokens.append("$"),
                Token::Question => tokens.append("?"),
                Token::Literal(ref lit) => lit.to_tokens(tokens),
                Token::Ident(ref ident) => ident.to_tokens(tokens),
                Token::Underscore => tokens.append("_"),
                Token::Lifetime(ref ident) => ident.to_tokens(tokens),
                Token::DocComment(ref com) => {
                    tokens.append(&format!("{}\n", com));
                }
            }
        }
    }

    impl BinOpToken {
        fn op(&self) -> &'static str {
            match *self {
                BinOpToken::Plus => "+",
                BinOpToken::Minus => "-",
                BinOpToken::Star => "*",
                BinOpToken::Slash => "/",
                BinOpToken::Percent => "%",
                BinOpToken::Caret => "^",
                BinOpToken::And => "&",
                BinOpToken::Or => "|",
                BinOpToken::Shl => "<<",
                BinOpToken::Shr => ">>",
            }
        }

        fn assign_op(&self) -> &'static str {
            match *self {
                BinOpToken::Plus => "+=",
                BinOpToken::Minus => "-=",
                BinOpToken::Star => "*=",
                BinOpToken::Slash => "/=",
                BinOpToken::Percent => "%=",
                BinOpToken::Caret => "^=",
                BinOpToken::And => "&=",
                BinOpToken::Or => "|=",
                BinOpToken::Shl => "<<=",
                BinOpToken::Shr => ">>=",
            }
        }
    }

    impl ToTokens for BinOpToken {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.op());
        }
    }
}
<|endoftext|>


<commit_before>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]

extern crate libtest;
pub use libtest::*;
<commit_msg>Use feature(test)<commit_after>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(test)]

extern crate libtest;
pub use libtest::*;
<|endoftext|>


<commit_before>//! A library for interacting with a HackRF device.
//!
//! ## Examples
//! ```
//! extern crate hackrf;
//!
//! use hackrf::{HackRF, HackRFResult};
//!
//! const SAMP_RATE: u64 = 2_000_000; // 2 MHz
//!
//! fn main() {
//!    if let Err(e) = run() {
//!        println!("{:?}", e);
//!    }
//! }
//!
//! fn run() -> HackRFResult<()> {
//!     let context = try!(hackrf::init());
//!
//!     let mut device = try!(HackRF::open(&context));
//!     try!(device.set_samp_rate(SAMP_RATE as f64));
//!     try!(device.set_freq(150_000_000));
//!
//!     let mut rx_stream = try!(device.rx_stream());
//!
//!     // Take 10 seconds worth of samples
//!     for _ in 0..10 * SAMP_RATE {
//!         let (i, q) = rx_stream.next_sample();
//!         // .. Do something with samples ..
//!     }
//!
//!     Ok(())
//! }
//! ```

extern crate hackrf_sys as ffi;

use std::ffi::CStr;
use std::os::raw::{c_int, c_void};

use std::sync::mpsc::{SyncSender, Receiver, TrySendError, sync_channel};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use std::{mem, slice, ops, fmt};
use std::rc::Rc;

use ffi::hackrf_error::*;

pub mod util;

/// The maximum size of each of the buffers used for receiving.
/// Note: this must be greater than or equal to the buffer size chosen for libusb.
const BUFFER_SIZE: usize = 262144;

/// An internal macro for handling hackrf errors.
macro_rules! hackrf_try {
    ($e:expr) => ({
        match $e {
            HACKRF_SUCCESS => (),
            error => return Err(parse_error(error)),
        }
    });
}

/// A error that can occur when trying to interact with a HackRF device.
///
/// ## Possible Error Values
///
///     HACKRF_ERROR_INVALID_PARAM = -2
///     HACKRF_ERROR_NOT_FOUND = -5
///     HACKRF_ERROR_BUSY = -6
///     HACKRF_ERROR_NO_MEM = -11
///     HACKRF_ERROR_LIBUSB = -1000
///     HACKRF_ERROR_THREAD = -1001
///     HACKRF_ERROR_STREAMING_THREAD_ERR = -1002
///     HACKRF_ERROR_STREAMING_STOPPED = -1003
///     HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004
///     HACKRF_ERROR_OTHER = -9999
///
/// See [libhackrf](https://github.com/mossmann/hackrf/tree/master/host/libhackrf) for more info.
#[derive(Debug)]
pub struct HackRFError {
    /// The description of the code.
    pub desc: String,

    /// The code returned by `libhackrf`.
    pub code: i32,
}

impl fmt::Display for HackRFError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error({}): {}", self.code, self.desc)
    }
}

/// A specialized Result type for HackRF operations
pub type HackRFResult<T> = Result<T, HackRFError>;

/// An internal function for obtaining the description from a HackRF error code.
fn parse_error(error_code: ffi::hackrf_error) -> HackRFError {
    unsafe {
        let desc = CStr::from_ptr(ffi::hackrf_error_name(error_code)).to_string_lossy();
        HackRFError {
            desc: desc.to_string(),
            code: error_code as i32,
        }
    }
}

/// Adjust a gain value to the nearest valid step
fn adjust_gain(gain: u32, min: u32, max: u32, step: u32) -> u32 {
    if gain < min { min }
    else if gain > max { max }
    else { (gain as f32 / step as f32).round() as u32 * step }
}

/// The HackRF context.
///
/// This struct is used ensure that `libhackrf` is initialized before it can be used. A context can
/// be obtained by calling hackrf::init().
///
/// ## Example
/// ```
/// let context = try!(hackrf::init());
/// // Use context
/// ```
pub struct HackRFContext(Rc<HackRFContextInner>);

/// Value for keeping track of any object that contains a reference to the context.
///
/// When this value is dropped, `libhackrf` will be closed.
struct HackRFContextInner;

impl Drop for HackRFContextInner {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_exit();
        }
    }
}

/// Initialize `libhackrf`, returning a context that can be used to connect to HackRF devices.
/// Once all references to the returned context go out of scope, the library will be closed
/// automatically.
pub fn init() -> HackRFResult<HackRFContext> {
    unsafe {
        hackrf_try!(ffi::hackrf_init());
    }
    Ok(HackRFContext(Rc::new(HackRFContextInner)))
}

/// A structure for managaing a HackRF device.
///
/// This structure contains methods for configuring the various settings of the HackRF. It also
/// provides a method for managing received samples as a blocking stream. Currently transmitting
/// samples and non-blocking streams are not supported.
///
/// ## Implementation notes
///
/// This library is a lightweight wrapper around the basic HackRF FFI interface. In addition to
/// the basic functionality it provides a blocking stream interface for receiving samples (See:
/// [`RxStream`](./struct.RxStream.html)).
///
/// Rust's type system is used to ensure that resources are not destroy or modified while the HackRF
/// is receiving samples (although it is possible there are problems with the implementation.). To
/// stop receiving samples it is sufficient to let the stream drop out of scope. For example:
///
/// ```
/// let context = try!(hackrf::init());
/// let mut device = try!(HackRF::open(&context));
///
/// // Configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
///
/// // Re-configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
/// ```
pub struct HackRF {
    inner: *mut ffi::hackrf_device,
    _context: Rc<HackRFContextInner>,
}

impl Drop for HackRF {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_close(self.inner);
        }
    }
}

impl HackRF {
    /// Attempt to open a connected HackRF device.
    pub fn open(context: &HackRFContext) -> HackRFResult<HackRF> {
        unsafe {
            let mut device = std::mem::zeroed();
            hackrf_try!(ffi::hackrf_open(&mut device));
            Ok(HackRF { inner: device, _context: context.0.clone() })
        }
    }

    /// Sets the center frequency (in Hz) of the HackRF: 5-6800 MHz.
    pub fn set_freq(&mut self, freq: u64) -> HackRFResult<()> {
        // TODO: Consider checking that the frequency is in a valid range.
        unsafe {
            hackrf_try!(ffi::hackrf_set_freq(self.inner, freq));
        }
        Ok(())
    }

    /// Sets amp gain to on/off.
    ///
    /// Warning: Enabling this in the presence of high power signals could damage the HackRF.
    pub fn set_amp_enable(&mut self, amp_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if amp_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_amp_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set antenna enable to on/off.
    pub fn set_antenna_enable(&mut self, antenna_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if antenna_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_antenna_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set LNA gain: 0-40 dB, 8dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_lna_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_lna_gain(self.inner, adjust_gain(gain, 0, 40, 8)));
        }
        Ok(())
    }

    /// Set VGA (IF) gain: 0-62 dB, with 2dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_vga_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_vga_gain(self.inner, adjust_gain(gain, 0, 62, 2)));
        }
        Ok(())
    }

    /// Sets the sample rate in Hz: 2-20 MHz.
    pub fn set_samp_rate(&mut self, samp_rate: f64) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_sample_rate(self.inner, samp_rate));

            // Automatically compute a good baseband filter bandwidth
            let bandwidth = ffi::hackrf_compute_baseband_filter_bw_round_down_lt(samp_rate as u32);
            try!(self.set_baseband_filter_bw(bandwidth));
        }
        Ok(())
    }

    /// Sets the baseband filter bandwidth.
    ///
    /// Note: This must be performed *after* setting the sample rate.
    pub fn set_baseband_filter_bw(&mut self, filter_bw: u32) -> HackRFResult<()> {
        unsafe {
            let adjusted_filter_bw = ffi::hackrf_compute_baseband_filter_bw(filter_bw);
            hackrf_try!(ffi::hackrf_set_baseband_filter_bandwidth(self.inner, adjusted_filter_bw));
        }
        Ok(())
    }

    /// Start an RX stream.
    pub fn rx_stream(&mut self, bound: usize) -> HackRFResult<RxStream> {
        let mut rx_stream = RxStream::new(bound, self);
        let sender = (&mut *rx_stream.sender) as *mut SyncSender<StackVec>;
        unsafe {
            match ffi::hackrf_start_rx(self.inner, rx_callback, sender as *mut c_void) {
                HACKRF_SUCCESS => Ok(rx_stream),
                error => Err(parse_error(error)),
            }
        }
    }
}

static OVERFLOW_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

/// A structure that manages receiving I/Q samples from the HackRF.
pub struct RxStream<'a> {
    hackrf_device: &'a HackRF,
    lookup_table: [f32; 256],
    local_index: usize,
    local_buffer: StackVec,
    sender: Box<SyncSender<StackVec>>,
    receiver: Receiver<StackVec>,
}

impl<'a> RxStream<'a> {
    /// Create a new instance of a RxStream
    fn new(bound: usize, hackrf_device: &'a HackRF) -> RxStream<'a> {
        fn gen_lookup_table() -> [f32; 256] {
            let mut data = [0.0; 256];
            for i in 0..256 {
                data[i] = (i as i8) as f32 / 128.0;
            }
            data
        }

        // Reset the overflow counter
        OVERFLOW_COUNT.store(0, Ordering::Relaxed);

        let (sender, receiver) = sync_channel(bound);
        RxStream {
            hackrf_device: hackrf_device,
            lookup_table: gen_lookup_table(),
            local_index: 0,
            local_buffer: StackVec::new(),
            sender: Box::new(sender),
            receiver: receiver,
        }
    }

    // Returns a reference to the internal receiver
    pub fn receiver(&mut self) -> &mut Receiver<StackVec> {
        &mut self.receiver
    }

    /// Return the next I/Q sample converted to floating point numbers. If there is no data
    /// avaliable, then this function is blocking.
    pub fn next_sample(&mut self) -> Option<(f32, f32)> {
        let sample = self.next_sample_raw();
        sample.map(|(i, q)| (self.lookup_table[i as usize], self.lookup_table[q as usize]))
    }

    /// Return the next raw I/Q sample from the HackRF. If there is no data avaliable, then this
    /// function is blocking.
    pub fn next_sample_raw(&mut self) -> Option<(u8, u8)> {
        if self.local_buffer.len() < self.local_index + 1 {
            self.local_buffer = match self.receiver.recv() {
                Ok(buffer) => buffer,
                Err(_) => return None,
            };
            self.local_index = 0;
        }

        let i = self.local_index;
        self.local_index += 2;
        Some((self.local_buffer[i], self.local_buffer[i + 1]))
    }

    /// Return how many times the stream dropped data frames
    pub fn overflow_count(&self) -> usize {
        OVERFLOW_COUNT.load(Ordering::Relaxed)
    }
}

impl<'a> Drop for RxStream<'a> {
    fn drop(&mut self) {
        unsafe {
            // TODO: investigate if this can ever fail under reasonable conditions
            ffi::hackrf_stop_rx(self.hackrf_device.inner);
        }
    }
}

/// A stack allocated vector with a maximum size
pub struct StackVec {
    data: [u8; BUFFER_SIZE],
    len: usize,
}

impl StackVec {
    fn new() -> StackVec {
        StackVec {
            data: [0; BUFFER_SIZE],
            len: 0
        }
    }

    /// Copy a slice into the vector, setting the vectors length to the length of the slice.
    /// Panics if the slice is too large.
    fn copy_slice(&mut self, slice: &[u8]) {
        self.data[0..slice.len()].copy_from_slice(slice);
        self.len = slice.len();
    }
}

impl ops::Deref for StackVec {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.data[0..self.len]
    }
}

/// The call back that is used in the stream abstraction
unsafe extern "C" fn rx_callback(transfer: *mut ffi::hackrf_transfer) -> c_int {
    let src_buffer = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

    // If the input buffer is too long, then an error has occured somewhere
    if src_buffer.len() > BUFFER_SIZE {
        return -1;
    }

    // Copy the transferred data into an owned structure
    let mut data = StackVec::new();
    data.copy_slice(src_buffer);

    let sender_raw: *mut SyncSender<StackVec> = mem::transmute((*transfer).rx_ctx);
    let sender = &mut *sender_raw;

    if let Err(e) = sender.try_send(data) {
        match e {
            // If the buffer is full drop the message and increment the overflow count
            TrySendError::Full(_) => { OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed); },

            // Report an error back to libhackrf
            TrySendError::Disconnected(_) => return -1,
        }
    }

    // Succesfully sent the data
    0
}

#[cfg(test)]
mod test {
    #[test]
    fn init_test() {
        super::init();
    }
}
<commit_msg>Allocate memory transfer buffers on the heap, and implement error for HackRF error.<commit_after>//! A library for interacting with a HackRF device.
//!
//! ## Examples
//! ```
//! extern crate hackrf;
//!
//! use hackrf::{HackRF, HackRFResult};
//!
//! const SAMP_RATE: u64 = 2_000_000; // 2 MHz
//!
//! fn main() {
//!    if let Err(e) = run() {
//!        println!("{:?}", e);
//!    }
//! }
//!
//! fn run() -> HackRFResult<()> {
//!     let context = try!(hackrf::init());
//!
//!     let mut device = try!(HackRF::open(&context));
//!     try!(device.set_samp_rate(SAMP_RATE as f64));
//!     try!(device.set_freq(150_000_000));
//!
//!     let mut rx_stream = try!(device.rx_stream());
//!
//!     // Take 10 seconds worth of samples
//!     for _ in 0..10 * SAMP_RATE {
//!         let (i, q) = rx_stream.next_sample();
//!         // .. Do something with samples ..
//!     }
//!
//!     Ok(())
//! }
//! ```

extern crate hackrf_sys as ffi;

use std::ffi::CStr;
use std::os::raw::{c_int, c_void};

use std::sync::mpsc::{SyncSender, Receiver, TrySendError, sync_channel};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use std::{mem, slice, fmt, error};
use std::rc::Rc;

use ffi::hackrf_error::*;

pub mod util;

/// The maximum size of each of the buffers used for receiving.
/// Note: this must be greater than or equal to the buffer size chosen for libusb.
const BUFFER_SIZE: usize = 262144;

/// An internal macro for handling hackrf errors.
macro_rules! hackrf_try {
    ($e:expr) => ({
        match $e {
            HACKRF_SUCCESS => (),
            error => return Err(parse_error(error)),
        }
    });
}

/// A error that can occur when trying to interact with a HackRF device.
///
/// ## Possible Error Values
///
///     HACKRF_ERROR_INVALID_PARAM = -2
///     HACKRF_ERROR_NOT_FOUND = -5
///     HACKRF_ERROR_BUSY = -6
///     HACKRF_ERROR_NO_MEM = -11
///     HACKRF_ERROR_LIBUSB = -1000
///     HACKRF_ERROR_THREAD = -1001
///     HACKRF_ERROR_STREAMING_THREAD_ERR = -1002
///     HACKRF_ERROR_STREAMING_STOPPED = -1003
///     HACKRF_ERROR_STREAMING_EXIT_CALLED = -1004
///     HACKRF_ERROR_OTHER = -9999
///
/// See [libhackrf](https://github.com/mossmann/hackrf/tree/master/host/libhackrf) for more info.
#[derive(Debug)]
pub struct HackRFError {
    /// The description of the code.
    pub desc: String,

    /// The code returned by `libhackrf`.
    pub code: i32,
}

impl fmt::Display for HackRFError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error({}): {}", self.code, self.desc)
    }
}

impl error::Error for HackRFError {
    fn description(&self) -> &str {
        &self.desc
    }
}

/// A specialized Result type for HackRF operations
pub type HackRFResult<T> = Result<T, HackRFError>;

/// An internal function for obtaining the description from a HackRF error code.
fn parse_error(error_code: ffi::hackrf_error) -> HackRFError {
    unsafe {
        let desc = CStr::from_ptr(ffi::hackrf_error_name(error_code)).to_string_lossy();
        HackRFError {
            desc: desc.to_string(),
            code: error_code as i32,
        }
    }
}

/// Adjust a gain value to the nearest valid step
fn adjust_gain(gain: u32, min: u32, max: u32, step: u32) -> u32 {
    if gain < min { min }
    else if gain > max { max }
    else { (gain as f32 / step as f32).round() as u32 * step }
}

/// The HackRF context.
///
/// This struct is used ensure that `libhackrf` is initialized before it can be used. A context can
/// be obtained by calling hackrf::init().
///
/// ## Example
/// ```
/// let context = try!(hackrf::init());
/// // Use context
/// ```
pub struct HackRFContext(Rc<HackRFContextInner>);

/// Value for keeping track of any object that contains a reference to the context.
///
/// When this value is dropped, `libhackrf` will be closed.
struct HackRFContextInner;

impl Drop for HackRFContextInner {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_exit();
        }
    }
}

/// Initialize `libhackrf`, returning a context that can be used to connect to HackRF devices.
/// Once all references to the returned context go out of scope, the library will be closed
/// automatically.
pub fn init() -> HackRFResult<HackRFContext> {
    unsafe {
        hackrf_try!(ffi::hackrf_init());
    }
    Ok(HackRFContext(Rc::new(HackRFContextInner)))
}

/// A structure for managaing a HackRF device.
///
/// This structure contains methods for configuring the various settings of the HackRF. It also
/// provides a method for managing received samples as a blocking stream. Currently transmitting
/// samples and non-blocking streams are not supported.
///
/// ## Implementation notes
///
/// This library is a lightweight wrapper around the basic HackRF FFI interface. In addition to
/// the basic functionality it provides a blocking stream interface for receiving samples (See:
/// [`RxStream`](./struct.RxStream.html)).
///
/// Rust's type system is used to ensure that resources are not destroy or modified while the HackRF
/// is receiving samples (although it is possible there are problems with the implementation.). To
/// stop receiving samples it is sufficient to let the stream drop out of scope. For example:
///
/// ```
/// let context = try!(hackrf::init());
/// let mut device = try!(HackRF::open(&context));
///
/// // Configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
///
/// // Re-configure HackRF
///
/// {
///     let mut rx_stream = try!(device.rx_stream());
///     // Get samples from rx stream
/// }
/// ```
pub struct HackRF {
    inner: *mut ffi::hackrf_device,
    _context: Rc<HackRFContextInner>,
}

impl Drop for HackRF {
    fn drop(&mut self) {
        unsafe {
            ffi::hackrf_close(self.inner);
        }
    }
}

impl HackRF {
    /// Attempt to open a connected HackRF device.
    pub fn open(context: &HackRFContext) -> HackRFResult<HackRF> {
        unsafe {
            let mut device = std::mem::zeroed();
            hackrf_try!(ffi::hackrf_open(&mut device));
            Ok(HackRF { inner: device, _context: context.0.clone() })
        }
    }

    /// Sets the center frequency (in Hz) of the HackRF: 5-6800 MHz.
    pub fn set_freq(&mut self, freq: u64) -> HackRFResult<()> {
        // TODO: Consider checking that the frequency is in a valid range.
        unsafe {
            hackrf_try!(ffi::hackrf_set_freq(self.inner, freq));
        }
        Ok(())
    }

    /// Sets amp gain to on/off.
    ///
    /// Warning: Enabling this in the presence of high power signals could damage the HackRF.
    pub fn set_amp_enable(&mut self, amp_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if amp_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_amp_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set antenna enable to on/off.
    pub fn set_antenna_enable(&mut self, antenna_enable: bool) -> HackRFResult<()> {
        unsafe {
            let value = if antenna_enable { 1 } else { 0 };
            hackrf_try!(ffi::hackrf_set_antenna_enable(self.inner, value));
        }
        Ok(())
    }

    /// Set LNA gain: 0-40 dB, 8dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_lna_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_lna_gain(self.inner, adjust_gain(gain, 0, 40, 8)));
        }
        Ok(())
    }

    /// Set VGA (IF) gain: 0-62 dB, with 2dB steps.
    /// If the specified gain falls outside of the valid range, the gain will be clamped.
    pub fn set_vga_gain(&mut self, gain: u32) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_vga_gain(self.inner, adjust_gain(gain, 0, 62, 2)));
        }
        Ok(())
    }

    /// Sets the sample rate in Hz: 2-20 MHz.
    pub fn set_samp_rate(&mut self, samp_rate: f64) -> HackRFResult<()> {
        unsafe {
            hackrf_try!(ffi::hackrf_set_sample_rate(self.inner, samp_rate));

            // Automatically compute a good baseband filter bandwidth
            let bandwidth = ffi::hackrf_compute_baseband_filter_bw_round_down_lt(samp_rate as u32);
            try!(self.set_baseband_filter_bw(bandwidth));
        }
        Ok(())
    }

    /// Sets the baseband filter bandwidth.
    ///
    /// Note: This must be performed *after* setting the sample rate.
    pub fn set_baseband_filter_bw(&mut self, filter_bw: u32) -> HackRFResult<()> {
        unsafe {
            let adjusted_filter_bw = ffi::hackrf_compute_baseband_filter_bw(filter_bw);
            hackrf_try!(ffi::hackrf_set_baseband_filter_bandwidth(self.inner, adjusted_filter_bw));
        }
        Ok(())
    }

    /// Start an RX stream.
    pub fn rx_stream(&mut self, bound: usize) -> HackRFResult<RxStream> {
        let mut rx_stream = RxStream::new(bound, self);
        let sender = (&mut *rx_stream.sender) as *mut SyncSender<Vec<u8>>;
        unsafe {
            match ffi::hackrf_start_rx(self.inner, rx_callback, sender as *mut c_void) {
                HACKRF_SUCCESS => Ok(rx_stream),
                error => Err(parse_error(error)),
            }
        }
    }
}

static OVERFLOW_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

/// A structure that manages receiving I/Q samples from the HackRF.
pub struct RxStream<'a> {
    hackrf_device: &'a HackRF,
    lookup_table: [f32; 256],
    local_index: usize,
    local_buffer: Vec<u8>,
    sender: Box<SyncSender<Vec<u8>>>,
    receiver: Receiver<Vec<u8>>,
}

impl<'a> RxStream<'a> {
    /// Create a new instance of a RxStream
    fn new(bound: usize, hackrf_device: &'a HackRF) -> RxStream<'a> {
        fn gen_lookup_table() -> [f32; 256] {
            let mut data = [0.0; 256];
            for i in 0..256 {
                data[i] = (i as i8) as f32 / 128.0;
            }
            data
        }

        // Reset the overflow counter
        OVERFLOW_COUNT.store(0, Ordering::Relaxed);

        let (sender, receiver) = sync_channel(bound);
        RxStream {
            hackrf_device: hackrf_device,
            lookup_table: gen_lookup_table(),
            local_index: 0,
            local_buffer: vec![],
            sender: Box::new(sender),
            receiver: receiver,
        }
    }

    // Returns a reference to the internal receiver
    pub fn receiver(&mut self) -> &mut Receiver<Vec<u8>> {
        &mut self.receiver
    }

    /// Return the next I/Q sample converted to floating point numbers. If there is no data
    /// avaliable, then this function is blocking.
    pub fn next_sample(&mut self) -> Option<(f32, f32)> {
        let sample = self.next_sample_raw();
        sample.map(|(i, q)| (self.lookup_table[i as usize], self.lookup_table[q as usize]))
    }

    /// Return the next raw I/Q sample from the HackRF. If there is no data avaliable, then this
    /// function is blocking.
    pub fn next_sample_raw(&mut self) -> Option<(u8, u8)> {
        if self.local_buffer.len() < self.local_index + 1 {
            self.local_buffer = match self.receiver.recv() {
                Ok(buffer) => buffer,
                Err(_) => return None,
            };
            self.local_index = 0;
        }

        let i = self.local_index;
        self.local_index += 2;
        Some((self.local_buffer[i], self.local_buffer[i + 1]))
    }

    /// Return how many times the stream dropped data frames
    pub fn overflow_count(&self) -> usize {
        OVERFLOW_COUNT.load(Ordering::Relaxed)
    }
}

impl<'a> Drop for RxStream<'a> {
    fn drop(&mut self) {
        unsafe {
            // TODO: investigate if this can ever fail under reasonable conditions
            ffi::hackrf_stop_rx(self.hackrf_device.inner);
        }
    }
}

/// The call back that is used in the stream abstraction
unsafe extern "C" fn rx_callback(transfer: *mut ffi::hackrf_transfer) -> c_int {
    let src_buffer = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

    // If the input buffer is too long, then an error has occured somewhere
    if src_buffer.len() > BUFFER_SIZE {
        return -1;
    }

    // Copy the transferred data into an owned structure
    let data = src_buffer.into();

    let sender_raw: *mut SyncSender<Vec<u8>> = mem::transmute((*transfer).rx_ctx);
    let sender = &mut *sender_raw;

    if let Err(e) = sender.try_send(data) {
        match e {
            // If the buffer is full drop the message and increment the overflow count
            TrySendError::Full(_) => { OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed); },

            // Report an error back to libhackrf
            TrySendError::Disconnected(_) => return -1,
        }
    }

    // Succesfully sent the data
    0
}

#[cfg(test)]
mod test {
    #[test]
    fn init_test() {
        super::init();
    }
}
<|endoftext|>


<commit_before>//! Functions for mapping over pixels, colors or subpixels of images.

use image::{
    GenericImage,
    ImageBuffer,
    Luma,
    Pixel,
    Primitive,
    Rgb,
    Rgba
};

use definitions::Image;

/// The type obtained by replacing the channel type of a given `Pixel` type.
pub trait WithChannel<C: Primitive>: Pixel {
    /// The new pixel type.
    type Pixel: Pixel<Subpixel=C> + 'static;
}

/// Alias to make uses of `WithChannel` less syntactically noisy.
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Applies `f` to each subpixel of the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::map::map_subpixels;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let scaled = gray_image_i16!(
///     -2i16, -4i16;
///     -6i16, -8i16);
///
/// assert_pixels_eq!(
///     map_subpixels(&image, |x| -2 * (x as i16)),
///     scaled);
/// # }
/// ```
pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
    where I: GenericImage<Pixel=P>,
          P: WithChannel<S> + 'static,
          S: Primitive + 'static,
          F: Fn(P::Subpixel) -> S
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            let mut out_channels = out.get_pixel_mut(x, y).channels_mut();
            for c in 0..P::channel_count() {
                out_channels[c as usize]
                    = f(unsafe {*image.unsafe_get_pixel(x, y)
                        .channels().get_unchecked(c as usize) });
            }
        }
    }

    out
}

/// Applies `f` to the color of each pixel in the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::map::map_colors;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let rgb = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// assert_pixels_eq!(
///     map_colors(&image, |p| { Rgb([p[0], (2 * p[0]), (3 * p[0])]) }),
///     rgb);
/// # }
/// ```
pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(pix));
            }
        }
    }

    out
}

/// Applies `f` to the colors of the pixels in the input images.
///
/// Requires `image1` and `image2` to have the same dimensions.
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::map_colors2;
///
/// let image1 = gray_image!(
///     1, 2,
///     3, 4
/// );
///
/// let image2 = gray_image!(
///     10, 20,
///     30, 40
/// );
///
/// let sum = gray_image!(
///     11, 22,
///     33, 44
/// );
///
/// assert_pixels_eq!(
///     map_colors2(&image1, &image2, |p, q| Luma([p[0] + q[0]])),
///     sum
/// );
/// # }
/// ```
pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
    where I: GenericImage<Pixel=P>,
          J: GenericImage<Pixel=Q>,
          P: Pixel,
          Q: Pixel,
          R: Pixel + 'static,
          F: Fn(P, Q) -> R
{
    assert_eq!(image1.dimensions(), image2.dimensions());

    let (width, height) = image1.dimensions();
    let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let p = image1.unsafe_get_pixel(x, y);
                let q = image2.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(p, q));
            }
        }
    }

    out
}

/// Applies `f` to each pixel in the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::map::map_pixels;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let rgb = rgb_image!(
///     [1, 0, 0], [2, 1, 0];
///     [3, 0, 1], [4, 1, 1]);
///
/// assert_pixels_eq!(
///     map_pixels(&image, |x, y, p| {
///         Rgb([p[0], x as u8, y as u8])
///     }),
///     rgb);
/// # }
/// ```
pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(u32, u32, P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(x, y, pix));
            }
        }
    }

    out
}

/// Creates a grayscale image by extracting the red channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::red_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     1, 2;
///     3, 4);
///
/// let actual = red_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn red_channel<I, C>(image: &I) -> Image<Luma<C>>
    where I: GenericImage<Pixel=Rgb<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| Luma([p[0]]))
}

/// Creates an RGB image by embedding a grayscale image in its red channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_red_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [1, 0, 0], [2, 0, 0];
///     [3, 0, 0], [4, 0, 0]);
///
/// let actual = as_red_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_red_channel<I, C>(image: &I) -> Image<Rgb<C>>
    where I: GenericImage<Pixel=Luma<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[0] = p[0];
        Rgb(cs)
    })
}

/// Creates a grayscale image by extracting the green channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::green_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     2, 4;
///     6, 8);
///
/// let actual = green_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn green_channel<I, C>(image: &I) -> Image<Luma<C>>
    where I: GenericImage<Pixel=Rgb<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| Luma([p[1]]))
}

/// Creates an RGB image by embedding a grayscale image in its green channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_green_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [0, 1, 0], [0, 2, 0];
///     [0, 3, 0], [0, 4, 0]);
///
/// let actual = as_green_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_green_channel<I, C>(image: &I) -> Image<Rgb<C>>
    where I: GenericImage<Pixel=Luma<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[1] = p[0];
        Rgb(cs)
    })
}

/// Creates a grayscale image by extracting the blue channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::blue_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     3, 6;
///     9, 12);
///
/// let actual = blue_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn blue_channel<I, C>(image: &I) -> Image<Luma<C>>
    where I: GenericImage<Pixel=Rgb<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| Luma([p[2]]))
}

/// Creates an RGB image by embedding a grayscale image in its blue channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_blue_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [0, 0, 1], [0, 0, 2];
///     [0, 0, 3], [0, 0, 4]);
///
/// let actual = as_blue_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_blue_channel<I, C>(image: &I) -> Image<Rgb<C>>
    where I: GenericImage<Pixel=Luma<C>>,
          C: Primitive + 'static
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[2] = p[0];
        Rgb(cs)
    })
}

<commit_msg>Run rustfmt on map.rs<commit_after>//! Functions for mapping over pixels, colors or subpixels of images.

use image::{GenericImage, ImageBuffer, Luma, Pixel, Primitive, Rgb, Rgba};

use definitions::Image;

/// The type obtained by replacing the channel type of a given `Pixel` type.
pub trait WithChannel<C: Primitive>: Pixel {
    /// The new pixel type.
    type Pixel: Pixel<Subpixel = C> + 'static;
}

/// Alias to make uses of `WithChannel` less syntactically noisy.
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
where
    T: Primitive + 'static,
    U: Primitive + 'static,
{
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
where
    T: Primitive + 'static,
    U: Primitive + 'static,
{
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
where
    T: Primitive + 'static,
    U: Primitive + 'static,
{
    type Pixel = Luma<U>;
}

/// Applies `f` to each subpixel of the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::map::map_subpixels;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let scaled = gray_image_i16!(
///     -2i16, -4i16;
///     -6i16, -8i16);
///
/// assert_pixels_eq!(
///     map_subpixels(&image, |x| -2 * (x as i16)),
///     scaled);
/// # }
/// ```
pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
where
    I: GenericImage<Pixel = P>,
    P: WithChannel<S> + 'static,
    S: Primitive + 'static,
    F: Fn(P::Subpixel) -> S,
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            let mut out_channels = out.get_pixel_mut(x, y).channels_mut();
            for c in 0..P::channel_count() {
                out_channels[c as usize] = f(unsafe {
                    *image.unsafe_get_pixel(x, y).channels().get_unchecked(
                        c as usize,
                    )
                });
            }
        }
    }

    out
}

/// Applies `f` to the color of each pixel in the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::map::map_colors;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let rgb = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// assert_pixels_eq!(
///     map_colors(&image, |p| { Rgb([p[0], (2 * p[0]), (3 * p[0])]) }),
///     rgb);
/// # }
/// ```
pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
where
    I: GenericImage<Pixel = P>,
    P: Pixel,
    Q: Pixel + 'static,
    F: Fn(P) -> Q,
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(pix));
            }
        }
    }

    out
}

/// Applies `f` to the colors of the pixels in the input images.
///
/// Requires `image1` and `image2` to have the same dimensions.
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::map_colors2;
///
/// let image1 = gray_image!(
///     1, 2,
///     3, 4
/// );
///
/// let image2 = gray_image!(
///     10, 20,
///     30, 40
/// );
///
/// let sum = gray_image!(
///     11, 22,
///     33, 44
/// );
///
/// assert_pixels_eq!(
///     map_colors2(&image1, &image2, |p, q| Luma([p[0] + q[0]])),
///     sum
/// );
/// # }
/// ```
pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
where
    I: GenericImage<Pixel = P>,
    J: GenericImage<Pixel = Q>,
    P: Pixel,
    Q: Pixel,
    R: Pixel + 'static,
    F: Fn(P, Q) -> R,
{
    assert_eq!(image1.dimensions(), image2.dimensions());

    let (width, height) = image1.dimensions();
    let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let p = image1.unsafe_get_pixel(x, y);
                let q = image2.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(p, q));
            }
        }
    }

    out
}

/// Applies `f` to each pixel in the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::map::map_pixels;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let rgb = rgb_image!(
///     [1, 0, 0], [2, 1, 0];
///     [3, 0, 1], [4, 1, 1]);
///
/// assert_pixels_eq!(
///     map_pixels(&image, |x, y, p| {
///         Rgb([p[0], x as u8, y as u8])
///     }),
///     rgb);
/// # }
/// ```
pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
where
    I: GenericImage<Pixel = P>,
    P: Pixel,
    Q: Pixel + 'static,
    F: Fn(u32, u32, P) -> Q,
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(x, y, pix));
            }
        }
    }

    out
}

/// Creates a grayscale image by extracting the red channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::red_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     1, 2;
///     3, 4);
///
/// let actual = red_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn red_channel<I, C>(image: &I) -> Image<Luma<C>>
where
    I: GenericImage<Pixel = Rgb<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| Luma([p[0]]))
}

/// Creates an RGB image by embedding a grayscale image in its red channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_red_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [1, 0, 0], [2, 0, 0];
///     [3, 0, 0], [4, 0, 0]);
///
/// let actual = as_red_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_red_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
    I: GenericImage<Pixel = Luma<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[0] = p[0];
        Rgb(cs)
    })
}

/// Creates a grayscale image by extracting the green channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::green_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     2, 4;
///     6, 8);
///
/// let actual = green_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn green_channel<I, C>(image: &I) -> Image<Luma<C>>
where
    I: GenericImage<Pixel = Rgb<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| Luma([p[1]]))
}

/// Creates an RGB image by embedding a grayscale image in its green channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_green_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [0, 1, 0], [0, 2, 0];
///     [0, 3, 0], [0, 4, 0]);
///
/// let actual = as_green_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_green_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
    I: GenericImage<Pixel = Luma<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[1] = p[0];
        Rgb(cs)
    })
}

/// Creates a grayscale image by extracting the blue channel of an RGB image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::blue_channel;
///
/// let image = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// let expected = gray_image!(
///     3, 6;
///     9, 12);
///
/// let actual = blue_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn blue_channel<I, C>(image: &I) -> Image<Luma<C>>
where
    I: GenericImage<Pixel = Rgb<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| Luma([p[2]]))
}

/// Creates an RGB image by embedding a grayscale image in its blue channel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::as_blue_channel;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let expected = rgb_image!(
///     [0, 0, 1], [0, 0, 2];
///     [0, 0, 3], [0, 0, 4]);
///
/// let actual = as_blue_channel(&image);
/// assert_pixels_eq!(actual, expected);
/// # }
/// ```
pub fn as_blue_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
    I: GenericImage<Pixel = Luma<C>>,
    C: Primitive + 'static,
{
    map_colors(image, |p| {
        let mut cs = [C::zero(); 3];
        cs[2] = p[0];
        Rgb(cs)
    })
}
<|endoftext|>


<commit_before>use crate::{Position, SquareMatrix};

#[derive(Debug)]
pub struct MarkMatrix {
    marks: SquareMatrix<Mark>,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
enum Mark {
    None,
    Star,
    Prime,
}

impl MarkMatrix {
    pub fn new(n: usize) -> Self {
        Self {
            marks: SquareMatrix::from_shape_fn((n, n), |_| Mark::None),
        }
    }

    #[inline]
    pub fn n(&self) -> usize {
        self.marks.shape()[0]
    }

    #[inline]
    fn get_mark(&self, pos: Position) -> Mark {
        self.marks[(pos.row, pos.column)]
    }

    #[inline]
    fn set_mark(&mut self, pos: Position, mark: Mark) {
        self.marks[(pos.row, pos.column)] = mark;
    }

    pub fn toggle_star(&mut self, pos: Position) {
        if self.is_star(pos) {
            self.unmark(pos);
        } else {
            self.star(pos);
        }
    }

    pub fn unmark(&mut self, pos: Position) {
        self.set_mark(pos, Mark::None);
    }

    pub fn star(&mut self, pos: Position) {
        self.set_mark(pos, Mark::Star);
    }

    pub fn prime(&mut self, pos: Position) {
        self.set_mark(pos, Mark::Prime);
    }

    pub fn is_star(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::Star => true,
            _ => false,
        }
    }

    pub fn is_prime(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::Prime => true,
            _ => false,
        }
    }

    #[cfg(test)]
    pub fn is_none(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::None => true,
            _ => false,
        }
    }

    pub fn each_star<F>(&self, mut f: F)
    where
        F: FnMut(Position),
    {
        let n = self.n();

        for row in 0..n {
            for column in 0..n {
                let pos = Position { row, column };
                if self.is_star(pos) {
                    f(pos);
                }
            }
        }
    }

    pub fn find_first_star_in_row(&self, row: usize) -> Option<usize> {
        for column in 0..self.n() {
            if self.is_star(Position { row, column }) {
                return Some(column);
            }
        }
        return None;
    }

    pub fn find_first_prime_in_row(&self, row: usize) -> Option<usize> {
        for column in 0..self.n() {
            if self.is_prime(Position { row, column }) {
                return Some(column);
            }
        }
        return None;
    }

    pub fn find_first_star_in_column(&self, column: usize) -> Option<usize> {
        for row in 0..self.n() {
            if self.is_star(Position { row, column }) {
                return Some(row);
            }
        }
        return None;
    }

    pub fn clear_primes(&mut self) {
        for row in 0..self.n() {
            for column in 0..self.n() {
                let pos = Position { row, column };
                if self.is_prime(pos) {
                    self.unmark(pos);
                }
            }
        }
    }
}
<commit_msg>MarkMatrix - Refactor<commit_after>use crate::{Position, SquareMatrix};

#[derive(Debug)]
pub struct MarkMatrix {
    marks: SquareMatrix<Mark>,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
enum Mark {
    None,
    Star,
    Prime,
}

impl MarkMatrix {
    pub fn new(n: usize) -> Self {
        Self {
            marks: SquareMatrix::from_shape_fn((n, n), |_| Mark::None),
        }
    }

    #[inline]
    pub fn n(&self) -> usize {
        self.marks.shape()[0]
    }

    #[inline]
    fn get_mark(&self, pos: Position) -> Mark {
        self.marks[(pos.row, pos.column)]
    }

    #[inline]
    fn set_mark(&mut self, pos: Position, mark: Mark) {
        self.marks[(pos.row, pos.column)] = mark;
    }

    pub fn toggle_star(&mut self, pos: Position) {
        let cell = self.marks.get_mut((pos.row, pos.column)).unwrap();
        if *cell == Mark::Star {
            *cell = Mark::None;
        } else {
            *cell = Mark::Star;
        }
    }

    pub fn star(&mut self, pos: Position) {
        self.set_mark(pos, Mark::Star);
    }

    pub fn prime(&mut self, pos: Position) {
        self.set_mark(pos, Mark::Prime);
    }

    pub fn is_star(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::Star => true,
            _ => false,
        }
    }

    pub fn is_prime(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::Prime => true,
            _ => false,
        }
    }

    #[cfg(test)]
    pub fn is_none(&self, pos: Position) -> bool {
        match self.get_mark(pos) {
            Mark::None => true,
            _ => false,
        }
    }

    #[inline]
    pub fn each_star<F>(&self, mut f: F)
    where
        F: FnMut(Position),
    {
        for (row, row_data) in self.marks.genrows().into_iter().enumerate() {
            for (column, &cell) in row_data.iter().enumerate() {
                if cell == Mark::Star {
                    f(Position { row, column });
                }
            }
        }
    }

    fn find_first_mark_in_row(&self, row: usize, mark: Mark) -> Option<usize> {
        self.marks
            .row(row)
            .iter()
            .enumerate()
            .find(|(_, &cell)| cell == mark)
            .map(|(column, _)| column)
    }

    fn find_first_mark_in_column(&self, column: usize, mark: Mark) -> Option<usize> {
        self.marks
            .column(column)
            .iter()
            .enumerate()
            .find(|(_, &cell)| cell == mark)
            .map(|(row, _)| row)
    }

    pub fn find_first_star_in_row(&self, row: usize) -> Option<usize> {
        self.find_first_mark_in_row(row, Mark::Star)
    }

    pub fn find_first_prime_in_row(&self, row: usize) -> Option<usize> {
        self.find_first_mark_in_row(row, Mark::Prime)
    }

    pub fn find_first_star_in_column(&self, column: usize) -> Option<usize> {
        self.find_first_mark_in_column(column, Mark::Star)
    }

    pub fn clear_primes(&mut self) {
        for cell in self.marks.iter_mut() {
            if *cell == Mark::Prime {
                *cell = Mark::None
            }
        }
    }
}
<|endoftext|>