<commit_before>extern crate canteen;
extern crate rustc_serialize;
extern crate postgres;
extern crate chrono;

use canteen::Canteen;
use canteen::route::*;
use canteen::request::*;
use canteen::response::*;

use rustc_serialize::json;
use rustc_serialize::{Encoder, Encodable};
use rustc_serialize::{Decoder, Decodable};
use postgres::{Connection, SslMode};

type Date = chrono::NaiveDate;

/* a full person record */
#[derive(Debug)]
struct Person {
    id:         i32,
    first_name: String,
    last_name:  String,
    dob:        Date,
}

impl Encodable for Person {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("Person", 4, |s| {
            try!(s.emit_struct_field("id", 0, |s| { s.emit_i32(self.id) }));
            try!(s.emit_struct_field("first_name", 1, |s| { s.emit_str(&self.first_name) }));
            try!(s.emit_struct_field("last_name", 2, |s| { s.emit_str(&self.last_name) }));
            try!(s.emit_struct_field("dob", 3, |s| { s.emit_str(&self.dob.format("%Y-%m-%d").to_string()) }));

            Ok(())
        })
    }
}

/* a person record without id, for HTTP POST */
#[derive(Debug)]
struct _PersonCreate {
    first_name: String,
    last_name:  String,
    dob:        Date,
}

impl Decodable for _PersonCreate {
    fn decode<D: Decoder>(d: &mut D) -> Result<_PersonCreate, D::Error> {
        d.read_struct("root", 3, |d| {
            let first_name = try!(d.read_struct_field("first_name", 0, |d| { d.read_str() }));
            let last_name = try!(d.read_struct_field("last_name", 0, |d| { d.read_str() }));
            let pre_dob = try!(d.read_struct_field("dob", 0, |d| { d.read_str() }));

            match Date::parse_from_str(&pre_dob, "%Y-%m-%d") {
                Ok(dob) => {
                    Ok(_PersonCreate {
                        first_name: first_name,
                        last_name:  last_name,
                        dob:        dob,
                    })
                },
                Err(_)  => {
                    Err(d.error("failed to parse date provided"))
                },
            }
        })

    }
}

fn create_person(req: &Request) -> Response {
    let mut res = Response::new();
    let pers: _PersonCreate = json::decode(&String::from_utf8(req.payload.clone()).unwrap()).unwrap();

    let conn = Connection::connect("postgresql://jeff@localhost/jeff", SslMode::None).unwrap();
    let cur = conn.query("insert into person (first_name, last_name, dob)\
                          values ($1, $2, $3) returning id",
                          &[&pers.first_name, &pers.last_name, &pers.dob]);

    let person_id: i32;

    match cur {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    person_id = rows.get(0).get("id");
                },
                _ => {
                    res.set_code(500);
                    res.append(String::from("{ message: 'person couldn\'t be created' }"));
                    return res;
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
            return res;
        }
    }

    match conn.query("select id, first_name, last_name, dob from person where id = $1", &[&person_id]) {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    let row = rows.get(0);
                    let p = Person {
                        id:         row.get("id"),
                        first_name: row.get("first_name"),
                        last_name:  row.get("last_name"),
                        dob:        row.get("dob"),
                    };

                    res.append(json::encode(&p).unwrap());
                },
                _ => {
                    res.set_code(404);
                    res.append(String::from("{ message: 'not found' }"));
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
        }
    }

    res
}

fn get_person(req: &Request) -> Response {
    let mut res = Response::new();
    let person_id: i32 = req.get("person_id");

    let conn = Connection::connect("postgresql://jeff@localhost/jeff", SslMode::None).unwrap();
    let cur = conn.query("select id, first_name, last_name, dob from person where id = $1", &[&person_id]);

    res.set_content_type("application/json");

    match cur {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    let row = rows.get(0);
                    let p = Person {
                        id:         row.get("id"),
                        first_name: row.get("first_name"),
                        last_name:  row.get("last_name"),
                        dob:        row.get("dob"),
                    };

                    res.append(json::encode(&p).unwrap());
                },
                _ => {
                    res.set_code(404);
                    res.append(String::from("{ message: 'not found' }"));
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
        }
    }

    res
}

fn main() {
    let mut cnt = Canteen::new(("127.0.0.1", 8080));

    cnt.add_route("/person", vec![Method::Post], create_person);
    cnt.add_route("/person/<int:person_id>", vec![Method::Get], get_person);
    cnt.add_route("/src/<path:path>", vec![Method::Get], Route::static_file);
    cnt.set_default(Route::err_404);

    cnt.run();
}

<commit_msg>add a route that returns many results<commit_after>extern crate canteen;
extern crate rustc_serialize;
extern crate postgres;
extern crate chrono;

use canteen::Canteen;
use canteen::route::*;
use canteen::request::*;
use canteen::response::*;

use rustc_serialize::json;
use rustc_serialize::{Encoder, Encodable};
use rustc_serialize::{Decoder, Decodable};
use postgres::{Connection, SslMode};

type Date = chrono::NaiveDate;

/* a full person record */
#[derive(Debug)]
struct Person {
    id:         i32,
    first_name: String,
    last_name:  String,
    dob:        Date,
}

impl Encodable for Person {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("Person", 4, |s| {
            try!(s.emit_struct_field("id", 0, |s| { s.emit_i32(self.id) }));
            try!(s.emit_struct_field("first_name", 1, |s| { s.emit_str(&self.first_name) }));
            try!(s.emit_struct_field("last_name", 2, |s| { s.emit_str(&self.last_name) }));
            try!(s.emit_struct_field("dob", 3, |s| { s.emit_str(&self.dob.format("%Y-%m-%d").to_string()) }));

            Ok(())
        })
    }
}

/* a person record without id, for HTTP POST */
#[derive(Debug)]
struct _PersonCreate {
    first_name: String,
    last_name:  String,
    dob:        Date,
}

impl Decodable for _PersonCreate {
    fn decode<D: Decoder>(d: &mut D) -> Result<_PersonCreate, D::Error> {
        d.read_struct("root", 3, |d| {
            let first_name = try!(d.read_struct_field("first_name", 0, |d| { d.read_str() }));
            let last_name = try!(d.read_struct_field("last_name", 0, |d| { d.read_str() }));
            let pre_dob = try!(d.read_struct_field("dob", 0, |d| { d.read_str() }));

            match Date::parse_from_str(&pre_dob, "%Y-%m-%d") {
                Ok(dob) => {
                    Ok(_PersonCreate {
                        first_name: first_name,
                        last_name:  last_name,
                        dob:        dob,
                    })
                },
                Err(_)  => {
                    Err(d.error("failed to parse date provided"))
                },
            }
        })

    }
}

fn create_person(req: &Request) -> Response {
    let mut res = Response::new();
    res.set_content_type("application/json");

    let pers: _PersonCreate = json::decode(&String::from_utf8(req.payload.clone()).unwrap()).unwrap();

    let conn = Connection::connect("postgresql://jeff@localhost/jeff", SslMode::None).unwrap();
    let cur = conn.query("insert into person (first_name, last_name, dob)\
                          values ($1, $2, $3) returning id",
                          &[&pers.first_name, &pers.last_name, &pers.dob]);

    let person_id: i32;

    match cur {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    person_id = rows.get(0).get("id");
                },
                _ => {
                    res.set_code(500);
                    res.append(String::from("{ message: 'person couldn\'t be created' }"));
                    return res;
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
            return res;
        }
    }

    match conn.query("select id, first_name, last_name, dob from person where id = $1", &[&person_id]) {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    let row = rows.get(0);
                    let p = Person {
                        id:         row.get("id"),
                        first_name: row.get("first_name"),
                        last_name:  row.get("last_name"),
                        dob:        row.get("dob"),
                    };

                    res.append(json::encode(&p).unwrap());
                },
                _ => {
                    res.set_code(404);
                    res.append(String::from("{ message: 'not found' }"));
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
        }
    }

    res
}

fn get_many_person(req: &Request) -> Response {
    let mut res = Response::new();
    res.set_content_type("application/json");

    let conn = Connection::connect("postgresql://jeff@localhost/jeff", SslMode::None).unwrap();
    let cur = conn.query("select id, first_name, last_name, dob from person order by id", &[]);

    match cur {
        Ok(rows)    => {
            let mut people: Vec<Person> = Vec::new();

            for row in rows.iter() {
                people.push(Person {
                    id:         row.get("id"),
                    first_name: row.get("first_name"),
                    last_name:  row.get("last_name"),
                    dob:        row.get("dob"),
                });
            }

            res.append(json::encode(&people).unwrap());
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
        }
    }

    res
}

fn get_single_person(req: &Request) -> Response {
    let mut res = Response::new();
    res.set_content_type("application/json");

    let person_id: i32 = req.get("person_id");

    let conn = Connection::connect("postgresql://jeff@localhost/jeff", SslMode::None).unwrap();
    let cur = conn.query("select id, first_name, last_name, dob from person where id = $1", &[&person_id]);

    match cur {
        Ok(rows)    => {
            match rows.len() {
                1 => {
                    let row = rows.get(0);
                    let p = Person {
                        id:         row.get("id"),
                        first_name: row.get("first_name"),
                        last_name:  row.get("last_name"),
                        dob:        row.get("dob"),
                    };

                    res.append(json::encode(&p).unwrap());
                },
                _ => {
                    res.set_code(404);
                    res.append(String::from("{ message: 'not found' }"));
                },
            }
        },
        Err(e)      => {
            res.set_code(500);
            res.append(format!("{{ message: '{:?}' }}", e));
        }
    }

    res
}

