<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements parallel traversal over the DOM tree.
//!
//! This traversal is based on Rayon, and therefore its safety is largely
//! verified by the type system.
//!
//! The primary trickiness and fine print for the above relates to the
//! thread safety of the DOM nodes themselves. Accessing a DOM element
//! concurrently on multiple threads is actually mostly "safe", since all
//! the mutable state is protected by an AtomicRefCell, and so we'll
//! generally panic if something goes wrong. Still, we try to to enforce our
//! thread invariants at compile time whenever possible. As such, TNode and
//! TElement are not Send, so ordinary style system code cannot accidentally
//! share them with other threads. In the parallel traversal, we explicitly
//! invoke |unsafe { SendNode::new(n) }| to put nodes in containers that may
//! be sent to other threads. This occurs in only a handful of places and is
//! easy to grep for. At the time of this writing, there is no other unsafe
//! code in the parallel traversal.

#![deny(missing_docs)]

use arrayvec::ArrayVec;
use context::TraversalStatistics;
use dom::{OpaqueNode, SendNode, TElement, TNode};
use rayon;
use scoped_tls::ScopedTLS;
use smallvec::SmallVec;
use std::borrow::Borrow;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// The maximum number of child nodes that we will process as a single unit.
///
/// Larger values will increase style sharing cache hits and general DOM locality
/// at the expense of decreased opportunities for parallelism. This value has not
/// been measured and could potentially be tuned.
pub const WORK_UNIT_MAX: usize = 16;

/// A set of nodes, sized to the work unit. This gets copied when sent to other
/// threads, so we keep it compact.
type WorkUnit<N> = ArrayVec<[SendNode<N>; WORK_UNIT_MAX]>;

/// Entry point for the parallel traversal.
#[allow(unsafe_code)]
pub fn traverse_dom<E, D>(traversal: &D,
                          root: E,
                          token: PreTraverseToken,
                          pool: &rayon::ThreadPool)
    where E: TElement,
          D: DomTraversal<E>,
{
    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Set up the SmallVec. We need to move this, and in most cases this is just
    // one node, so keep it small.
    let mut nodes = SmallVec::<[SendNode<E::ConcreteNode>; 8]>::new();

    debug_assert!(traversal.is_parallel());
    // Handle Gecko's eager initial styling. We don't currently support it
    // in conjunction with bottom-up traversal. If we did, we'd need to put
    // it on the context to make it available to the bottom-up phase.
    let depth = if token.traverse_unstyled_children_only() {
        debug_assert!(!D::needs_postorder_traversal());
        for kid in root.as_node().traversal_children() {
            if kid.as_element().map_or(false, |el| el.get_data().is_none()) {
                nodes.push(unsafe { SendNode::new(kid) });
            }
        }
        root.depth() + 1
    } else {
        nodes.push(unsafe { SendNode::new(root.as_node()) });
        root.depth()
    };

    if nodes.is_empty() {
        return;
    }

    let traversal_data = PerLevelTraversalData {
        current_dom_depth: depth,
    };
    let tls = ScopedTLS::<D::ThreadLocalContext>::new(pool);
    let root = root.as_node().opaque();

    pool.install(|| {
        rayon::scope(|scope| {
            let nodes = nodes;
            traverse_nodes(&*nodes,
                           DispatchMode::TailCall,
                           root,
                           traversal_data,
                           scope,
                           pool,
                           traversal,
                           &tls);
        });
    });

    // Dump statistics to stdout if requested.
    if dump_stats {
        let slots = unsafe { tls.unsafe_get() };
        let mut aggregate = slots.iter().fold(TraversalStatistics::default(), |acc, t| {
            match *t.borrow() {
                None => acc,
                Some(ref cx) => &cx.borrow().statistics + &acc,
            }
        });
        aggregate.finish(traversal, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}

/// A callback to create our thread local context.  This needs to be
/// out of line so we don't allocate stack space for the entire struct
/// in the caller.
#[inline(never)]
fn create_thread_local_context<'scope, E, D>(
    traversal: &'scope D,
    slot: &mut Option<D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>
{
    *slot = Some(traversal.create_thread_local_context())
}

/// A parallel top-down DOM traversal.
///
/// This algorithm traverses the DOM in a breadth-first, top-down manner. The
/// goals are:
/// * Never process a child before its parent (since child style depends on
///   parent style). If this were to happen, the styling algorithm would panic.
/// * Prioritize discovering nodes as quickly as possible to maximize
///   opportunities for parallelism.
/// * Style all the children of a given node (i.e. all sibling nodes) on
///   a single thread (with an upper bound to handle nodes with an
///   abnormally large number of children). This is important because we use
///   a thread-local cache to share styles between siblings.
#[inline(always)]
#[allow(unsafe_code)]
fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
                                  root: OpaqueNode,
                                  mut traversal_data: PerLevelTraversalData,
                                  scope: &'a rayon::Scope<'scope>,
                                  pool: &'scope rayon::ThreadPool,
                                  traversal: &'scope D,
                                  tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>,
{
    debug_assert!(nodes.len() <= WORK_UNIT_MAX);

    // Collect all the children of the elements in our work unit. This will
    // contain the combined children of up to WORK_UNIT_MAX nodes, which may
    // be numerous. As such, we store it in a large SmallVec to minimize heap-
    // spilling, and never move it.
    let mut discovered_child_nodes = SmallVec::<[SendNode<E::ConcreteNode>; 128]>::new();
    {
        // Scope the borrow of the TLS so that the borrow is dropped before
        // a potential recursive call when we pass TailCall.
        let mut tlc = tls.ensure(
            |slot: &mut Option<D::ThreadLocalContext>| create_thread_local_context(traversal, slot));

        for n in nodes {
            // If the last node we processed produced children, spawn them off
            // into a work item. We do this at the beginning of the loop (rather
            // than at the end) so that we can traverse the children of the last
            // sibling directly on this thread without a spawn call.
            //
            // This has the important effect of removing the allocation and
            // context-switching overhead of the parallel traversal for perfectly
            // linear regions of the DOM, i.e.:
            //
            // <russian><doll><tag><nesting></nesting></tag></doll></russian>
            //
            // Which are not at all uncommon.
            if !discovered_child_nodes.is_empty() {
                let children = mem::replace(&mut discovered_child_nodes, Default::default());
                let mut traversal_data_copy = traversal_data.clone();
                traversal_data_copy.current_dom_depth += 1;
                traverse_nodes(&*children,
                               DispatchMode::NotTailCall,
                               root,
                               traversal_data_copy,
                               scope,
                               pool,
                               traversal,
                               tls);
            }

            let node = **n;
            let mut children_to_process = 0isize;
            traversal.process_preorder(&traversal_data, &mut *tlc, node);
            if let Some(el) = node.as_element() {
                traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
                    children_to_process += 1;
                    discovered_child_nodes.push(unsafe { SendNode::new(kid) })
                });
            }

            traversal.handle_postorder_traversal(&mut *tlc, root, node,
                                                 children_to_process);
        }
    }

    // Handle the children of the last element in this work unit. If any exist,
    // we can process them (or at least one work unit's worth of them) directly
    // on this thread by passing TailCall.
    if !discovered_child_nodes.is_empty() {
        traversal_data.current_dom_depth += 1;
        traverse_nodes(&discovered_child_nodes,
                       DispatchMode::TailCall,
                       root,
                       traversal_data,
                       scope,
                       pool,
                       traversal,
                       tls);
    }
}

