<commit_before>#![feature(convert)]
#![feature(plugin,test)]
#![plugin(quickcheck_macros)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate test;

use std::collections::HashMap;
use yak_client::YakError;

use std::env;

use yak_client::Client;
use test::Bencher;

pub fn open_from_env(env_var: &str, name: &str) -> Client {
  let yak_url = env::var(env_var).ok()
    .expect(format!("env var {} not found", env_var).as_str());
  let full_url = format!("{}-{}", yak_url, name);
  Client::connect(&full_url).unwrap()
}

pub fn open_client(name: &str) -> (Client, Client) {
  let head = open_from_env("YAK_HEAD", name);
  let tail = open_from_env("YAK_TAIL", name);
  (head, tail)
}

#[bench]
fn bench_simple_write(b: &mut Bencher) {
  env_logger::init().unwrap_or(());

  let (mut head, mut tail) = open_client("bench_simple_put");
  head.truncate().unwrap();
  let key = "foo";
  let val = "bar";

  b.iter(|| head.write(key.as_bytes(), val.as_bytes()).unwrap());
}

#[bench]
fn bench_simple_read(b: &mut Bencher) {
  env_logger::init().unwrap_or(());

  let (mut head, mut tail) = open_client("bench_simple_put");
  head.truncate().unwrap();
  let key = "foo";
  let val = "bar";
  head.write(key.as_bytes(), val.as_bytes()).unwrap();

  b.iter(|| tail.read(key.as_bytes()).unwrap());
}
<commit_msg>Get Benches working on nightly again.<commit_after>#![feature(convert)]
#![feature(plugin,test)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate test;

use std::collections::HashMap;
use yak_client::YakError;

use std::env;

use yak_client::Client;
use test::Bencher;

pub fn open_from_env(env_var: &str, name: &str) -> Client {
  let yak_url = env::var(env_var).ok()
    .expect(format!("env var {} not found", env_var).as_str());
  let full_url = format!("{}-{}", yak_url, name);
  Client::connect(&full_url).unwrap()
}

pub fn open_client(name: &str) -> (Client, Client) {
  let head = open_from_env("YAK_HEAD", name);
  let tail = open_from_env("YAK_TAIL", name);
  (head, tail)
}

#[bench]
fn bench_simple_write(b: &mut Bencher) {
  env_logger::init().unwrap_or(());

  let (mut head, mut tail) = open_client("bench_simple_put");
  head.truncate().unwrap();
  let key = "foo";
  let val = "bar";

  b.iter(|| head.write(key.as_bytes(), val.as_bytes()).unwrap());
}

#[bench]
fn bench_simple_read(b: &mut Bencher) {
  env_logger::init().unwrap_or(());

  let (mut head, mut tail) = open_client("bench_simple_put");
  head.truncate().unwrap();
  let key = "foo";
  let val = "bar";
  head.write(key.as_bytes(), val.as_bytes()).unwrap();

  b.iter(|| tail.read(key.as_bytes()).unwrap());
}
<|endoftext|>


<commit_before>use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::ty::TyCtxt;
use rustc_index::vec::Idx;
use std::fmt::Debug;
use std::io::{self, Write};

use super::pretty::dump_mir_def_ids;

/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<W>(
    tcx: TyCtxt<'_>,
    single: Option<DefId>,
    w: &mut W,
) -> io::Result<()>
where
    W: Write,
{
    let def_ids = dump_mir_def_ids(tcx, single);

    let use_subgraphs = def_ids.len() > 1;
    if use_subgraphs {
        writeln!(w, "digraph __crate__ {{")?;
    }

    for def_id in def_ids {
        let body = &tcx.optimized_mir(def_id);
        write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
    }

    if use_subgraphs {
        writeln!(w, "}}")?;
    }

    Ok(())
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!(
        "{}_{}",
        def_id.krate.index(),
        def_id.index.index(),
    )
}