fn main() {
    let mut cnt = Canteen::new(("127.0.0.1", 8080));

    cnt.add_route("/person", vec![Method::Post], create_person);
    cnt.add_route("/person", vec![Method::Get], get_many_person);
    cnt.add_route("/person/<int:person_id>", vec![Method::Get], get_single_person);
    cnt.add_route("/src/<path:path>", vec![Method::Get], Route::static_file);
    cnt.set_default(Route::err_404);

    cnt.run();
}

<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::mem;
use std::cmp;
use js_types::js_type::JsT;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

struct ChunkList<T> {
    curr: Vec<T>,
    rest: Vec<Vec<T>>,
}

impl<T> ChunkList<T> {
    fn grow(&mut self) {
        let new_cap = self.curr.capacity()
                               .checked_mul(2)
                               .expect("ChunkList: In method `grow`, `checked_mul` returned None. Aborting!");
        let chunk = mem::replace(&mut self.curr, Vec::with_capacity(new_cap));
        self.rest.push(chunk);
    }
}

struct GranularArena<T> {
    chunks: RefCell<ChunkList<T>>,
}

impl<T> GranularArena<T> {
    fn new() -> GranularArena<T> {
        let sz = cmp::max(1, mem::size_of::<T>());
        GranularArena::with_capacity(INITIAL_SIZE / sz)
    }

    fn with_capacity(cap: usize) -> GranularArena<T> {
        let cap = cmp::max(MIN_CAP, cap);
        GranularArena {
            chunks: RefCell::new(ChunkList {
                curr: Vec::with_capacity(cap),
                rest: Vec::new(),
            }),
        }
    }

    fn alloc(&self, val: T) -> &mut T {
        let mut chunks = self.chunks.borrow_mut();
        let next_item_idx = chunks.curr.len();
        chunks.curr.push(val);

        let new_item_ref = {
            let new_item_ref = &mut chunks.curr[next_item_idx];

            // According to what I've read online, this extends the lifetime of
            // the returned ref from that of `chunks` as borrowed on line 47 to
            // that of `self`. This is allowable because we never grow the inner
            // `Vec`s beyond their initial cap, and the returned reference is
            // unique since it's &mut, which means the arene never gives away
            // refs to existing items.
            unsafe { mem::transmute::<&mut T, &mut T>(new_item_ref) }
        };

        if chunks.curr.len() == chunks.curr.capacity() {
            chunks.grow();
        }

        new_item_ref
    }

    // TODO Figure out what granular deallocation will mean
    // TODO Is there a better way to allocate? Should I group items that are
    // temporally-local together? They sort of will be anyway, but is it worth
    // it to force such a thing?
}

pub struct Compartment {
    source: String,
    arena: GranularArena<JsT>,
}

impl Compartment {
    pub fn new(source: &str) -> Compartment {
        Compartment {
            source: String::from(source),
            arena: GranularArena::new(),
        }
    }

    pub fn alloc_inside(&self, js_t: JsT) -> &mut JsT {
        self.arena.alloc(js_t)
    }
}
<commit_msg>Turn Compartment into Scope and give it a UuidMap as well as a parent and children<commit_after>use std::cell::RefCell;
use std::cmp;
use std::mem;

use alloc::ref_manip::UuidMap;
use js_types::js_type::JsT;
use uuid::Uuid;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

struct ChunkList<T> {
    curr: Vec<RefCell<T>>,
    rest: Vec<Vec<RefCell<T>>>,
}

impl<T> ChunkList<T> {
    fn grow(&mut self) {
        let new_cap = self.curr.capacity()
                               .checked_mul(2)
                               .expect("ChunkList: In method `grow`, `checked_mul` returned None. Aborting!");
        let chunk = mem::replace(&mut self.curr, Vec::with_capacity(new_cap));
        self.rest.push(chunk);
    }
}

struct GranularArena<T> {
    chunks: RefCell<ChunkList<T>>,
}

impl<T> GranularArena<T> {
    fn new() -> GranularArena<T> {
        let sz = cmp::max(1, mem::size_of::<T>());
        GranularArena::with_capacity(INITIAL_SIZE / sz)
    }

    fn with_capacity(cap: usize) -> GranularArena<T> {
        let cap = cmp::max(MIN_CAP, cap);
        GranularArena {
            chunks: RefCell::new(ChunkList {
                curr: Vec::with_capacity(cap),
                rest: Vec::new(),
            }),
        }
    }

    fn alloc(&self, val: T) -> &RefCell<T> {
        let mut chunks = self.chunks.borrow_mut();
        let next_item_idx = chunks.curr.len();
        chunks.curr.push(RefCell::new(val));

        let new_item_ref = {
            let new_item_ref = &chunks.curr[next_item_idx];

            unsafe { mem::transmute::<&RefCell<T>, &RefCell<T>>(new_item_ref) }
        };

        if chunks.curr.len() == chunks.curr.capacity() {
            chunks.grow();
        }

        new_item_ref
    }

    // TODO Figure out what granular deallocation will mean
    // TODO Is there a better way to allocate? Should I group items that are
    // temporally-local together? They sort of will be anyway, but is it worth
    // it to force such a thing?
}

pub struct Scope<'u> {
    source: String,
    parent: Option<Box<Scope<'u>>>,
    children: Vec<Box<Scope<'u>>>,
    arena: GranularArena<JsT>,
    uuid_map: UuidMap<'u>,
}

impl<'u> Scope<'u> {
    pub fn new(source: &str) -> Scope<'u> {
        Scope {
            source: String::from(source),
            parent: None,
            children: Vec::new(),
            arena: GranularArena::new(),
            uuid_map: UuidMap::new(),
        }
    }

    pub fn alloc_inside(&'u mut self, js_t: JsT) {
        let jst_ref = self.arena.alloc(js_t);
        self.uuid_map.insert_ref(jst_ref);
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g.
    /// subtracting elements in an Add impl.
    ///
    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl Add for Foo {
    ///     type Output = Foo;
    ///
    ///     fn add(self, other: Foo) -> Foo {
    ///         Foo(self.0 - other.0)
    ///     }
    /// }
    /// ```
    pub SUSPICIOUS_ARITHMETIC_IMPL,
    correctness,
    "suspicious use of operators in impl of arithmetic trait"
}

declare_clippy_lint! {
    /// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g.
    /// subtracting elements in an AddAssign impl.
    ///
    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl AddAssign for Foo {
    ///     fn add_assign(&mut self, other: Foo) {
    ///         *self = *self - other;
    ///     }
    /// }
    /// ```
    pub SUSPICIOUS_OP_ASSIGN_IMPL,
    correctness,
    "suspicious use of operators in impl of OpAssign trait"
}

declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]);

impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
        if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind {
            match binop.node {
                hir::BinOpKind::Eq
                | hir::BinOpKind::Lt
                | hir::BinOpKind::Le
                | hir::BinOpKind::Ne
                | hir::BinOpKind::Ge
                | hir::BinOpKind::Gt => return,
                _ => {},
            }

            // Check for more than one binary operation in the implemented function
            // Linting when multiple operations are involved can result in false positives
            if_chain! {
                let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
                if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn);
                if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
                let body = cx.tcx.hir().body(body_id);
                let mut visitor = BinaryExprVisitor { nb_binops: 0 };

                then {
                    walk_expr(&mut visitor, &body.value);
                    if visitor.nb_binops > 1 {
                        return;
                    }
                }
            }

            if let Some(impl_trait) = check_binop(
                cx,
                expr,
                binop.node,
                &["Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor", "Shl", "Shr"],
                &[
                    hir::BinOpKind::Add,
                    hir::BinOpKind::Sub,
                    hir::BinOpKind::Mul,
                    hir::BinOpKind::Div,
                    hir::BinOpKind::Rem,
                    hir::BinOpKind::BitAnd,
                    hir::BinOpKind::BitOr,
                    hir::BinOpKind::BitXor,
                    hir::BinOpKind::Shl,
                    hir::BinOpKind::Shr,
                ],
            ) {
                span_lint(
                    cx,
                    SUSPICIOUS_ARITHMETIC_IMPL,
                    binop.span,
                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                );
            }

            if let Some(impl_trait) = check_binop(
                cx,
                expr,
                binop.node,
                &[
                    "AddAssign",
                    "SubAssign",
                    "MulAssign",
                    "DivAssign",
                    "BitAndAssign",
                    "BitOrAssign",
                    "BitXorAssign",
                    "RemAssign",
                    "ShlAssign",
                    "ShrAssign",
                ],
                &[
                    hir::BinOpKind::Add,
                    hir::BinOpKind::Sub,
                    hir::BinOpKind::Mul,
                    hir::BinOpKind::Div,
                    hir::BinOpKind::BitAnd,
                    hir::BinOpKind::BitOr,
                    hir::BinOpKind::BitXor,
                    hir::BinOpKind::Rem,
                    hir::BinOpKind::Shl,
                    hir::BinOpKind::Shr,
                ],
            ) {
                span_lint(
                    cx,
                    SUSPICIOUS_OP_ASSIGN_IMPL,
                    binop.span,
                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                );
            }
        }
    }
}