/// Controls whether traverse_nodes may make a recursive call to continue
/// doing work, or whether it should always dispatch work asynchronously.
#[derive(Clone, Copy, PartialEq)]
enum DispatchMode {
    TailCall,
    NotTailCall,
}

impl DispatchMode {
    fn is_tail_call(&self) -> bool { matches!(*self, DispatchMode::TailCall) }
}

#[inline]
fn traverse_nodes<'a, 'scope, E, D>(nodes: &[SendNode<E::ConcreteNode>],
                                    mode: DispatchMode,
                                    root: OpaqueNode,
                                    traversal_data: PerLevelTraversalData,
                                    scope: &'a rayon::Scope<'scope>,
                                    pool: &'scope rayon::ThreadPool,
                                    traversal: &'scope D,
                                    tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>,
{
    debug_assert!(!nodes.is_empty());

    // This is a tail call from the perspective of the caller. However, we only
    // want to actually dispatch the job as a tail call if there's nothing left
    // in our local queue. Otherwise we need to return to it to maintain proper
    // breadth-first ordering.
    let may_dispatch_tail = mode.is_tail_call() &&
        !pool.current_thread_has_pending_tasks().unwrap();

    // In the common case, our children fit within a single work unit, in which
    // case we can pass the SmallVec directly and avoid extra allocation.
    if nodes.len() <= WORK_UNIT_MAX {
        let work = nodes.iter().cloned().collect::<WorkUnit<E::ConcreteNode>>();
        if may_dispatch_tail {
            top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
        } else {
            scope.spawn(move |scope| {
                let work = work;
                top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
            });
        }
    } else {
        for chunk in nodes.chunks(WORK_UNIT_MAX) {
            let nodes = chunk.iter().cloned().collect::<WorkUnit<E::ConcreteNode>>();
            let traversal_data_copy = traversal_data.clone();
            scope.spawn(move |scope| {
                let n = nodes;
                top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls)
            });
        }
    }
}
<commit_msg>Auto merge of #17563 - julian-seward1:master, r=bholley<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements parallel traversal over the DOM tree.
//!
//! This traversal is based on Rayon, and therefore its safety is largely
//! verified by the type system.
//!
//! The primary trickiness and fine print for the above relates to the
//! thread safety of the DOM nodes themselves. Accessing a DOM element
//! concurrently on multiple threads is actually mostly "safe", since all
//! the mutable state is protected by an AtomicRefCell, and so we'll
//! generally panic if something goes wrong. Still, we try to to enforce our
//! thread invariants at compile time whenever possible. As such, TNode and
//! TElement are not Send, so ordinary style system code cannot accidentally
//! share them with other threads. In the parallel traversal, we explicitly
//! invoke |unsafe { SendNode::new(n) }| to put nodes in containers that may
//! be sent to other threads. This occurs in only a handful of places and is
//! easy to grep for. At the time of this writing, there is no other unsafe
//! code in the parallel traversal.

#![deny(missing_docs)]

use arrayvec::ArrayVec;
use context::TraversalStatistics;
use dom::{OpaqueNode, SendNode, TElement, TNode};
use rayon;
use scoped_tls::ScopedTLS;
use smallvec::SmallVec;
use std::borrow::Borrow;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// The maximum number of child nodes that we will process as a single unit.
///
/// Larger values will increase style sharing cache hits and general DOM locality
/// at the expense of decreased opportunities for parallelism. This value has not
/// been measured and could potentially be tuned.
pub const WORK_UNIT_MAX: usize = 16;

/// A set of nodes, sized to the work unit. This gets copied when sent to other
/// threads, so we keep it compact.
type WorkUnit<N> = ArrayVec<[SendNode<N>; WORK_UNIT_MAX]>;

/// Entry point for the parallel traversal.
#[allow(unsafe_code)]
pub fn traverse_dom<E, D>(traversal: &D,
                          root: E,
                          token: PreTraverseToken,
                          pool: &rayon::ThreadPool)
    where E: TElement,
          D: DomTraversal<E>,
{
    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Set up the SmallVec. We need to move this, and in most cases this is just
    // one node, so keep it small.
    let mut nodes = SmallVec::<[SendNode<E::ConcreteNode>; 8]>::new();

    debug_assert!(traversal.is_parallel());
    // Handle Gecko's eager initial styling. We don't currently support it
    // in conjunction with bottom-up traversal. If we did, we'd need to put
    // it on the context to make it available to the bottom-up phase.
    let depth = if token.traverse_unstyled_children_only() {
        debug_assert!(!D::needs_postorder_traversal());
        for kid in root.as_node().traversal_children() {
            if kid.as_element().map_or(false, |el| el.get_data().is_none()) {
                nodes.push(unsafe { SendNode::new(kid) });
            }
        }
        root.depth() + 1
    } else {
        nodes.push(unsafe { SendNode::new(root.as_node()) });
        root.depth()
    };

    if nodes.is_empty() {
        return;
    }

    let traversal_data = PerLevelTraversalData {
        current_dom_depth: depth,
    };
    let tls = ScopedTLS::<D::ThreadLocalContext>::new(pool);
    let root = root.as_node().opaque();

    pool.install(|| {
        rayon::scope(|scope| {
            let nodes = nodes;
            traverse_nodes(&*nodes,
                           DispatchMode::TailCall,
                           0,
                           root,
                           traversal_data,
                           scope,
                           pool,
                           traversal,
                           &tls);
        });
    });

    // Dump statistics to stdout if requested.
    if dump_stats {
        let slots = unsafe { tls.unsafe_get() };
        let mut aggregate = slots.iter().fold(TraversalStatistics::default(), |acc, t| {
            match *t.borrow() {
                None => acc,
                Some(ref cx) => &cx.borrow().statistics + &acc,
            }
        });
        aggregate.finish(traversal, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}

/// A callback to create our thread local context.  This needs to be
/// out of line so we don't allocate stack space for the entire struct
/// in the caller.
#[inline(never)]
fn create_thread_local_context<'scope, E, D>(
    traversal: &'scope D,
    slot: &mut Option<D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>
{
    *slot = Some(traversal.create_thread_local_context())
}

/// A parallel top-down DOM traversal.
///
/// This algorithm traverses the DOM in a breadth-first, top-down manner. The
/// goals are:
/// * Never process a child before its parent (since child style depends on
///   parent style). If this were to happen, the styling algorithm would panic.
/// * Prioritize discovering nodes as quickly as possible to maximize
///   opportunities for parallelism.
/// * Style all the children of a given node (i.e. all sibling nodes) on
///   a single thread (with an upper bound to handle nodes with an
///   abnormally large number of children). This is important because we use
///   a thread-local cache to share styles between siblings.
#[inline(always)]
#[allow(unsafe_code)]
fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
                                  recursion_depth: usize,
                                  root: OpaqueNode,
                                  mut traversal_data: PerLevelTraversalData,
                                  scope: &'a rayon::Scope<'scope>,
                                  pool: &'scope rayon::ThreadPool,
                                  traversal: &'scope D,
                                  tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>,
{
    debug_assert!(nodes.len() <= WORK_UNIT_MAX);

    // Collect all the children of the elements in our work unit. This will
    // contain the combined children of up to WORK_UNIT_MAX nodes, which may
    // be numerous. As such, we store it in a large SmallVec to minimize heap-
    // spilling, and never move it.
    let mut discovered_child_nodes = SmallVec::<[SendNode<E::ConcreteNode>; 128]>::new();
    {
        // Scope the borrow of the TLS so that the borrow is dropped before
        // a potential recursive call when we pass TailCall.
        let mut tlc = tls.ensure(
            |slot: &mut Option<D::ThreadLocalContext>| create_thread_local_context(traversal, slot));

        for n in nodes {
            // If the last node we processed produced children, spawn them off
            // into a work item. We do this at the beginning of the loop (rather
            // than at the end) so that we can traverse the children of the last
            // sibling directly on this thread without a spawn call.
            //
            // This has the important effect of removing the allocation and
            // context-switching overhead of the parallel traversal for perfectly
            // linear regions of the DOM, i.e.:
            //
            // <russian><doll><tag><nesting></nesting></tag></doll></russian>
            //
            // Which are not at all uncommon.
            if !discovered_child_nodes.is_empty() {
                let children = mem::replace(&mut discovered_child_nodes, Default::default());
                let mut traversal_data_copy = traversal_data.clone();
                traversal_data_copy.current_dom_depth += 1;
                traverse_nodes(&*children,
                               DispatchMode::NotTailCall,
                               recursion_depth,
                               root,
                               traversal_data_copy,
                               scope,
                               pool,
                               traversal,
                               tls);
            }

            let node = **n;
            let mut children_to_process = 0isize;
            traversal.process_preorder(&traversal_data, &mut *tlc, node);
            if let Some(el) = node.as_element() {
                traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
                    children_to_process += 1;
                    discovered_child_nodes.push(unsafe { SendNode::new(kid) })
                });
            }

            traversal.handle_postorder_traversal(&mut *tlc, root, node,
                                                 children_to_process);
        }
    }

    // Handle the children of the last element in this work unit. If any exist,
    // we can process them (or at least one work unit's worth of them) directly
    // on this thread by passing TailCall.
    if !discovered_child_nodes.is_empty() {
        traversal_data.current_dom_depth += 1;
        traverse_nodes(&discovered_child_nodes,
                       DispatchMode::TailCall,
                       recursion_depth,
                       root,
                       traversal_data,
                       scope,
                       pool,
                       traversal,
                       tls);
    }
}