/// Write a graphviz DOT graph of the MIR.
pub fn write_mir_fn_graphviz<'tcx, W>(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
    body: &Body<'_>,
    subgraph: bool,
    w: &mut W,
) -> io::Result<()>
where
    W: Write,
{
    let kind = if subgraph { "subgraph" } else { "digraph" };
    let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR
    let def_name = graphviz_safe_def_name(def_id);
    writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?;

    // Global graph properties
    writeln!(w, r#"    graph [fontname="monospace"];"#)?;
    writeln!(w, r#"    node [fontname="monospace"];"#)?;
    writeln!(w, r#"    edge [fontname="monospace"];"#)?;

    // Graph label
    write_graph_label(tcx, def_id, body, w)?;

    // Nodes
    for (block, _) in body.basic_blocks().iter_enumerated() {
        write_node(def_id, block, body, w)?;
    }

    // Edges
    for (source, _) in body.basic_blocks().iter_enumerated() {
        write_edges(def_id, source, body, w)?;
    }
    writeln!(w, "}}")
}

/// Write a graphviz HTML-styled label for the given basic block, with
/// all necessary escaping already performed. (This is suitable for
/// emitting directly, as is done in this module, or for use with the
/// LabelText::HtmlStr from libgraphviz.)
///
/// `init` and `fini` are callbacks for emitting additional rows of
/// data (using HTML enclosed with `<tr>` in the emitted text).
pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
                                              body: &Body<'_>,
                                              w: &mut W,
                                              num_cols: u32,
                                              init: INIT,
                                              fini: FINI) -> io::Result<()>
    where INIT: Fn(&mut W) -> io::Result<()>,
          FINI: Fn(&mut W) -> io::Result<()>
{
    let data = &body[block];

    write!(w, r#"
"#)?;

    // Basic block number at the top.
    write!(w, r#"
{blk}
"#,
           attrs=r#"bgcolor="gray" align="center""#,
           colspan=num_cols,
           blk=block.index())?;

    init(w)?;

    // List of statements in the middle.
    if !data.statements.is_empty() {
        write!(w, r#"
"#)?;
        for statement in &data.statements {
            write!(w, "{}
", escape(statement))?;
        }
        write!(w, "
")?;
    }

    // Terminator head at the bottom, not including the list of successor blocks. Those will be
    // displayed as labels on the edges between blocks.
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    write!(w, r#"
{}
"#, dot::escape_html(&terminator_head))?;

    fini(w)?;

    // Close the table
    write!(w, "
")
}

/// Write a graphviz DOT node for the given basic block.
fn write_node<W: Write>(
    def_id: DefId,
    block: BasicBlock,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
    write!(w, r#"    {} [shape="none", label=<"#, node(def_id, block))?;
    write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?;
    // Close the node label and the node itself.
    writeln!(w, ">];")
}

/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
fn write_edges<W: Write>(
    def_id: DefId,
    source: BasicBlock,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    let terminator = body[source].terminator();
    let labels = terminator.kind.fmt_successor_labels();

    for (&target, label) in terminator.successors().zip(labels) {
        let src = node(def_id, source);
        let trg = node(def_id, target);
        writeln!(w, r#"    {} -> {} [label="{}"];"#, src, trg, label)?;
    }

    Ok(())
}

/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
/// all the variables and temporaries.
fn write_graph_label<'tcx, W: Write>(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    write!(w, "    label=<fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;

    // fn argument types.
    for (i, arg) in body.args_iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w,
               "{:?}: {}",
               Place::from(arg),
               escape(&body.local_decls[arg].ty)
        )?;
    }

    write!(w, ") -> {}", escape(&body.return_ty()))?;
    write!(w, r#"
"#)?;

    for local in body.vars_and_temps_iter() {
        let decl = &body.local_decls[local];

        write!(w, "let ")?;
        if decl.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }

        write!(w, r#"{:?}: {};
"#,
               Place::from(local), escape(&decl.ty))?;
    }

    for var_debug_info in &body.var_debug_info {
        write!(w, r#"debug {} => {};
"#,
               var_debug_info.name, escape(&var_debug_info.place))?;
    }

    writeln!(w, ">;")
}

fn node(def_id: DefId, block: BasicBlock) -> String {
    format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
}

fn escape<T: Debug>(t: &T) -> String {
    dot::escape_html(&format!("{:?}", t))
}
<commit_msg>Rollup merge of #66988 - osa1:issue66985, r=matthewjasper<commit_after>use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::ty::TyCtxt;
use rustc_index::vec::Idx;
use std::fmt::Debug;
use std::io::{self, Write};

use super::pretty::dump_mir_def_ids;

/// Write a graphviz DOT graph of a list of MIRs.
pub fn write_mir_graphviz<W>(
    tcx: TyCtxt<'_>,
    single: Option<DefId>,
    w: &mut W,
) -> io::Result<()>
where
    W: Write,
{
    let def_ids = dump_mir_def_ids(tcx, single);

    let use_subgraphs = def_ids.len() > 1;
    if use_subgraphs {
        writeln!(w, "digraph __crate__ {{")?;
    }

    for def_id in def_ids {
        let body = &tcx.optimized_mir(def_id);
        write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
    }

    if use_subgraphs {
        writeln!(w, "}}")?;
    }

    Ok(())
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!(
        "{}_{}",
        def_id.krate.index(),
        def_id.index.index(),
    )
}

/// Write a graphviz DOT graph of the MIR.
pub fn write_mir_fn_graphviz<'tcx, W>(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
    body: &Body<'_>,
    subgraph: bool,
    w: &mut W,
) -> io::Result<()>
where
    W: Write,
{
    let kind = if subgraph { "subgraph" } else { "digraph" };
    let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR
    let def_name = graphviz_safe_def_name(def_id);
    writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?;

    // Global graph properties
    writeln!(w, r#"    graph [fontname="monospace"];"#)?;
    writeln!(w, r#"    node [fontname="monospace"];"#)?;
    writeln!(w, r#"    edge [fontname="monospace"];"#)?;

    // Graph label
    write_graph_label(tcx, def_id, body, w)?;

    // Nodes
    for (block, _) in body.basic_blocks().iter_enumerated() {
        write_node(def_id, block, body, w)?;
    }

    // Edges
    for (source, _) in body.basic_blocks().iter_enumerated() {
        write_edges(def_id, source, body, w)?;
    }
    writeln!(w, "}}")
}

/// Write a graphviz HTML-styled label for the given basic block, with
/// all necessary escaping already performed. (This is suitable for
/// emitting directly, as is done in this module, or for use with the
/// LabelText::HtmlStr from libgraphviz.)
///
/// `init` and `fini` are callbacks for emitting additional rows of
/// data (using HTML enclosed with `<tr>` in the emitted text).
pub fn write_node_label<W: Write, INIT, FINI>(block: BasicBlock,
                                              body: &Body<'_>,
                                              w: &mut W,
                                              num_cols: u32,
                                              init: INIT,
                                              fini: FINI) -> io::Result<()>
    where INIT: Fn(&mut W) -> io::Result<()>,
          FINI: Fn(&mut W) -> io::Result<()>
{
    let data = &body[block];

    write!(w, r#"
"#)?;

    // Basic block number at the top.
    write!(w, r#"
{blk}
"#,
           attrs=r#"bgcolor="gray" align="center""#,
           colspan=num_cols,
           blk=block.index())?;

    init(w)?;

    // List of statements in the middle.
    if !data.statements.is_empty() {
        write!(w, r#"
"#)?;
        for statement in &data.statements {
            write!(w, "{}
", escape(statement))?;
        }
        write!(w, "
")?;
    }

    // Terminator head at the bottom, not including the list of successor blocks. Those will be
    // displayed as labels on the edges between blocks.
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    write!(w, r#"
{}
"#, dot::escape_html(&terminator_head))?;

    fini(w)?;

    // Close the table
    write!(w, "
")
}

/// Write a graphviz DOT node for the given basic block.
fn write_node<W: Write>(
    def_id: DefId,
    block: BasicBlock,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
    write!(w, r#"    {} [shape="none", label=<"#, node(def_id, block))?;
    write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?;
    // Close the node label and the node itself.
    writeln!(w, ">];")
}

/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
fn write_edges<W: Write>(
    def_id: DefId,
    source: BasicBlock,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    let terminator = body[source].terminator();
    let labels = terminator.kind.fmt_successor_labels();

    for (&target, label) in terminator.successors().zip(labels) {
        let src = node(def_id, source);
        let trg = node(def_id, target);
        writeln!(w, r#"    {} -> {} [label="{}"];"#, src, trg, label)?;
    }

    Ok(())
}

/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
/// all the variables and temporaries.
fn write_graph_label<'tcx, W: Write>(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
    body: &Body<'_>,
    w: &mut W,
) -> io::Result<()> {
    write!(w, "    label=<fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;

    // fn argument types.
    for (i, arg) in body.args_iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w,
               "{:?}: {}",
               Place::from(arg),
               escape(&body.local_decls[arg].ty)
        )?;
    }

    write!(w, ") -> {}", escape(&body.return_ty()))?;
    write!(w, r#"
"#)?;

    for local in body.vars_and_temps_iter() {
        let decl = &body.local_decls[local];

        write!(w, "let ")?;
        if decl.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }

        write!(w, r#"{:?}: {};
"#,
               Place::from(local), escape(&decl.ty))?;
    }

    for var_debug_info in &body.var_debug_info {
        write!(w, r#"debug {} => {};
"#,
               var_debug_info.name, escape(&var_debug_info.place))?;
    }

    writeln!(w, ">;")
}

fn node(def_id: DefId, block: BasicBlock) -> String {
    format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
}

fn escape<T: Debug>(t: &T) -> String {
    dot::escape_html(&format!("{:?}", t))
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::sync::Arc;

use buffer::sys::UnsafeBuffer;
use command_buffer::states_manager::StatesManager;
use device::Queue;
use memory::Content;

use sync::AccessFlagBits;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

/// Trait for objects that represent either a buffer or a slice of a buffer.
pub unsafe trait Buffer {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }
}

#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    pub buffer: &'a UnsafeBuffer,
    pub offset: usize
}

unsafe impl<'a, B: ?Sized> Buffer for &'a B where B: Buffer + 'a {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }
}

unsafe impl<B: ?Sized> Buffer for Arc<B> where B: Buffer {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }
}

/// Extension trait for `Buffer`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedBuffer<States = StatesManager>: Buffer {
    /// Returns a new state that corresponds to the moment after a slice of the buffer has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    // TODO: what should be the behavior if `num_command` is equal to the `num_command` of a
    // previous transition?
    fn transition(&self, states: &mut States, num_command: usize, offset: usize, size: usize,
                  write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(&self, in_s: &mut States, out: &mut States) -> Option<PipelineBarrierRequest>;

    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<F>(&self, states: &States, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>;
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the buffer hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region. There is literaly no reason to pass `false`
    /// here, but it is included just in case.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the buffer that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    /// Offset of start of the range to flush.
    pub offset: isize,
    /// Size of the range to flush.
    pub size: usize,
    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Arc<Semaphore>, PipelineStages)>,
    pub post_semaphore: Option<Arc<Semaphore>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

unsafe impl<B:? Sized, S> TrackedBuffer<S> for Arc<B> where B: TrackedBuffer<S> {
    #[inline]
    fn transition(&self, states: &mut S, num_command: usize, offset: usize,
                  size: usize, write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>
    {
        (**self).transition(states, num_command, offset, size, write, stage, access)
    }

    #[inline]
    fn finish(&self, i: &mut S, o: &mut S) -> Option<PipelineBarrierRequest> {
        (**self).finish(i, o)
    }

    #[inline]
    fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>
    {
        (**self).on_submit(states, queue, fence)
    }
}

unsafe impl<'a, B: ?Sized, S> TrackedBuffer<S> for &'a B where B: TrackedBuffer<S> + 'a {
    #[inline]
    fn transition(&self, states: &mut S, num_command: usize, offset: usize,
                  size: usize, write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>
    {
        (**self).transition(states, num_command, offset, size, write, stage, access)
    }

    #[inline]
    fn finish(&self, i: &mut S, o: &mut S) -> Option<PipelineBarrierRequest> {
        (**self).finish(i, o)
    }

    #[inline]
    fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>
    {
        (**self).on_submit(states, queue, fence)
    }
}

pub unsafe trait TypedBuffer: Buffer {
    type Content: ?Sized + 'static;

    #[inline]
    fn len(&self) -> usize where Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }
}
<commit_msg>Add some methods to Buffer<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::sync::Arc;

use buffer::BufferSlice;
use buffer::sys::UnsafeBuffer;
use command_buffer::states_manager::StatesManager;
use device::Queue;
use memory::Content;

use sync::AccessFlagBits;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

/// Trait for objects that represent either a buffer or a slice of a buffer.
pub unsafe trait Buffer {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }

    #[inline]
    fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self> where Self: Sized + TypedBuffer {
        BufferSlice::from(self)
    }

    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self> where Self: Sized + TypedBuffer {
        BufferSlice::from(self)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    pub buffer: &'a UnsafeBuffer,
    pub offset: usize
}

unsafe impl<'a, B: ?Sized> Buffer for &'a B where B: Buffer + 'a {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }
}

unsafe impl<B: ?Sized> Buffer for Arc<B> where B: Buffer {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }
}

/// Extension trait for `Buffer`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedBuffer<States = StatesManager>: Buffer {
    /// Returns a new state that corresponds to the moment after a slice of the buffer has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    // TODO: what should be the behavior if `num_command` is equal to the `num_command` of a
    // previous transition?
    fn transition(&self, states: &mut States, num_command: usize, offset: usize, size: usize,
                  write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(&self, in_s: &mut States, out: &mut States) -> Option<PipelineBarrierRequest>;

    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<F>(&self, states: &States, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>;
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the buffer hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region. There is literaly no reason to pass `false`
    /// here, but it is included just in case.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the buffer that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    /// Offset of start of the range to flush.
    pub offset: isize,
    /// Size of the range to flush.
    pub size: usize,
    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Arc<Semaphore>, PipelineStages)>,
    pub post_semaphore: Option<Arc<Semaphore>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

unsafe impl<B:? Sized, S> TrackedBuffer<S> for Arc<B> where B: TrackedBuffer<S> {
    #[inline]
    fn transition(&self, states: &mut S, num_command: usize, offset: usize,
                  size: usize, write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>
    {
        (**self).transition(states, num_command, offset, size, write, stage, access)
    }

    #[inline]
    fn finish(&self, i: &mut S, o: &mut S) -> Option<PipelineBarrierRequest> {
        (**self).finish(i, o)
    }

    #[inline]
    fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>
    {
        (**self).on_submit(states, queue, fence)
    }
}

unsafe impl<'a, B: ?Sized, S> TrackedBuffer<S> for &'a B where B: TrackedBuffer<S> + 'a {
    #[inline]
    fn transition(&self, states: &mut S, num_command: usize, offset: usize,
                  size: usize, write: bool, stage: PipelineStages, access: AccessFlagBits)
                  -> Option<PipelineBarrierRequest>
    {
        (**self).transition(states, num_command, offset, size, write, stage, access)
    }

    #[inline]
    fn finish(&self, i: &mut S, o: &mut S) -> Option<PipelineBarrierRequest> {
        (**self).finish(i, o)
    }

    #[inline]
    fn on_submit<F>(&self, states: &S, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>
    {
        (**self).on_submit(states, queue, fence)
    }
}

pub unsafe trait TypedBuffer: Buffer {
    type Content: ?Sized + 'static;

    #[inline]
    fn len(&self) -> usize where Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }
}

unsafe impl<B: ?Sized> TypedBuffer for Arc<B> where B: TypedBuffer {
    type Content = B::Content;
}

unsafe impl<'a, B: ?Sized + 'a> TypedBuffer for &'a B where B: TypedBuffer {
    type Content = B::Content;
}
<|endoftext|>


<commit_before>// Code from The Rust Project (https://github.com/rust-lang/rust)
//
// https://github.com/rust-lang/rust/blob/master/src/bootstrap/sanity.rs
//
// The Rust Project is dual-licensed under Apache 2.0 and MIT terms.

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;

pub struct CommandFinder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl CommandFinder {
    pub fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default(),
        }
    }

    pub fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(&path) {
                    let target = path.join(&cmd);
                    let mut cmd_alt = cmd.clone();
                    cmd_alt.push(".exe");
                    if target.is_file() || // some/path/git
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists()
                    {
                        // some/path/git/git.exe
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}
<commit_msg>Make cmd_finder.rs not to follow symbolic link to test if python is installed. (#112)<commit_after>// Code from The Rust Project (https://github.com/rust-lang/rust)
//
// https://github.com/rust-lang/rust/blob/master/src/bootstrap/sanity.rs
//
// The Rust Project is dual-licensed under Apache 2.0 and MIT terms.

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;

pub struct CommandFinder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl CommandFinder {
    pub fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default(),
        }
    }

    pub fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(&path) {
                    let target = path.join(&cmd);
                    let mut cmd_alt = cmd.clone();
                    cmd_alt.push(".exe");
                    let mut symlink_is_file = false;
                    if let Ok(metadata) = target.with_extension("exe").symlink_metadata() {
                        symlink_is_file = metadata.is_file()
                    }
                    if target.is_file() || // some/path/git
                symlink_is_file ||
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists()
                    {
                        // some/path/git/git.exe
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=180;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
							if extra_time {
								break;
							}
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
				}
				println!("Stopping jobs and waiting for cleanup");
				job_handle.stop_jobs();
				break;
			}
		}
	}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<commit_msg>adding lean_cuda and mean_gpu test<commit_after>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=180;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
							if extra_time {
								break;
							}
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
				}
				println!("Stopping jobs and waiting for cleanup");
				job_handle.stop_jobs();
				break;
			}
		}
	}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	mine_async_for_duration(plugin_path_vec, 180);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<|endoftext|>


<commit_before>use num::{PrimInt, Signed};
use num::traits::CheckedShr;
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// Otherwise, to avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed + CheckedShr> (coefficients: &mut [T], input: T)->Result <(),()> {
  if coefficients.len() <= 1 {return Ok(());}
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() <= 1 {return true;}
  let mut factor = T::one();
  let input = input.abs();
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  for (power, coefficient) in coefficients.iter().enumerate() {
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    if coefficient == &T::min_value() {return false;}
    match coefficient.abs().checked_mul (&factor) {
      None => return false,
      Some (term) => if term > running_maximum {return false;},
    }
    if power + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to; magnitudes > result aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->T {
  if coefficients.len() <= 1 || coefficients [1..].iter().all (| coefficient | coefficient == &T::zero()) {return T::max_value()}
  // if we know that there's at least one nonzero non-constant coefficient, T::max_value is never legal, so we can pick a min that definitely legal and a max that's definitely not
  let mut min = -T::one();
  let mut max = T::max_value();
  while min + T::one() < max {
    let mid = (min >> 1u32) + (max >> 1u32) + (min & max & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid;
    }
  }
  min
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to.
/// Magnitudes >= result*2 aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: &mut [T], maximum: MaximumFn)->T {
  if coefficients.len() <= 1 {return T::max_value()}
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    while magnitude > (running_maximum >> (result_shift*power)) {
      if result_shift == 0 {return -T::one();}
      result_shift -= 1;
    }
  }
  T::one() << result_shift
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }

  quickcheck! {
    fn exact_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range < 0 || safe_to_translate_polynomial_to (& coefficients, range, maxima)
    }

    fn exact_safe_translation_range_is_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range == i64::max_value() || !safe_to_translate_polynomial_to (& coefficients, range + 1, maxima)
    }
  }
}
<commit_msg>Wrote another test and fixed the compile error it detected<commit_after>use num::{PrimInt, Signed};
use num::traits::CheckedShr;
use std::mem;
use std::cmp::{min};

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn right_shift_nicely_rounded <T: PrimInt> (input: T, shift: usize)->T {
  let divisor = T::one() << shift;
  let mask = divisor - T::one();
  if (input & mask) << 1 == divisor {
    let shifted = input >> shift;
    shifted + (shifted & T::one())
  } else {
    (input + (divisor >> 1)) >> shift
  }
}

/// Approximately evaluate an integer polynomial at an input in the range [-0.5, 0.5].
///
/// The input is represented as an integer combined with a right-shift size.
/// Each coefficient, except the constant one, must obey coefficient.abs() <= T::max_value() >> shift.
/// The constant coefficient must obey coefficient.abs() <= T::max_value() - (T::max_value() >> shift),
/// i.e. be small enough that you can add one of the other coefficients to it without overflowing.
/// Given these conditions, the result is guaranteed to be strictly within 1 of the ideal result.
/// For instance, if the ideal result was 2.125, this function could return 2 or 3,
/// but if it was 2, this function can only return exactly 2.
pub fn evaluate_polynomial_at_small_input <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->T {
  let half = (T::one() << shift) >> 1;
  assert!(-half <= input && input <= half, "inputs to evaluate_polynomial_at_small_input must be in the range [-0.5, 0.5]");

  if coefficients.len () == 0 {return T::zero()}

  let mut result = T::zero();
  for coefficient in coefficients.iter().skip(1).rev() {
    result = right_shift_nicely_rounded ((result + (*coefficient).into())*input, shift);
  }
  result + coefficients [0].into()
}

/// Translate a polynomial horizontally, letting it take inputs relative to a given input instead of relative to 0.
///
/// This is equivalent to replacing its coefficients with its Taylor coefficients at the given input.
/// This is equivalent to translating the graph *left* by the given input amount.
///
/// For constant polynomials, this is a no-op.
///
/// Otherwise, to avoid overflow, each term, when evaluating at the given input,
/// must obey term.abs() <= T::max_value() >> (coefficients.len() - 1).
/// If this condition is broken, translate_polynomial() returns Err and makes no changes.
pub fn translate_polynomial <T: PrimInt + Signed + CheckedShr> (coefficients: &mut [T], input: T)->Result <(),()> {
  if coefficients.len() <= 1 {return Ok(());}
  if !safe_to_translate_polynomial_to (coefficients, input, |_| T::max_value()) {return Err (())}
  translate_polynomial_unchecked (coefficients, input) ;
  Ok (())
}

/// Same as translate_polynomial(), but assume no overflow will occur.
///
/// Useful in performance-critical code when you already know there won't be overflow,
/// such as in the range returned by conservative_safe_polynomial_translation_range.
pub fn translate_polynomial_unchecked <T: PrimInt + Signed> (coefficients: &mut [T], input: T) {
  coefficients.reverse();
  for index in 0..coefficients.len() {
    let coefficient = mem::replace (&mut coefficients [index], T::zero());
    for derivative in (1..(index + 1)).rev() {
      coefficients [derivative] = coefficients [derivative]*input + coefficients [derivative - 1]
    }
    coefficients [0] = coefficients [0]*input + coefficient
  }
}

pub fn safe_to_translate_polynomial_to <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], input: T, maximum: MaximumFn)->bool {
  if coefficients.len() <= 1 {return true;}
  let mut factor = T::one();
  let input = input.abs();
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  for (power, coefficient) in coefficients.iter().enumerate() {
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    if coefficient == &T::min_value() {return false;}
    match coefficient.abs().checked_mul (&factor) {
      None => return false,
      Some (term) => if term > running_maximum {return false;},
    }
    if power + 1 < coefficients.len() { match factor.checked_mul (&input) {
      None => return false,
      Some (next_factor) => factor = next_factor,
    }}
  }
  true
}