fn check_binop(
    cx: &LateContext<'_>,
    expr: &hir::Expr<'_>,
    binop: hir::BinOpKind,
    traits: &[&'static str],
    expected_ops: &[hir::BinOpKind],
) -> Option<&'static str> {
    let mut trait_ids = vec![];
    let [krate, module] = crate::utils::paths::OPS_MODULE;

    for &t in traits {
        let path = [krate, module, t];
        if let Some(trait_id) = get_trait_def_id(cx, &path) {
            trait_ids.push(trait_id);
        } else {
            return None;
        }
    }

    // Get the actually implemented trait
    let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);

    if_chain! {
        if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
        if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.res.def_id());
        if binop != expected_ops[idx];
        then{
            return Some(traits[idx])
        }
    }

    None
}

struct BinaryExprVisitor {
    nb_binops: u32,
}

impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
        match expr.kind {
            hir::ExprKind::Binary(..)
            | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
            | hir::ExprKind::AssignOp(..) => self.nb_binops += 1,
            _ => {},
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<commit_msg>formatting<commit_after>use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g.
    /// subtracting elements in an Add impl.
    ///
    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl Add for Foo {
    ///     type Output = Foo;
    ///
    ///     fn add(self, other: Foo) -> Foo {
    ///         Foo(self.0 - other.0)
    ///     }
    /// }
    /// ```
    pub SUSPICIOUS_ARITHMETIC_IMPL,
    correctness,
    "suspicious use of operators in impl of arithmetic trait"
}

declare_clippy_lint! {
    /// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g.
    /// subtracting elements in an AddAssign impl.
    ///
    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// impl AddAssign for Foo {
    ///     fn add_assign(&mut self, other: Foo) {
    ///         *self = *self - other;
    ///     }
    /// }
    /// ```
    pub SUSPICIOUS_OP_ASSIGN_IMPL,
    correctness,
    "suspicious use of operators in impl of OpAssign trait"
}

declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]);

impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
        if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind {
            match binop.node {
                hir::BinOpKind::Eq
                | hir::BinOpKind::Lt
                | hir::BinOpKind::Le
                | hir::BinOpKind::Ne
                | hir::BinOpKind::Ge
                | hir::BinOpKind::Gt => return,
                _ => {},
            }

            // Check for more than one binary operation in the implemented function
            // Linting when multiple operations are involved can result in false positives
            if_chain! {
                let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
                if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn);
                if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
                let body = cx.tcx.hir().body(body_id);
                let mut visitor = BinaryExprVisitor { nb_binops: 0 };

                then {
                    walk_expr(&mut visitor, &body.value);
                    if visitor.nb_binops > 1 {
                        return;
                    }
                }
            }

            if let Some(impl_trait) = check_binop(
                cx,
                expr,
                binop.node,
                &[
                    "Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor", "Shl", "Shr"
                ],
                &[
                    hir::BinOpKind::Add,
                    hir::BinOpKind::Sub,
                    hir::BinOpKind::Mul,
                    hir::BinOpKind::Div,
                    hir::BinOpKind::Rem,
                    hir::BinOpKind::BitAnd,
                    hir::BinOpKind::BitOr,
                    hir::BinOpKind::BitXor,
                    hir::BinOpKind::Shl,
                    hir::BinOpKind::Shr,
                ],
            ) {
                span_lint(
                    cx,
                    SUSPICIOUS_ARITHMETIC_IMPL,
                    binop.span,
                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                );
            }

            if let Some(impl_trait) = check_binop(
                cx,
                expr,
                binop.node,
                &[
                    "AddAssign",
                    "SubAssign",
                    "MulAssign",
                    "DivAssign",
                    "BitAndAssign",
                    "BitOrAssign",
                    "BitXorAssign",
                    "RemAssign",
                    "ShlAssign",
                    "ShrAssign",
                ],
                &[
                    hir::BinOpKind::Add,
                    hir::BinOpKind::Sub,
                    hir::BinOpKind::Mul,
                    hir::BinOpKind::Div,
                    hir::BinOpKind::BitAnd,
                    hir::BinOpKind::BitOr,
                    hir::BinOpKind::BitXor,
                    hir::BinOpKind::Rem,
                    hir::BinOpKind::Shl,
                    hir::BinOpKind::Shr,
                ],
            ) {
                span_lint(
                    cx,
                    SUSPICIOUS_OP_ASSIGN_IMPL,
                    binop.span,
                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
                );
            }
        }
    }
}

fn check_binop(
    cx: &LateContext<'_>,
    expr: &hir::Expr<'_>,
    binop: hir::BinOpKind,
    traits: &[&'static str],
    expected_ops: &[hir::BinOpKind],
) -> Option<&'static str> {
    let mut trait_ids = vec![];
    let [krate, module] = crate::utils::paths::OPS_MODULE;

    for &t in traits {
        let path = [krate, module, t];
        if let Some(trait_id) = get_trait_def_id(cx, &path) {
            trait_ids.push(trait_id);
        } else {
            return None;
        }
    }

    // Get the actually implemented trait
    let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);

    if_chain! {
        if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
        if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.res.def_id());
        if binop != expected_ops[idx];
        then{
            return Some(traits[idx])
        }
    }

    None
}

struct BinaryExprVisitor {
    nb_binops: u32,
}

impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
        match expr.kind {
            hir::ExprKind::Binary(..)
            | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
            | hir::ExprKind::AssignOp(..) => self.nb_binops += 1,
            _ => {},
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Unlicense

mod pager;

/// Mock hardware abstraction layer for unit tests.
#[cfg(test)]
mod hal_test;

/// Publish hardware abstraction layer for unit tests.
#[cfg(test)]
use hal_test as hal;

/// Live hardware abstraction layer for integration tests and releases.
#[cfg(not(test))]
mod hal;

use crate::pager::{PhysAddr, PhysAddrRange, VirtAddr};
use crate::Result;

/// Materialise empty struct implementating Arch trait.
pub struct Arch {}

impl super::ArchTrait for Arch {
    fn ram_range() -> Result<PhysAddrRange> {
        // FIXME: Collect from DTB
        Ok(PhysAddrRange::between(
            PhysAddr::at(0x4000_0000),
            PhysAddr::at(0x5000_0000),
        ))
    }
    fn kernel_base() -> VirtAddr {
        const UPPER_VA_BITS: usize = 39;
        let result = VirtAddr::at(!((1 << (UPPER_VA_BITS + 1)) - 1));
        result
    }

    fn pager_init() -> Result<()> {
        pager::init()
    }

    fn enable_paging(_page_directory: &impl super::PageDirectory) {
        unimplemented!()
    }

    fn handler_init() -> Result<()> {
        unimplemented!()
    }

    fn thread_init() -> Result<()> {
        unimplemented!()
    }

    fn wait_forever() -> ! {
        unimplemented!()
    }
}

#[cfg(not(test))]
pub use hal::_reset;

/// Construct an empty page directory.
pub fn new_page_directory() -> impl super::PageDirectory {
    pager::new_page_directory()
}

#[cfg(test)]
mod tests {
    extern crate std;

    #[test]
    fn it_works() {
        info!("marker")
    }
}
<commit_msg>Further streamline module and fix typo.<commit_after>// SPDX-License-Identifier: Unlicense

mod pager;

/// Live hardware abstraction layer for integration tests and releases.
#[cfg(not(test))]
mod hal;

/// Mock hardware abstraction layer for unit tests.
#[cfg(test)]
mod hal_test;

/// Publish hardware abstraction layer for unit tests.
#[cfg(test)]
use hal_test as hal;

use crate::pager::{PhysAddr, PhysAddrRange, VirtAddr};
use crate::Result;

/// Materialise empty struct implementing Arch trait.
pub struct Arch {}

impl super::ArchTrait for Arch {
    fn ram_range() -> Result<PhysAddrRange> {
        // FIXME: Collect from DTB
        Ok(PhysAddrRange::between(
            PhysAddr::at(0x4000_0000),
            PhysAddr::at(0x5000_0000),
        ))
    }
    fn kernel_base() -> VirtAddr {
        const UPPER_VA_BITS: usize = 39;
        let result = VirtAddr::at(!((1 << (UPPER_VA_BITS + 1)) - 1));
        result
    }

    fn pager_init() -> Result<()> {
        pager::init()
    }

    fn enable_paging(_page_directory: &impl super::PageDirectory) {
        unimplemented!()
    }

    fn handler_init() -> Result<()> {
        unimplemented!()
    }

    fn thread_init() -> Result<()> {
        unimplemented!()
    }

    fn wait_forever() -> ! {
        unimplemented!()
    }
}

#[cfg(not(test))]
pub use hal::_reset;

/// Construct an empty page directory.
pub fn new_page_directory() -> impl super::PageDirectory {
    pager::new_page_directory()
}

#[cfg(test)]
mod tests {
    extern crate std;

    #[test]
    fn it_works() {
        info!("marker")
    }
}
<|endoftext|>


<commit_before>extern crate bit_vec;

use self::bit_vec::BitVec;
use std::mem;
use std::fmt;

use nfa::{AUTO_START, AUTO_STUCK};
use automaton::{Automaton, Match};

pub type Input = u8;
pub type StateNumber = usize;
pub type PatternNumber = usize;

pub struct DFAState {
    transitions: Box<[StateNumber]>,
    pattern_ends: Vec<PatternNumber>,
}

pub struct DFA {
    states: Box<[DFAState]>,
    finals: BitVec,
    dict: Vec<Vec<Input>>,
}

pub struct DDFA {
    states: Box<[DDFAState]>,
    dict: Vec<Vec<Input>>,
}

// Living dangerously: raw pointers baby
#[derive(Clone, PartialEq)]
pub struct DDFAState {
    transitions: Box<[*const DDFAState]>,
    pattern_ends: Vec<PatternNumber>,
    is_final: bool,
}

impl DFAState {
    pub fn new(transitions: Box<[StateNumber]>, pattern_ends: Vec<PatternNumber>) -> Self {
        DFAState {
            transitions: transitions,
            pattern_ends: pattern_ends,
        }
    }
}

impl DFA {
    pub fn new(states: Box<[DFAState]>, finals: BitVec, dict: Vec<Vec<Input>>) -> Self {
        DFA {
            states: states,
            finals: finals,
            dict: dict,
        }
    }

    pub fn into_ddfa(self) -> Result<DDFA, ()> {
        let states_len = self.states.len();
        let mut states = vec![DDFAState::new(Box::new([]), Vec::new(), false); states_len]
            .into_boxed_slice();

        let states_start: *mut DDFAState = (*states).as_mut_ptr();

        for (i, ref st) in self.states.iter().enumerate() {
            let mut v: Vec<*const DDFAState> = Vec::with_capacity(st.transitions.len());
            for &offset in st.transitions.iter() {
                if offset >= states_len {
                    return Err(());
                }
                unsafe {
                    v.push(states_start.offset(offset as isize) as *const DDFAState);
                }
            }
            states[i].transitions = v.into_boxed_slice();
            states[i].pattern_ends = self.states[i].pattern_ends.clone();
            states[i].is_final = self.finals[i];
        }
        Ok(DDFA::new(states, self.dict))
    }

    pub fn apply(&self, input: &[u8]) -> Vec<PatternNumber> {
        let mut cur_state = AUTO_START;
        for &byte in input {
            cur_state = self.states[cur_state].transitions[byte as usize];
            if cur_state == AUTO_STUCK {
                break;
            }
        }
        self.states[cur_state].pattern_ends.clone()
    }
}

impl Automaton<Input> for DFA {
    type State = StateNumber;

    fn start_state(&self) -> Self::State {
        AUTO_START
    }

    fn stuck_state(&self) -> Self::State {
        AUTO_STUCK
    }

    #[inline]
    fn next_state(&self, &state: &Self::State, &input: &Input) -> Self::State {
        self.states[state].transitions[input as usize]
    }

    #[inline]
    fn has_match(&self, &state: &Self::State, patt_no_offset: usize) -> bool {
        patt_no_offset < self.states[state].pattern_ends.len()
    }

    #[inline]
    fn get_match(&self, &state: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match {
        let patt_no = self.states[state].pattern_ends[patt_no_offset];
        Match {
            patt_no: patt_no,
            start: text_offset - self.dict[patt_no].len(),
            end: text_offset,
        }
    }
}

impl DDFAState {
    fn new(transitions: Box<[*const DDFAState]>,
           pattern_ends: Vec<PatternNumber>,
           is_final: bool)
           -> Self {
        DDFAState {
            transitions: transitions,
            pattern_ends: pattern_ends,
            is_final: is_final,
        }
    }
}

impl DDFA {
    fn new(states: Box<[DDFAState]>, dict: Vec<Vec<Input>>) -> Self {
        DDFA {
            states: states,
            dict: dict,
        }
    }

    pub fn apply(&self, input: &[u8]) -> Vec<PatternNumber> {
        let mut cur_state: *const DDFAState = &self.states[AUTO_START];
        let stuck = &self.states[AUTO_STUCK];
        for &byte in input {
            cur_state = unsafe { (*cur_state).transitions[byte as usize] };
            if cur_state == stuck {
                break;
            }
        }
        unsafe { (*cur_state).pattern_ends.clone() }
    }
}

impl Automaton<Input> for DDFA {
    type State = *const DDFAState;

    fn start_state(&self) -> Self::State {
        &self.states[AUTO_START]
    }

    fn stuck_state(&self) -> Self::State {
        &self.states[AUTO_STUCK]
    }

    #[inline]
    fn next_state(&self, &state: &Self::State, &input: &Input) -> Self::State {
        unsafe { (*state).transitions[input as usize] }
    }

    #[inline]
    fn has_match(&self, &state: &Self::State, patt_no_offset: usize) -> bool {
        patt_no_offset < unsafe { (*state).pattern_ends.len() }
    }

    #[inline]
    fn get_match(&self, &state: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match {
        let patt_no = unsafe { (*state).pattern_ends[patt_no_offset] };
        Match {
            patt_no: patt_no,
            start: text_offset - self.dict[patt_no].len(),
            end: text_offset,
        }
    }
}

// The Debug::fmt implementation for DFA and DDFA are extremely similar. The only differences are in
//  computing the finality of a state and computing the index of a state in the states array.
// Therefore we share these with a macro:
macro_rules! debug_impl {
    ($struct_name:ident, $compute_finality:item, $compute_start:item, $compute_tr_no:item) => {
        impl fmt::Debug for $struct_name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $compute_finality
                $compute_start
                $compute_tr_no
                let start = compute_start(&self);
                for (i, state) in (*self.states).into_iter().enumerate() {
                    if i == AUTO_STUCK {
                        try!(write!(f, "{} (stuck),\n", AUTO_STUCK));
                        continue;
                    }
                    try!(write!(f, "{}", i));
                    if i == AUTO_START {
                        try!(write!(f, " (start)"));
                    }
                    if compute_finality(&self, state, i) {
                        try!(write!(f, " (final)"));
                    }
                    try!(write!(f, ": {{"));
                    if !state.transitions.is_empty() {
                        try!(write!(f, "\n"));
                    }
                    let mut last_c = 0;
                    let mut iter = (*state.transitions)
                        .into_iter()
                        .enumerate()
                        .peekable();
                    while let Some((c, tr)) = iter.next() {
                        if let Some(&(c2, tr2)) = iter.peek() {
                            if tr == tr2 {
                                continue;
                            }
                            let tr_no = compute_tr_no(tr, start);
                            if c == last_c {
                                try!(write!(f, "  {:?}: {:?},\n", c as u8 as char, tr_no));
                            } else {
                                try!(write!(f, "  [{:?}-{:?}]: {:?},\n",
                                   last_c as u8 as char,
                                   (c as u8) as char,
                                   tr_no));
                            }
                            last_c = c2;
                        }
                    }
                    try!(write!(f, "}},\n"));
                }
                Ok(())
            }
        }
    }
}

debug_impl!(
    DFA,
    #[allow(unused_variables)]
    fn compute_finality(dfa: &DFA, state: &DFAState, i: usize) -> bool {
        dfa.finals[i]
    },
    #[allow(unused_variables)]
    fn compute_start(dfa: &DFA) -> () {
        ()
    },
    #[allow(unused_variables)]
    fn compute_tr_no(tr: &StateNumber, start: ()) -> &StateNumber {
        tr
    }
);

debug_impl!(
    DDFA,
    #[allow(unused_variables)]
    fn compute_finality(ddfa: &DDFA, state: &DDFAState, i: usize) -> bool {
        state.is_final
    },
    fn compute_start(ddfa: &DDFA) -> *const DDFAState {
        &ddfa.states[AUTO_START] as *const DDFAState
    },
    fn compute_tr_no(tr: &*const DDFAState, start: *const DDFAState) -> usize {
        (*tr as usize - start as usize) / mem::size_of::<DDFAState>()
    }
);

#[cfg(test)]
mod tests {
    use nfa::NFA;

    static BASIC_DICTIONARY: &'static [&'static str] = &["a", "ab", "bab", "bc", "bca", "c", "caa"];

    #[test]
    fn basic_ignore_prefixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_postfixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_postfixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_pre_postfixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_prefixes();
        nfa.ignore_postfixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_pre_postfixes_order() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_postfixes();
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    use automaton::Automaton;
    use std::iter;

    fn haystack_same(letter: char) -> String {
        iter::repeat(letter).take(10000).collect()
    }

    #[test]
    fn from_bench_basic_one_byte() {
        let needles = vec!["a"];
        let haystack = &haystack_same('z');

        let mut nfa = NFA::from_dictionary(needles);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();

        assert!(dfa.find( haystack.as_bytes()).next().is_none());
    }

    static HAYSTACK_SHERLOCK: &'static str = include_str!("../benches/sherlock.txt");

    #[test]
    fn from_bench_sherlock_alt1() {
        let needles = vec!["Sherlock", "Street"];
        let count = 158;

        let haystack = HAYSTACK_SHERLOCK;

        let mut nfa = NFA::from_dictionary(needles);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();

        assert_eq!(count, dfa.find(haystack.as_bytes()).count());
    }
}
<commit_msg>Switched to get_unchecked for slightly more performance<commit_after>extern crate bit_vec;

use self::bit_vec::BitVec;
use std::mem;
use std::fmt;

use nfa::{AUTO_START, AUTO_STUCK};
use automaton::{Automaton, Match};

pub type Input = u8;
pub type StateNumber = usize;
pub type PatternNumber = usize;

pub struct DFAState {
    transitions: Box<[StateNumber]>,
    pattern_ends: Vec<PatternNumber>,
}