/// Controls whether traverse_nodes may make a recursive call to continue
/// doing work, or whether it should always dispatch work asynchronously.
#[derive(Clone, Copy, PartialEq)]
enum DispatchMode {
    TailCall,
    NotTailCall,
}

impl DispatchMode {
    fn is_tail_call(&self) -> bool { matches!(*self, DispatchMode::TailCall) }
}

// On x86_64-linux, a recursive cycle requires 3472 bytes of stack.  Limiting
// the depth to 150 therefore should keep the stack use by the recursion to
// 520800 bytes, which would give a generously conservative margin should we
// decide to reduce the thread stack size from its default of 2MB down to 1MB.
const RECURSION_DEPTH_LIMIT: usize = 150;

#[inline]
fn traverse_nodes<'a, 'scope, E, D>(nodes: &[SendNode<E::ConcreteNode>],
                                    mode: DispatchMode,
                                    recursion_depth: usize,
                                    root: OpaqueNode,
                                    traversal_data: PerLevelTraversalData,
                                    scope: &'a rayon::Scope<'scope>,
                                    pool: &'scope rayon::ThreadPool,
                                    traversal: &'scope D,
                                    tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
    where E: TElement + 'scope,
          D: DomTraversal<E>,
{
    debug_assert!(!nodes.is_empty());

    // This is a tail call from the perspective of the caller. However, we only
    // want to actually dispatch the job as a tail call if there's nothing left
    // in our local queue. Otherwise we need to return to it to maintain proper
    // breadth-first ordering. We also need to take care to avoid stack
    // overflow due to excessive tail recursion. The stack overflow isn't
    // observable to content -- we're still completely correct, just not
    // using tail recursion any more. See bug 1368302.
    debug_assert!(recursion_depth <= RECURSION_DEPTH_LIMIT);
    let may_dispatch_tail = mode.is_tail_call() &&
        recursion_depth != RECURSION_DEPTH_LIMIT &&
        !pool.current_thread_has_pending_tasks().unwrap();

    // In the common case, our children fit within a single work unit, in which
    // case we can pass the SmallVec directly and avoid extra allocation.
    if nodes.len() <= WORK_UNIT_MAX {
        let work = nodes.iter().cloned().collect::<WorkUnit<E::ConcreteNode>>();
        if may_dispatch_tail {
            top_down_dom(&work, recursion_depth + 1, root,
                         traversal_data, scope, pool, traversal, tls);
        } else {
            scope.spawn(move |scope| {
                let work = work;
                top_down_dom(&work, 0, root,
                             traversal_data, scope, pool, traversal, tls);
            });
        }
    } else {
        for chunk in nodes.chunks(WORK_UNIT_MAX) {
            let nodes = chunk.iter().cloned().collect::<WorkUnit<E::ConcreteNode>>();
            let traversal_data_copy = traversal_data.clone();
            scope.spawn(move |scope| {
                let n = nodes;
                top_down_dom(&*n, 0, root,
                             traversal_data_copy, scope, pool, traversal, tls)
            });
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@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.

//! internal class to handle OpenAl context and device.
//!
//! Work as a Singleton, check_al_context must be called before each OpenAl object
//! to be sure that the context is created.

#![macro_use]

use std::ffi::CString;
use std::cell::RefCell;
use std::ptr;
use std::sync::Mutex;
use libc;
use openal::ffi;
use record_context;
use record_context::RecordContext;

lazy_static! {
    static ref AL_CONTEXT: Mutex<Result<OpenAlData, String>> = Mutex::new(OpenAlData::new());
}

#[derive(Clone)]
pub struct OpenAlData {
    pub al_context: ffi::ALCcontextPtr,
    pub al_device: ffi::ALCdevicePtr,
    pub al_capt_device: ffi::ALCdevicePtr
}

impl OpenAlData {
    /// Create a new OpenAlData struct
    ///
    /// Private method.
    fn new() -> Result<OpenAlData, String> {
        let device = unsafe { ffi::alcOpenDevice(ptr::null_mut()) };
        if device == 0 {
            return Err("internal error: cannot open the default device.".to_string());
        }
        let context = unsafe { ffi::alcCreateContext(device, ptr::null_mut()) };
        if context == 0 {
            return Err("internal error: cannot create the OpenAL context.".to_string());
        }
        if unsafe { ffi::alcMakeContextCurrent(context) } == ffi::ALC_FALSE {
            return Err("internal error: cannot make the OpenAL context current.".to_string());
        }

        unsafe {
            libc::atexit(cleanup_openal_context);
        }

        Ok(
            OpenAlData {
                al_context: context,
                al_device: device,
                al_capt_device: 0
            }
        )
    }

    /// Check if the context is created.
    ///
    /// This function check is the OpenAl context is already created.
    /// If context doesn't exist, create it, and store it in a local_data,
    /// else get it from the local data and return it.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_context() -> Result<(), String> {
        if unsafe { ffi::alcGetCurrentContext() != 0 } {
            return Ok(())
        }
        match AL_CONTEXT.lock() {
            Ok(guard) => {
                match *guard {
                    Ok(_) => Ok(()),
                    Err(ref err) => Err(err.clone())
                }
            },
            Err(poison_error) => Err(
                String::from(format!("Can't lock OpenAL context mutex: {}", poison_error))
            )
        }
    }

    fn is_input_context_init() -> Result<RecordContext, String> {
        match AL_CONTEXT.lock() {
            Ok(mut guard) => {
                if let Ok(ref mut new_context) = *guard {
                    if new_context.al_capt_device != 0 {
                        Ok(record_context::new(new_context.al_capt_device))
                    } else {
                        let c_str = CString::new("ALC_EXT_CAPTURE").unwrap();
                        if unsafe {
                            ffi::alcIsExtensionPresent(new_context.al_device, c_str.as_ptr()) } == ffi::ALC_FALSE {
                            return Err("Error: no input device available on your system.".to_string())
                        } else {
                            new_context.al_capt_device = unsafe {
                            ffi::alcCaptureOpenDevice(ptr::null_mut(),
                                                        44100,
                                                        ffi::AL_FORMAT_MONO16,
                                                        44100) };
                            if new_context.al_capt_device == 0 {
                                return Err("internal error: cannot open the default capture device.".to_string())
                            } else {
                                let cap_device = new_context.al_capt_device;
                                return Ok(record_context::new(cap_device))
                            }
                        }
                    }
                } else {
                    Err("Error: you must request the input context, \
                        in the task where you initialize ears.".to_string())
                }
            },
            Err(poison_error) => Err(
                String::from(format!("Can't lock OpenAL context mutex: {}", poison_error))
            )
        }
    }

    /// Check if the input context is created.
    ///
    /// This function check if the input OpenAl context is already created.
    /// The input openAL context need the normal AL context + its own extension.
    /// So check if the context exist first, then load the input extension.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_input_context() -> Result<RecordContext, String> {
        if unsafe { !ffi::alcGetCurrentContext() == 0 } {
            OpenAlData::is_input_context_init()
        } else {
            match OpenAlData::check_al_context() {
                Ok(_)    => OpenAlData::is_input_context_init(),
                Err(err) => Err(err)
            }
        }
    }
}

extern "C" fn cleanup_openal_context() {
    if let Ok(mut guard) = AL_CONTEXT.lock() {
        if let Ok(ref mut context) = *guard {
            unsafe {
                ffi::alcDestroyContext(context.al_context);
                if context.al_capt_device != 0 {
                    ffi::alcCaptureCloseDevice(context.al_capt_device);
                }
                ffi::alcCloseDevice(context.al_device);
            }
        }
    }
}

macro_rules! check_openal_context(
    ($def_ret:expr) => (
            match OpenAlData::check_al_context() {
                Ok(_)    => {},
                Err(err) => { println!("{}", err); return $def_ret; }
            }
        );
);
<commit_msg>Add function to check direct channel capabilities<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@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.

//! internal class to handle OpenAl context and device.
//!
//! Work as a Singleton, check_al_context must be called before each OpenAl object
//! to be sure that the context is created.

#![macro_use]

use std::ffi::CString;
use std::cell::RefCell;
use std::ptr;
use std::sync::Mutex;
use libc;
use openal::ffi;
use record_context;
use record_context::RecordContext;

lazy_static! {
    static ref AL_CONTEXT: Mutex<Result<OpenAlData, String>> = Mutex::new(OpenAlData::new());
}

#[derive(Clone)]
pub struct OpenAlData {
    pub al_context: ffi::ALCcontextPtr,
    pub al_device: ffi::ALCdevicePtr,
    pub al_capt_device: ffi::ALCdevicePtr
}

impl OpenAlData {
    /// Create a new OpenAlData struct
    ///
    /// Private method.
    fn new() -> Result<OpenAlData, String> {
        let device = unsafe { ffi::alcOpenDevice(ptr::null_mut()) };
        if device == 0 {
            return Err("internal error: cannot open the default device.".to_string());
        }
        let context = unsafe { ffi::alcCreateContext(device, ptr::null_mut()) };
        if context == 0 {
            return Err("internal error: cannot create the OpenAL context.".to_string());
        }
        if unsafe { ffi::alcMakeContextCurrent(context) } == ffi::ALC_FALSE {
            return Err("internal error: cannot make the OpenAL context current.".to_string());
        }

        unsafe {
            libc::atexit(cleanup_openal_context);
        }

        Ok(
            OpenAlData {
                al_context: context,
                al_device: device,
                al_capt_device: 0
            }
        )
    }

    /// Check if the context is created.
    ///
    /// This function check is the OpenAl context is already created.
    /// If context doesn't exist, create it, and store it in a local_data,
    /// else get it from the local data and return it.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_context() -> Result<(), String> {
        if unsafe { ffi::alcGetCurrentContext() != 0 } {
            return Ok(())
        }
        match AL_CONTEXT.lock() {
            Ok(guard) => {
                match *guard {
                    Ok(_) => Ok(()),
                    Err(ref err) => Err(err.clone())
                }
            },
            Err(poison_error) => Err(
                String::from(format!("Can't lock OpenAL context mutex: {}", poison_error))
            )
        }
    }

    fn is_input_context_init() -> Result<RecordContext, String> {
        match AL_CONTEXT.lock() {
            Ok(mut guard) => {
                if let Ok(ref mut new_context) = *guard {
                    if new_context.al_capt_device != 0 {
                        Ok(record_context::new(new_context.al_capt_device))
                    } else {
                        let c_str = CString::new("ALC_EXT_CAPTURE").unwrap();
                        if unsafe {
                            ffi::alcIsExtensionPresent(new_context.al_device, c_str.as_ptr()) } == ffi::ALC_FALSE {
                            return Err("Error: no input device available on your system.".to_string())
                        } else {
                            new_context.al_capt_device = unsafe {
                            ffi::alcCaptureOpenDevice(ptr::null_mut(),
                                                        44100,
                                                        ffi::AL_FORMAT_MONO16,
                                                        44100) };
                            if new_context.al_capt_device == 0 {
                                return Err("internal error: cannot open the default capture device.".to_string())
                            } else {
                                let cap_device = new_context.al_capt_device;
                                return Ok(record_context::new(cap_device))
                            }
                        }
                    }
                } else {
                    Err("Error: you must request the input context, \
                        in the task where you initialize ears.".to_string())
                }
            },
            Err(poison_error) => Err(
                String::from(format!("Can't lock OpenAL context mutex: {}", poison_error))
            )
        }
    }

    /// Check if AL_SOFT_direct_channels extension is present
    ///
    /// # Return
    /// true if the extension is present, otherwise false.
    pub fn direct_channel_capable() -> bool {
        let c_str = CString::new("AL_SOFT_direct_channels").unwrap();
        unsafe {
            ffi::alIsExtensionPresent(c_str.as_ptr()) == ffi::AL_TRUE
        }
    }

    /// Check if the input context is created.
    ///
    /// This function check if the input OpenAl context is already created.
    /// The input openAL context need the normal AL context + its own extension.
    /// So check if the context exist first, then load the input extension.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_input_context() -> Result<RecordContext, String> {
        if unsafe { !ffi::alcGetCurrentContext() == 0 } {
            OpenAlData::is_input_context_init()
        } else {
            match OpenAlData::check_al_context() {
                Ok(_)    => OpenAlData::is_input_context_init(),
                Err(err) => Err(err)
            }
        }
    }
}