/// Find the range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to; magnitudes > result aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
pub fn exact_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: & [T], maximum: MaximumFn)->T {
  if coefficients.len() <= 1 || coefficients [1..].iter().all (| coefficient | coefficient == &T::zero()) {return T::max_value()}
  // if we know that there's at least one nonzero non-constant coefficient, T::max_value is never legal, so we can pick a min that definitely legal and a max that's definitely not
  let mut min = -T::one();
  let mut max = T::max_value();
  while min + T::one() < max {
    let mid = (min >> 1u32) + (max >> 1u32) + (min & max & T::one());
    if safe_to_translate_polynomial_to (coefficients, mid, & maximum) {
      min = mid;
    } else {
      max = mid;
    }
  }
  min
}

/// Find a range of inputs to which the polynomial can safely be translated.
///
/// Magnitudes <= result are safe to translate to.
/// Magnitudes >= result*2 aren't.
/// If even the initial value is out of bounds, this function returns -1.
///
/// The third argument can impose a stricter maximum on the resulting coefficients.
///
/// This function is much faster than exact_safe_polynomial_translation_range, at the cost of being less precise.
pub fn conservative_safe_polynomial_translation_range <T: PrimInt + Signed + CheckedShr, MaximumFn: Fn (usize)->T> (coefficients: &[T], maximum: MaximumFn)->T {
  if coefficients.len() <= 1 {return T::max_value()}
  let sum_safety_shift = coefficients.len() as u32 - 1;
  let mut running_maximum = T::max_value();
  let mut result_shift = mem::size_of::<T>()*8 - 2;
  for (power, coefficient) in coefficients.iter().enumerate() {
    let magnitude = coefficient.abs();
    running_maximum = min (running_maximum, maximum (power).checked_shr (sum_safety_shift).unwrap_or (T::zero()));
    while magnitude > (running_maximum >> (result_shift*power)) {
      if result_shift == 0 {return -T::one();}
      result_shift -= 1;
    }
  }
  T::one() << result_shift
}