pub struct DFA {
    states: Box<[DFAState]>,
    finals: BitVec,
    dict: Vec<Vec<Input>>,
}

pub struct DDFA {
    states: Box<[DDFAState]>,
    dict: Vec<Vec<Input>>,
}

// Living dangerously: raw pointers baby
#[derive(Clone, PartialEq)]
pub struct DDFAState {
    transitions: Box<[*const DDFAState]>,
    pattern_ends: Vec<PatternNumber>,
    is_final: bool,
}

impl DFAState {
    pub fn new(transitions: Box<[StateNumber]>, pattern_ends: Vec<PatternNumber>) -> Self {
        DFAState {
            transitions: transitions,
            pattern_ends: pattern_ends,
        }
    }
}

impl DFA {
    pub fn new(states: Box<[DFAState]>, finals: BitVec, dict: Vec<Vec<Input>>) -> Self {
        DFA {
            states: states,
            finals: finals,
            dict: dict,
        }
    }

    pub fn into_ddfa(self) -> Result<DDFA, ()> {
        let states_len = self.states.len();
        let mut states = vec![DDFAState::new(Box::new([]), Vec::new(), false); states_len]
            .into_boxed_slice();

        let states_start: *mut DDFAState = (*states).as_mut_ptr();

        for (i, ref st) in self.states.iter().enumerate() {
            let mut v: Vec<*const DDFAState> = Vec::with_capacity(st.transitions.len());
            for &offset in st.transitions.iter() {
                if offset >= states_len {
                    return Err(());
                }
                unsafe {
                    v.push(states_start.offset(offset as isize) as *const DDFAState);
                }
            }
            states[i].transitions = v.into_boxed_slice();
            states[i].pattern_ends = self.states[i].pattern_ends.clone();
            states[i].is_final = self.finals[i];
        }
        Ok(DDFA::new(states, self.dict))
    }

    pub fn apply(&self, input: &[u8]) -> Vec<PatternNumber> {
        let mut cur_state = AUTO_START;
        for &byte in input {
            cur_state = self.states[cur_state].transitions[byte as usize];
            if cur_state == AUTO_STUCK {
                break;
            }
        }
        self.states[cur_state].pattern_ends.clone()
    }
}

impl Automaton<Input> for DFA {
    type State = StateNumber;

    fn start_state(&self) -> Self::State {
        AUTO_START
    }

    fn stuck_state(&self) -> Self::State {
        AUTO_STUCK
    }

    #[inline]
    fn next_state(&self, &state: &Self::State, &input: &Input) -> Self::State {
        self.states[state].transitions[input as usize]
    }

    #[inline]
    fn has_match(&self, &state: &Self::State, patt_no_offset: usize) -> bool {
        patt_no_offset < self.states[state].pattern_ends.len()
    }

    #[inline]
    fn get_match(&self, &state: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match {
        let patt_no = self.states[state].pattern_ends[patt_no_offset];
        Match {
            patt_no: patt_no,
            start: text_offset - self.dict[patt_no].len(),
            end: text_offset,
        }
    }
}

impl DDFAState {
    fn new(transitions: Box<[*const DDFAState]>,
           pattern_ends: Vec<PatternNumber>,
           is_final: bool)
           -> Self {
        DDFAState {
            transitions: transitions,
            pattern_ends: pattern_ends,
            is_final: is_final,
        }
    }
}

impl DDFA {
    fn new(states: Box<[DDFAState]>, dict: Vec<Vec<Input>>) -> Self {
        DDFA {
            states: states,
            dict: dict,
        }
    }

    pub fn apply(&self, input: &[u8]) -> Vec<PatternNumber> {
        let mut cur_state: *const DDFAState = &self.states[AUTO_START];
        let stuck = &self.states[AUTO_STUCK];
        for &byte in input {
            cur_state = unsafe { (*cur_state).transitions[byte as usize] };
            if cur_state == stuck {
                break;
            }
        }
        unsafe { (*cur_state).pattern_ends.clone() }
    }
}

impl Automaton<Input> for DDFA {
    type State = *const DDFAState;

    fn start_state(&self) -> Self::State {
        &self.states[AUTO_START]
    }

    fn stuck_state(&self) -> Self::State {
        &self.states[AUTO_STUCK]
    }

    #[inline]
    fn next_state(&self, &state: &Self::State, &input: &Input) -> Self::State {
        unsafe { *(*state).transitions.get_unchecked(input as usize) }
    }

    #[inline]
    fn has_match(&self, &state: &Self::State, patt_no_offset: usize) -> bool {
        patt_no_offset < unsafe { (*state).pattern_ends.len() }
    }

    #[inline]
    fn get_match(&self, &state: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match {
        let patt_no = unsafe { *(*state).pattern_ends.get_unchecked(patt_no_offset) };
        Match {
            patt_no: patt_no,
            start: text_offset - self.dict[patt_no].len(),
            end: text_offset,
        }
    }
}

// The Debug::fmt implementation for DFA and DDFA are extremely similar. The only differences are in
//  computing the finality of a state and computing the index of a state in the states array.
// Therefore we share these with a macro:
macro_rules! debug_impl {
    ($struct_name:ident, $compute_finality:item, $compute_start:item, $compute_tr_no:item) => {
        impl fmt::Debug for $struct_name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $compute_finality
                $compute_start
                $compute_tr_no
                let start = compute_start(&self);
                for (i, state) in (*self.states).into_iter().enumerate() {
                    if i == AUTO_STUCK {
                        try!(write!(f, "{} (stuck),\n", AUTO_STUCK));
                        continue;
                    }
                    try!(write!(f, "{}", i));
                    if i == AUTO_START {
                        try!(write!(f, " (start)"));
                    }
                    if compute_finality(&self, state, i) {
                        try!(write!(f, " (final)"));
                    }
                    try!(write!(f, ": {{"));
                    if !state.transitions.is_empty() {
                        try!(write!(f, "\n"));
                    }
                    let mut last_c = 0;
                    let mut iter = (*state.transitions)
                        .into_iter()
                        .enumerate()
                        .peekable();
                    while let Some((c, tr)) = iter.next() {
                        if let Some(&(c2, tr2)) = iter.peek() {
                            if tr == tr2 {
                                continue;
                            }
                            let tr_no = compute_tr_no(tr, start);
                            if c == last_c {
                                try!(write!(f, "  {:?}: {:?},\n", c as u8 as char, tr_no));
                            } else {
                                try!(write!(f, "  [{:?}-{:?}]: {:?},\n",
                                   last_c as u8 as char,
                                   (c as u8) as char,
                                   tr_no));
                            }
                            last_c = c2;
                        }
                    }
                    try!(write!(f, "}},\n"));
                }
                Ok(())
            }
        }
    }
}

debug_impl!(
    DFA,
    #[allow(unused_variables)]
    fn compute_finality(dfa: &DFA, state: &DFAState, i: usize) -> bool {
        dfa.finals[i]
    },
    #[allow(unused_variables)]
    fn compute_start(dfa: &DFA) -> () {
        ()
    },
    #[allow(unused_variables)]
    fn compute_tr_no(tr: &StateNumber, start: ()) -> &StateNumber {
        tr
    }
);

debug_impl!(
    DDFA,
    #[allow(unused_variables)]
    fn compute_finality(ddfa: &DDFA, state: &DDFAState, i: usize) -> bool {
        state.is_final
    },
    fn compute_start(ddfa: &DDFA) -> *const DDFAState {
        &ddfa.states[AUTO_START] as *const DDFAState
    },
    fn compute_tr_no(tr: &*const DDFAState, start: *const DDFAState) -> usize {
        (*tr as usize - start as usize) / mem::size_of::<DDFAState>()
    }
);

#[cfg(test)]
mod tests {
    use nfa::NFA;