extern "C" fn cleanup_openal_context() {
    if let Ok(mut guard) = AL_CONTEXT.lock() {
        if let Ok(ref mut context) = *guard {
            unsafe {
                ffi::alcDestroyContext(context.al_context);
                if context.al_capt_device != 0 {
                    ffi::alcCaptureCloseDevice(context.al_capt_device);
                }
                ffi::alcCloseDevice(context.al_device);
            }
        }
    }
}

macro_rules! check_openal_context(
    ($def_ret:expr) => (
            match OpenAlData::check_al_context() {
                Ok(_)    => {},
                Err(err) => { println!("{}", err); return $def_ret; }
            }
        );
);
<|endoftext|>


<commit_before>extern crate protobuf_codegen_pure;

use std::env;
use std::path::PathBuf;
use std::process::exit;

fn main() {
    let args = env::args_os()
        .skip(1)
        .map(PathBuf::from)
        .collect::<Vec<_>>();

    if args.len() != 2 {
        eprintln!(
            "usage: {} <input.proto> <include>",
            env::args().next().unwrap()
        );
        exit(1);
    }

    assert!(args.len() >= 2);
    let (input, includes) = args.split_at(1);
    let t =
        protobuf_codegen_pure::parse_and_typecheck(includes, input).expect("parse_and_typecheck");
    for fd in t.file_descriptors {
        println!("{:#?}", fd);
    }
}
<commit_msg>Warn parse-and-typecheck is not public<commit_after>extern crate protobuf_codegen_pure;