#[cfg (test)]
mod tests {
  use super::*;
  use num::{Zero, One, FromPrimitive};
  use num::bigint::BigInt;
  use num::rational::{Ratio, BigRational};
  use rand::distributions::Distribution;
  use rand::distributions::range::{Range};
  use rand::{Rng, SeedableRng};

  fn evaluate_polynomial_exactly <Coefficient: Copy, T: PrimInt + Signed + From <Coefficient>> (coefficients: & [Coefficient], input: T, shift: usize)->BigRational
    where BigInt: From <Coefficient> + From <T> {
    let mut result: BigRational = Ratio::zero();
    let input = Ratio::new(BigInt::from (input), BigInt::one() << shift);
    for coefficient in coefficients.iter().rev() {
      result = result*&input + BigInt::from(*coefficient);
    }
    result
  }

  #[test]
  fn test_right_shift_nicely_rounded() {
    let inputs: Vec<(i64, usize, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(right_shift_nicely_rounded (input, shift), result);
      assert_eq!(right_shift_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_evaluate_polynomial_at_small_input() {
    let mut generator =::rand::chacha::ChaChaRng::from_seed ([33; 32]) ;
    for shift in 0..5 {
      let shift = 1 << shift;
      let half = 1i64 << (shift - 1);
      let maximum = i64::max_value() >> shift;
      let constant_maximum = i64::max_value() - maximum;
      let range = Range::new_inclusive (- maximum, maximum) ;
      let constant_range = Range::new_inclusive (- constant_maximum, constant_maximum);
      let mut test_inputs = vec![- half, - half + 1, - 1, 0, 1, half - 1, half];
      if half > 2 {for _ in 0..6 {test_inputs.push (generator.gen_range (- half + 2, half - 1));}}
      for _ in 0..40 {
        let mut coefficients = vec![constant_range.sample (&mut generator)];
        while generator.gen() {coefficients.push (range.sample (&mut generator));}
        for input in test_inputs.iter() {
          let result = evaluate_polynomial_at_small_input (& coefficients,*input, shift);

          let perfect_result = evaluate_polynomial_exactly (& coefficients,*input, shift);
          let difference = Ratio::from_integer (FromPrimitive::from_i64 (result).unwrap()) - perfect_result;
          assert!(difference < Ratio::from_integer (FromPrimitive::from_i64 (1).unwrap()));
        }
      }
    }
  }

  quickcheck! {
    fn exact_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range < 0 || safe_to_translate_polynomial_to (& coefficients, range, maxima)
    }

    fn exact_safe_translation_range_is_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", range);
      range == i64::max_value() || !safe_to_translate_polynomial_to (& coefficients, range + 1, maxima)
    }

    fn conservative_safe_translation_range_is_safe (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range <= exact_range
    }

    fn conservative_safe_translation_range_is_within_half_maximal (coefficients_and_maxima: Vec<(i64, i64)>)->bool {
      let coefficients: Vec<_> = coefficients_and_maxima.iter().map (| & (coefficient,_) | coefficient).collect();
      let maxima = | index: usize | coefficients_and_maxima [index].1;
      let exact_range = exact_safe_polynomial_translation_range (& coefficients, maxima);
      let conservative_range = conservative_safe_polynomial_translation_range (& coefficients, maxima);
      println!( "{:?}", (exact_range, conservative_range));
      conservative_range == exact_range || conservative_range > exact_range >> 1
    }
  }
}
<|endoftext|>


<commit_before>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Test that every method gives the correct result for valid values.
//! Except iterators, which are stateful.

use std::char;
use std::str::{self,FromStr};
use std::hash::Hash;
use std::collections::hash_map::DefaultHasher;
extern crate encode_unicode;
use encode_unicode::*;

#[test]
fn equal_defaults() {
    assert_eq!(Utf8Char::default().to_char(), char::default());
    assert_eq!(Utf16Char::default().to_char(), char::default());
}

#[test]
fn same_size_as_char() {
    use std::mem::size_of;
    assert_eq!(size_of::<Utf8Char>(), size_of::<char>());
    assert_eq!(size_of::<Utf16Char>(), size_of::<char>());
}

#[test]
#[cfg(feature="std")]
fn read_iterator() {
    use std::io::Read;
    use std::cmp::min;

    let uc = 'ä'.to_utf8();
    assert_eq!(uc.len(), 2);
    for chunk in 1..5 {
        let mut buf = [b'E'; 6];
        let mut iter = uc.into_iter();
        let mut written = 0;
        for _ in 0..4 {
            assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
            let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
            assert_eq!(wrote, min(2-written, chunk));
            written += wrote;
            for &b in &buf[written..] {assert_eq!(b, b'E');}
            assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
        }
        assert_eq!(written, 2);
    }
}

const EDGES_AND_BETWEEN: [u32;13] = [
    0x0,// min
    0x3b,// between
    0x7f,// max 1-byte UTF-8
    0x80,// min 2-byte UTF-8
    0x111,// between
    0x7ff,// max 2-byte UTF-8
    0x800,// min 3-byte UTF-8
    0xd7ff,// before reserved
    0xe000,// after reserved
    0xffff,// max UTF-16 single and 3-byte UTF-8
    0x10000,// min UTF-16 surrogate and 4-byte UTF-8
    0xabcde,// between
    0x10ffff,// max
];

fn eq_cmp_hash(c: char) -> (Utf8Char, Utf16Char) {
    let sh = &mut DefaultHasher::new();
    let u8c = c.to_utf8();
    assert_eq!(u8c.to_char(), c);
    assert_eq!(u8c.hash(sh), c.hash(sh));
    let u16c = c.to_utf16();
    assert_eq!(u16c.to_char(), c);
    assert_eq!(u16c.hash(sh), c.hash(sh));

    for other in &EDGES_AND_BETWEEN {
        let other = unsafe{ char::from_u32_unchecked(*other) };

        let u8other = other.to_utf8();
        assert_eq!(u8c == u8other,  c == other);
        assert_eq!(u8c.hash(sh)==other.hash(sh),  c.hash(sh)==u8other.hash(sh));
        assert_eq!(u8c.cmp(&u8other), c.cmp(&other));

        let u16other = other.to_utf16();
        assert_eq!(u16c == u16other,  c == other);
        assert_eq!(u16c.hash(sh)==other.hash(sh),  c.hash(sh)==u16other.hash(sh));
        assert_eq!(u16c.cmp(&u16other), c.cmp(&other));
    }
    (u8c, u16c)
}

fn iterators(c: char) {
    let mut iter = c.iter_utf8_bytes();
    let mut buf = [0; 4];
    let mut iter_ref = c.encode_utf8(&mut buf[..]).as_bytes().iter();
    for _ in 0..6 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }

    let mut iter = c.iter_utf16_units();
    let mut buf = [0; 2];
    let mut iter_ref = c.encode_utf16(&mut buf[..]).iter();
    for _ in 0..4 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }
}

fn test(c: u32) {
    let c = char::from_u32(c).expect(&format!("{:x} is not a valid char", c));
    assert_eq!(char::from_u32_detailed(c as u32), Ok(c));
    let (u8c, u16c) = eq_cmp_hash(c);
    iterators(c);

    // UTF-8
    let mut buf = [0; 4];
    let reference = c.encode_utf8(&mut buf[..]).as_bytes();
    let len = reference.len(); // short name because it is used in many places.
    assert_eq!(reference[0].extra_utf8_bytes(), Ok(len-1));
    assert_eq!(reference[0].extra_utf8_bytes_unchecked(), len-1);

    for i in c.len_utf8()..5 {
        let mut test_dst = [b'F';4];
        assert_eq!(c.to_utf8_slice(&mut test_dst[..i]), len);
        for b in &mut test_dst[len..] {// Test that it doesn't write too much
            assert_eq!(*b, b'F', "c={:?}, i={}, utf8_len={}", c, i, len);
            *b = 0;
        }
        assert_eq!(&test_dst[..len], reference);
        assert_eq!(AsRef::<[u8]>::as_ref(&u8c), reference);
        assert_eq!(u8c.to_array(), (test_dst, len));
    }
    let (mut arr,arrlen) = u8c.to_array();
    assert_eq!(arrlen, len);
    assert_eq!(Utf8Char::from_array(arr), Ok(u8c));
    assert_eq!(c.to_utf8_array(),  (arr, len));

    let str_ = str::from_utf8(reference).unwrap();
    let ustr = Utf8Char::from_str(str_).unwrap();
    assert_eq!(ustr.to_array().0, arr);// bitwise equality
    assert_eq!(char::from_utf8_array(arr), Ok(c));
    assert_eq!(char::from_utf8_slice(reference), Ok((c,len)));
    for b in arr.iter_mut().skip(arrlen) {
        *b = b'F';// from_slice_start must not read these.
    }
    assert_eq!(Utf8Char::from_slice_start(&arr), Ok((u8c,len)));// Test that it doesn't read too much
    assert_eq!(Utf8Char::from_slice_start(reference), Ok((u8c,len)));

    // UTF-16
    let mut buf = [0; 2];
    let reference = c.encode_utf16(&mut buf[..]);
    let len = reference.len();
    for i in c.len_utf16()..3 {
        let mut test_dst = [0;2];
        assert_eq!(c.to_utf16_slice(&mut test_dst[..i]), len);
        assert_eq!(&test_dst[..len], reference);
        assert_eq!(u16c.to_slice(&mut test_dst[..i]), len);
    }
    assert_eq!(reference[0].utf16_needs_extra_unit(), Some(len==2));
    assert_eq!(reference[0].utf16_is_leading_surrogate(), len==2);
    assert_eq!(char::from_utf16_slice(&reference[..len]), Ok((c,len)));
    let tuple = c.to_utf16_tuple();
    assert_eq!(tuple, (reference[0],reference.get(1).cloned()));
    assert_eq!(char::from_utf16_tuple(tuple), Ok(c));
    assert_eq!(c.to_utf16().to_char(), c);
}