    static BASIC_DICTIONARY: &'static [&'static str] = &["a", "ab", "bab", "bc", "bca", "c", "caa"];

    #[test]
    fn basic_ignore_prefixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_postfixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_postfixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_pre_postfixes() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_prefixes();
        nfa.ignore_postfixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    #[test]
    fn basic_ignore_pre_postfixes_order() {
        let mut nfa = NFA::from_dictionary(BASIC_DICTIONARY);
        nfa.ignore_postfixes();
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();
        for (patt_no, &word) in BASIC_DICTIONARY.iter().enumerate() {
            assert!(dfa.apply(word.as_bytes()).contains(&patt_no));
        }
        assert!(!dfa.apply("bbc".as_bytes()).is_empty());
        assert!(!dfa.apply("abb".as_bytes()).is_empty());
    }

    use automaton::Automaton;
    use std::iter;

    fn haystack_same(letter: char) -> String {
        iter::repeat(letter).take(10000).collect()
    }

    #[test]
    fn from_bench_basic_one_byte() {
        let needles = vec!["a"];
        let haystack = &haystack_same('z');

        let mut nfa = NFA::from_dictionary(needles);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();

        assert!(dfa.find( haystack.as_bytes()).next().is_none());
    }

    static HAYSTACK_SHERLOCK: &'static str = include_str!("../benches/sherlock.txt");

    #[test]
    fn from_bench_sherlock_alt1() {
        let needles = vec!["Sherlock", "Street"];
        let count = 158;

        let haystack = HAYSTACK_SHERLOCK;

        let mut nfa = NFA::from_dictionary(needles);
        nfa.ignore_prefixes();
        let dfa = nfa.powerset_construction().into_dfa().unwrap();

        assert_eq!(count, dfa.find(haystack.as_bytes()).count());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

use remove_dir_all::remove_dir_all;
use std::path::{self, Path, PathBuf};
use std::{fmt, fs, io};

use crate::error::IoResultExt;
use crate::Builder;

/// Create a new temporary directory.
///
/// The `tempdir` function creates a directory in the file system
/// and returns a [`TempDir`].
/// The directory will be automatically deleted when the `TempDir`s
/// destructor is run.
///
/// # Resource Leaking
///
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use tempfile::tempdir;
/// use std::fs::File;
/// use std::io::{self, Write};
///
/// # fn main() {
/// #     if let Err(_) = run() {
/// #         ::std::process::exit(1);
/// #     }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`
/// let dir = tempdir()?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// # Ok(())
/// # }
/// ```
///
/// [`TempDir`]: struct.TempDir.html
/// [resource-leaking]: struct.TempDir.html#resource-leaking
pub fn tempdir() -> io::Result<TempDir> {
    TempDir::new()
}

/// Create a new temporary directory.
///
/// The `tempdir` function creates a directory in the file system
/// and returns a [`TempDir`].
/// The directory will be automatically deleted when the `TempDir`s
/// destructor is run.
///
/// # Resource Leaking
///
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use tempfile::tempdir;
/// use std::fs::File;
/// use std::io::{self, Write};
///
/// # fn main() {
/// #     if let Err(_) = run() {
/// #         ::std::process::exit(1);
/// #     }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`,
/// let dir = tempdir()?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// # Ok(())
/// # }
/// ```
///
/// [`TempDir`]: struct.TempDir.html
/// [resource-leaking]: struct.TempDir.html#resource-leaking
pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
    TempDir::new_in(dir)
}

/// A directory in the filesystem that is automatically deleted when
/// it goes out of scope.
///
/// The [`TempDir`] type creates a directory on the file system that
/// is deleted once it goes out of scope. At construction, the
/// `TempDir` creates a new directory with a randomly generated name.
///
/// The default constructor, [`TempDir::new()`], creates directories in
/// the location returned by [`std::env::temp_dir()`], but `TempDir`
/// can be configured to manage a temporary directory in any location
/// by constructing with a [`Builder`].
///
/// After creating a `TempDir`, work with the file system by doing
/// standard [`std::fs`] file system operations on its [`Path`],
/// which can be retrieved with [`TempDir::path()`]. Once the `TempDir`
/// value is dropped, the directory at the path will be deleted, along
/// with any files and directories it contains. It is your responsibility
/// to ensure that no further file system operations are attempted
/// inside the temporary directory once it has been deleted.
///
/// # Resource Leaking
///
/// Various platform-specific conditions may cause `TempDir` to fail
/// to delete the underlying directory. It's important to ensure that
/// handles (like [`File`] and [`ReadDir`]) to files inside the
/// directory are dropped before the `TempDir` goes out of scope. The
/// `TempDir` destructor will silently ignore any errors in deleting
/// the directory; to instead handle errors call [`TempDir::close()`].
///
/// Note that if the program exits before the `TempDir` destructor is
/// run, such as via [`std::process::exit()`], by segfaulting, or by
/// receiving a signal like `SIGINT`, then the temporary directory
/// will not be deleted.
///
/// # Examples
///
/// Create a temporary directory with a generated name:
///
/// ```
/// use std::fs::File;
/// use std::io::Write;
/// use tempfile::TempDir;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`
/// let tmp_dir = TempDir::new()?;
/// # Ok(())
/// # }
/// ```
///
/// Create a temporary directory with a prefix in its name:
///
/// ```
/// use std::fs::File;
/// use std::io::Write;
/// use tempfile::Builder;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`,
/// // whose name will begin with 'example'.
/// let tmp_dir = Builder::new().prefix("example").tempdir()?;
/// # Ok(())
/// # }
/// ```
///
/// [`File`]: http://doc.rust-lang.org/std/fs/struct.File.html
/// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
/// [`ReadDir`]: http://doc.rust-lang.org/std/fs/struct.ReadDir.html
/// [`Builder`]: struct.Builder.html
/// [`TempDir::close()`]: struct.TempDir.html#method.close
/// [`TempDir::new()`]: struct.TempDir.html#method.new
/// [`TempDir::path()`]: struct.TempDir.html#method.path
/// [`TempDir`]: struct.TempDir.html
/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
pub struct TempDir {
    path: Option<PathBuf>,
}

impl TempDir {
    /// Attempts to make a temporary directory inside of `env::temp_dir()`.
    ///
    /// See [`Builder`] for more configuration.
    ///
    /// The directory and everything inside it will be automatically deleted
    /// once the returned `TempDir` is destroyed.
    ///
    /// # Errors
    ///
    /// If the directory can not be created, `Err` is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of `std::env::temp_dir()`
    /// let tmp_dir = TempDir::new()?;
    ///
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    ///
    /// // `tmp_dir` goes out of scope, the directory as well as
    /// // `tmp_file` will be deleted here.
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`Builder`]: struct.Builder.html
    pub fn new() -> io::Result<TempDir> {
        Builder::new().tempdir()
    }

    /// Attempts to make a temporary directory inside of `dir`.
    /// The directory and everything inside it will be automatically
    /// deleted once the returned `TempDir` is destroyed.
    ///
    /// # Errors
    ///
    /// If the directory can not be created, `Err` is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::{self, File};
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of the current directory
    /// let tmp_dir = TempDir::new_in(".")?;
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
        Builder::new().tempdir_in(dir)
    }

    /// Accesses the [`Path`] to the temporary directory.
    ///
    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
    ///
    /// # Examples
    ///
    /// ```
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// let tmp_path;
    ///
    /// {
    ///    let tmp_dir = TempDir::new()?;
    ///    tmp_path = tmp_dir.path().to_owned();
    ///
    ///    // Check that the temp directory actually exists.
    ///    assert!(tmp_path.exists());
    ///
    ///    // End of `tmp_dir` scope, directory will be deleted
    /// }
    ///
    /// // Temp directory should be deleted by now
    /// assert_eq!(tmp_path.exists(), false);
    /// # Ok(())
    /// # }
    /// ```
    pub fn path(&self) -> &path::Path {
        self.path.as_ref().unwrap()
    }

    /// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located.
    ///
    /// This consumes the [`TempDir`] without deleting directory on the filesystem, meaning that
    /// the directory will no longer be automatically deleted.
    ///
    /// [`TempDir`]: struct.TempDir.html
    /// [`PathBuf`]: http://doc.rust-lang.org/std/path/struct.PathBuf.html
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// let tmp_dir = TempDir::new()?;
    ///
    /// // Persist the temporary directory to disk,
    /// // getting the path where it is.
    /// let tmp_path = tmp_dir.into_path();
    ///
    /// // Delete the temporary directory ourselves.
    /// fs::remove_dir_all(tmp_path)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn into_path(mut self) -> PathBuf {
        self.path.take().unwrap()
    }

    /// Closes and removes the temporary directory, returning a `Result`.
    ///
    /// Although `TempDir` removes the directory on drop, in the destructor
    /// any errors are ignored. To detect errors cleaning up the temporary
    /// directory, call `close` instead.
    ///
    /// # Errors
    ///
    /// This function may return a variety of [`std::io::Error`]s that result from deleting
    /// the files and directories contained with the temporary directory,
    /// as well as from deleting the temporary directory itself. These errors
    /// may be platform specific.
    ///
    /// [`std::io::Error`]: http://doc.rust-lang.org/std/io/struct.Error.html
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of `std::env::temp_dir()`.
    /// let tmp_dir = TempDir::new()?;
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    ///
    /// // By closing the `TempDir` explicitly we can check that it has
    /// // been deleted successfully. If we don't close it explicitly,
    /// // the directory will still be deleted when `tmp_dir` goes out
    /// // of scope, but we won't know whether deleting the directory
    /// // succeeded.
    /// drop(tmp_file);
    /// tmp_dir.close()?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn close(mut self) -> io::Result<()> {
        let result = remove_dir_all(self.path()).with_err_path(|| self.path());

        // Prevent the Drop impl from removing the dir a second time.
        self.path = None;

        result
    }
}

impl AsRef<Path> for TempDir {
    fn as_ref(&self) -> &Path {
        self.path()
    }
}

impl fmt::Debug for TempDir {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TempDir")
            .field("path", &self.path())
            .finish()
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        // Path is `None` if `close()` or `into_path()` has been called.
        if let Some(ref p) = self.path {
            let _ = remove_dir_all(p);
        }
    }
}

pub(crate) fn create(path: PathBuf) -> io::Result<TempDir> {
    fs::create_dir(&path)
        .with_err_path(|| &path)
        .map(|_| TempDir { path: Some(path) })
}
<commit_msg>Reduce size of `TempDir` by 1 pointer<commit_after>// Copyright 2015 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.

use remove_dir_all::remove_dir_all;
use std::path::{self, Path, PathBuf};
use std::{fmt, fs, io};

use crate::error::IoResultExt;
use crate::Builder;