use std::env;
use std::path::PathBuf;
use std::process::exit;

fn main() {
    let args = env::args_os()
        .skip(1)
        .map(PathBuf::from)
        .collect::<Vec<_>>();

    if args.len() != 2 {
        eprintln!(
            "usage: {} <input.proto> <include>",
            env::args().next().unwrap()
        );
        exit(1);
    }

    eprintln!(
        "{} is not a part of public interface",
        env::args().next().unwrap()
    );

    assert!(args.len() >= 2);
    let (input, includes) = args.split_at(1);
    let t =
        protobuf_codegen_pure::parse_and_typecheck(includes, input).expect("parse_and_typecheck");
    for fd in t.file_descriptors {
        println!("{:#?}", fd);
    }
}
<|endoftext|>


<commit_before>/**
This module contains a set of iterator extensions.  Rather than being named for the type of iterator they are implemented on, they are named for the method (or group of associated methods) being implemented.

# Standard Features

The iterator extensions, where possible, should implement the following features:

- `Clone`, which produces an *independent* version of the iterator.
- `DoubleEndedIterator`.
- `ExactSizeIterator`.
- `RandomAccessIterator`.
- `Show`.
- Accurate `size_hint` (depending on the transform being performed, and the accuracy of the underlying iterator).
- An `unwrap` method, which returns any owned values passed into the iterator; typically, this is the original iterator.
*/

pub use self::accumulate::AccumulateIterator;
pub use self::cartesian_product::CartesianProductIterator;
pub use self::clone_each::CloneEachIterator;
pub use self::group_by::GroupByIterator;
pub use self::indexed::IndexedIterator;
pub use self::fold::{FoldlIterator, FoldrIterator};
pub use self::intersperse::IntersperseIterator;
pub use self::keep_some::KeepSomeIterator;
pub use self::pad_tail_to::PadTailToIterator;
pub use self::pacing_walk::PacingWalkIterator;
pub use self::round_robin::RoundRobinIterator;
pub use self::skip_exactly::SkipExactlyIterator;
pub use self::sorted::SortedIterator;
pub use self::stride::StrideIterator;
pub use self::take_exactly::TakeExactlyIterator;
pub use self::tee::TeeIterator;
pub use self::zip_longest::ZipLongestIterator;

pub mod accumulate;
pub mod cartesian_product;
pub mod clone_each;
pub mod group_by;
pub mod indexed;
pub mod fold;
pub mod intersperse;
pub mod keep_some;
pub mod pad_tail_to;
pub mod pacing_walk;
pub mod round_robin;
pub mod skip_exactly;
pub mod sorted;
pub mod stride;
pub mod take_exactly;
pub mod tee;
pub mod zip_longest;
<commit_msg>Added grabbag::iter::prelude.<commit_after>/**
This module contains a set of iterator extensions.  Rather than being named for the type of iterator they are implemented on, they are named for the method (or group of associated methods) being implemented.

# Standard Features

The iterator extensions, where possible, should implement the following features:

- `Clone`, which produces an *independent* version of the iterator.
- `DoubleEndedIterator`.
- `ExactSizeIterator`.
- `RandomAccessIterator`.
- `Show`.
- Accurate `size_hint` (depending on the transform being performed, and the accuracy of the underlying iterator).
- An `unwrap` method, which returns any owned values passed into the iterator; typically, this is the original iterator.
*/

pub use self::prelude::*;

pub mod accumulate;
pub mod cartesian_product;
pub mod clone_each;
pub mod group_by;
pub mod indexed;
pub mod fold;
pub mod intersperse;
pub mod keep_some;
pub mod pad_tail_to;
pub mod pacing_walk;
pub mod round_robin;
pub mod skip_exactly;
pub mod sorted;
pub mod stride;
pub mod take_exactly;
pub mod tee;
pub mod zip_longest;

pub mod prelude {
    pub use super::accumulate::AccumulateIterator;
    pub use super::cartesian_product::CartesianProductIterator;
    pub use super::clone_each::CloneEachIterator;
    pub use super::group_by::GroupByIterator;
    pub use super::indexed::IndexedIterator;
    pub use super::fold::{FoldlIterator, FoldrIterator};
    pub use super::intersperse::IntersperseIterator;
    pub use super::keep_some::KeepSomeIterator;
    pub use super::pad_tail_to::PadTailToIterator;
    pub use super::pacing_walk::PacingWalkIterator;
    pub use super::round_robin::RoundRobinIterator;
    pub use super::skip_exactly::SkipExactlyIterator;
    pub use super::sorted::SortedIterator;
    pub use super::stride::StrideIterator;
    pub use super::take_exactly::TakeExactlyIterator;
    pub use super::tee::TeeIterator;
    pub use super::zip_longest::ZipLongestIterator;
}
<|endoftext|>