#[test]
fn edges_middle() {
    for c in &EDGES_AND_BETWEEN {
        test(*c);
    }
}

#[test]
#[ignore]
fn all() {
    for c in std::iter::Iterator::chain(0..0xd800, 0xe000..0x110000) {
        test(c);
    }
}
<commit_msg>Test Utf16Char::as_ref()<commit_after>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Test that every method gives the correct result for valid values.
//! Except iterators, which are stateful.

use std::char;
use std::str::{self,FromStr};
use std::hash::Hash;
use std::collections::hash_map::DefaultHasher;
extern crate encode_unicode;
use encode_unicode::*;

#[test]
fn equal_defaults() {
    assert_eq!(Utf8Char::default().to_char(), char::default());
    assert_eq!(Utf16Char::default().to_char(), char::default());
}

#[test]
fn same_size_as_char() {
    use std::mem::size_of;
    assert_eq!(size_of::<Utf8Char>(), size_of::<char>());
    assert_eq!(size_of::<Utf16Char>(), size_of::<char>());
}

#[test]
#[cfg(feature="std")]
fn read_iterator() {
    use std::io::Read;
    use std::cmp::min;

    let uc = 'ä'.to_utf8();
    assert_eq!(uc.len(), 2);
    for chunk in 1..5 {
        let mut buf = [b'E'; 6];
        let mut iter = uc.into_iter();
        let mut written = 0;
        for _ in 0..4 {
            assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
            let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
            assert_eq!(wrote, min(2-written, chunk));
            written += wrote;
            for &b in &buf[written..] {assert_eq!(b, b'E');}
            assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
        }
        assert_eq!(written, 2);
    }
}