/// Create a new temporary directory.
///
/// The `tempdir` function creates a directory in the file system
/// and returns a [`TempDir`].
/// The directory will be automatically deleted when the `TempDir`s
/// destructor is run.
///
/// # Resource Leaking
///
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use tempfile::tempdir;
/// use std::fs::File;
/// use std::io::{self, Write};
///
/// # fn main() {
/// #     if let Err(_) = run() {
/// #         ::std::process::exit(1);
/// #     }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`
/// let dir = tempdir()?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// # Ok(())
/// # }
/// ```
///
/// [`TempDir`]: struct.TempDir.html
/// [resource-leaking]: struct.TempDir.html#resource-leaking
pub fn tempdir() -> io::Result<TempDir> {
    TempDir::new()
}

/// Create a new temporary directory.
///
/// The `tempdir` function creates a directory in the file system
/// and returns a [`TempDir`].
/// The directory will be automatically deleted when the `TempDir`s
/// destructor is run.
///
/// # Resource Leaking
///
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use tempfile::tempdir;
/// use std::fs::File;
/// use std::io::{self, Write};
///
/// # fn main() {
/// #     if let Err(_) = run() {
/// #         ::std::process::exit(1);
/// #     }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`,
/// let dir = tempdir()?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// # Ok(())
/// # }
/// ```
///
/// [`TempDir`]: struct.TempDir.html
/// [resource-leaking]: struct.TempDir.html#resource-leaking
pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
    TempDir::new_in(dir)
}

/// A directory in the filesystem that is automatically deleted when
/// it goes out of scope.
///
/// The [`TempDir`] type creates a directory on the file system that
/// is deleted once it goes out of scope. At construction, the
/// `TempDir` creates a new directory with a randomly generated name.
///
/// The default constructor, [`TempDir::new()`], creates directories in
/// the location returned by [`std::env::temp_dir()`], but `TempDir`
/// can be configured to manage a temporary directory in any location
/// by constructing with a [`Builder`].
///
/// After creating a `TempDir`, work with the file system by doing
/// standard [`std::fs`] file system operations on its [`Path`],
/// which can be retrieved with [`TempDir::path()`]. Once the `TempDir`
/// value is dropped, the directory at the path will be deleted, along
/// with any files and directories it contains. It is your responsibility
/// to ensure that no further file system operations are attempted
/// inside the temporary directory once it has been deleted.
///
/// # Resource Leaking
///
/// Various platform-specific conditions may cause `TempDir` to fail
/// to delete the underlying directory. It's important to ensure that
/// handles (like [`File`] and [`ReadDir`]) to files inside the
/// directory are dropped before the `TempDir` goes out of scope. The
/// `TempDir` destructor will silently ignore any errors in deleting
/// the directory; to instead handle errors call [`TempDir::close()`].
///
/// Note that if the program exits before the `TempDir` destructor is
/// run, such as via [`std::process::exit()`], by segfaulting, or by
/// receiving a signal like `SIGINT`, then the temporary directory
/// will not be deleted.
///
/// # Examples
///
/// Create a temporary directory with a generated name:
///
/// ```
/// use std::fs::File;
/// use std::io::Write;
/// use tempfile::TempDir;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`
/// let tmp_dir = TempDir::new()?;
/// # Ok(())
/// # }
/// ```
///
/// Create a temporary directory with a prefix in its name:
///
/// ```
/// use std::fs::File;
/// use std::io::Write;
/// use tempfile::Builder;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`,
/// // whose name will begin with 'example'.
/// let tmp_dir = Builder::new().prefix("example").tempdir()?;
/// # Ok(())
/// # }
/// ```
///
/// [`File`]: http://doc.rust-lang.org/std/fs/struct.File.html
/// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
/// [`ReadDir`]: http://doc.rust-lang.org/std/fs/struct.ReadDir.html
/// [`Builder`]: struct.Builder.html
/// [`TempDir::close()`]: struct.TempDir.html#method.close
/// [`TempDir::new()`]: struct.TempDir.html#method.new
/// [`TempDir::path()`]: struct.TempDir.html#method.path
/// [`TempDir`]: struct.TempDir.html
/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
pub struct TempDir {
    path: Option<Box<Path>>,
}

impl TempDir {
    /// Attempts to make a temporary directory inside of `env::temp_dir()`.
    ///
    /// See [`Builder`] for more configuration.
    ///
    /// The directory and everything inside it will be automatically deleted
    /// once the returned `TempDir` is destroyed.
    ///
    /// # Errors
    ///
    /// If the directory can not be created, `Err` is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of `std::env::temp_dir()`
    /// let tmp_dir = TempDir::new()?;
    ///
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    ///
    /// // `tmp_dir` goes out of scope, the directory as well as
    /// // `tmp_file` will be deleted here.
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`Builder`]: struct.Builder.html
    pub fn new() -> io::Result<TempDir> {
        Builder::new().tempdir()
    }

    /// Attempts to make a temporary directory inside of `dir`.
    /// The directory and everything inside it will be automatically
    /// deleted once the returned `TempDir` is destroyed.
    ///
    /// # Errors
    ///
    /// If the directory can not be created, `Err` is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::{self, File};
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of the current directory
    /// let tmp_dir = TempDir::new_in(".")?;
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
        Builder::new().tempdir_in(dir)
    }

    /// Accesses the [`Path`] to the temporary directory.
    ///
    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
    ///
    /// # Examples
    ///
    /// ```
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// let tmp_path;
    ///
    /// {
    ///    let tmp_dir = TempDir::new()?;
    ///    tmp_path = tmp_dir.path().to_owned();
    ///
    ///    // Check that the temp directory actually exists.
    ///    assert!(tmp_path.exists());
    ///
    ///    // End of `tmp_dir` scope, directory will be deleted
    /// }
    ///
    /// // Temp directory should be deleted by now
    /// assert_eq!(tmp_path.exists(), false);
    /// # Ok(())
    /// # }
    /// ```
    pub fn path(&self) -> &path::Path {
        self.path.as_ref().unwrap()
    }

    /// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located.
    ///
    /// This consumes the [`TempDir`] without deleting directory on the filesystem, meaning that
    /// the directory will no longer be automatically deleted.
    ///
    /// [`TempDir`]: struct.TempDir.html
    /// [`PathBuf`]: http://doc.rust-lang.org/std/path/struct.PathBuf.html
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// let tmp_dir = TempDir::new()?;
    ///
    /// // Persist the temporary directory to disk,
    /// // getting the path where it is.
    /// let tmp_path = tmp_dir.into_path();
    ///
    /// // Delete the temporary directory ourselves.
    /// fs::remove_dir_all(tmp_path)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn into_path(mut self) -> PathBuf {
        self.path.take().unwrap().into()
    }

    /// Closes and removes the temporary directory, returning a `Result`.
    ///
    /// Although `TempDir` removes the directory on drop, in the destructor
    /// any errors are ignored. To detect errors cleaning up the temporary
    /// directory, call `close` instead.
    ///
    /// # Errors
    ///
    /// This function may return a variety of [`std::io::Error`]s that result from deleting
    /// the files and directories contained with the temporary directory,
    /// as well as from deleting the temporary directory itself. These errors
    /// may be platform specific.
    ///
    /// [`std::io::Error`]: http://doc.rust-lang.org/std/io/struct.Error.html
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use std::io::Write;
    /// use tempfile::TempDir;
    ///
    /// # use std::io;
    /// # fn run() -> Result<(), io::Error> {
    /// // Create a directory inside of `std::env::temp_dir()`.
    /// let tmp_dir = TempDir::new()?;
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
    /// let mut tmp_file = File::create(file_path)?;
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
    ///
    /// // By closing the `TempDir` explicitly we can check that it has
    /// // been deleted successfully. If we don't close it explicitly,
    /// // the directory will still be deleted when `tmp_dir` goes out
    /// // of scope, but we won't know whether deleting the directory
    /// // succeeded.
    /// drop(tmp_file);
    /// tmp_dir.close()?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn close(mut self) -> io::Result<()> {
        let result = remove_dir_all(self.path()).with_err_path(|| self.path());

        // Prevent the Drop impl from removing the dir a second time.
        self.path = None;

        result
    }
}

impl AsRef<Path> for TempDir {
    fn as_ref(&self) -> &Path {
        self.path()
    }
}

impl fmt::Debug for TempDir {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TempDir")
            .field("path", &self.path())
            .finish()
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        // Path is `None` if `close()` or `into_path()` has been called.
        if let Some(ref p) = self.path {
            let _ = remove_dir_all(p);
        }
    }
}

pub(crate) fn create(path: PathBuf) -> io::Result<TempDir> {
    fs::create_dir(&path)
        .with_err_path(|| &path)
        .map(|_| TempDir {
            path: Some(path.into_boxed_path()),
        })
}
<|endoftext|>


<commit_before>use autograd::function::*;
use tensor::Tensor;
use ::*;

pub type VarList<T> = Vec<Variable<T>>;

pub struct VariableImpl<T> {
    data: Option<Tensor<T>>,
    grad_fn: OptRcMut<Function<T>>,
    grad: OptRcMut<Variable<T>>,
	// version_counter etc ...
}

pub struct Variable<T> {
    value: RcMut<VariableImpl<T>>,
}

impl<T> Clone for Variable<T> {
    fn clone(&self) -> Self {
        Variable { value: self.value.clone() }
    }
}

pub struct SavedVariable<T> {
    data: Box<Tensor<T>>,
    grad_fn: OptRcMut<Function<T>>,
    grad: OptRcMut<Variable<T>>,
	// version_counter etc ...
}