<commit_before>// the PhantomData instances in this file are just to stop compiler complaints
// about missing generics; feel free to remove them

/// A Matcher is a single rule of fizzbuzz: given a function on T, should
/// a word be substituted in? If yes, which word?
pub struct Matcher<T>(std::marker::PhantomData<T>);

impl<T> Matcher<T> {
    pub fn new<F, S>(_matcher: F, _subs: S) -> Matcher<T> {
        unimplemented!()
    }
}

/// A Fizzy is a set of matchers, which may be applied to an iterator.
///
/// Strictly speaking, it's usually more idiomatic to use `iter.map()` than to
/// consume an iterator with an `apply` method. Given a Fizzy instance, it's
/// pretty straightforward to construct a closure which applies it to all
/// elements of the iterator. However, we're using the `apply` pattern
/// here because it's a simpler interface for students to implement.
///
/// Also, it's a good excuse to try out using impl trait.
pub struct Fizzy<T>(std::marker::PhantomData<T>);

impl<T> Fizzy<T> {
    pub fn new() -> Self {
        unimplemented!()
    }

    // feel free to change the signature to `mut self` if you like
    pub fn add_matcher(self, _matcher: Matcher<T>) -> Self {
        unimplemented!()
    }

    /// map this fizzy onto every element of an interator, returning a new iterator
    pub fn apply<I>(self, _iter: I) -> impl Iterator<Item = String> {
        // unimplemented!() doesn't actually work, here; () is not an Iterator
        // that said, this is probably not the actual implementation you desire
        Vec::new().into_iter()
    }
}

/// convenience function: return a Fizzy which applies the standard fizz-buzz rules
pub fn fizz_buzz<T>() -> Fizzy<T> {
    unimplemented!()
}
<commit_msg>Fixed a typographical error (#887)<commit_after>// the PhantomData instances in this file are just to stop compiler complaints
// about missing generics; feel free to remove them

/// A Matcher is a single rule of fizzbuzz: given a function on T, should
/// a word be substituted in? If yes, which word?
pub struct Matcher<T>(std::marker::PhantomData<T>);

impl<T> Matcher<T> {
    pub fn new<F, S>(_matcher: F, _subs: S) -> Matcher<T> {
        unimplemented!()
    }
}

/// A Fizzy is a set of matchers, which may be applied to an iterator.
///
/// Strictly speaking, it's usually more idiomatic to use `iter.map()` than to
/// consume an iterator with an `apply` method. Given a Fizzy instance, it's
/// pretty straightforward to construct a closure which applies it to all
/// elements of the iterator. However, we're using the `apply` pattern
/// here because it's a simpler interface for students to implement.
///
/// Also, it's a good excuse to try out using impl trait.
pub struct Fizzy<T>(std::marker::PhantomData<T>);

impl<T> Fizzy<T> {
    pub fn new() -> Self {
        unimplemented!()
    }

    // feel free to change the signature to `mut self` if you like
    pub fn add_matcher(self, _matcher: Matcher<T>) -> Self {
        unimplemented!()
    }

    /// map this fizzy onto every element of an iterator, returning a new iterator
    pub fn apply<I>(self, _iter: I) -> impl Iterator<Item = String> {
        // unimplemented!() doesn't actually work, here; () is not an Iterator
        // that said, this is probably not the actual implementation you desire
        Vec::new().into_iter()
    }
}

/// convenience function: return a Fizzy which applies the standard fizz-buzz rules
pub fn fizz_buzz<T>() -> Fizzy<T> {
    unimplemented!()
}
<|endoftext|>


<commit_before>pub type Value = i32;
pub type ForthResult = Result<(), Error>;

pub struct Forth;

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

impl Forth {
    pub fn new() -> Forth {
        unimplemented!()
    }

    pub fn stack(&self) -> Vec<Value> {
        unimplemented!()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        unimplemented!("result of evaluating '{}'", input)
    }
}
<commit_msg>forth: Change stack return type to slice (#1032)<commit_after>pub type Value = i32;
pub type ForthResult = Result<(), Error>;

pub struct Forth;

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

impl Forth {
    pub fn new() -> Forth {
        unimplemented!()
    }

    pub fn stack(&self) -> &[Value] {
        unimplemented!()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        unimplemented!("result of evaluating '{}'", input)
    }
}
<|endoftext|>


<commit_before>pub mod header;
pub mod constants;
pub mod fat;
pub mod utils;
//pub mod section;
//pub mod load_command;
//pub mod symbol;

use std::path::Path;
use std::fs::File;
use std::io;
//use std::io::Read;
//use std::io::Seek;
//use std::io::SeekFrom::Start;

#[derive(Debug)]
pub struct Mach {
    pub header: header::Header,
}

impl Mach {
    fn get_header(mut fd: File, offset: u64, size: usize, path_str: &::std::ffi::OsStr) -> io::Result<Mach> {
        if size < header::SIZEOF_MACH_HEADER as usize {
            let error = io::Error::new(io::ErrorKind::Other, format!("{:?} size is smaller than an Mach-o header", path_str));
            Err(error)
        } else {
            let header = try!(header::Header::from_fd(&mut fd, offset));
            Ok(Mach {
                header: header,
            })
        }
    }

    pub fn from_path<'a>(path: &Path) -> io::Result<Mach> {
        let mut fd = try!(File::open(&path));
        let metadata = fd.metadata().unwrap();

        let size = metadata.len();
        let path_str = path.as_os_str();

        if size < 4 {
            let error = io::Error::new(io::ErrorKind::Other, format!("{:?} size is smaller than a magical number", path_str));
            return Err(error);
        }
        let magic = try!(utils::peek_magic(&mut fd));
        match magic {
            fat::FAT_CIGAM => {
                let arches = try!(fat::FatArch::from_path(path));
                println!("{:?}", arches);
                if let Some(arch) = fat::FatArch::find_cputype(&arches, constants::cputype::CPU_TYPE_X86_64) {
                    Self::get_header(fd, arch.offset as u64, arch.size as usize, path_str)
                } else {
                    let error = io::Error::new(io::ErrorKind::Other, format!("{:?} does not contain an x86_64 binary", path_str));
                    Err(error)
                }
            },
            header::MH_CIGAM_64 | header::MH_MAGIC_64 => {
                Self::get_header(fd, 0, size as usize, path_str)
            },
            magic => {
                let error = io::Error::new(io::ErrorKind::Other, format!("{:?} unknown magic number: 0x{:x}", path_str, magic));
                Err(error)
            }
        }
    }
}
<commit_msg>mach: use find_64 instead of finding specific x86_64<commit_after>pub mod header;
pub mod constants;
pub mod fat;
pub mod utils;
//pub mod section;
//pub mod load_command;
//pub mod symbol;

use std::path::Path;
use std::fs::File;
use std::io;
//use std::io::Read;
//use std::io::Seek;
//use std::io::SeekFrom::Start;

#[derive(Debug)]
pub struct Mach {
    pub header: header::Header,
}

impl Mach {
    fn get_header(mut fd: File, offset: u64, size: usize, path_str: &::std::ffi::OsStr) -> io::Result<Mach> {
        if size < header::SIZEOF_MACH_HEADER as usize {
            let error = io::Error::new(io::ErrorKind::Other, format!("{:?} size is smaller than an Mach-o header", path_str));
            Err(error)
        } else {
            let header = try!(header::Header::from_fd(&mut fd, offset));
            Ok(Mach {
                header: header,
            })
        }
    }

    pub fn from_path<'a>(path: &Path) -> io::Result<Mach> {
        let mut fd = try!(File::open(&path));
        let metadata = fd.metadata().unwrap();

        let size = metadata.len();
        let path_str = path.as_os_str();

        if size < 4 {
            let error = io::Error::new(io::ErrorKind::Other, format!("{:?} size is smaller than a magical number", path_str));
            return Err(error);
        }
        let magic = try!(utils::peek_magic(&mut fd));
        match magic {
            fat::FAT_CIGAM => {
                let arches = try!(fat::FatArch::from_path(path));
                println!("{:?}", arches);
                if let Some(arch) = fat::FatArch::find_64(&arches) {
                    Self::get_header(fd, arch.offset as u64, arch.size as usize, path_str)
                } else {
                    let error = io::Error::new(io::ErrorKind::Other, format!("{:?} does not contain an x86_64 binary", path_str));
                    Err(error)
                }
            },
            header::MH_CIGAM_64 | header::MH_MAGIC_64 => {
                Self::get_header(fd, 0, size as usize, path_str)
            },
            magic => {
                let error = io::Error::new(io::ErrorKind::Other, format!("{:?} unknown magic number: 0x{:x}", path_str, magic));
                Err(error)
            }
        }
    }
}
<|endoftext|>