const EDGES_AND_BETWEEN: [u32;13] = [
    0x0,// min
    0x3b,// between
    0x7f,// max 1-byte UTF-8
    0x80,// min 2-byte UTF-8
    0x111,// between
    0x7ff,// max 2-byte UTF-8
    0x800,// min 3-byte UTF-8
    0xd7ff,// before reserved
    0xe000,// after reserved
    0xffff,// max UTF-16 single and 3-byte UTF-8
    0x10000,// min UTF-16 surrogate and 4-byte UTF-8
    0xabcde,// between
    0x10ffff,// max
];

fn eq_cmp_hash(c: char) -> (Utf8Char, Utf16Char) {
    let sh = &mut DefaultHasher::new();
    let u8c = c.to_utf8();
    assert_eq!(u8c.to_char(), c);
    assert_eq!(u8c.hash(sh), c.hash(sh));
    let u16c = c.to_utf16();
    assert_eq!(u16c.to_char(), c);
    assert_eq!(u16c.hash(sh), c.hash(sh));

    for other in &EDGES_AND_BETWEEN {
        let other = unsafe{ char::from_u32_unchecked(*other) };

        let u8other = other.to_utf8();
        assert_eq!(u8c == u8other,  c == other);
        assert_eq!(u8c.hash(sh)==other.hash(sh),  c.hash(sh)==u8other.hash(sh));
        assert_eq!(u8c.cmp(&u8other), c.cmp(&other));

        let u16other = other.to_utf16();
        assert_eq!(u16c == u16other,  c == other);
        assert_eq!(u16c.hash(sh)==other.hash(sh),  c.hash(sh)==u16other.hash(sh));
        assert_eq!(u16c.cmp(&u16other), c.cmp(&other));
    }
    (u8c, u16c)
}