pub struct BackwardArgs {}

impl<T> Variable<T> {
    pub fn apply(&mut self, callback: fn(&mut Tensor<T>)) {
        let mut v = self.value.borrow_mut();
        if let Some(ref mut t) = v.data {
            callback(&mut *t);
        }
    }
    pub fn view(&self, dims: &[i32]) -> Self {
        self.clone()
    }
    // Computes the gradient of current variable w.r.t. graph leaves
    pub fn backward(&mut self, args: &BackwardArgs) {}
    // Detach from graph
    pub fn detach_(&mut self) {}
    // return a new variable detached from graph
    pub fn detach(&self) -> Variable<T> {
        self.clone()
    }
}

impl<T> Default for Variable<T> {
    fn default() -> Self {
        let v = VariableImpl {
            data: None,
            grad_fn: None,
            grad: None,
        };
        Variable { value: RcMutNew(v) }
    }
}
<commit_msg>implement new() functions and data() accessor<commit_after>use autograd::function::*;
use tensor::Tensor;
use ::*;

pub type VarList<T> = Vec<Variable<T>>;

pub struct VariableImpl<T> {
    data: Tensor<T>,
    grad_fn: OptRcMut<Function<T>>,
    grad: OptRcMut<Variable<T>>,
	// version_counter etc ...
}

impl<T> VariableImpl<T> {
    fn new(data: Tensor<T>) -> Self {
        VariableImpl {
            data: data,
            grad_fn: None,
            grad: None,
        }
    }
}

pub struct Variable<T> {
    value: RcMut<VariableImpl<T>>,
}

impl<T> Clone for Variable<T> {
    fn clone(&self) -> Self {
        Variable { value: self.value.clone() }
    }
}

pub struct SavedVariable<T> {
    data: Box<Tensor<T>>,
    grad_fn: OptRcMut<Function<T>>,
    grad: OptRcMut<Variable<T>>,
	// version_counter etc ...
}

#[derive(Default, Clone)]
pub struct BackwardArgs {}

impl<T> Variable<T> {
    pub fn new(data: Tensor<T>) -> Self {
        Variable { value: RcMutNew(VariableImpl::new(data)) }
    }
    pub fn apply(&mut self, callback: fn(&mut Tensor<T>)) {
        let mut v = self.value.borrow_mut();
        callback(&mut v.data);
    }
    // XXX FIXME
    pub fn data(&mut self) -> Tensor<T> {
        self.value.borrow_mut().data.clone()
    }
    pub fn view(&self, dims: &[i32]) -> Self {
        self.clone()
    }
    // Computes the gradient of current variable w.r.t. graph leaves
    pub fn backward(&mut self, args: &BackwardArgs) {}
    // Detach from graph
    pub fn detach_(&mut self) {}
    // return a new variable detached from graph
    pub fn detach(&self) -> Variable<T> {
        self.clone()
    }
}

impl<T> Default for Variable<T> {
    fn default() -> Self {
        let v = VariableImpl {
            data: Tensor::new(),
            grad_fn: None,
            grad: None,
        };
        Variable { value: RcMutNew(v) }
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use liquid_dsp::LiquidComplex32;

use num::complex::Complex;
use std::mem;

// Rust does not support C complex numbers in the same way on 32 and 64 bit platforms:
// https://github.com/rust-lang/rfcs/issues/793
// Therefore this workaround is needed.
//
// Type `LiquidComplex32` is used here because standard `num::complex::Complex` does not have #[repr(C)].
// Function `ccexpf` is implemented in complex.c
//
// Notice that `ccexpf` does not return value, it just changes `z` value in place.
// For some reson it did not work correctly on ARM (BeagleBoneBlack) if `ccexpf` returned
// calculated `LiquidComplex32` struct. Although it worked on Mac OS X and 64/32 bit X86 Ubuntu.
extern {
    pub fn ccexpf(z: *mut LiquidComplex32);
}

use std::f32::consts::PI;

#[cfg(test)]
use std;

#[cfg(test)]
fn assert_eq_delta(a: f32, b: f32, delta: f32) {
    let relative_error = ((a - b) / b).abs();
    if relative_error >= delta {
        panic!("`(left == right)` (left: `{}`, right: `{}`)'", a, b);
    }
}

#[test]
fn test_cexpf() {
    // cargo test -- --nocapture
    // to see prints

    let mut a = Complex::<f32>::new(0.0, 0.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.0, 0.000001);
    assert_eq_delta(a.im, 0.0, 0.000001);

    let mut a = Complex::<f32>::new(1.0, 1.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.468694, 0.000001);
    assert_eq_delta(a.im, 2.2873552, 0.000001);

    let mut a = Complex::<f32>::new(70.0, 70.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1593075600000000000000000000000f32, 0.000001);
    assert_eq_delta(a.im, 1946674600000000000000000000000f32, 0.000001);

    let mut a = Complex::<f32>::new(1_000_000.0, 1_000_000.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq!(a.re, std::f32::INFINITY);
    assert_eq!(a.im, -std::f32::INFINITY);

    //println!("a={:?}", a);
}

pub fn convert_iqi16_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of i16 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 4 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(4) {
        let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
        let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn convert_iqf32_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of f32 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 8 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(8) {
        let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
        let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn shift_frequency(inbuf: &[Complex<f32>], samplenum: &mut u64, shift_hz: f64, samplerate: u32) -> Vec<Complex<f32>> {
    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len());

    for sample in inbuf {
        let mut corrector = Complex::<f32>::new(0.0, -2. * PI * (shift_hz as f64 / samplerate as f64 * *samplenum as f64) as f32);
        unsafe { ccexpf(mem::transmute(&mut corrector))};

        output.push(sample * corrector);
        *samplenum += 1;
    }

    // if samplenum grows too big it introduses noise in floating point math therefore samplenum should be zeroed

    // zero after evey period does not work with AX25 decoding, however FM audio is nice
    // there must be some kind of error here:
    // if *samplenum as f32 > samplerate as f32 / shift_hz as f32 {
    //     *samplenum = 0
    // }

    // ... so use this instead:
    if *samplenum > 1_000_000 {
        *samplenum = 0;
    }

    output
}
<commit_msg>fix issue in shift_frequency where samplenum was not zeroed on optimal time<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use liquid_dsp::LiquidComplex32;

use num::complex::Complex;
use std::mem;
use std::ops::Rem;

// Rust does not support C complex numbers in the same way on 32 and 64 bit platforms:
// https://github.com/rust-lang/rfcs/issues/793
// Therefore this workaround is needed.
//
// Type `LiquidComplex32` is used here because standard `num::complex::Complex` does not have #[repr(C)].
// Function `ccexpf` is implemented in complex.c
//
// Notice that `ccexpf` does not return value, it just changes `z` value in place.
// For some reson it did not work correctly on ARM (BeagleBoneBlack) if `ccexpf` returned
// calculated `LiquidComplex32` struct. Although it worked on Mac OS X and 64/32 bit X86 Ubuntu.
extern {
    pub fn ccexpf(z: *mut LiquidComplex32);
}

use std::f32::consts::PI;

#[cfg(test)]
use std;

#[cfg(test)]
fn assert_eq_delta(a: f32, b: f32, delta: f32) {
    let relative_error = ((a - b) / b).abs();
    if relative_error >= delta {
        panic!("`(left == right)` (left: `{}`, right: `{}`)'", a, b);
    }
}

#[test]
fn test_cexpf() {
    // cargo test -- --nocapture
    // to see prints

    let mut a = Complex::<f32>::new(0.0, 0.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.0, 0.000001);
    assert_eq_delta(a.im, 0.0, 0.000001);

    let mut a = Complex::<f32>::new(1.0, 1.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.468694, 0.000001);
    assert_eq_delta(a.im, 2.2873552, 0.000001);

    let mut a = Complex::<f32>::new(70.0, 70.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1593075600000000000000000000000f32, 0.000001);
    assert_eq_delta(a.im, 1946674600000000000000000000000f32, 0.000001);

    let mut a = Complex::<f32>::new(1_000_000.0, 1_000_000.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq!(a.re, std::f32::INFINITY);
    assert_eq!(a.im, -std::f32::INFINITY);

    //println!("a={:?}", a);
}

pub fn convert_iqi16_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of i16 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 4 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(4) {
        let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
        let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn convert_iqf32_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of f32 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 8 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(8) {
        let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
        let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn shift_frequency(inbuf: &[Complex<f32>], samplenum: &mut u64, samplenum_ofs: &mut u64, shift_hz: f64, samplerate: u32) -> Vec<Complex<f32>> {
    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len());

    for sample in inbuf {
        let mut corrector = Complex::<f32>::new(0.0, -2. * PI * (shift_hz / samplerate as f64 * (*samplenum + *samplenum_ofs) as f64) as f32);
        unsafe { ccexpf(mem::transmute(&mut corrector))};

        output.push(sample * corrector);
        *samplenum += 1;
    }

    // if samplenum grows too big it introduses noise in floating point math therefore samplenum should be zeroed
    if (*samplenum + *samplenum_ofs) as f64 * shift_hz >= samplerate as f64 {
        *samplenum_ofs = (((*samplenum + *samplenum_ofs) as f64 * shift_hz).rem(samplerate as f64) / shift_hz) as u64;
        *samplenum = 0;
    }

    output
}
<|endoftext|>