<commit_before>#[allow(unused_imports)]
use std::cmp::*;

extern crate num_cpus;
extern crate crossbeam;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

#[derive(PartialEq)]
struct ScoredChoice {
    idx: usize,
    score: f64,
}

impl PartialOrd for ScoredChoice {
    fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
        if other.score == self.score {
            // We fall back to an array index comparison in order to guarantee a stable sort;
            // otherwise the matches may be displayed in a nondeterministic order.
            Some(self.idx.cmp(&other.idx))
        } else {
            other.score.partial_cmp(&self.score)
        }
    }
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    if choices.len() > 100 {
        compute_matches_multi_threaded(choices, query, filter_only)
    } else {
        compute_matches_single_threaded(choices, query, filter_only)
    }
}

pub fn compute_matches_single_threaded<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    let mut ret = Vec::new();
    for (i, choice) in choices.iter().enumerate() {
        let score = if filter_only { filter(choice, query) } else { score(choice, query) };
        if score > 0_f64 {
            ret.push(ScoredChoice{ idx: i, score: score });
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

pub fn compute_matches_multi_threaded<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    use std::sync::mpsc::channel;
    let (tx, rx) = channel();
    let workers = num_cpus::get();
    crossbeam::scope(|scope| {
        for current_worker in 0..workers {
            let tx = tx.clone();
            scope.spawn(move || {
                let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
                for i in lower_bound..upper_bound {
                    let score = if filter_only { filter(choices[i], query) } else { score(choices[i], query) };
                    tx.send(ScoredChoice{ idx: i, score: score }).unwrap()
                }
            });
        }
    });

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

fn score(choice: &str, query: &str) -> f64 {
    if query.is_empty() {
        return 1.0;
    }
    if choice.is_empty() {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            score as f64 / choice.len() as f64
        }
    }
}

fn filter(choice: &str, query: &str) -> f64 {
    if query.is_empty() {
        return 1.0;
    }
    if choice.is_empty() {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => 0.0,
        Some(_) => 1.0,
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.is_empty() || choice.is_empty() {
        return Vec::new();
    }
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(choice, query).unwrap();
    get_match_indices(choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    indices
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    q == c || *q == c.to_ascii_lowercase()
}

#[cfg(test)]
mod tests {
    use super::{chars_equal, find_end_of_match, get_match_indices, get_slice_indices, score};

    #[test]
    fn chars_equal_test() {
        assert!(chars_equal(&'a', &'a'));
        assert!(!chars_equal(&'a', &'b'));
        assert!(chars_equal(&'A', &'A'));
        assert!(!chars_equal(&'A', &'a'));
        assert!(chars_equal(&'a', &'A'));
    }

    #[test]
    fn get_match_indices_test() {
        assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
        assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
        assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
    }

    #[test]
    fn find_end_of_match_test() {
        assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
        assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
        assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
        assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
        assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
        assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
        assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
    }

    #[test]
    fn unicode_boundary_handling_test() {
        score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
    }

    #[test]
    fn basic_scoring() {
        assert_eq!(score("", "a"), 0.0);
        assert_eq!(score("a", ""), 1.0);
        assert_eq!(score("short", "longer"), 0.0);
        assert_eq!(score("a", "b"), 0.0);
        assert_eq!(score("ab", "ac"), 0.0);

        assert!(score("a", "a") > 0.0);
        assert!(score("ab", "a") > 0.0);
        assert!(score("ba", "a") > 0.0);
        assert!(score("bab", "a") > 0.0);
        assert!(score("babababab", "aaaa") > 0.0);

        assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
        assert_eq!(score("ab", "ab"), 0.5);
        assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
        assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
    }

    #[test]
    fn character_matching() {
        assert!(score("/! symbols $^", "/!$^") > 0.0);

        assert_eq!(score("a", "A"), 0.0);
        assert_eq!(score("A", "a"), 1.0);
        assert_eq!(score("A", "A"), 1.0);

        assert_eq!(score("a", "aa"), 0.0);
    }

    #[test]
    fn match_equality() {
        assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
        assert!(score("README.md", "em") > score("benchmark.rb", "em"));
        assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

        assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
        assert!(score("foo", "foo") > score("longer foo", "foo"));
        assert!(score("foo", "foo") > score("foo longer", "foo"));
        assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

        assert!(score("long 12 long", "12") > score("1 long 2", "12"));

        assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
        assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
    }

    #[test]
    fn get_slice_indices_test() {
        assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

        assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
        assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

        assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
        assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
        assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

        assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
        assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
        assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
        assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

        assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
        assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

        assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
        assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
    }
}
<commit_msg>Remove unused compiler directive<commit_after>use std::cmp::*;

extern crate num_cpus;
extern crate crossbeam;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

#[derive(PartialEq)]
struct ScoredChoice {
    idx: usize,
    score: f64,
}

impl PartialOrd for ScoredChoice {
    fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
        if other.score == self.score {
            // We fall back to an array index comparison in order to guarantee a stable sort;
            // otherwise the matches may be displayed in a nondeterministic order.
            Some(self.idx.cmp(&other.idx))
        } else {
            other.score.partial_cmp(&self.score)
        }
    }
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    if choices.len() > 100 {
        compute_matches_multi_threaded(choices, query, filter_only)
    } else {
        compute_matches_single_threaded(choices, query, filter_only)
    }
}

pub fn compute_matches_single_threaded<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    let mut ret = Vec::new();
    for (i, choice) in choices.iter().enumerate() {
        let score = if filter_only { filter(choice, query) } else { score(choice, query) };
        if score > 0_f64 {
            ret.push(ScoredChoice{ idx: i, score: score });
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

pub fn compute_matches_multi_threaded<'a>(choices: &[&'a str], query: &str, filter_only: bool) -> Vec<&'a str> {
    use std::sync::mpsc::channel;
    let (tx, rx) = channel();
    let workers = num_cpus::get();
    crossbeam::scope(|scope| {
        for current_worker in 0..workers {
            let tx = tx.clone();
            scope.spawn(move || {
                let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
                for i in lower_bound..upper_bound {
                    let score = if filter_only { filter(choices[i], query) } else { score(choices[i], query) };
                    tx.send(ScoredChoice{ idx: i, score: score }).unwrap()
                }
            });
        }
    });

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

fn score(choice: &str, query: &str) -> f64 {
    if query.is_empty() {
        return 1.0;
    }
    if choice.is_empty() {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            score as f64 / choice.len() as f64
        }
    }
}

fn filter(choice: &str, query: &str) -> f64 {
    if query.is_empty() {
        return 1.0;
    }
    if choice.is_empty() {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => 0.0,
        Some(_) => 1.0,
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.is_empty() || choice.is_empty() {
        return Vec::new();
    }
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(choice, query).unwrap();
    get_match_indices(choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    indices
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    q == c || *q == c.to_ascii_lowercase()
}

#[cfg(test)]
mod tests {
    use super::{chars_equal, find_end_of_match, get_match_indices, get_slice_indices, score};

    #[test]
    fn chars_equal_test() {
        assert!(chars_equal(&'a', &'a'));
        assert!(!chars_equal(&'a', &'b'));
        assert!(chars_equal(&'A', &'A'));
        assert!(!chars_equal(&'A', &'a'));
        assert!(chars_equal(&'a', &'A'));
    }

    #[test]
    fn get_match_indices_test() {
        assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
        assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
        assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
    }

    #[test]
    fn find_end_of_match_test() {
        assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
        assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
        assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
        assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
        assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
        assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
        assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
    }

    #[test]
    fn unicode_boundary_handling_test() {
        score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
    }

    #[test]
    fn basic_scoring() {
        assert_eq!(score("", "a"), 0.0);
        assert_eq!(score("a", ""), 1.0);
        assert_eq!(score("short", "longer"), 0.0);
        assert_eq!(score("a", "b"), 0.0);
        assert_eq!(score("ab", "ac"), 0.0);

        assert!(score("a", "a") > 0.0);
        assert!(score("ab", "a") > 0.0);
        assert!(score("ba", "a") > 0.0);
        assert!(score("bab", "a") > 0.0);
        assert!(score("babababab", "aaaa") > 0.0);

        assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
        assert_eq!(score("ab", "ab"), 0.5);
        assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
        assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
    }

    #[test]
    fn character_matching() {
        assert!(score("/! symbols $^", "/!$^") > 0.0);

        assert_eq!(score("a", "A"), 0.0);
        assert_eq!(score("A", "a"), 1.0);
        assert_eq!(score("A", "A"), 1.0);

        assert_eq!(score("a", "aa"), 0.0);
    }

    #[test]
    fn match_equality() {
        assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
        assert!(score("README.md", "em") > score("benchmark.rb", "em"));
        assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

        assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
        assert!(score("foo", "foo") > score("longer foo", "foo"));
        assert!(score("foo", "foo") > score("foo longer", "foo"));
        assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

        assert!(score("long 12 long", "12") > score("1 long 2", "12"));

        assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
        assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
    }

    #[test]
    fn get_slice_indices_test() {
        assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

        assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
        assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

        assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
        assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
        assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

        assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
        assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
        assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
        assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

        assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
        assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

        assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
        assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::cmp::min;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &[char], chars: &[char]) -> Option<usize> {
    let first_char = chars[0];
    let rest = &chars[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_min = None;
    let smallest_possible_match = chars.len();
    for i in indices.iter() {
        let last_index = find_end_of_match(string, rest, *i);
        if last_index.is_some() {
            let idx = last_index.unwrap() - *i + 1;
            if current_min.is_some() {
                let cm = min(current_min.unwrap(), idx);
                current_min = Some(cm);
                if cm == smallest_possible_match {
                    break;
                }
            } else {
                current_min = Some(idx)
            }
        }
    }
    return current_min;
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if char == *c {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if x == c {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
        } else {
            return None;
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Rewrite compute_match_length<commit_after>use std::ascii::AsciiExt;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some((ub - lb + 1))
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if char == *c {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if x == c {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
        } else {
            return None;
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>use meta::Meta;
use serialization;
use has_meta::HasMeta;
use object_header::ObjectHeader;
use error::GitError;
use object_id::ObjectId;

#[deriving(PartialEq, Show)]
pub struct Blob {
    pub meta: Meta,
    pub size: uint,
    pub contents: Vec<u8>,
}

impl HasMeta for Blob {
    fn get_meta(&self) -> &Meta {
        &self.meta
    }
}

pub fn encode(blob: &Blob) -> Vec<u8> {
    serialization::encode(blob, blob.contents.as_slice())
}

pub fn decode(bytes: &[u8]) -> Result<Blob, GitError> {
    let (data, header) = serialization::decode(bytes);
    decode_body(data, &header)
}

fn decode_body(bytes: &[u8], header: &ObjectHeader) -> Result<Blob, GitError> {
    Ok(Blob {
        meta: Meta {
            id: ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741140"),
            header: *header,
        },
        size: bytes.len(),
        contents: bytes.into_vec(),
    })
}<commit_msg>Implement a function for finding blobs<commit_after>use meta::Meta;
use serialization;
use has_meta::HasMeta;
use object_header::ObjectHeader;
use error::GitError;
use error::NotFound;
use object_id::ObjectId;
use repository::Repository;
use object_database;
use eobject::EBlob;

#[deriving(PartialEq, Show)]
pub struct Blob {
    pub meta: Meta,
    pub size: uint,
    pub contents: Vec<u8>,
}

impl HasMeta for Blob {
    fn get_meta(&self) -> &Meta {
        &self.meta
    }
}

pub fn encode(blob: &Blob) -> Vec<u8> {
    serialization::encode(blob, blob.contents.as_slice())
}

pub fn decode(bytes: &[u8]) -> Result<Blob, GitError> {
    let (data, header) = serialization::decode(bytes);
    decode_body(data, &header)
}

pub fn decode_body(bytes: &[u8], header: &ObjectHeader) -> Result<Blob, GitError> {
    Ok(Blob {
        meta: Meta {
            id: ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741140"),
            header: *header,
        },
        size: bytes.len(),
        contents: bytes.into_vec(),
    })
}

pub fn find(id: &ObjectId, repository: &Repository) -> Result<Blob, GitError> {
    match object_database::find_object_by_id(repository, id) {
        Ok(box EBlob(c)) => Ok(c),
        Err(e) => Err(e),
        _ => Err(NotFound),
    }
}<|endoftext|>