fn iterators(c: char) {
    let mut iter = c.iter_utf8_bytes();
    let mut buf = [0; 4];
    let mut iter_ref = c.encode_utf8(&mut buf[..]).as_bytes().iter();
    for _ in 0..6 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }

    let mut iter = c.iter_utf16_units();
    let mut buf = [0; 2];
    let mut iter_ref = c.encode_utf16(&mut buf[..]).iter();
    for _ in 0..4 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }
}

fn test(c: u32) {
    let c = char::from_u32(c).expect(&format!("{:x} is not a valid char", c));
    assert_eq!(char::from_u32_detailed(c as u32), Ok(c));
    let (u8c, u16c) = eq_cmp_hash(c);
    iterators(c);

    // UTF-8
    let mut buf = [0; 4];
    let reference = c.encode_utf8(&mut buf[..]).as_bytes();
    let len = reference.len(); // short name because it is used in many places.
    assert_eq!(reference[0].extra_utf8_bytes(), Ok(len-1));
    assert_eq!(reference[0].extra_utf8_bytes_unchecked(), len-1);
    assert_eq!(AsRef::<[u8]>::as_ref(&u8c), reference);

    for i in c.len_utf8()..5 {
        let mut test_dst = [b'F';4];
        assert_eq!(c.to_utf8_slice(&mut test_dst[..i]), len);
        for b in &mut test_dst[len..] {// Test that it doesn't write too much
            assert_eq!(*b, b'F', "c={:?}, i={}, utf8_len={}", c, i, len);
            *b = 0;
        }
        assert_eq!(&test_dst[..len], reference);
        assert_eq!(u8c.to_array(), (test_dst, len));
    }
    let (mut arr,arrlen) = u8c.to_array();
    assert_eq!(arrlen, len);
    assert_eq!(Utf8Char::from_array(arr), Ok(u8c));
    assert_eq!(c.to_utf8_array(),  (arr, len));

    let str_ = str::from_utf8(reference).unwrap();
    let ustr = Utf8Char::from_str(str_).unwrap();
    assert_eq!(ustr.to_array().0, arr);// bitwise equality
    assert_eq!(char::from_utf8_array(arr), Ok(c));
    assert_eq!(char::from_utf8_slice(reference), Ok((c,len)));
    for b in arr.iter_mut().skip(arrlen) {
        *b = b'F';// from_slice_start must not read these.
    }
    assert_eq!(Utf8Char::from_slice_start(&arr), Ok((u8c,len)));// Test that it doesn't read too much
    assert_eq!(Utf8Char::from_slice_start(reference), Ok((u8c,len)));

    // UTF-16
    let mut buf = [0; 2];
    let reference = c.encode_utf16(&mut buf[..]);
    let len = reference.len();
    for i in c.len_utf16()..3 {
        let mut test_dst = [0;2];
        assert_eq!(c.to_utf16_slice(&mut test_dst[..i]), len);
        assert_eq!(&test_dst[..len], reference);
        assert_eq!(u16c.to_slice(&mut test_dst[..i]), len);
    }
    assert_eq!(reference[0].utf16_needs_extra_unit(), Some(len==2));
    assert_eq!(reference[0].utf16_is_leading_surrogate(), len==2);
    assert_eq!(u16c.as_ref(), reference);
    assert_eq!(char::from_utf16_slice(&reference[..len]), Ok((c,len)));
    let tuple = c.to_utf16_tuple();
    assert_eq!(tuple, (reference[0],reference.get(1).cloned()));
    assert_eq!(char::from_utf16_tuple(tuple), Ok(c));
    assert_eq!(c.to_utf16().to_char(), c);
}

#[test]
fn edges_middle() {
    for c in &EDGES_AND_BETWEEN {
        test(*c);
    }
}

#[test]
#[ignore]
fn all() {
    for c in std::iter::Iterator::chain(0..0xd800, 0xe000..0x110000) {
        test(c);
    }
}
<|endoftext|>


<commit_before>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count => 3 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args").map_or(vec![], |m| shlex::split(m.as_str()).unwrap());

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;

                    match select(&val, &command.args[1]) {
                        Ok(results) => !results.is_empty(),
                        Err(_) => false,
                    }
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    match select(&val, &command.args[1]) {
                        Ok(results) => {
                            let pat: Value = serde_json::from_str(&command.args[2]).unwrap();

                            !results.is_empty() && results.into_iter().any(|val| *val == pat)
                        }
                        Err(_) => false,
                    }
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => results.len() == expected,
                Err(_) => false,
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}
<commit_msg>Make bad shlex parsing a pretty error<commit_after>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count => 3 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args")
            .map_or(Some(vec![]), |m| shlex::split(m.as_str()));

        let args = match args {
            Some(args) => args,
            None => {
                print_err(
                    &format!("Invalid arguments to shlex::split: `{}`", cap.name("args").unwrap().as_str()),
                    lineno
                );
                errors = true;
                continue;
            }
        };

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;

                    match select(&val, &command.args[1]) {
                        Ok(results) => !results.is_empty(),
                        Err(_) => false,
                    }
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    match select(&val, &command.args[1]) {
                        Ok(results) => {
                            let pat: Value = serde_json::from_str(&command.args[2]).unwrap();

                            !results.is_empty() && results.into_iter().any(|val| *val == pat)
                        }
                        Err(_) => false,
                    }
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => results.len() == expected,
                Err(_) => false,
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}
<|endoftext|>